diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..12994ad5 --- /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: 185f4b5bbc10bfdea4af823f9ba0f58d +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/02-teaching-philosophies/index.html b/02-teaching-philosophies/index.html new file mode 100644 index 00000000..13811075 --- /dev/null +++ b/02-teaching-philosophies/index.html @@ -0,0 +1,376 @@ + + + + + + + CodeRefinery teaching philosophies — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery teaching philosophies

+
+

Ice-breaker in groups (20 minutes)

+
    +
  • Share your approach to teaching and your teaching philosophy with your group.

  • +
  • Please share your tricks and solutions in the live document for others.

  • +
+

Additional ice-breaker questions:

+
    +
  • What is your motivation for taking this training?

  • +
  • How structured or informal are your own teaching needs?

  • +
  • What difference do you notice between the teaching what we (also +Carpentries) do and traditional academic teaching?

  • +
  • What other skills need to be taught, but academic teaching isn’t the right setting?

  • +
+
+
+

Here CodeRefinery instructors share their training philosophy to show that we +all have different teaching styles and how these differences are beneficial to +CodeRefinery workshops.

+

It is important to explain how much we value individuals and that there is not +one way to teach but as many ways as individuals. We want to help each other to +find the way that is best for each of us.

+
+

Video recordings

+

Recently we have recorded some of the below as videos: +https://www.youtube.com/playlist?list=PLpLblYHCzJAAHF89P-GCjEXWC8CF-7nhX

+
+
+

Anne Fouilloux

+

I regularly teach Carpentries workshops so I try to apply what I have learnt to CodeRefinery workshops. However, I know our target audience is very much different and that I need to adapt my teaching style. I am still trying to find what works best in which situations and this is why I like so much CodeRefinery workshops. We usually have a wider range of skills and very mixed backgrounds so we usually have to be more careful with the pace and time given for exercises.

+

Some considerations:

+
    +
  • I spend quite a lot of time reading the CodeRefinery material and practising myself exercises. I particularly like to read the instructor notes just before teaching: they usually highlight important aspects both for preparing and teaching.

  • +
  • I usually do not show too much in advance the material as I think it prevents asking questions. If you have less competent practitioners in the classroom, they can easily copy-paste to avoid slowing down the entire classroom.

  • +
  • Ideally, I’d like to give several exercises so anyone can work at its own pace. I find it is important that everybody gets something different from the workshop.

  • +
  • I love breaks as it gives us an opportunity to discuss with attendees on their research topics. I am especially interested to understand what software they write and how they plan to use what they learn during our workshops.

  • +
+
+
+

Bjørn Lindi

+

My teaching style has changed a bit since I started with CodeRefinery. In the beginning I had this “BLOB” (Binary Large OBject) of knowledge and experience that I wanted to to convey to the participants. With experience and some help from the Carpentries Instructor training, I have realized I need to serialize the “BLOB”, to be able to share it with others.

+

In a similar fashion as you would do with a binary large object which you intend to send over the wire, you will need stop signals, check-sums and re-transmissions, when you give a lecture. I have come to appreciate the natural periods/breaks the lessons offers, the questions raised, the errors that appear during type-along and the re-transmission. Co-instructors are good to use for re-transmission or broadening a specific topic.

+

When I started with CodeRefinery my inclination was to give a lecture. Today I am trying to be a guide during a learning experience, a learning experience which includes me as well. That may sound a bit self-centric, but is in fact the opposite, as I have to be more sensitive to what is going on in the room. The more conscious I am of being a guide, the better lesson.

+

Tools that I find useful in preparing a lesson is concept maps and Learner Personas, though I have develop to few them.

+ +
+
+

Thor Wikfeldt

+

I never want to leave any learner behind and I really don’t like seeing confused, blank faces in the classroom. +At the same time I sometimes worry about some participants getting bored if a lesson is progressing slowly. +This is always a difficult compromise and something I struggle with!

+

I try to focus on making concepts intuitive, to “make sense” to the learners. Of course this is usually +based on how I learned the topic myself and how it makes sense to me.

+

I try to establish connections between topics: “this thing here is similar to what we saw in the previous +lesson where we learned about X…”.

+

Before mastering a lesson by teaching in many times I try to “follow the script”. After becoming very +familiar with a lesson I start to improvise more and react more dynamically to questions, e.g. by taking a +detour to explain a confusing topic more clearly.

+

What I think I do too often: copy-paste code/text from lesson material. This can leave learners behind - +typing out the code and describing it is slower, but more learning takes place. More advanced learners +will hopefully “be compensated” by interesting advanced exercises which follow.

+
+
+

Stefan Negru

+

A lesson is a conversation, it is useful if both the trainer and the trainee are engaged. +For that reason I try to have, most of the time, a conversation with the classroom and +after we finish parts of a lesson, step back and see how we might use what we learned.

+

That brings me to another point I follow throughout the lessons, answering questions like:

+
    +
  • How can we apply in practice what we just learned?

  • +
  • Do you see yourself (the trainee) using that in practice, why or why not?

  • +
+

Most of the times those seem like open-ended questions to the trainees that just learned +something new, so I try to find examples, most of the times from personal experience.

+

Last thing is that analogies are important when I teach, I try to find analogies in order +to simplify a convoluted part of a lesson.

+
+
+

Radovan Bast

+

My teaching changed by 180 degrees after taking the Carpentries instructor +training. Before that I used slides, 45 minute lecture blocks, and separate +exercise sessions. After the Carpentries instructor training I embraced the +interaction, exercises, demos, and typos.

+

My goal for a lesson is to spark curiosity to try things after the lesson, +both for the novices (“This looks like a useful tool, I want to try using it +after the workshop.”) and the more experienced participants (“Aha - I did not +know you could do this. I wonder whether I can make it work with X.”). I like +to start lessons with a question because this makes participants look up from +their browsers.

+

Keeping both the novices and the experts engaged during a lesson can be +difficult and offering additional exercises seems to be a good compromise.

+

For me it is a good sign if there are many questions. I like to encourage +questions by asking questions to the participants. But I also try not to go +into a rabbit hole when I get a question where only experts will appreciate +the answer.

+

I try to avoid jargon and “war stories” from the professional developers’ +perspective or the business world. Most researchers may not relate to them. +For examples I always try to use the research context. Avoid “customer”, +“production”, also a lot of Agile jargon is hard to relate to.

+

Less and clear is better than more and unclear. Simple examples are better +than complicated examples. Almost never I have felt or got the feedback that +something was too simple. I am repeating in my head to not use the words +“simply”, “just”, “easy”. If participants take home one or two points from +a lesson, that’s for me success.

+

I prepare for the lesson by reading the instructor guide and all issues and +open pull requests. I might not be able to solve issues, but I don’t want to +be surprised by known issues. I learn the material to a point where I know +precisely what comes next and am never surprised by the next episode or +slide. This allows me to skip and distill the essence and not read bullet +point by bullet point.

+

I try to never deviate from the script and if I do, be very explicit about +it.

+

A great exercise I can recommend is to watch a tutorial on a new programming +language/tool you have never used. It can feel very overwhelming and fast to +get all these new concepts and tools thrown at self. This can prepare me for +how a participant might feel.

+

I find it very helpful if there is somebody else in the room who helps me +detecting when I go too fast or become too confusing. I like when two +instructors complement each other during a lesson but when doing that to +others, I am often worried of interrupting their flow and timing too much.

+

A mistake I often do is to type too fast and in my mind I force myself +to slow down.

+
+
+

Sabry Razick

+

My approach is to show it is fun to demystify concepts. Once a concept is +not a mystery anymore, the learners will understand is what it means, where +it is coming from, why it is in place and what it could it offer for their future. +I try to relate concepts to real life with a twist of humour whenever possible if +the outcome is certain not be offensive to any one. I use diagrams whenever possible, +I have spent weeks creating diagrams that is sometime three or four sentences. That +effort I consider worthwhile as my intention is not to teach, but to demystify. +Once that is achieved, learners will learn the nitty gritty on their own easily +and with confidence, when they have the use-case.

+
+
+

Juho Lehtonen

+

I’m gradually realising the different ways to get a hint whether the workshop +participants are still following or perhaps bored. I assume it’s communicating +with the class, with exercises and simply by asking now and then. I also try +to remember to observe how people look like (puzzled, bored) while I teach, not +so obvious for me.

+

I believe that learners communicating with each other, in addition to with +instructors and helpers, really helps them to understand things faster. (At least +it helps me). So I try to make sure that no one sits or works alone at the workshops.

+
+
+

Richard Darst

+

Like many people, I’ve often been teaching, but rarely a teacher. I +tend to teach like I am doing an informal mentorship. +I’ve realized long ago that my most important lessons weren’t +learned in classes, but by a combination of seeing things done by +friends and independent study after that. I’ve realized that +teaching (the things I teach) is trying to correct these differences +in backgrounds.

+

My main job is supporting computing infrastructure, so my teaching +is very grounded in real-world problems. I’m often start at the +very basics, because this is what I see missing most often.

+

When teaching, I like lots of audience questions and don’t mind +going off-script a bit (even though I know it should be minimized). +I find that sufficient audience interest allows any lesson to be a +success - you don’t have to know everything perfectly, just show how +you’d approach a problem.

+
+
+

João M. da Silva

+

I started giving technical trainings twenty years ago, and hence my perspective +is perhaps more inclined towards the development of hands-on abilities and +capability to solve problems, independently or in a team.

+

But the development of hands-on practical skills, requires some essential +knowledge about the domain and some willingness to try different approaches +in case one gets stuck. Some call this the “KSA approach” +(“Knowledge-Skills-Attitude). Hence, I +try to impart the essential knowledge (and where to find out more) at my +trainings. And to encourage and challenge students in order to make them +overcome their self-perceived limits (e.g. “I’m a Humanist, I can’t use +Python virtualenv”).

+

I’ve been trying to study more about the Cognitive aspects of learning over the years, +and I should find out the time to return to that. There’s very interesting +research in Problem Solving, with Learning being a important component in that domain.

+

Storytelling: humans are neurologically made for paying attention to good +stories, and that’s something that I try to put into account: to give +a lesson like it would be a relevant narrative for the students, one that they +could relate to and help them in their work

+

I like to draw and be creative with that, but have to pay attention to +my handwriting during my trainings. I reckon that Architectural diagrams +help students to understand the big picture, so I should invest more on +those when development training material. I would also like to start looking into +Concept Maps and Semantic Trees in training.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/03-teaching-style/index.html b/03-teaching-style/index.html new file mode 100644 index 00000000..866db22e --- /dev/null +++ b/03-teaching-style/index.html @@ -0,0 +1,507 @@ + + + + + + + Interactive teaching style — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interactive teaching style

+
+

What are the top issues new instructors face?

+ +
+
+
+

The Carpentries and CodeRefinery approaches to teaching

+

Here we will give you a very short overview of the Carpentries approach to teaching and highlight +parts that are most important for teaching CodeRefinery style lessons.

+

Most CodeRefinery instructors have completed the +Carpentry instructor training workshop, which +anyone can apply for

+
+

This material

+

This section is derived from the +Carpentries instructor training material. +We encourage you to further study this material later, and to sign up for a 2-day Carpentry +intructor training workshop.

+
+
+
+

Key principles

+

The “Carpentries” approach to teaching is based on:

+
    +
  • Applying research-based teaching principles, especially as they apply to the +Carpentries audience.

  • +
  • Understanding the importance of a respectful and inclusive classroom environment.

  • +
+
+

Carpentries teaching principles

+
    +
  • Learners need to practice what they are learning in real time and get feedback on what they +are doing. That is why the teaching approach relies on live coding.

  • +
  • Learners best learn in a respectful classroom environment, so the Carpentries use a +Code of Conduct.

  • +
  • Learners are encouraged to help each other during workshops as this improves their confidence +and reinforces concepts taught.

  • +
  • Carpentry instructors try to have learners do something that they think is useful in their +daily work within 15 minutes of starting each lesson.

  • +
+

What to Teach

+

In CodeRefinery, we follow The Carpentries teaching principles but in addition to live coding +we often use group discussions to put in context the concepts we are teaching.

+

Applying these teaching principles are not sufficient and in addition we need to be able to check +the effectiveness of our methods.

+
+
+
+
+

On the importance of feedback

+

Feedback is an essential part of effective learning. Feedback is bi-directional:

+
    +
  • To be effective, instructors need feedback on their learners’ progress. Learners can also check their progress and ask relevant questions to get clarification.

  • +
  • Instructors also need feedback on their teaching. For instance, this can help them to adapt the pace, add/skip optional exercises and improve their teaching.

  • +
+
+

Getting/giving feedback on learners’ progress

+

This feedback comes through what is called formative assessments (in contrast +to summative assessment).

+
+

Summative Assessment

+

Summative assessment is used +to judge whether a learner has reached an acceptable level of competence. +Usually at the end of a course +Learners either “pass” or “fail” a summative assessment. +One example is a driving exam, +which tells the rest of society whether someone can safely be allowed on the road. Most assessment done in university +courses is summative, and is used to assign course grades.

+
+
+

Formative assessment

+

Formative assessment takes place during teaching and learning. It sounds like +a fancy term, but it can be used to describe any interaction or activity +that provides feedback to both instructors and learners about learners’ level of understanding of the +material. For learners, this feedback can help focus their study efforts. For instructors, it allows them to refocus +their instruction to respond to challenges that learners are facing. +Used continuously

+
+

Learners don’t “pass” or “fail” formative assessments; they are simply a feedback mechanism. +For example, a music teacher might ask a learner to play a scale very slowly +in order to see whether they are breathing correctly, +and if not, what they should change.

+

Formative assessment is most useful when it happens frequently (we’ll talk about how frequently later) +and when the results are easily interpretable by the learner and instructor.

+

CodeRefinery uses different instruments to get feedback from learners:

+
    +
  • Surveys: we will discuss about CodeRefinery pre/post-surveys in the episode +Running a workshop: online.

  • +
  • Exercises: we have many exercises during CodeRefinery workshops and use polls too but not necessarily many multiple-choice questions. +This is something that we may change in the future but the initial reason was that we build on existing knowledge +(see below section on our target audience) and give recommendations for best software practices: +there is no unique solution and you would like our learners to choose the approach that is most suitable for them. +For the same reasons, we have many optional exercises to accommodate the different levels. +We would like everyone to get something useful out of the CodeRefinery workshops.

  • +
+
+
+

Getting/giving feedback on teaching

+

Teaching is a skill. One of the objective of the CodeRefinery Instructor training is to give you +the confidence in teaching CodeRefinery lessons. Later we will have group work where we will +practice teaching some lessons.

+

Before doing so, we will learn here to give feedback on teaching using the same +positive-vs-negative and content-vs-presentation rubric.

+
+

Give feedback on teaching (optional, 10 mn)

+

This exercise aims at learning to give feedback. It is optional as we have +similar exercises when practising teaching). +As a group, we will watch this video of teaching and +give feedback on two axes: positive vs. negative and content vs. presentation. Have each person in +the class add one point to a 2x2 grid on a whiteboard or in the shared notes (hackMD, etherpad, google doc) without duplicating any points. +For online instructor training event, use breakout room (4-5 persons per group) to facilitate discussion. Then each group reports to the shared notes. +You can use a rubric (used during The Carpentries teaching demos) to help you take notes. +What did other people see that you missed? What did they think that you strongly agree or disagree with?

+
+
+
+
+
+

Who are the learners

+

The first task in teaching is to figure out who your learners are. The Carpentries approach is +based on the work of researchers like Patricia Benner, +who applied the +Dreyfus model of skill acquisition +in her studies of +how nurses progress from novice to expert +(see also books by Benner). +This work indicates that through practice and formal instruction, learners acquire skills and advance +through distinct stages. In simplified form, the three stages of this model are:

+
+

Novices, competent practitioners and experts

+

Novice, Competent Practitioner, Expert

+
    +
  • Novice: someone who doesn’t know what they don’t know, i.e., +they don’t yet know what the key ideas in the domain are or how they relate. +One sign that someone is a novice is that their questions “aren’t even wrong”.

    +
      +
    • Example: A novice learner in a Carpentries workshop might never have heard of the bash +shell, and therefore may have no understanding of how it relates to their file system or +other programs on their computer.

    • +
    • Example HPC: A learner who has never executed a program on remote computer in headless mode

    • +
    • Example HPC: A learner who has no understanding about using a queue system and having a +hard time why a program can not be run directly after login in.

    • +
    +
  • +
  • Competent practitioner: someone who has enough understanding for everyday purposes. +They won’t know all the details of how something works and their understanding may not +be entirely accurate, but it is sufficient for completing normal tasks with normal +effort under normal circumstances.

    +
      +
    • Example: A competent practitioner in a Carpentries workshop might have used the shell +before and understand how to move around directories and use individual programs, but +they might not understand how they can fit these programs together to build scripts +and automate large tasks.

    • +
    • Example: A competent practitioner in a CodeRefinery workshop is someone that understands +the concepts of best software practices and its importance. He/she clearly sees the +benefits of applying best software practices but he/she does not fully know yet how and +what to use for their own projects.

    • +
    • Example HPC: Knows how to establish a connection to a cluster and have submitted jobs. +But may not know how to request optimal amount of resources in a job and how to setup +parallel jobs

    • +
    +
  • +
  • Expert: someone who can easily handle situations that are out of the ordinary.

    +
      +
    • Example: An expert in a Carpentries workshop may have experience writing and running shell +scripts and, when presented with a problem, immediately sees how these skills can be used +to solve the problem.

    • +
    • Example HPC: A learner who has a good understanding of the queue system, parallel processing +and understand how to interpret error reports when something goes wrong and knows how to +get help.

    • +
    +
  • +
+
+
+

Cognitive Development and Mental Models

+

Effective learning is facilitated by the creation of a well-founded mental model. A mental model +is a collection of concepts and facts, along with the relationships between those concepts, which +a person has about a topic. For example, a long-time resident of the United States may have an +advanced understanding of the location of US states, major cities and landmarks, weather patterns, +regional economies and demographic patterns, as well as the relationships among these, compared +with their understanding of these relationships for other countries. In other words, their mental +model of the United States is more complex compared with their mental model of other countries.

+

We can distinguish between a novice and a competent practitioner for a given domain based +on the complexity of their mental models.

+
    +
  • A novice is someone who has not yet built a mental model of the domain. +They therefore reason by analogy and guesswork, borrowing bits and pieces +of their mental models of other domains which seem superficially similar.

  • +
  • A competent practitioner is someone who has a mental model that’s good enough +for everyday purposes. This model does not have to be completely accurate in order +to be useful: for example, the average driver’s mental model of how a car works +probably doesn’t include most of the complexities that a mechanical engineer +would be concerned with.

  • +
+

We could expect a mixture of learners from novice and competent practitioner groups +in HPC training events.

+

Mental Models

+
+
+
+

How “knowledge” gets in the way

+

Mental models are hardly ever built from scratch. Every learner comes to a topic with +some amount of information, ideas and opinions about the topic. This is true even in +the case where a learner can’t articulate their prior knowledge and beliefs.

+

In many cases, this prior knowledge is incomplete or inaccurate. Inaccurate beliefs +can be termed “misconceptions” and can impede learning by making it more difficult for +learners to incorporate new, correct information into their mental models. +Correcting learners’ misconceptions is at least as important as presenting them with +correct information. Broadly speaking, misconceptions fall into three categories:

+
    +
  • Simple factual errors, such as believing that Vancouver is the capital of +British Columbia. These are the easiest to correct.

  • +
  • Broken models, such as believing that motion and acceleration must be in the +same direction. We can address these by having learners reason through examples to +see contradictions.

  • +
  • Fundamental beliefs, such as “the world is only a few thousand years old” or +“human beings cannot affect the planet’s climate”. These beliefs are deeply connected +to the learner’s social identity and are the hardest to change.

  • +
+

The current HPC carpentry workshop material are aimed at Novice of HPC

+

Among Novice learners there might be learners who are experts in their domain and very +competent in the program they are executing, but may not have used a HPC system before. +Then among the competent practitioners There might be learners who repeat some procedures +they have inherited but lack a in-depth understanding of what’s going on. That is why it is +important to get accurate feedback, before and during the workshops to understand the learner profiles.

+
+

Exercise: How to identify learner profiles?

+
    +
  1. How to identify leaner profiles from surveys and during the class

  2. +
  3. Which types of learners should the leassons focus on

  4. +
+
+
+
+
+
+

CodeRefinery Curriculum and Reverse Instructional Design (with recommendations for HPC carpentries)

+

When writing a CodeRefinery lesson, we take a “reverse” approach to instruction, +as described in Wiggins and McTighe’s +Understanding by Design, +that keeps the focus firmly on learning outcomes. The order of preparation in this case becomes

+
    +
  • Determine your learning objectives

  • +
  • Decide what constitutes evidence that objectives have been met, and design assessments +to target that evidence

  • +
  • Design instruction: Sort assessments in order of increasing complexity, +and write content that connects everything together

  • +
+
+

Working with learning objectives

+

Each CodeRefinery lesson (also the HPC capentries lessons) usually has a learning objectives section. +Good learning objectives are quite specific about the intended effect of a lesson on its learners. +We aim to create learning objectives that are specific, accurate, and informative for +both learners and instructors.

+
+
+

Using Bloom’s Taxonomy to write effective learning objectives

+

Bloom’s Taxonomy is a framework for thinking about learning that breaks progress down into discrete, hierarchical steps. +While many ideas have come and gone in education, Bloom’s has remained a useful tool for educators, in particular because the +hierarchy seems to be reasonably valid: outcomes at the top of the hierarchy cannot be achieved without mastery of outcomes at +the bottom. In the long term, everybody wants to be at the top. However, in aiming to meet learners where they are, we also +need to be mindful about helping them to “grow a level,” helping them to recognize when they have achieved that growth, and +guiding them to look ahead to where we might not be able to take them.

+

Bloom's Taxonomy

+

Image credit: Vanderbilt University Center for Teaching

+
+
+

Revisiting Learning objectives

+

When using existing teaching material, reverse instructional design principles might be applied as +follows:

+
    +
  1. Review the lesson’s learning objectives carefully, thinking about how they will work for your audience

  2. +
  3. Scan the lesson to identify promising points to check in with your learners, using formative assessment to verify that objectives have been met

  4. +
  5. Review the connecting content in detail to be sure everything works and you have anticipated likely problems and questions.

  6. +
+

We strongly encourage you to read them before teaching a lesson and to review whether they still match the content of the lesson:

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_sources/02-teaching-philosophies.md.txt b/_sources/02-teaching-philosophies.md.txt new file mode 100644 index 00000000..66bae95b --- /dev/null +++ b/_sources/02-teaching-philosophies.md.txt @@ -0,0 +1,237 @@ +--- +layout: episode +title: "Our teaching philosophies" +teaching: 0 +exercises: 30 +questions: + - "What are our teaching philosophies?" +--- + +# CodeRefinery teaching philosophies + +> ## Ice-breaker in groups (20 minutes) +> +> - Share your approach to teaching and your teaching philosophy with your group. +> - Please share your tricks and solutions in the live document for others. +> +> Additional ice-breaker questions: +> - What is your motivation for taking this training? +> - How structured or informal are your own teaching needs? +> - What difference do you notice between the teaching what we (also +> Carpentries) do and traditional academic teaching? +> - What other skills need to be taught, but academic teaching isn't the right setting? +{: .challenge} + +--- + +Here CodeRefinery instructors share their training philosophy to show that we +all have different teaching styles and how these differences are beneficial to +CodeRefinery workshops. + +It is important to explain how much we value individuals and that there is not +one way to teach but as many ways as individuals. We want to help each other to +find the way that is best for each of us. + +> ## Video recordings +> +> Recently we have recorded some of the below as videos: +> +{: .prereq} + +> ## Anne Fouilloux +> +> I regularly teach Carpentries workshops so I try to apply what I have learnt to CodeRefinery workshops. However, I know our target audience is very much different and that I need to adapt my teaching style. I am still trying to find what works best in which situations and this is why I like so much CodeRefinery workshops. We usually have a wider range of skills and very mixed backgrounds so we usually have to be more careful with the pace and time given for exercises. +> +> Some considerations: +> - I spend quite a lot of time reading the CodeRefinery material and practising myself exercises. I particularly like to read the instructor notes just before teaching: they usually highlight important aspects both for preparing and teaching. +> - I usually do not show too much in advance the material as I think it prevents asking questions. If you have less competent practitioners in the classroom, they can easily copy-paste to avoid slowing down the entire classroom. +> - Ideally, I'd like to give several exercises so anyone can work at its own pace. I find it is important that everybody gets something different from the workshop. +> - I love breaks as it gives us an opportunity to discuss with attendees on their research topics. I am especially interested to understand what software they write and how they plan to use what they learn during our workshops. +{: .challenge} + +> ## Bjørn Lindi +> +> My teaching style has changed a bit since I started with CodeRefinery. In the beginning I had this "BLOB" (Binary Large OBject) of knowledge and experience that I wanted to to convey to the participants. With experience and some help from the Carpentries Instructor training, I have realized I need to serialize the "BLOB", to be able to share it with others. +> +>In a similar fashion as you would do with a binary large object which you intend to send over the wire, you will need stop signals, check-sums and re-transmissions, when you give a lecture. I have come to appreciate the natural periods/breaks the lessons offers, the questions raised, the errors that appear during type-along and the re-transmission. Co-instructors are good to use for re-transmission or broadening a specific topic. +> +>When I started with CodeRefinery my inclination was to give a lecture. Today I am trying to be a guide during a learning experience, a learning experience which includes me as well. That may sound a bit self-centric, but is in fact the opposite, as I have to be more sensitive to what is going on in the room. The more conscious I am of being a guide, the better lesson. +> +>Tools that I find useful in preparing a lesson is concept maps and Learner Personas, though I have develop to few them. +>- [Concept Maps](https://teachtogether.tech/#s:memory-concept-maps) +>- [Learner Personas](https://teachtogether.tech/#s:process-personas) +{: .challenge} + +> ## Thor Wikfeldt +> +> I never want to leave any learner behind and I really don't like seeing confused, blank faces in the classroom. +> At the same time I sometimes worry about some participants getting bored if a lesson is progressing slowly. +> This is always a difficult compromise and something I struggle with! +> +> I try to focus on making concepts intuitive, to "make sense" to the learners. Of course this is usually +> based on how I learned the topic myself and how it makes sense to me. +> +> I try to establish connections between topics: "this thing here is similar to what we saw in the previous +> lesson where we learned about X...". +> +> Before mastering a lesson by teaching in many times I try to "follow the script". After becoming very +> familiar with a lesson I start to improvise more and react more dynamically to questions, e.g. by taking a +> detour to explain a confusing topic more clearly. +> +> What I think I do too often: copy-paste code/text from lesson material. This can leave learners behind - +> typing out the code and describing it is slower, but more learning takes place. More advanced learners +> will hopefully "be compensated" by interesting advanced exercises which follow. +{: .challenge} + +> ## Stefan Negru +> +> A lesson is a conversation, it is useful if both the trainer and the trainee are engaged. +> For that reason I try to have, most of the time, a conversation with the classroom and +> after we finish parts of a lesson, step back and see how we might use what we learned. +> +> That brings me to another point I follow throughout the lessons, answering questions like: +> * How can we apply in practice what we just learned? +> * Do you see yourself (the trainee) using that in practice, why or why not? +> +> Most of the times those seem like open-ended questions to the trainees that just learned +> something new, so I try to find examples, most of the times from personal experience. +> +> Last thing is that analogies are important when I teach, I try to find analogies in order +> to simplify a convoluted part of a lesson. +{: .challenge} + +> ## Radovan Bast +> +> My teaching changed by 180 degrees after taking the Carpentries instructor +> training. Before that I used slides, 45 minute lecture blocks, and separate +> exercise sessions. After the Carpentries instructor training I embraced the +> interaction, exercises, demos, and typos. +> +> My goal for a lesson is to spark curiosity to try things after the lesson, +> both for the novices ("This looks like a useful tool, I want to try using it +> after the workshop.") and the more experienced participants ("Aha - I did not +> know you could do this. I wonder whether I can make it work with X."). I like +> to start lessons with a question because this makes participants look up from +> their browsers. +> +> Keeping both the novices and the experts engaged during a lesson can be +> difficult and offering additional exercises seems to be a good compromise. +> +> For me it is a good sign if there are many questions. I like to encourage +> questions by asking questions to the participants. But I also try not to go +> into a rabbit hole when I get a question where only experts will appreciate +> the answer. +> +> I try to avoid jargon and "war stories" from the professional developers' +> perspective or the business world. Most researchers may not relate to them. +> For examples I always try to use the research context. Avoid "customer", +> "production", also a lot of Agile jargon is hard to relate to. +> +> Less and clear is better than more and unclear. Simple examples are better +> than complicated examples. Almost never I have felt or got the feedback that +> something was too simple. I am repeating in my head to not use the words +> "simply", "just", "easy". If participants take home one or two points from +> a lesson, that's for me success. +> +> I prepare for the lesson by reading the instructor guide and all issues and +> open pull requests. I might not be able to solve issues, but I don't want to +> be surprised by known issues. I learn the material to a point where I know +> precisely what comes next and am never surprised by the next episode or +> slide. This allows me to skip and distill the essence and not read bullet +> point by bullet point. +> +> I try to never deviate from the script and if I do, be very explicit about +> it. +> +> A great exercise I can recommend is to watch a tutorial on a new programming +> language/tool you have never used. It can feel very overwhelming and fast to +> get all these new concepts and tools thrown at self. This can prepare me for +> how a participant might feel. +> +> I find it very helpful if there is somebody else in the room who helps me +> detecting when I go too fast or become too confusing. I like when two +> instructors complement each other during a lesson but when doing that to +> others, I am often worried of interrupting their flow and timing too much. +> +> A mistake I often do is to type too fast and in my mind I force myself +> to slow down. +{: .challenge} + +> ## Sabry Razick +> My approach is to show it is fun to demystify concepts. Once a concept is +> not a mystery anymore, the learners will understand is what it means, where +> it is coming from, why it is in place and what it could it offer for their future. +> I try to relate concepts to real life with a twist of humour whenever possible if +> the outcome is certain not be offensive to any one. I use diagrams whenever possible, +> I have spent weeks creating diagrams that is sometime three or four sentences. That +> effort I consider worthwhile as my intention is not to teach, but to demystify. +> Once that is achieved, learners will learn the nitty gritty on their own easily +> and with confidence, when they have the use-case. +> +> +{: .challenge} + +> ## Juho Lehtonen +> I'm gradually realising the different ways to get a hint whether the workshop +> participants are still following or perhaps bored. I assume it's communicating +> with the class, with exercises and simply by asking now and then. I also try +> to remember to observe how people look like (puzzled, bored) while I teach, not +> so obvious for me. +> +> I believe that learners communicating with each other, in addition to with +> instructors and helpers, really helps them to understand things faster. (At least +> it helps me). So I try to make sure that no one sits or works alone at the workshops. +{: .challenge} + +> ## Richard Darst +> +> Like many people, I've often been teaching, but rarely a teacher. I +> tend to teach like I am doing an informal mentorship. +> I've realized long ago that my most important lessons weren't +> learned in classes, but by a combination of seeing things done by +> friends and independent study after that. I've realized that +> teaching (the things I teach) is trying to correct these differences +> in backgrounds. +> +> My main job is supporting computing infrastructure, so my teaching +> is very grounded in real-world problems. I'm often start at the +> very basics, because this is what I see missing most often. +> +> When teaching, I like lots of audience questions and don't mind +> going off-script a bit (even though I know it should be minimized). +> I find that sufficient audience interest allows any lesson to be a +> success - you don't have to know everything perfectly, just show how +> you'd approach a problem. +> +{: .challenge} + +> ## João M. da Silva +> +> I started giving technical trainings twenty years ago, and hence my perspective +> is perhaps more inclined towards the development of hands-on abilities and +> capability to solve problems, independently or in a team. +> +> But the development of hands-on practical skills, requires some essential +> knowledge about the domain and some willingness to try different approaches +> in case one gets stuck. Some call this the "KSA approach" +> ("Knowledge-Skills-Attitude). Hence, I +> try to impart the essential knowledge (and where to find out more) at my +> trainings. And to encourage and challenge students in order to make them +> overcome their self-perceived limits (e.g. "I'm a Humanist, I can't use +> Python virtualenv"). +> +> I've been trying to study more about the Cognitive aspects of learning over the years, +> and I should find out the time to return to that. There's very interesting +> research in Problem Solving, with Learning being a important component in that domain. +> +> Storytelling: humans are neurologically made for paying attention to good +> stories, and that's something that I try to put into account: to give +> a lesson like it would be a relevant narrative for the students, one that they +> could relate to and help them in their work +> +> I like to draw and be creative with that, but have to pay attention to +> my handwriting during my trainings. I reckon that Architectural diagrams +> help students to understand the big picture, so I should invest more on +> those when development training material. I would also like to start looking into +> Concept Maps and Semantic Trees in training. +{: .challenge} diff --git a/_sources/03-teaching-style.md.txt b/_sources/03-teaching-style.md.txt new file mode 100644 index 00000000..8164130c --- /dev/null +++ b/_sources/03-teaching-style.md.txt @@ -0,0 +1,336 @@ +--- +layout: episode +title: "Carpentries and CodeRefinery approach to teaching" +teaching: 30 +exercises: 30 +questions: + - "What pedagogical concepts underpin CodeRefinery and Carpentry workshops?" + - "How to get and give feedback?" + - "Who are the CodeRefinery learners?" + - "Why is it important to define learning objectives?" +objectives: + - "Explain The Carpentries and CodeRefinery approaches to teaching" + - "Understand what is meant by feedback, cognitive development, mental models and reverse instructional design" + - "Explain and practice important pedagogical concepts" +keypoints: + - "CodeRefinery lessons and teaching build on these principles" +--- +# Interactive teaching style + + +## What are the top issues new instructors face? + +```{solution} + - 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. + - Get the speed correct. Not too fast and not too slow. + - 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. + - 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. + - Special issues when lessons delivered online (discussed during Workshop preparation and organization) +``` + + +# The Carpentries and CodeRefinery approaches to teaching + +Here we will give you a very short overview of the Carpentries approach to teaching and highlight +parts that are most important for teaching CodeRefinery style lessons. + +Most CodeRefinery instructors have completed the +[Carpentry instructor training workshop](https://carpentries.github.io/instructor-training/), which +[anyone can apply for](https://carpentries.org/become-instructor/) + +> ## This material +> +> This section is derived from the +> [Carpentries instructor training material](https://carpentries.github.io/instructor-training/). +> We encourage you to further study this material later, and to sign up for a 2-day Carpentry +> intructor training workshop. +{: .callout} + +--- + +## Key principles + +The "Carpentries" approach to teaching is based on: + +- Applying research-based teaching principles, especially as they apply to the + Carpentries audience. +- Understanding the importance of a respectful and inclusive classroom environment. + + +### Carpentries teaching principles + +- Learners need to practice what they are learning in real time and get **feedback** on what they + are doing. That is why the teaching approach relies on **live coding**. +- Learners best learn in a respectful classroom environment, so the Carpentries use a + [Code of Conduct](https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html). +- Learners are encouraged to help each other during workshops as this improves their confidence + and reinforces concepts taught. +- Carpentry instructors try to have learners do something that they think is useful in their + daily work within **15 minutes of starting each lesson**. + +![What to Teach](https://carpentries.github.io/instructor-training/fig/what-to-teach.png) + +In CodeRefinery, we follow The Carpentries teaching principles but in addition to **live coding** +we often use **group discussions** to put in context the concepts we are teaching. + +Applying these teaching principles are not sufficient and in addition we need to be able to check +the effectiveness of our methods. + +--- + +## On the importance of feedback + +Feedback is an essential part of effective learning. Feedback is bi-directional: +- To be effective, instructors need feedback on their learners' progress. Learners can also check their progress and ask relevant questions to get clarification. +- Instructors also need feedback on their teaching. For instance, this can help them to adapt the pace, add/skip optional exercises and improve their teaching. + +### Getting/giving feedback on learners' progress + +This feedback comes through what is called *formative assessments* (in contrast + to *summative assessment*). + +> ## Summative Assessment +> *Summative assessment* is used +> to judge whether a learner has reached an acceptable level of competence. +> Usually at the end of a course +> Learners either "pass" or "fail" a summative assessment. +> One example is a driving exam, +> which tells the rest of society whether someone can safely be allowed on the road. Most assessment done in university +> courses is summative, and is used to assign course grades. +{: .callout} + +> ## Formative assessment +> *Formative assessment* takes place during teaching and learning. It sounds like +> a fancy term, but it can be used to describe any interaction or activity +> that provides feedback to both instructors and learners about learners' level of understanding of the +> material. For learners, this feedback can help focus their study efforts. For instructors, it allows them to refocus +> their instruction to respond to challenges that learners are facing. +> Used continuously +{: .callout} + +Learners don't "pass" or "fail" formative assessments; they are simply a feedback mechanism. +For example, a music teacher might ask a learner to play a scale very slowly +in order to see whether they are breathing correctly, +and if not, what they should change. + +Formative assessment is most useful when it happens frequently (we'll talk about how frequently later) +and when the results are easily interpretable by the learner and instructor. + + +CodeRefinery uses different instruments to get feedback from learners: + +- Surveys: we will discuss about CodeRefinery pre/post-surveys in the episode + {doc}`workshops-online`. +- Exercises: we have many exercises during CodeRefinery workshops and use polls too but not necessarily many multiple-choice questions. + This is something that we may change in the future but the initial reason was that we build on existing knowledge + (see below section on our target audience) and give recommendations for best software practices: + there is no unique solution and you would like our learners to choose the approach that is most suitable for them. + For the same reasons, we have many optional exercises to accommodate the different levels. + We would like everyone to get something useful out of the CodeRefinery workshops. + +### Getting/giving feedback on teaching + +Teaching is a skill. One of the objective of the CodeRefinery Instructor training is to give you +the confidence in teaching CodeRefinery lessons. Later we will have group work where we will +practice teaching some lessons. + +Before doing so, we will learn here to give feedback on teaching using the same +positive-vs-negative and content-vs-presentation rubric. + +> ## Give feedback on teaching (optional, 10 mn) +> This exercise aims at learning to give feedback. It is optional as we have +> similar exercises when {doc}`practising teaching `). +> As a group, we will watch [this video of teaching](https://www.youtube.com/watch?v=-ApVt04rB4U) and +> give feedback on two axes: positive vs. negative and content vs. presentation. Have each person in +> the class add one point to a 2x2 grid on a whiteboard or in the shared notes (hackMD, etherpad, google doc) without duplicating any points. +> For online instructor training event, use breakout room (4-5 persons per group) to facilitate discussion. Then each group reports to the shared notes. +> You can use a [rubric](http://carpentries.github.io/instructor-training/demos_rubric/) (used during The Carpentries teaching demos) to help you take notes. +> What did other people see that you missed? What did they think that you strongly agree or disagree with? +> +{: .challenge} + +--- + +## Who are the learners + +The first task in teaching is to figure out who your learners are. The Carpentries approach is +based on the work of researchers like [Patricia Benner](https://en.wikipedia.org/wiki/Patricia_Benner), +who applied the +[Dreyfus model of skill acquisition](https://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition) +in her studies of +[how nurses progress from novice to expert](http://journals.sagepub.com/doi/10.1177/0270467604265061) +([see also books by Benner](https://www.worldcat.org/search?q=au%3ABenner%2C+Patricia+E.&qt=hot_author)). +This work indicates that through practice and formal instruction, learners acquire skills and advance +through distinct stages. In simplified form, the three stages of this model are: + +### Novices, competent practitioners and experts + +![Novice, Competent Practitioner, Expert](https://carpentries.github.io/instructor-training/fig/skill-level.svg) + +* *Novice*: someone who doesn't know what they don't know, i.e., + they don't yet know what the key ideas in the domain are or how they relate. + One sign that someone is a novice is that their questions "aren't even wrong". + + - Example: A *novice* learner in a Carpentries workshop might never have heard of the bash + shell, and therefore may have no understanding of how it relates to their file system or + other programs on their computer. + + - Example HPC: A learner who has never executed a program on remote computer in headless mode + + - Example HPC: A learner who has no understanding about using a queue system and having a + hard time why a program can not be run directly after login in. + +* *Competent practitioner*: someone who has enough understanding for everyday purposes. + They won't know all the details of how something works and their understanding may not + be entirely accurate, but it is sufficient for completing normal tasks with normal + effort under normal circumstances. + + - Example: A *competent practitioner* in a Carpentries workshop might have used the shell + before and understand how to move around directories and use individual programs, but + they might not understand how they can fit these programs together to build scripts + and automate large tasks. + + - Example: A *competent practitioner* in a CodeRefinery workshop is someone that understands + the concepts of best software practices and its importance. He/she clearly sees the + benefits of applying best software practices but he/she does not fully know yet how and + what to use for their own projects. + + - Example HPC: Knows how to establish a connection to a cluster and have submitted jobs. + But may not know how to request optimal amount of resources in a job and how to setup + parallel jobs + + +* *Expert*: someone who can easily handle situations that are out of the ordinary. + + - Example: An *expert* in a Carpentries workshop may have experience writing and running shell + scripts and, when presented with a problem, immediately sees how these skills can be used + to solve the problem. + + - Example HPC: A learner who has a good understanding of the queue system, parallel processing + and understand how to interpret error reports when something goes wrong and knows how to + get help. + + +### Cognitive Development and Mental Models + +Effective learning is facilitated by the creation of a well-founded mental model. A mental model +is a collection of concepts and facts, along with the relationships between those concepts, which +a person has about a topic. For example, a long-time resident of the United States may have an +advanced understanding of the location of US states, major cities and landmarks, weather patterns, +regional economies and demographic patterns, as well as the relationships among these, compared +with their understanding of these relationships for other countries. In other words, their mental +model of the United States is more complex compared with their mental model of other countries. + +We can distinguish between a *novice* and a *competent practitioner* for a given domain based +on the complexity of their mental models. + +* A *novice* is someone who has not yet built a mental model of the domain. + They therefore reason by analogy and guesswork, borrowing bits and pieces + of their mental models of other domains which seem superficially similar. +* A *competent practitioner* is someone who has a mental model that's good enough + for everyday purposes. This model does not have to be completely accurate in order + to be useful: for example, the average driver's mental model of how a car works + probably doesn't include most of the complexities that a mechanical engineer + would be concerned with. + +We could expect a mixture of learners from *novice* and *competent practitioner* groups +in HPC training events. + +![Mental Models](https://carpentries.github.io/instructor-training/fig/mental_models.svg) + +--- + +### How “knowledge” gets in the way + +Mental models are hardly ever built from scratch. Every learner comes to a topic with +some amount of information, ideas and opinions about the topic. This is true even in +the case where a learner can’t articulate their prior knowledge and beliefs. + +In many cases, this prior knowledge is incomplete or inaccurate. Inaccurate beliefs +can be termed “misconceptions” and can impede learning by making it more difficult for +learners to incorporate new, correct information into their mental models. +Correcting learners’ misconceptions is at least as important as presenting them with +correct information. Broadly speaking, misconceptions fall into three categories: + +- **Simple factual errors**, such as believing that Vancouver is the capital of + British Columbia. These are the easiest to correct. +- **Broken models**, such as believing that motion and acceleration must be in the + same direction. We can address these by having learners reason through examples to + see contradictions. +- **Fundamental beliefs**, such as “the world is only a few thousand years old” or + “human beings cannot affect the planet’s climate”. These beliefs are deeply connected + to the learner’s social identity and are the hardest to change. + + +The current HPC carpentry workshop material are aimed at **Novice** of HPC + +Among *Novice* learners there might be learners who are experts in their domain and very +competent in the program they are executing, but may not have used a HPC system before. +Then among the **competent practitioners** There might be learners who repeat some procedures +they have inherited but lack a in-depth understanding of what's going on. That is why it is +important to get accurate feedback, before and during the workshops to understand the learner profiles. + + +> ## Exercise: How to identify learner profiles? +> +> 1. How to identify leaner profiles from surveys and during the class +> 2. Which types of learners should the leassons focus on +{: .challenge} + +--- + +## CodeRefinery Curriculum and Reverse Instructional Design (with recommendations for HPC carpentries) + +When writing a CodeRefinery lesson, we take a “reverse” approach to instruction, +as described in Wiggins and McTighe’s +[Understanding by Design](http://www.worldcat.org/title/understanding-by-design/oclc/56491025), +that keeps the focus firmly on learning outcomes. The order of preparation in this case becomes + +- Determine your learning objectives +- Decide what constitutes evidence that objectives have been met, and design assessments + to target that evidence +- Design instruction: Sort assessments in order of increasing complexity, + and write content that connects everything together + +### Working with learning objectives + +Each CodeRefinery lesson (also the HPC capentries lessons) usually has a *learning objectives* section. +Good learning objectives are quite specific about the intended effect of a lesson on its learners. +We aim to create learning objectives that are specific, accurate, and informative for +both learners and instructors. + + +### Using Bloom's Taxonomy to write effective learning objectives + +[Bloom's Taxonomy](https://cft.vanderbilt.edu/guides-sub-pages/blooms-taxonomy/) is a framework for thinking about learning that breaks progress down into discrete, hierarchical steps. +While many ideas have come and gone in education, Bloom's has remained a useful tool for educators, in particular because the +hierarchy seems to be reasonably valid: outcomes at the top of the hierarchy cannot be achieved without mastery of outcomes at +the bottom. In the long term, everybody wants to be at the top. However, in aiming to meet learners where they are, we also +need to be mindful about helping them to ["grow a level,"](https://software-carpentry.org/blog/2018/03/tractenberg-summary.html) helping them to recognize when they have achieved that growth, and +guiding them to look ahead to where we might not be able to take them. + +![Bloom's Taxonomy](https://carpentries.github.io/instructor-training/fig/Blooms.png) + +Image credit: Vanderbilt University Center for Teaching + +### Revisiting Learning objectives + +When using existing teaching material, *reverse instructional design* principles might be applied as +follows: + +1. Review the lesson's learning objectives carefully, thinking about how they will work for your audience +2. Scan the lesson to identify promising points to check in with your learners, using formative assessment to verify that objectives have been met +3. Review the connecting content in detail to be sure everything works and you have anticipated likely problems and questions. + + +We strongly encourage you to read them before teaching a lesson and to review whether they still match the content of the lesson: diff --git a/_sources/about-coderefinery.md.txt b/_sources/about-coderefinery.md.txt new file mode 100644 index 00000000..fac5c923 --- /dev/null +++ b/_sources/about-coderefinery.md.txt @@ -0,0 +1,100 @@ +# About the CodeRefinery project and CodeRefinery workshops + +```{keypoints} +- Teaches intermediate-level software development tool lessons +- Training network for other lessons, too +- Publicly-funded discrete projects (3 projects actually) transitioning towards an open community project +- We have online material, teaching, and exercise sessions +- We want more people to work with us, and to work with more people +``` + +CodeRefinery is a +[Nordic e-Infrastructure Collaboration (NeIC)](https://neic.no/) +project that has started in October 2016 and is +funded until February 2025. + +The funding from 2022-2025 is designed to keep this project active +beyond 2025 by forming a support network and building a community of +instructors and contributors. + +```{discussion} History + +The CodeRefinery project idea grew out of two [SeSE](http://sese.nu) courses given at KTH Stockholm in 2014 and 2016: +- [http://sese.nu/scientific-software-development-toolbox/](http://sese.nu/scientific-software-development-toolbox/) +- [http://sese.nu/scientific-software-development-toolbox-2016/](http://sese.nu/scientific-software-development-toolbox-2016/) + +The project proposal was submitted to NeIC in 2015, accepted in 2015, and started in 2016. + +We have started by porting own lessons to the Carpentries teaching style and +format, and collaboratively and iteratively grew and improved the material to +its present form. +``` + + +## Main goals + +- Develop and maintain **training material on software best practices** for researchers that already write code. Our material addresses all academic disciplines and tries to be as programming language-independent as possible. +- Provide a [code repository hosting service](https://coderefinery.org/repository/) that is open and free for all researchers based in universities and research institutes from Nordic countries. +- Provide **training opportunities** in the Nordics using Carpentries and CodeRefinery training materials. +- Articulate and implement the CodeRefinery **sustainability plan**. + + +## Impact + +We collect feedback and survey results to measure our impact. + +3-6 months after attending a workshop, past participants are asked to complete a short post-workshop survey. +The survey questions aim to establish what impact CodeRefinery workshops have on how past participants develop +research software. + +[Pre- and post-workshop survey results](https://coderefinery.org/about/impact/) + +- Overall quality of research software has improved: more reusable, modular, reproducible and documented. +- Collaboration on research software development has become easier +- Past participants share their new knowledge with colleagues +- Usage of several tools is improved, and new tools are adopted + +[Free-form answers](https://coderefinery.org/#what-do-our-participants-say-after-attending-a-workshop) +also suggest that workshops are having the intended effects on how people develop code. A common theme is: +> *I wish I had known this stuff already as a grad student 10+ years ago...* + +We would love to get suggestions on how we can better quantify our impact. This +would make it easier for us to convince institutions to partner with us and +also open up funding opportunities. + + +## Target audience + +### Carpentries audience + +The Carpentries aims to teach computational **competence** to learners through an applied approach, avoiding the theoretical and general in favor of the practical and specific. + +**Learners do not need to have any prior experience in programming.** One major goal of a Carpentry workshop is to raise awareness on the tools researchers can learn/use to speed up their research. + +By showing learners how to solve specific problems with specific tools and providing hands-on practice, learners develops confidence for future learning. + +> ## Novices +> We often qualify Carpentry learners as **novices**: they do not know what they need to learn yet. A typical example is the usage of version control: the Carpentry `git` lesson aims to give a very high level conceptual overview of Git but it does not explain how it can be used in research projects. +{: .callout} + + +### CodeRefinery audience + +In that sense, CodeRefinery workshops differ from Carpentry workshops as we assume our audience already writes code and scripts and we aim at teaching them **best software practices**. + +Our learners usually do not have a good overview of **best software practices** but are aware of the need to learn them. Very often, they know the tools (Git, Jupyter, etc.) we are teaching but have difficulties to make the best use of them in their software development workflow. + +Whenever we can, we should direct learners that do not have sufficient coding experience to Carpentries workshops. + +> ## Competent practitioners +> We often qualify CodeRefinery learners as **competent practitioners** because they already have an understanding of their needs. +> *Novices* and *competent practitioners* will be more clearly defined in the {doc}`next section <03-teaching-style>`. +{: .callout} + +> ## Best software practices for whom? +> It can be useful to ask the question: *best software practices for whom*? +> CodeRefinery teaches *best software practices* derived from producing and +> shipping software. These practices are also very good for sharing software, +> though our audience will probably not need to embrace *all* aspects of +> software engineering. +{: .callout} diff --git a/_sources/backward-lesson-design.md.txt b/_sources/backward-lesson-design.md.txt new file mode 100644 index 00000000..7f141b0b --- /dev/null +++ b/_sources/backward-lesson-design.md.txt @@ -0,0 +1,152 @@ +(backwards-lesson-design)= + +# Backwards lesson design + +It happens far too often: someone creates a lesson, but they think +about what is interesting to them, not what is important for the +learners. In fact, an earlier version of this instructor training had +this very issue. + +It is critical to backwards design almost any piece of communication, +especially something as widespread as teaching. + + +## The approach + +- You don't think about how to do something and try to explain it. +- Avoid the typical approach *"I want to show a number of things which I think are cool about + tool X - how do I press these into 90 minutes?"* +- Instead, you start defining your target audience by answering to questions + such **What is the expected educational level of my audience?**, **Have they + been already exposed to the technologies I am planning to teach?**, **What + tools do they already use?**, **What are the main issues they are currently + experiencing?**. It is important to discuss these points with a group of + colleagues, preferably from diverse backgrounds and institutions to reduce + biases. Once you clarified your target audience, it is useful to create + **learner personas**; that will help you during the development process by + providing concrete examples of potential learners showing up at your + workshops. For each **learner personas**, try to think of what is **useful to + them**: *"What do they **need** to + [remember/understand/apply/analyze/evaluate/create](https://coderefinery.github.io/instructor-training/03-teaching-style/#using-bloom-s-taxonomy-to-write-effective-learning-objectives)?"*. + Asking and answering to these questions will allow you to define the + background knowledge (starting points) and goals (end points) of your + learners. Then, you create a sequence of exercises which test incrementally + progressing tasks and acquisition of the new skills (from starting to end + points). +- Then, you write the minimum amount + of material to teach the gap between exercises. + + +## The process + +As described in ["A lesson design process" in the book Teaching Tech +Together](https://teachtogether.tech/en/index.html#s:process): + +1. Understand your learners + +2. Brainstorm rough ideas + +3. Create an summative assessment to know your overall goal + + * CodeRefinery translation: think of the things your learners will + be able to do at the end of the lesson. Think simple! The + simpler the better. Think of three main points they will + remember, of which maybe one or two are a concrete skill. + +4. Create formative assessments to go from the starting point to this. + + * CodeRefinery translation: think of some engaging and active + exercises. + +5. Order the formative assessments (exercises) into a reasonable order. + +6. Write just enough material to get from one assessment (exercise) to + another. + +7. Describe the course so the learners know if it is relevant to them. + +We can't emphasize enough how important it is to **know your end +state and keep it simple**. + +```{discussion} Example: designing an HPC Carpentry lesson + +Let's take as an example the *[HPC Carpentry lesson](https://hpc-carpentry.github.io/hpc-intro/)* + +**Target audience** + - What is the expected educational level of my audience? + - A PhD student, postdoc or young researcher. + - Have they been already exposed to the technologies I am planning to teach? + - The word **HPC** is not new to them and they may have already used an HPC but are still not capable of giving a proper definition of HPC. In addition, we do not expect them to know much about parallelism and they cannot make any distinction between various available parallelism paradigms. + - What tools do they already use? + - serial codes, multi-threaded codes, data parallelism; usually out-of-the-box tools. + - they may have tried to "scale" their code (multiprocessing, threading, GPUs) with more or less success. + - What are the main issues they are currently experiencing? + - they cannot solve their problems either because they would like to run the same code but with many different datasets or because their problem is larger (more computations/memory). + - most of the time they know their codes can run on HPC (from the documentation) but never really had the opportunity to try it out. + - Very few will have their own codes where they may have tried different things to speed it up (threading, task parallelism) but have no clear strategy. + +**Learner persona** + - Sonya is a 1st year PhD student: she recently moved to Oslo and joined the + Computational and Systems Neuroscience group. She will be using the + [NEST](https://nest-simulator.readthedocs.io/), a simulator for spiking + neural network model. She used NEST during her master thesis but on her + small cluster: **she never used an HPC resource** and is really excited about it. + - Robert is a field ecologist who obtained his PhD 6 months ago. He is now + working on a new project with Climate scientists and as a consequence will + need to run global climate models. He is **not very familiar with command + line** even though he attended a Software Carpentry workshop and the idea to + use HPC is a bit terrifying. He knows that he will get support from his + team who has extensive experience with HPC but would like to become more + independent and be able to **run his own simulations** (rather than copying + existing cases). + - Jessica is a postdoc working on a project that investigates numerically the + complex dynamics arising at the tip of a fluid-driven rupture. Fluid + dynamics will be computed by a finite element method solving the + compressible Navier-Stokes equations on a moving mesh. She **uses a code she + has developed** during her PhD and that is based on existing libraries. She + has mostly ran it on a local desktop; her work during her PhD was very + limited due to the lack of computing resources and she is now very keen is + **moving to HPC**; she knows that it will requires some work, in particular to + parallelize her code. This HPC training will be her first experience with + HPC. + +**Learning outcomes** + - Understand the difference between HPCs and other local/remote machines + - Understand the notion of core, nodes, cluster, shared/distributed memory, etc. + - Understand the notion of login nodes. + - Understand the need for a scheduler and how to use it appropriately + - Understand why optimising I/O is important on HPC and how to best use HPC filesystems + - Understand the need to parallelize (or use existing parallel) codes and in which cases HPCs is a must (when communications is required) + - Understand how to get your code ready to use on HPC (access to libraries, installation of your own libraries/software, etc.) + - Understand that an HPC is an operational machine and is not meant for developing codes. + +**Exercises** + - Get basic information such the number of CPUs, memory from your laptop and try to do the same on a HPC. Discuss outcomes. + - Try to create files on the different filesystems on your HPC resource and access them. + - Create different types of job scripts, submit and check outputs. + - Make a concrete example to run a specific software on your HPC (something like GROMACS). +``` + + +## Exercises + +```{exercise} Backwards-design a lesson/topic +Choose a simple lesson topic and apply backwards lesson design. You +won't get all the way through, but come up with a logical +progression of exercises. + +The section you pick should require **screen sharing** and be of some **follow-along +task** (preferably using a shell). + +Some suggestions: +- Regular expressions +- Making papers in LaTeX +- Making figures in your favorite programming language +- Linux shell basics +- Something non-technical, such as painting a room +- An instructor training for CodeRefinery +- Some aspect from an already existing lesson +- [Introduction to high-performance computing](https://hpc-carpentry.github.io/hpc-intro/) (or an episode therein) +- [Unix shell in a HPC context](https://hpc-carpentry.github.io/hpc-shell/) (or an episode therein) +- A lesson you always wanted to teach +``` diff --git a/_sources/collaboration-models.rst.txt b/_sources/collaboration-models.rst.txt new file mode 100644 index 00000000..11ea3e68 --- /dev/null +++ b/_sources/collaboration-models.rst.txt @@ -0,0 +1,69 @@ +Collaboration models +==================== + + + +Model: CodeRefinery +------------------- + +* Before Covid-19, workshops were physically around the Nordics, + instructors would travel (or already be there). + + * Maximum size: ~40 people + * High workload per person + +* After several small scaling attempts, now we have: + + * Two large workshops per year - livestream format + * Combined organization efforts + * Instructors from each location - on average two lessons taught. + * Locations with staff can have **local breakout rooms**: physical + place to help during exercises. + +* Others in the world can register and interact using HackMD, but no + promises of help. + +* Content still available to anyone in the world: live + instant + replay. + +* Course page and material: + https://coderefinery.github.io/2022-03-22-workshop/ + + + +Model: Python for Scientific Computing +-------------------------------------- + +* Aalto Scientific Computing wanted to host a course, **Python for + Scientific Computing** +* ASC came up with initial vision and announced it +* ASC hosted an open initial meeting, inviting any interested + organizers or instructors +* We went over the plan and refined the topics and schedule. We also + decided things such as the date, organizers, and instructors for + each lesson. +* Registration was open to everyone in the world, non-Nordic + participants could watch via livestream. +* People prepared their parts and came together and presented. + Organizers kept everything on track. +* **Compared to the amount of effort each person put in, the results + were great.** +* A 2021 version also happened and was even larger. +* Course page: https://scicomp.aalto.fi/training/scip/python-for-scicomp/ +* Material: https://aaltoscicomp.github.io/python-for-scicomp/ + + + +Exercises +--------- + +.. exercise:: List successes and failures in collaborative teaching + + Using HackMD, list some successes and failures in collaborative + teaching that you have experienced. + +.. exercise:: Recommendations for co-teaching + + If you have experience with co-teaching, what approach/technique/trick + can you recommend a colleague who would like to try co-teaching for the + first time? diff --git a/_sources/distributed.md.txt b/_sources/distributed.md.txt new file mode 100644 index 00000000..477f0d2f --- /dev/null +++ b/_sources/distributed.md.txt @@ -0,0 +1,32 @@ +# Distributed workshop organization + +```{keypoints} +- If another university/organization wants to run the course, they can easily join our existing course at little cost/risk to them and to us. +- Each organization that joins provides a great benefit to us (helpers, instructors). +- They can reserve an in-person breakout room and provide mentors while watching the livestream: A great experience for their audience. +``` + + +## It is easier to join and follow than to start or lead + +Organizing a course is time intensive and so is developing a course. Many +courses given in country A are also relevant in other countries and instead of +developing and possibly re-inventing courses independently in different places, +it is so much more rewarding to collaborate and share. + +In our courses we wish and try to make it easier for teams and organizations +and universities to join, at little risk and cost to them, possibly for a short +period of time, possibly only as observer. Later observers can progress to +exercise leads, expert helpers, instructors, and co-organizers. + +One model that we have successfully tried is that the course is delivered via +live-stream to all partners and all the partner needs to do is to reserve a +room and motivate few people to help local learners as exercise leads during +exercise sessions which can happen in-person. + +```{discussion} Lessons learned from organizing larger workshops + +- **One person is needed to coordinate the registration process** and this person should + not have teaching duties in addition to this role. +- Generally it helps to have **well-defined roles** (see {ref}`workshop-roles`). +``` diff --git a/_sources/diversity-and-inclusion.rst.txt b/_sources/diversity-and-inclusion.rst.txt new file mode 100644 index 00000000..5baf30d2 --- /dev/null +++ b/_sources/diversity-and-inclusion.rst.txt @@ -0,0 +1,58 @@ +Diversity and inclusion +======================= + +When we are teaching, we fill a critical role in between people and +technology. We are not un-involved technical staff teaching asocial +topics, but we are very connected to the social context of the tools. +Unfortunately, there are major demographic imbalances in most +computing. + + + +Primary articles +---------------- + +* Several sections from the Carpentries Instructor Training: + `Motivation and demotivation + `__ + and `Equity, inclusion, accessibility + `__. +* Exercise leaders `During the workshop + `__ + + + +Support services vs diversity +----------------------------- + +Study this presentation by Richard Darst: + +* Watch: https://www.youtube.com/watch?v=z1VS1wleN-o +* Or read: https://docs.google.com/presentation/d/e/2PACX-1vQkzOMFI5SFnx69D4qRq_3N-mtcv7GUbPZd4A6UYpEKZUMGK0FL5W0RsSe6Alzxv1nE635Yl1GpyCKk/pub + +Summary: + +* Computing is hard and quite often our ability to learn quickly is + connected to our social group. +* Good technical services serve the role of mentors +* This mentorship helps to equalize +* Our entire system of research should be configured for more + equality. Modernization usually takes it the other way. + + + +Exercises +--------- + +.. exercise:: Reflect on how your job can be defined to promote diversity. + + What are some (possibly surprising) ways that your job promote + diversity and equality among people of different backgrounds? + + + +See also +-------- + +(none yet) + diff --git a/_sources/exercises.rst.txt b/_sources/exercises.rst.txt new file mode 100644 index 00000000..4aa70a72 --- /dev/null +++ b/_sources/exercises.rst.txt @@ -0,0 +1,10 @@ +Exercise list +============= + +This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests. + +.. exerciselist:: diff --git a/_sources/future.md.txt b/_sources/future.md.txt new file mode 100644 index 00000000..edb0dec6 --- /dev/null +++ b/_sources/future.md.txt @@ -0,0 +1,55 @@ +# Possibilities for Carpentries + +```{keypoints} +- Carpentries is currently designed around small workshops, so many of these ideas can't directly apply +- Yet **many of these tools and also team teaching can still be used** +- You can run your own breakout room for any of our workshops +- Join as observer if you want to see our workshop organization and tools in action +``` + +CodeRefinery workshops can be a good progression step after taking a +Carpentries workshop. + +Helping out at a CodeRefinery workshop as exercise lead can be a good +progression step for those who have helped out at a Carpentries workshop or who +have taken the Carpentries instructor training. + + +# CodeRefinery's plans + +```{keypoints} +- We are continuing to focus on online-first with local breakout rooms +- We welcome people joining us, either individually or as an organization +- Still interested in collaboration with Carpentries +- We need to become better at marketing and outreach +``` + + +## Biggest open problems + +- How to give helpers and contributors more credit and visibility +- How to promote/engage new members +- What are we? Non-profit? Institution collaboration network? Selling services? +- Funding and sustainability (but we have ideas: collaboration network) + + +## How you can join + +Individual level: + +- Join [CodeRefinery + chat](https://coderefinery.github.io/manuals/chat/) +- Lead a team, co-teach, or help organize a workshop +- Generally provide marketing and outreach + +Organization level: +- Have your organization join CodeRefinery +- Officially co-advertise and co-teach workshops +- Run local breakout rooms and join a workshop as a team +- Send an observer to a workshop + + +## Aside: Nordic-RSE (research software engineers) + +- [Nordic-RSE online unconference 2022](https://nordic-rse.org/events/2022-online-unconference/) +- [Bi-weekly meetings](https://nordic-rse.org/events/meeting/#community-discussions-biweekly) diff --git a/_sources/guide.rst.txt b/_sources/guide.rst.txt new file mode 100644 index 00000000..e05b9679 --- /dev/null +++ b/_sources/guide.rst.txt @@ -0,0 +1,14 @@ +Instructor's guide +------------------ + +In a lesson that was further developed, this would include an +instructor's guide that mentioned: + +* Background of why the course is how it is +* Recommendations of teaching it +* Known pitfalls of teaching it, so that other instructors can avoid + them +* Possibly how to contribute, long-term plans, etc. + +For example, see `git-intro's instructor guide +`__. diff --git a/_sources/hackmd.rst.txt b/_sources/hackmd.rst.txt new file mode 100644 index 00000000..1347785b --- /dev/null +++ b/_sources/hackmd.rst.txt @@ -0,0 +1,66 @@ +HackMD +====== + +The name "HackMD" doesn't do this concept justice, nor do the more +common descriptions of "shared notes" or "collaborative document". It +is a full replacement for chat: perhaps it could be called **random +access chat** or **parallel 2D chat** ? + +**HackMD** itself is a web service for collaborative documents in +Markdown. This isn't special to HackMD, but we have used it for its +scalability, markdown support, and privacy in the "view" mode. + + + +Primary articles +---------------- + +* HackMD instructors for the audience: https://coderefinery.github.io/manuals/hackmd-mechanics/ +* HackMD manager role description: https://coderefinery.github.io/manuals/hackmd-helper/ +* Example published HackMD after six 3-hour CodeRefinery sessions: https://coderefinery.github.io/2022-03-22-workshop/questions/ + + + +Advantages +---------- + +* Synchronous questions, no disadvantage for quiet people. +* Anonymous questions. +* Parallel answers by a large number of helpers. +* Easier to go back and review past questions during Q&A sessions + (compared to scrolling through chat), for example finding important + or unanswered questions. +* The above can make a course feel much more interactive than it would + otherwise. + + + +Disadvantages +------------- + +* *Overwhelming* flood of information + + * But you wanted more interaction, right? + * Co-teaching helps here, one person can focus on watching. + * Students must be warned to be deliberate about where they focus + their attention (different learners have different interests). + +* It is another tool to use + + * Not required for basic learners, learners can begin using when + they are comfortable. + + + +Exercise +-------- + +.. exercise:: + + * Actively use HackMD during this course. + * Observe how the instructors integrate it during the course + itself, and can immediately respond to the questions. + * Observe how instructors occasionally mention and screenshare + HackMD to validate to the audience that it is being watched. + * Keep HackMD open. Can you balance it and watching. Does it + increase or decrease engagement? diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..e2073282 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,146 @@ +Community teaching training +=========================== + +.. admonition:: Under development (mid 2022) + + As of mid-2022, this material has been reworked for our summer workshop and + for the CarpentryCon 2022 workshop. The material will continue to be + improved before a longer training session in the autumn. + + This material is the new version of our previous `Instructor + training `__. + + +What this course covers +----------------------- + +In 2020, we got farther from our offices but closer to each other. If +you could adapt to the circumstances, a huge number of possibilities +were opened - in particular with collaborative teaching. In this +training, you will learn how we use them. Teaching from 2019 is +almost obsolete - join us to learn more. + +- **Tools of teaching**: how to make the most out of online (and + other) teaching. +- **Workshop organization, collaboratively**: our vision of teaching + together outside of our silos. +- **Socio-technical factors**: social and technical barriers to + learning, why you need to care, and what you can do about them. +- **Lesson development, collaboratively**: how to design lessons and + teaching materials so that they can be open and shared. + + +Who is the course for? +---------------------- + +Teaching is a profession, but also something that everyone needs to be +able to do to some degree, since everyone has their own personal +specialties they will either teach or mentor. + +This course can be relevant for different learner personas: + +- **You run a practical teaching program** at your institution (for example + as part of a research computing group) and would like to learn best + practices for collaborative teaching, so that you aren't re-inventing + the same thing over and over again. + +- **You are a technical specialist** who is frustrated with the way you + currently try to teach others who need to use your software or + infrastructure. You can't spend too much time to become a + professional, but you know you need something more than what you've + been doing. Thus, you would like to adopt some of the best practices of + designing and teaching interactive, hands-on workshops. + +- **You've been teaching alone**, but would like to join a collaboration + network for more co-teaching and to reduce the amount of duplication + of effort. + +- **You are interested in teaching CodeRefinery lessons**, and would like a + comprehensive kick-start to how CodeRefinery works, either to join us, + or teach its lessons with us or independently. + + +.. toctree:: + :maxdepth: 1 + :caption: Preparation + + preparation + + +.. toctree:: + :maxdepth: 1 + :caption: Introduction + + welcome + about-coderefinery + + +.. toctree:: + :maxdepth: 1 + :caption: Teaching tools + + teaching-online + team-teaching + hackmd + teams + livestreaming + instructor-tech-setup + video-recording + video-editing + + distributed + + +.. toctree:: + :maxdepth: 1 + :caption: Workshop organization + + why-teach-together + distributed + collaboration-models + workshop-roles + + +.. toctree:: + :maxdepth: 1 + :caption: Social-technical considerations + + why-are-computers-hard + diversity-and-inclusion + Accessibility and usability (placeholder) + Mentoring (placeholder) + + +.. toctree:: + :maxdepth: 1 + :caption: Lesson design and development + + lessons-with-version-control + backward-lesson-design + + +.. toctree:: + :maxdepth: 1 + :caption: Wrap-up, future, and getting involved + + future + + +.. toctree:: + :maxdepth: 1 + :caption: Reference + + other-resources + guide + exercises + + +.. toctree:: + :maxdepth: 1 + :caption: Old contents - we need to move/merge + + 02-teaching-philosophies.md + 03-teaching-style.md + workshops-online.md + teaching-strategies + teaching-practice.md diff --git a/_sources/instructor-tech-setup.md.txt b/_sources/instructor-tech-setup.md.txt new file mode 100644 index 00000000..676f52e4 --- /dev/null +++ b/_sources/instructor-tech-setup.md.txt @@ -0,0 +1,93 @@ +# Instructor tech setup + +```{keypoints} +- Screenshare: **portrait layout** instead of sharing entire screen +- Prompt: **adjust your prompt** to make commands easy to read +- **Readability** and beauty is important: adjust your setup for your audience +- **Share the history** of your commands +- Get set up a **few days in advance** and get an outside reviewer +``` + + +## Screenshare + +Compare the following two screen-shares (you can find many more in +[the coderefinery manuals](https://coderefinery.github.io/manuals/instructor-tech-online/): + +```{figure} https://coderefinery.github.io/manuals/_images/screenshare-fullhd.png +:width: 80% + +FullHD. +``` + +```{figure} https://coderefinery.github.io/manuals/_images/s10-kickstart-prompt-log.png +:width: 45% + +Portrait, latest proposed best practices. +``` + +Share a portrait layout (left or right half of your screen) +instead of sharing entire screen. + +Motivation: +- This makes it easier for you to look at some other notes or to coordinate + with other instructors at the same time + without distracting with too much information. +- This makes it possible for participants to have something else open in the + other screen half: terminal or browser or notebook. + + +## Adjust your prompt/configuration/colors + +Adjust your prompt to make commands easy to read. What looks good for your own +work (many terminals, small font, extensions, shortcuts, color scheme) is +usually not the best for other people watching you. Adjust your setup for your +audience. Remove distractions. + +You *need* to spend some time getting set up before you teach. 10 minutes +before the session starts is typically too late. Get set up a **few days in +advance** and get an outside reviewer. + +```{discussion} Should instructors be forced to have a consistent screenshare? + +There are pros and cons to all instructors using the same screenshare and prompt. + +- What are the advantages? +- What are the opportunities of instructors showing different setups? +- How does it depend on the lesson and the experience of learners? +``` + + +## Share the history of your commands + +Even if you type slowly it is almost impossible to follow every command. We +all get distracted or want to read up on something or while following a command +fails on the learner laptop while instructor gets no error. + +Add pauses and share the commands that you have typed so that one can catch up. + + +## More examples and how to set it up + +- Generally making your screen look good (prompt, remove distractions, + command line history, etc): + +- Online setup for screen-shares: + + + +## Exercises + +```{exercise} Evaluate screen captures + +Evaluate screenshots within the [instructor tech +setup](https://coderefinery.github.io/manuals/instructor-tech-online/) lesson. +Use the collaborative document to make a list of the trade-offs of each one. +Which one do you prefer? Which are useful in each situation? +``` + +```{exercise} Set up your own environment + +Set up your screen to teach something. Get some feedback from +another learner. We will discuss among the class. +``` diff --git a/_sources/lessons-with-version-control.md.txt b/_sources/lessons-with-version-control.md.txt new file mode 100644 index 00000000..82bed4ea --- /dev/null +++ b/_sources/lessons-with-version-control.md.txt @@ -0,0 +1,106 @@ +# Lesson development with version control + +So, we want to practically share. We have these minimum requirements: + +* Someone can get the preferred form of modification, to improve + without limitation. + +* It is trivial to track differences and send the changes back to the + source, with little cost to the original maintainer. + +Especially with the second of these, version control in an online +platform seems to be the only reasonable option. + + +## Version control and static site generators + +CodeRefinery and the Carpentries use git and Github to develop +lessons. The general procedure is this: + +* Version control to store the raw files in text format +* A static website compiler to convert them to HTML files +* Serving to the public via Github Pages (but this could be replaced + with other systems) + +This allows for true collaborative development and community +contributions. + +Carpentries uses a custom website complierer based on R, CodeRefinery +uses the Sphinx documentation engine which is used in many different +projects for documentation. CodeRefinery's use of a standard tool +allows us to build on a huge and growing ecosystem of extensions and +themes, and promotes local reuse. + +The exact static website generator used isn't so important, as long as +some form of version control is used. + +A open-source license is the last bit to consider: without a license, +it can't be reused and passed on, and there is little incentive for +someone to contribute. + + +## CodeRefinery lesson tools + +CodeRefinery uses the following tools to actually make its lessons +right now: + +* [Sphinx](https://www.sphinx-doc.org/) (a common documentation + generator, widely used in open source projects in general) +* The [sphinx-lesson](https://github.com/coderefinery/sphinx-lesson), which is more of + a small collection of other extensions than new development itself. +* Github for hosting lessons: +* Github Actions and Github Pages for building and web serving our + lessons. + + +## Exercises + +```{exercise} Contribute to a sample lesson +* Open this very lesson in GitHub (it uses the same format as + typical CodeRefinery lessons): + + +* Browse the files and understand the general idea. Check out at + least these and use HackMD to record their functions: + + * .github/workflows/sphinx.yml + * content/conf.py + * content/index.rst + * content/lessons-with-version-control.rst + +* If you want, try to make a pull request to this lesson. It + doesn't have to have any significant content, it can be a pure + test pull request. +``` + +```{exercise} (advanced) Create your own lesson +Use the +[sphinx-lesson-template](https://github.com/coderefinery/sphinx-lesson-template) +to create a new lesson of your choice. Alternatively, use the current +Carpentries system, or some other system of your choice. +``` + + +## Recommendations and lessons learned + +- Convert feedback about lessons and suggestions for improvements into *issues* + so that these don't get lost. +- Make your lesson citable: get a DOI. +- Credit contributors (not only Git commits). +- Instructor guide is essential for new instructors. +- Lesson changes should be accompanied with instructor guide changes (it's like + a documentation for the lesson material). +- Apply and validate {ref}`backwards-lesson-design` again and again. +- Make it possible to try out new ideas (by making the lesson branch-able). +- Before making larger changes, talk with somebody and discuss these changes. +- For substantial changes we recommend to first open an issue and describe your + idea and collect feedback before you start with an extensive rewrite. +- For things still under construction, open a draft pull request to collect + feedback and to signal to others what you are working on. + + +## See also + +- [CodeRefinery git-intro](https://coderefinery.github.io/git-intro/) +- [CodeRefinery git-collaborative](https://coderefinery.github.io/git-collaborative/) +- [Carpentries lesson development](https://docs.carpentries.org/topic_folders/lesson_development/index.html) diff --git a/_sources/livestreaming.rst.txt b/_sources/livestreaming.rst.txt new file mode 100644 index 00000000..3ccf56e4 --- /dev/null +++ b/_sources/livestreaming.rst.txt @@ -0,0 +1,84 @@ +Livestreaming +============= + +In a large lecture, in effect, you don't interact with most people - +not even close. Yet, trying to force this limited interaction greatly +limits our possible reach, and keeps us in an awkward state of +expecting live interaction yet usually receiving minimal. When we try +this online, it forces a closed + +Teaching via livestreaming allows us to: + +* Reach a near-unlimited number of people +* Fully embrace online tools for interaction, instead of asking people + to speak up. This equalizes the participation for shy or passive + participants. +* By being large, be more efficient and use the extra resources for + meaningful interactions in small groups. + + + +Primary articles +---------------- + +* CodeRefinery MOOC strategy: + https://coderefinery.github.io/manuals/coderefinery-mooc/ +* Intro to livestream teaching: + https://coderefinery.github.io/manuals/livestream-teaching/ +* Broadcaster role description (hints on the actual tools): + https://coderefinery.github.io/manuals/broadcaster/ +* OBS (open broadcaster software) and livestream crash course: + https://coderefinery.github.io/manuals/obs/ + + +Summary +------- + +* There are actually three levels here. + + * In-person + * Online meeting + * Online livestream + +.. figure:: https://coderefinery.github.io/manuals/_images/mooc-diagram.png + + The general presence and information flow within the MOOC strategy. + +* CodeRefinery livestreams via Twitch, but Twitch is not an essential + aspect. + +* We can invite anyone in the world, no risk of disruptions from + trolls. + +* This has enabled us to fully embrace strategies such as HackMD and + co-teaching. + + * While we tried these in-person, they didn't work well since the + loud, extroverted people would dominate. + + + +Tech details +~~~~~~~~~~~~ + +* We stream by using OBS to capture a Zoom meeting. We can switch + between a gallery view, screenshare, and mixed. + +* Dedicated instructor Zoom meeting - no learners. Thus, no chance of + privacy violations. + + * Learners can attend different ways: a) independently online b) + in-person breakout room c) Zoom breakout rooms. + +* We don't have time to get into details here... see the linked + documents and also join us for in-person experience while we improve + our materials more. + + + +Exercises +--------- + +.. exercise:: (advanced) Set up and install OBS as a livestreaming tool. + + This exercise is open-ended. diff --git a/_sources/other-resources.md.txt b/_sources/other-resources.md.txt new file mode 100644 index 00000000..0b04ff9b --- /dev/null +++ b/_sources/other-resources.md.txt @@ -0,0 +1,23 @@ +# Other resources + +- The future of teaching" (35 min content only, 45 min with Q&A, or 15 min reading). + [Watch it on YouTube](https://www.youtube.com/watch?v=S9Jor12Cxdc) + or [read it](https://hackmd.io/KRqQirJ_Rn2SHcE-t1iAUg) if you prefer. +- [The old "CodeRefinery instructor training" + program](https://coderefinery.github.io/instructor-training/): this is + replaced by what you are reading now. +- [CodeRefinery manuals](https://coderefinery.github.io/manuals/) +- Our gradual pathway to instructor from the manuals: + [helper intro](https://coderefinery.github.io/manuals/helper-intro/) and + [instructor intro](https://coderefinery.github.io/manuals/instructor-intro/). +- [Carpentries instructor training](https://carpentries.org/instructors/): + more intensive, but focused only on teaching. +- [Carpentries curriculum development handbook](https://cdh.carpentries.org/) +- [Teaching Tech Together](https://teachtogether.tech/): a book + about similar topics by someone involved in Carpentries. +- [Carpentries general organizational documentation](https://docs.carpentries.org/) +- [How to help someone use a computer, by Phil Agre](https://www.librarian.net/stax/4965/how-to-help-someone-use-a-computer-by-phil-agre/). + Summary: Most of our teaching challenge is helping people to overcome bad user + interface design. +- [The Science of Learning](https://carpentries.github.io/instructor-training/files/papers/science-of-learning-2015.pdf): + provides a brief overview of some key evidence-based results in teaching. diff --git a/_sources/placeholder.rst.txt b/_sources/placeholder.rst.txt new file mode 100644 index 00000000..09e53552 --- /dev/null +++ b/_sources/placeholder.rst.txt @@ -0,0 +1,2 @@ +Placeholder +=========== diff --git a/_sources/preparation.md.txt b/_sources/preparation.md.txt new file mode 100644 index 00000000..86b75960 --- /dev/null +++ b/_sources/preparation.md.txt @@ -0,0 +1,46 @@ +# Pre-workshop preparation + +These things will help you get the most out of this workshop, by +giving you a broad overview at the beginning that you might only get +later on in the lesson. + +Don't worry if you don't have time to do everything here. The most +important ones are listed first. + + +## Read "How to help someone use a computer" (5 min) + +[How to help someone use a computer, by Phil +Agre](https://www.librarian.net/stax/4965/how-to-help-someone-use-a-computer-by-phil-agre/). +Summary: Most of our teaching challenge is helping people to overcome bad user +interface design. + + +## Browse a CodeRefinery lesson (5 min) + +Please take 5 minutes and go through a [CodeRefinery +lesson](https://coderefinery.org/lessons/) and understand the general +layout. Don't go in-depth to any of the material (unless you want, +obviously). We would recommend +[git-intro](https://coderefinery.github.io/git-intro/) if you don't +have a preference. + + +## (optional) Watch "The future of teaching" (35 min content only, 45 min with Q&A, or 15 min reading) + +The "The Future of Teaching" talk is a summary of many things in this +course. You could watch it as a preparation (or if you are reading on +your own, as a summary). This is low priority, since we will cover +most of these things in the course itself. +[Watch it on YouTube](https://www.youtube.com/watch?v=S9Jor12Cxdc) +or [read it](https://hackmd.io/KRqQirJ_Rn2SHcE-t1iAUg) if you prefer. + + +## (optional) Read "The science of learning" (20 min) + +Read this short paper [The Science of +Learning](https://carpentries.github.io/instructor-training/files/papers/science-of-learning-2015.pdf) +which provides a brief overview of some key evidence-based results in +teaching. This paper is also used by [The +Carpentries](https://carpentries.org/) for their Instructor Training +workshops. diff --git a/_sources/teaching-online.md.txt b/_sources/teaching-online.md.txt new file mode 100644 index 00000000..1c334769 --- /dev/null +++ b/_sources/teaching-online.md.txt @@ -0,0 +1,27 @@ +# Teaching online + +Is online teaching better or worse? As usual for that question, "it's +all a trade-off". We believe that many people tried to directly +translate in-person strategies to online, and teaching suffered. In +some ways, this even revealed the flaws of in-person pedagogy (remove +some interaction and not much is left other than an info-dump). + +```{exercise} +Using HackMD, brainstorm advantages and disadvantages of online and +in-person teaching. For each disadvantage of each, think of ways to compensate. + +``` + +* We won't elaborate more here right now - most of the rest of the + course somehow relates to online teaching! +* We will see many techniques which compensate for some of the + disadvantages in the section **tools of teaching**. +* **Workshop organization** will discuss new collaborative + opportunities with online teaching. + + + +## See also + +* The rest of this course +* CodeRefinery manuals: https://coderefinery.github.io/manuals/ diff --git a/_sources/teaching-practice.md.txt b/_sources/teaching-practice.md.txt new file mode 100644 index 00000000..1323c867 --- /dev/null +++ b/_sources/teaching-practice.md.txt @@ -0,0 +1,76 @@ +# Teaching practice and feedback + +Goals of the teaching practice: + +- In groups of 4-5 persons we will practice teaching a **5-minute segment + of a lesson of your choice**. +- The section you pick should require **screen sharing** and be of some + **demonstration or follow-along task** (preferably using a shell) to also + practice having a good screen-sharing setup. +- We will practice giving **constructive feedback**. +- We will practice improving our 5-minute segment by taking the feedback into account. +- In both session you can teach the same topic/segment but if you prefer you can also + change the topic/aspect for the second session. + +--- + +## Instructor demo + +- In order to demonstrate the goals of this section, the instructor + will make a 5-minute demo for your evaluation. +- It is designed to include some good and bad practices for you to + notice. + +--- + +## Teaching demos part 1 + +In group rooms, 50 minutes. + +```{challenge} +- We organize the breakout rooms to not only discuss one lesson/topic so that it is more interesting + to listen and also probably we will all get more useful feedback. +- Give each other **constructive verbal feedback** on the teaching demos, for example + using [this demo rubric](https://carpentries.github.io/instructor-training/demos_rubric/). +- Write down questions (in the collaborative document) that you would like to + discuss in the main room or interesting conclusions which you would like to + share with others. +``` + +## Teaching demos, part 2 + +In group rooms, 50 minutes. + +```{challenge} +- In the second round we distribute the rooms differently so that you can + present it to a **new group of workshop participants** and can receive new + feedback. +- Ask for feedback and one/few point(s) you want to improve. +- In your second trial check whether you feel the demonstration improved. +- Share your lessons learned in the collaborative document. +- Give us also feedback on this exercise format. Was it useful? What can we improve? +``` + +--- + +## Discussion + +```{discussion} Main room discussion + - We discuss questions and conclusions which came up during the group work session. +``` + +--- + +## Optional: feedback for two live-coding examples + +```{challenge} +Teaching by live coding is a +[performance art which requires practice](https://teachtogether.tech/#s:performance-exercises). +This exercise highlights some typical pitfalls that most instructors +fall into sooner or later, and also shows how to avoid them. +Watch closely since we will be giving feedback! +- Watch these two videos: [video 1](https://youtu.be/bXxBeNkKmJE) and + [video 2](https://youtu.be/SkPmwe_WjeY) +- What was better in video 1 and what was better in video 2? +- Please give feedback in the shared workshop document. +``` diff --git a/_sources/teaching-strategies.md.txt b/_sources/teaching-strategies.md.txt new file mode 100644 index 00000000..2e93a217 --- /dev/null +++ b/_sources/teaching-strategies.md.txt @@ -0,0 +1,220 @@ +# How to teach online + +```{objectives} +- Understand the benefits and disadvantage of online teaching, + compared to in-person + +- Set up a good screen share + +- Understand the benefits and disadvantages of team teaching + +- Prepare for the teaching practice +``` + + +## Why teaching mechanics matter + +- When you teach, you are mainly showing a basic example for the + learner to follow along +- The learner has a *lot* more to think about than you do, so you need + to minimize the possible distractions and unnecessary weirdness. +- A learner will often only one small screen, limiting the number of + things that they can think about. +- You are must faster than learners (5 times possibly?) You have to + do things to slow yourself down. +- It's easy to save these mechanics until the end, and then you run + out of time. + + + + +## Shell sharing + +```{discussion} Discussion: what goes into a good shell share or demonstration? + +When you are following along with a type-along demonstration, what +things: + +- Are useful to make it easy to follow along +- Make it harder to follow along + +Answer in the collaborative notes +``` + +When doing any demonstration, there are difficulties: + +- If one misses something, you can't rewind to see it - is there any + way to catch up? +- The learner must get oriented with the whole picture, while + instructor knows precisely where to focus. + +A good **shell share** has some of the following properties: + +- Large font +- Shell history, available separately from the main shell window +- Closely matches the type-along instructions + +We have a collection of shell sharing systems: +- We will look over [lesson presentation +hints](https://coderefinery.github.io/manuals/instructor-tech-setup/#terminal-history-window). +- There are other things you can copy +- Whatever you do, do *something*. + +```{discussion} +The instructor will demonstrate several shell-sharing systems. You +will use this in the teaching practice. +``` + + + +## Screen sharing + +`````{discussion} + +Look at the various [screen layouts in the CodeRefinery +manuals](https://coderefinery.github.io/manuals/instructor-tech-setup/#screen-sharing). +Use the HackMD to comment about what which are better or worse. + +````{output} HackMD prototype +:class: dropdown +``` +- S1 + - good: + - bad: +- S2 + - good: + - bad: +- S3 + - good: + - bad: +- S4 + - good: + - bad: +- Student layouts: + - ... +- Instructor layouts: + - ... +``` +```` +````` + +- Many learners will have a smaller screen than you. +- You should plan for learners with only one small screen. +- A learner will **need to focus on both your screen share and their + work**. +- Sharing your a whole screen is almost always a bad idea, if you want + the learners to do anything at the same time. +- If you constrict yourself, then your experience is more similar to + that of a learner. + +Vertical sharing: +- CodeRefinery has recently started trialing a **vertical share** + system, where you share a vertical half of your screen. +- This allows learners with one screen to display your screen + side-by-side with their learn +- Zoom provides a "Share a part of screen" that is good for this. + + + +## Meta-talk + +Don't just teach, also make sure you guide the learners through the +course. + +- You know what you just discussed, and what is coming next, but + learners are often stuck thinking about now. +- Give a lot of "meta-talk" that is not just about the topic you are + teaching, but how you are teaching it. +- Examples + - **Why** you are doing each episode + - What is the purpose of each exercise + - Clearly state what someone should accomplish in each exercise and + how long it will take - don't assume this is obvious. + - What is the point of each lesson. How much should people expect + to get from it? Should you follow everything, or are some things + advanced and optional? Make that clear. + + + +## Teach teaching + +- Demonstration-based teaching require two different types of focus: + - Doing the mechanical steps as a demonstration + - Explaining why you are doing it +- This is a lot for one person to keep in mind, so can multiple people + work together for this? +- Team teaching idea: + - One person is doing the demonstrations + - One person is giving the commentary about what they are doing + - The lecture becomes a discussion between two people instead. + +Advantages: +- This reduces the pressure on each person (reduces demo effect) +- You are less likely to forget things +- It slows you down in teaching +- It makes the lesson more interesting to listen to +- One person can follow questions +- Great for introducing new instructors (which half is easier to start + with?) + +Disadvantage: +- Requires two people's time +- Requires coordination when preparing (slows you down in preparation) +- Unfamiliar concept to most people + + + +## Questions + +- Questions are great, and important for any practical and interactive + class +- But questions in main room doesn't scale to very large rooms. +- CodeRefinery strategy: HackMD for questions + - Chat is not good enough, you can't reply to old things + - HackMD allows threaded replies and follow up later + - You need some other helpers to watch HackMD and answer, and bring + things up to you. And let you know how things are going. + - Learners can ask anonymously + - Learners don't have to worry about interrupting the flow. + - Disadvantage: can produce information overload, warn people to not + follow too closely + - With too few people, it can turn out to be very quiet. +- We will learn more about HackMD questions tomorrow in + {doc}`workshops-online`. + +```{seealso} +* {doc}`workshops-online` +* [HackMD +mechanics](https://coderefinery.github.io/manuals/hackmd-mechanics/) +and [HackMD +helpers](https://coderefinery.github.io/manuals/hackmd-helper/) on +CodeRefinery manulas. +``` + + + +## Teaching practice + +In {doc}`teaching-practice`, you will break into groups and try to +apply these strategies to a five-minute example session. + + + +## See also + +In this lesson: + +* {doc}`workshops-online` + +CodeRefinery manuals: + +* [Instructor tech + setup](https://coderefinery.github.io/manuals/instructor-tech-setup/) +* [Lesson preparation + hints](https://coderefinery.github.io/manuals/presenting/) (more + focused on in-person) +* [Instructor + introduction](https://coderefinery.github.io/manuals/presenting/) - + has a lot of tips for new instructors, but also more things about + the workshop. +* [Workshop prep call](https://coderefinery.github.io/manuals/workshop-prep-call/) diff --git a/_sources/team-teaching.rst.txt b/_sources/team-teaching.rst.txt new file mode 100644 index 00000000..b6531b3f --- /dev/null +++ b/_sources/team-teaching.rst.txt @@ -0,0 +1,82 @@ +Team teaching +============= + +One of the most significant improvemest of our teaching has been the +concept of **co-teaching**. + +.. admonition:: Co-teaching + + Wikipedia: Co-teaching or team teaching is the division of labor + between educators to plan, organize, instruct and make assessments + on the same group of students, generally in the a common + classroom,[1] and often with a strong focus on those teaching as a + team complementing one another's particular skills or other + strengths. + +*This is not strictly an effect of moving online*. However, the +larger number of instructors and larger audiences make this practical +on a wide scale. + + + +Primary article +--------------- + +https://coderefinery.github.io/manuals/team-teaching/ + + + +Benefits +-------- + +* The course seems very interactive, much more so than expecting + students to speak up. The co-teacher can take on the "voice of the + audience". +* Quicker preparation time since co-teachers can rely on each other in + unexpected situations. +* One co-teacher can be effectively learning at the same time and thus + acting as the "voice of the audience" in another way. +* Great way to onboard new instructors - extensive training and + preparation no longer needed. +* More active minds means better able to watch and react to other + feedback, such as HackMD or chat. +* Less workload - one person does not have to prepare perfectly, any + uncertainty can usually be quickly answered by the other. + + + +Strategies +---------- + +In reality, these strategies are mixed and matched even within a +lesson, and there are many things between these: + +* One person gives lectures, one does the typing during demos. +* "Interview": One primarily doing the "teaching", one guiding by + asking questions - either as an interviewer or as a virtual learner. + +Things that don't work (are not team teaching): + +* Dividing up a lesson into parts, each person gives different parts + independently. + + + +Exercises +--------- + +.. exercise:: + + Divide into groups of two or three. Choose one of the two models + in the team-teaching page, and quickly (5 min) prepare a short + topic (3-5 min) to team teach. You can quickly scan the + "preparation" section at the bottom. + + The challenge is not just to give the lesson, but to prepare the + lesson quickly and rely on each other to give a good lesson anyway. + + +See also +-------- + +(none yet) diff --git a/_sources/teams.rst.txt b/_sources/teams.rst.txt new file mode 100644 index 00000000..cf03ccb2 --- /dev/null +++ b/_sources/teams.rst.txt @@ -0,0 +1,106 @@ +Teams +===== + +Everyone wants interaction in courses, yet when a group size gets too +large, it doesn't have much interaction. A event in a physical space +naturally makes teams based on who is nearby. When done online, this +needs to be more explicit. + + + +Primary articles +---------------- + +* Exercise leader role description: + https://coderefinery.github.io/manuals/exercise-leaders/ +* Local breakout rooms: + https://coderefinery.github.io/manuals/local-breakout-rooms/?highlight=teams + + + +Basic concepts +-------------- + +- Teams are pre-assigned +- **Exercise leaders** (aka helpers) assigned per team +- Teams stay together during the whole workshop. +- Learners can sign up either alone... +- ... or they can sign up with **a pre-made team**: people who know + each. "bring your own breakout room": + + - When two people in a work group learn a skill, uptake within the + group is often much higher. Thus, we strongly encourage pre-made + teams that know each other. + + - Teams that all come from the same group or field, with a helper + from that field, can transition to help + + + +Online +------ + +In the best online implementations, our teams have these properties: + +- Coordination of breakout rooms is a *lot* of work. +- In zoom, we could request learners to rename to ``(N) Learner + Name``, and then quickly assign people. Now, you can have learners + self-select their rooms. But will they actually do this, or stay in + main room? + +- One helper is assigned per team. + + - In fact, we would limit the number of registrations to 5× the + number of helpers so that all teams have a helper + +- Our registration system (indico) is capable of mailing personalized + messages per person with their team information. This is quite a + bit of work to manage. + +But they have these disadvantages: + +- Much, much harder registration coordination, almost to the point of + being impossible. +- Number of attendees. +- Difficulties when attendees drop out partway through a course. + + + +In-person +--------- + +Teams may natuarally form based on setting location, but + +- Teams may happen naturally by sitting at the same table +- Do teams stay the same day after day? +- Do teams get arranged in a manner useful for learning? +- Do you have one helper per team? +- Do you encourage people to interact explicitly enough? +- Do you ensure that no one gets left out in the crowd? Are the teams + explicit enough? + + + +Discussion: what we actually do +------------------------------- + +- For large enough CodeRefinery workshops, assign teams with one + helper each. Deal with re-adjustment +- The livestream option allows everyone else to follow along. +- In other workshops, create breakout rooms but somehow try let people + self-assign. Most don't. +- For large workshops without enough staff help, livestream and + encourage people to form their own teams and watch themselves - we + don't actually need to be involved. +- Teams can be delegated to a local organizer. + + + +Exercises +--------- + +.. exercise:: Teams + + Consider these questions: + + - Should teams have similar or different people in them? diff --git a/_sources/video-editing.rst.txt b/_sources/video-editing.rst.txt new file mode 100644 index 00000000..869a34b3 --- /dev/null +++ b/_sources/video-editing.rst.txt @@ -0,0 +1,404 @@ +Video editing +============= + +Video recordings could be useful for people attending a course later, +but also are (perhaps more) useful for **immediate review and catching +up after missing a day in a workshop**. For this, they need to be +released immediately, within a few hours of the workshop. +CodeRefinery can do this. + +Hypothesis: videos must be processed the same evening as they were +recorded, otherwise (it may never happen) or (it's too late to be +useful). To do that, we have to make processing *good enough* (not +perfect) and *fast* and *distributeable* + + +Primary articles +---------------- +* Video editor role description: + https://coderefinery.github.io/manuals/video-editor/ +* ffmpeg-editlist: the primary tool: https://github.com/coderefinery/ffmpeg-editlist + + * Example YAML editlists: + https://github.com/AaltoSciComp/video-editlists-asc + + +Summary +------- + +* Basic principle: privacy is more important than any other factor. + If we can't guarantee privacy, we can't release videos at all. + + - Disclaimers such as "if you don't want to appear in a recording, + leave your video off and don't say anything", since a) accidents + happen especially when coming back from breakout rooms. b) it + creates an incentive to not interact or participate in the course. + +* Livestreaming is important here: by separating the instruction from + the audience audio/video, there is no privacy risk in the raw + recording. They could be released or shared unprocessed. + +* Our 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”.) + +* `ffmpeg-editlist + `__ allows us to + define an edit in a text file (crowdsourceable on Github), and then + generate videos very quickly. + + + +Exercises +--------- + +Exercise A +~~~~~~~~~~ + +These exercises will take you through the whole sequence. + +.. exercise:: Editing-1: Get your sample video + + Download a sample video: + + * Video (raw): http://users.aalto.fi/~darstr1/sample-video/ffmpeg-editlist-demo-kickstart-2023.mkv + * Whisper subtitles (of raw video): + http://users.aalto.fi/~darstr1/sample-video/ffmpeg-editlist-demo-kickstart-2023.srt + * `Schedule of workshop + `__ + (day 1, 11:35--12:25) - used for making the descriptions. + + +.. exercise:: Editing-2: Run Whisper to generate raw subtitles and test video. + + First off, install Whisper and generate the base subtitles, based + on the. Since this is probably too much to expect for a short + lesson, they are provided for you (above), but if you want you can + try using Whisper, or generating the subtitles some other way. + + You can start generating subtitles now, while you do the next + steps, so that they are ready by the time you are ready to apply + the editlist. ffmpeg-editlist can also slice up the subtitles from + the main video to make subtitles for each segment you cut out. + + Whisper is left as an exercise to the reader. + + .. solution:: + + Example Whisper command: + + .. code-block:: + + whisper --device cuda --output_format srt --initial_prompt="Welcome to CodeRefinery day four." --lang en --condition_on_previous_text False INPUT.mkv + + An initial prompt like this make Whisper more likely to output + full sentences, instead of a stream of words with no + punctuation. + + +.. exercise:: Editing-3: Create the basic editlist.yaml file + + Install `ffmpeg-editlist + `__ and try to + follow its instructions, to create an edit with these features: + + * The input definition. + * Two output sections: the "Intro to the course", and "From data + storage to your science" talks (Remember it said the recording + started at 11:35... look at the schedule for hints on when it + might start!). This should have a start/end timestamp from the + *original* video. + + A basic example: + + .. code-block:: yaml + + - input: day1-raw.mkv + + # This is the output from one section. Your result should have two of these sections. + - output: part1.mkv + title: something + description: >- + some long + description of the + segment + editlist: + - start: 10:00 # start timestamp of the section, in *original* video + - end: 20:00 # end timestamp of the section, in the *original* video + + .. solution:: + + This is an excerpt from our `actual editlist file of this course + `__ + + .. code-block:: yaml + + - input: day1-obs.mkv + + - output: day1-intro.mkv + title: 1.2 Introduction + description: >- + General introduction to the workshop. + + https://scicomp.aalto.fi/training/kickstart/intro/ + + editlist: + - start: 00:24:10 + - end: 00:37:31 + + + - output: day1-from-data-storage-to-your-science.mkv + title: "1.3 From data storage to your science" + description: >- + Data is how most computational work starts, whether it is + externally collected, simulation code, or generated. And these + days, you can work on data even remotely, and these workflows + aren't obvious. We discuss how data storage choices lead to + computational workflows. + + https://hackmd.io/@AaltoSciComp/SciCompIntro + + editlist: + - start: 00:37:43 + - end: 00:50:05 + + +.. admonition:: Discussion: what makes a video easy to edit? + :class: discussion + + * Clear speaking and have high audio quality. + * For subtitle generation: Separate sentences cleanly, otherwise it + gets in a "stream of words" instead of "punctuated sentences" + mode. + * Clearly screen-sharing the place you are at, including section + name. + * Clear transitions, "OK, now let's move on to the next lesson, + LESSON-NAME. Going back to the main page, we see it here." + * Clearly indicate where the transitions are + * Hover mouse cursor over the area you are currently talking about. + * Scroll screen when you move on to a new topic. + * Accurate course webpage and sticking to the schedule + + All of these are also good for learners. By editing videos, you + become an advocate for good teaching overall. + + +.. exercise:: Editing-4: Run ffmpeg-editlist + + Install ffmpeg-editlist: ``pip install ffmpeg-editlist[srt]`` (you + may want to use a virtual environment, but these are very minimal + dependencies). + + The ``ffmpeg`` command line tool must be available in your + ``PATH``. + + .. solution:: + + It can be run with (where ``.`` is the directory containing the + input files): + + .. code-block:: console + + $ ffmpeg-editlist editlist.yaml . + + Just running like this is quick and works, but the stream may be + garbled in the first few seconds (because it's missing a key + frame). (A future exercise will go over fixing this. + Basically, add the ``--reencode`` option, which re-encodes the + video (this is **slow**). Don't do it yet. + + Look at the ``.info.txt`` files that come out. + + +.. exercise:: Editing-5: Add more features + + * Several chapter definitions.(re-run and you should see a + ``.info.txt`` file also generated). Video chapter definitions + are timestamps of the *original* video, that get translated to + timestamps of the *output* video. + + .. code-block:: yaml + + - output: part1.mkv + editlist: + - start: 10:00 + - -: Introduction # <-- New, `-` means "at start time" + - 10:45: Part 1 # <-- New + - 15:00: Part 2 # <-- New + - end: 20:00 + + Look at the ``.info.txt`` files that come out now. What is new in it? + + * Add in "workshop title", "workshop description", and see the + ``.info.txt`` files that come out now. This is ready for + copy-pasting into a YouTube description (first line is the title, + rest is the description). + + Look at the new ``.info.txt`` files. What is new? + + .. solution:: + + * This course actually didn't have chapters for the first day + sessions, but you can `see chapters for day 2 here + `__, + for example. + * `Example of the workshop description for this course + `__ + * Example info.txt file for the general introduction to the + course. The part after the ``-----`` is the workshop description. + + .. code-block:: + + 1.2 Introduction - HPC/SciComp Kickstart summer 2023 + + General introduction to the workshop. + + https://scicomp.aalto.fi/training/kickstart/intro/ + + 00:00 Begin introduction <-- Invented for the exercise demo, not real + 03:25 Ways to attend <-- Invented for the exercise demo, not real + 07:12 What if you get lost <-- Invented for the exercise demo, not real + + ----- + + This is part of the Aalto Scientific Computing "Getting + started with Scientific Computing and HPC Kickstart" 2023 + workshop. The videos are available to everyone, but may be + most useful to the people who attended the workshop and want + to review later. + + Playlist: + https://www.youtube.com/playlist?list=PLZLVmS9rf3nMKR2jMglaN4su3ojWtWMVw + + Workshop webpage: + https://scicomp.aalto.fi/training/scip/kickstart-2023/ + + Aalto Scientific Computing: https://scicomp.aalto.fi/ + + +.. exercise:: Editing-6: Subtitles + + Re-run ffmpeg-editlist with the ``--srt`` option (you have to + install it with ``pip install ffmpeg-editlist[srt]`` to pull in the + necessary dependency). Notice how ``.srt`` files come out now. + + Use some subtitle editor to edit the *original* subtitle file, to + fix up any transcription mistakes you may find. You could edit + directly, use ``subtitle-editor`` on Linux, or find some other + tool. + + What do you learn from editing the subtitles? + + .. solution:: + + ..code-block:: + + $ ffmpeg-editlist --srt editlist.yaml + + There should now be a ``.srt`` file also generated. It + generated by finding the ``.srt`` of the original video, and + cutting it the same way it cuts the video. Look and you see it + aligns with the original. + + This means that someone could have been working on fixing the + Whisper subtitles while someone else was doing the yaml-editing. + + +.. exercise:: Editing-6: Subtitles + + Re-run ffmpeg-editlist with the ``--srt`` option (you have to + install it with ``pip install ffmpeg-editlist[srt]`` to pull in the + necessary dependency). Notice how ``.srt`` files come out now. + + Use some subtitle editor to edit the *original* subtitle file, to + fix up any transcription mistakes you may find. You could edit + directly, use ``subtitle-editor`` on Linux, or find some other + tool. + + What do you learn from editing the subtitles? + + +.. exercise:: Editing-7: Generate the final output file. + + * Run ffmpeg-editlist with the ``--reencode`` option: this + re-encodes the video and makes sure that there is no black point + at the start. + + * If you re-run with ``--check``, it won't output a new video file, + but it *will* re-output the ``.info.txt`` and ``.srt`` files. + This is useful when you adjust descriptions or chapters. + + +.. admonition:: Discussion: how to distribute this? + :class: discussion + + Create a flowchat of all the parts that need to be done, and which + parts can be done in parallel. Don't forget things that you might + need to do before the workshop starts. + + How hard was this editing? Was it worth it? + + + +Exercise B +~~~~~~~~~~ + +This is similar to the above but more brief and not on a real example +video. + +.. exercise:: Use ffmpeg-editlist to edit this sample video + + Prerequisites: ``ffmpeg`` must be installed on your computer + outside of Python. Be able to install ffmpeg-editlist. This is + simple in a Python virtual environment, but if not the only + dependency is ``PyYAML``. + + * Download the sample video: http://users.aalto.fi/~darstr1/sample-video/sample-video-to-edit.raw.mkv + * Copy a sample editlist YAML + * Modify it to cut out the dead time at the beginning and the end. + * If desired, add a description and table-of-contents to the + video. + * Run ffmpeg-editlist to produce a processed video. + +.. solution:: + + .. code:: yaml + + - input: sample-video-to-edit.raw.mkv + - output: sample-video-to-edit.processed.mkv + description: > + editlist: + - start: 00:16 + - 00:15: demonstration + - 00:20: discussion + - stop: 00:25 + + .. code:: console + + $ ffmpeg-editlist editlist.yaml video/ -o video/ + + Along with the processed video, we get + ``sample-video-to-edit.processed.mkv.info.txt``:: + + This is a sample video + + + 00:00 Demonstration + 00:04 Discussion + + + +See also +-------- + +* ffmpeg-editlist demo: https://www.youtube.com/watch?v=thvMNTBJg2Y +* Full demo of producing videos (everything in these exercises): https://www.youtube.com/watch?v=_CoBNe-n2Ak +* Example YAML editlists: + https://github.com/AaltoSciComp/video-editlists-asc diff --git a/_sources/video-recording.md.txt b/_sources/video-recording.md.txt new file mode 100644 index 00000000..4c051dc4 --- /dev/null +++ b/_sources/video-recording.md.txt @@ -0,0 +1,64 @@ +# Video recording + +```{keypoints} +- We don't expect many people to watch the recording from scratch later (but + some do) (some might look afterwards a few pieces, cmp. reading a book vs + look ing sth up from a book) +- Learners getting an "instant replay" to review, or to **make up for a lost day**, is great. +- Privacy is more important than any other factor +- **Recording only works if privacy is guaranteed and effort is low**. + This is only possible with the **instructor-audience split setup** of livestreaming. +``` + + +## We try to release videos on the same day + +Video recordings could be useful for people attending a course later, but also +are (perhaps more) useful for **immediate review and catching up after missing +a day in a workshop**. + +For this, they need to be released immediately, within a few hours of the +workshop (see {doc}`video-editing`). CodeRefinery can do this. + +For the videos to be released soon we need to make sure we guarantee privacy of +learners (see below). Our livestream setup makes the privacy guarantee easy at +the cost of separating instructors and learners into different video rooms. + +Good preparation and documentation helps to make video recording and video +editing easier. + + +## Privacy is more important than any other factor + +If we can't guarantee privacy, we can't release videos at all. + +Some events add a disclaimers such as "if you don't want to appear +in a recording, leave your video off and don't say anything". We +would prefer not to do this, since: +- we *know* accidents happen (especially when coming back from breakout rooms) +- it creates an incentive to not interact by voice/video +- it could pressure participants to not object in order "to not be difficult" + +**Livestreaming solves this for us**: + +- By separating the instruction from + the audience audio/video, there is no privacy risk in the raw + recording. They could be released or shared unprocessed. + +- Recording with Zoom in a large meeting with all the instructors and + learners is simple, but not good for privacy: there are always + mistakes, reviewing takes too long. + +- Livestream platforms also provide instant recordings of the whole + stream, and some make instant replays possible. This could remove + the need for making our own videos, since one of the most important + cases is this instant replay idea. + + +## Broadcasting role and setup + +In the live-streaming setup, the Broadcasting role is central to video +recording. + +Broadcaster description (most is not directly about recording): + diff --git a/_sources/welcome.md.txt b/_sources/welcome.md.txt new file mode 100644 index 00000000..a3b9e8c6 --- /dev/null +++ b/_sources/welcome.md.txt @@ -0,0 +1,65 @@ +# Welcome and introduction + +```{discussion} What do we want to get out of this workshop +- Introduction of instructors and helpers +- Each instructor can say what we want to get out of the instructor training +- But we want to know from everybody and collect these in the live notes +``` + +--- + +## Goals for this workshop + +```{discussion} Goals for this instructor training +- **Inspire teachers and staff who have to teach indirectly as part of + their job**: use best practices for the modern world, especially + for online teaching. +- **Promote collaboration in teaching**: less going alone. +- **Promote CodeRefinery sustainability**: form a network that can + work together to share the work and benefits. +``` + + +### Giving confidence + +> *Goal number one should be that we give participants the confidence to +> independently apply the tools or knowledge learnt. This is more important +> that giving a "complete" overview.* [Lucy Whalley gave this great comment at one of our workshops] + +- You don't have to know everything to use (or teach) something. +- For the large majority of topics we teach, there are many resources online + which provide how-to guides or tutorials. And the Stack Overflow answer bank + isn't getting any smaller. So we need to ask why do people attend in-person + sessions if there is information freely available? Our impression is that + it is for confidence building, identity formation, perhaps signposting to + resources. +- This also links with building a welcoming/inclusive environment: for example, + imposter syndrome, which disproportionately affects under-represented groups + ([link](https://www.ncda.org/aws/NCDA/pt/sd/news_article/245005/_PARENT/CC_layout_details/false)), + can manifest as low self-confidence --> building the confidence of + students in the classroom may lead to a more diverse community. + +--- + +## Tools for this workshop + +We often start workshops with these: +- [HackMD mechanics and controls](https://coderefinery.github.io/manuals/hackmd-mechanics/) +- [Zoom mechanics and controls](https://coderefinery.github.io/manuals/zoom-mechanics/) (but this got less relevant + since starting teaching via live-streaming where participants only interact via HackMD) + +--- + +## Code of Conduct + +- We follow [The CodeRefinery Code of + Conduct](https://coderefinery.org/about/code-of-conduct/). +- This is a hands-on, interactive workshop. + - Be kind to each other and help each other as best you can. + - If you can't help someone or there is some problem, let someone know. + - If you notice something that prevents you from learning as well as you can, let us know and don't suffer silently. +- It's also about the little things: + - volume + - font size + - generally confusing instructor + - **not enough breaks** diff --git a/_sources/why-are-computers-hard.rst.txt b/_sources/why-are-computers-hard.rst.txt new file mode 100644 index 00000000..a36b27a1 --- /dev/null +++ b/_sources/why-are-computers-hard.rst.txt @@ -0,0 +1,65 @@ +Why are computers hard? +======================= + +Most of the time, when teaching, our difficulty is not what you expect. + + + +Initial reading +--------------- + +Read the following: + +.. admonition:: How to help someone use a computer, by Phil Agre + + https://www.librarian.net/stax/4965/how-to-help-someone-use-a-computer-by-phil-agre/ + +Of each of the points made, how many are related to: + +* The computing itself +* The user interface +* The ability of the user to work in the computing environment +* Something else + + + +Usability +--------- + +As said in the text above: + + Most user interfaces are terrible. When people make mistakes it’s + usually the fault of the interface. You’ve forgotten how many ways + you’ve learned to adapt to bad interfaces. You’ve forgotten how + many things you once assumed that the interface would be able to + do for you. + + + +Deep abstraction layers +----------------------- + +Most technology is built on abstraction layers, for good reason. They +help simplify implementation and understanding. + + +.. exercise:: + + Think of a tool or technology that is easy to understand and use if + you understand the underlying abstraction layers, but is almost + impossible otherwise. + + + +Conclusion: what are we teaching, then? +--------------------------------------- + +As teachers of computing, we fill a critical role that is more +determined by our audience, than the technology we are teaching. + + + +See also +-------- + +(none yet) diff --git a/_sources/why-teach-together.rst.txt b/_sources/why-teach-together.rst.txt new file mode 100644 index 00000000..c2831c38 --- /dev/null +++ b/_sources/why-teach-together.rst.txt @@ -0,0 +1,84 @@ +Why teach together? +=================== + +We usually say so much about the value of collaboration. Despite us +saying this, our teaching is still far too alone. Covid-19 gave us a +kick that reduced our barriers and led to lasting changes in how we +taught (eventually leading to this very course). + +Open Science / FAIR data is heavily emphazised these days. But let's +add a "C" to FAIR: "collaborative". Instead of people doing their own +thing and releasing, develop, iterate, and maintain **collaboratively**. + + + +Ways to teach together +---------------------- + +* Develop materials together - avoid duplication. +* :doc:`team-teaching` +* Extensive use of helpers and team leaders. +* HackMD for parallel and mass answers. + + + +Advantages +---------- + +* You need to teach anyway, less effort if you combine. +* If done right, minimal extra effort for others to receive benefit (+ + you get publicity). +* Many of the previously presented teaching strategies work best in + large courses - this makes the course more engaging than a small + event with minimal interaction. +* More engaging for the audience. +* Easier on-boarding of new instructors (less "scary" to teach a new course + with other instructors). + + +Challenges and disadvantages +---------------------------- + +* Coordination + + * Finding suitable partners with the same vision + * Coordination efforts (if others don't understand the vision). + +* Materials + + * May not be perfectly tuned to your own audience + * May not iterate as fast as you need + +* Co-teaching + + * Difficulty in finding co-teachers + * Required effort of syncing among staff + * It might revert to independent teaching if you aren't careful. + +* HackMD + + * Can possibly overload both student and teacher. + + + +Exercises +--------- + +.. exercise:: What similarities do we have? + + Using HackMD, make two lists: + + * What courses do you think your local community would benefit + from, which you don't currently have? `+1` other people's items + which are also relevant to you. + + * Which courses are you thinking of preparing for your local + community? `+1` other people's items which you would be + interested in helping out with. + + + +See also +-------- + +* :doc:`collaboration-models` diff --git a/_sources/workshop-roles.rst.txt b/_sources/workshop-roles.rst.txt new file mode 100644 index 00000000..351b994b --- /dev/null +++ b/_sources/workshop-roles.rst.txt @@ -0,0 +1,77 @@ +.. _workshop-roles: + +Workshop roles +============== + +Running massive workshops requires a lot of people. We have a variety +of roles with different levels of support. + +As usual, roles are a plan, and a plans are made to be updated. + + + +Primary articles +---------------- + +* Workshop roles: https://coderefinery.github.io/manuals/roles-overview/ + + + +Summary +------- + +Lower levels mean "top level sometimes split into some of these +sub-roles". + +* **Instructor coordinator:** coordinates schedule and instructors + + * **Instructor:** Teaches along with a co-teacher. + + * **Expert helper:** Spare person, usually watching HackMD but also + rotates among breakout rooms. Often instructs some lessons. + + * **Director:** Manages the flow of the schedule during the + workshop, introduces each lesson, etc. (often the instructor + coordinator) + + * **Broadcaster:** Manages the livestreaming + + * **Video editor:** Edits and publishes videos the day of the + workshop. + +* **Registration coordinator:** coordinates registration, helpers, and + breakout rooms. + + * **Exercise leader coordinator:** Onboards exercise leaders + * **Host:** Manages the learner breakout rooms, learner questions, + etc. (often the registration coordinator) + * **Advertisement coordinator:** Advertises and outreaches + +* Under both registration coordinator and instructor coordinator + + * **HackMD manager:** always watches and formats HackMD and + publishes it same-day. "Eyes on the ground" via HackMD and chat + and quickly communicates important information to instructor and + registration coordinators. + +* **Learner:** attends and learns +* **Exercise leader:** serves as a guide to the team, receives small + amount of training before the workshop. + + + +Exercises +--------- + +.. exercise:: How many people teach in your workshops? + + * Using HackMD, make a histogram of how many (instructors + + organizers) you typically have in your workshops. + * List some of the common roles you have used. + + + +See also +-------- + +(none yet) diff --git a/_sources/workshops-online.md.txt b/_sources/workshops-online.md.txt new file mode 100644 index 00000000..abf5222c --- /dev/null +++ b/_sources/workshops-online.md.txt @@ -0,0 +1,256 @@ +--- +layout: episode +title: "Lessons learned from running online and in-person workshops" +teaching: 20 +exercises: 10 +questions: + - "What are the steps for organizing a CodeRefinery workshop?" + - "What can I learn about running my own workshop?" + - "What have we learned from running large online workshops?" +objectives: + - "Learn how to use the manuals to organize and teach a workshop." +keypoints: + - "There are many aspects to consider to deliver a successful workshop." + - "CodeRefinery maintains a number of manuals - use them when preparing a workshop." +--- + +> ## Workshop manuals +> CodeRefinery maintains a number of [workshop manuals](https://github.com/coderefinery/manuals/) +> with most of the "primary" information. This episode condenses this +> into a quick overview. +{: .callout} + + +# Running a workshop: online + + +## Online teaching discussion + +```{discussion} Discussion: Online vs in-person + +In notes: +- Compare and contrast the benefits of online teaching with + in-person: {advantage, disadvantage} × {content, presentation} +- How do you have to prepare differently? +- What are your own experiences? +``` + + + +## Case study: Mega-CodeRefinery and Finland HPC Kickstart + +- Mega-CodeRefinery + - Audience of around 90-100 + - "bring your own breakout room" (see below) + - 3 days/week, 6 days total + - Lessons as normal in CodeRefinery +- HPC Kickstart + - 250 registered, ~180 max participants + - Multi-university: local differences made this much harder to manage. + - Breakout rooms not pre-planned. + +Mega-CodeRefinery worked very well, HPC kickstart didn't - but not +because of the size. + + + +## General workshop arrangements + +> ## Manuals link +> - [before the +> workshop](https://github.com/coderefinery/manuals/blob/master/workshop-administration.md#before-the-workshop) +{: .callout} + +- Select a coordinator, recruit instructors (at least 3 is important), + find helpers +- Find a good lecture room: + [requirements](https://github.com/coderefinery/manuals/blob/master/workshop-requirements-inperson.md) +- Set up workshop webpage using the [Github, template + repository](https://github.com/coderefinery/template-workshop-webpage]: + [see + manuals](https://github.com/coderefinery/manuals/blob/master/workshop-administration.md#set-up-workshop-page) +- Advertising the workshop +- Communication with registered participants + + + +## CodeRefinery online scaling strategy + +- We started online workshops in 2020 March, for the obvious reasons. +- First, we started with two "normal size" (20 people) practice + workshops +- Then we did a 100 person workshop. It went well, but there is less + tolerance for problems. + + +### Basic preparation + +- You need more breaks are needed +- People have a way of doing too many things and not focusing. +- "[How to attend an online + workshop](https://coderefinery.github.io/manuals/how-to-attend-online/)" + guide to prepare learners + +### Basic platform: Zoom + +- Zoom (not the most ethical, but worked well and was available) +- [Zoom mechanics: instructions for + students](https://coderefinery.github.io/manuals/zoom-mechanics/). + - Mostly things that are known + - We don't use Zoom interaction features much anymore + (faster/slower/etc), but breakout rooms and HackMD instead +- See also: [Online training + manual](https://coderefinery.github.io/manuals/online-training/) + (which is getting a bit old compared to what is below). + +### Breakout rooms, bring your own team + +- Breakout rooms are + - Static: same people across whole workshop + - Contain one helper per room (see below) +- Team registration: accept a "team" field when registering, people on the + same team are put together. + - Gives motivations for learners to bring their colleagues and + learn together. + - More than one person learning together greatly increases update +- You need a powerful enough registration system to assign rooms and + email them to people! +- We ask people to name themselves "(N) Firstname Lastname" or "(N,H) + Firstname Lastname" for helpers. Then it is fast to assign them to + their designated breakout rooms. +- See also: [Breakout room + mechanics](https://coderefinery.github.io/manuals/breakout-rooms-helping/) + + +### Helper training + +- Each breakout room has a helper +- Helper should be a little bit familiar, but not expected to be able + to answer all questions. +- Special, custom [helper + training](https://coderefinery.github.io/manuals/helper-intro/) + since helpers make or break the workshop +- Helper recruitment: + - Our networks + - Team registration: if a team registers with their own helper, then + they are guaranteed to get in together. "bring your own breakout + room" + - Former learners, ask them to come back. +- Two helper trainings the week before the workshop. + +### Staff roles + +To reduce stress on any one person, we clearly define the different +roles and try to avoid overlap. We actually have enough people for +all of these, so it works well. + +- Workshop coordinator + - Registration, etc. +- Zoom host + - Handles registration, breakout rooms, recording, Zoom chat. +- HackMD helper + - Dedicated to watching HackMD and answering questions quickly. + - [Host on manuals](https://coderefinery.github.io/manuals/host/) +- Expert helpers + - "Spare hands" who rotate between breakout rooms and make sure + helpers are doing well. + - Give feedback to instructor about how breakout rooms are going. + - Take the place of missing helpers. + - Easy way for any people with a bit of spare time to help out. + - [Expert helpers in workshop](https://coderefinery.github.io/manuals/expert-helpers/) +- Instructors + - Teach, they shouldn't overlap with the above roles (but serve as + expert helpers other times). + - Usually also improve the lesson a bit before teaching + - [General staff intro in manuals](https://coderefinery.github.io/manuals/instructor-intro/) +- Workshop preparation meeting + - Get together, introduce roles, kickstart instructors + - [Workshop prep meeting in manuals](https://coderefinery.github.io/manuals/workshop-prep-call/) + + +### HackMD + +- We've been using it here +- Chat doesn't work wen large, written + document does. +- HackMD can just about scale to ~100 person workshop. Recommend + learners keep it in view mode while not editing. +- Voice questions are still allowed, but will be recorded. Staff + raise important questions from HackMD to the instructor immediately. +- HackMD also allows communication when in breakout rooms. +- You can get multiple answers, and answers can be improved over + time. +- [HackMD + mechanics](https://coderefinery.github.io/manuals/hackmd-mechanics/) + and [HackMD + helpers](https://coderefinery.github.io/manuals/hackmd-helper/). + +### Recording and streaming + +- When you have 100 people, main room is quiet anyway: you don't lose + much by recording. + - Questions anonymously in HackMD, privacy loss is not so bad +- Breakout rooms are never recorded +- Streaming + - We streamed via Twitch: https://twitch.tv/coderefinery + - We typically get 5-40 viewers. + - Zoom can directly send the stream to Twitch: no extra software + needed. + - Twitch archives videos for 14 days, which allows learners to get + an instant reply (we get hundreds of views in the next days). + - So while possibly not useful for new people to learn, the instant + reply *is* very useful. Instructor can also work on problems in + main stream during breakout rooms, which learners can watch + later. + - Streamers also have access to HackMD to ask questions. +- Certain tricks needed to keep learners from appearing in recording + or stream + - "Spotlight video", host does not go to gallery view, uses dual + monitor mode. We are still figuring this out. + +### Installation time + +- People *have* to be ready once we start, or else everything fails. +- Two installation help times the week before. +- Every email emphasizes that you have to be prepared, and "requires" + you to attend workshops (but really it's only) +- Installation instructions include *steps to verify* +- Installation instructions also include *video demonstrations* of + installation and verification. +- We haven't had that many installation problems, but also we keep the + requirements simple. +- Helper introduction is right before software install time, so + helpers can stay and help with install if they want. +- *Design to be easy to install and get set up.* + +### Other notes + +- Make breakout sessions as long as possible: 10 minutes is really too + short. 20 minutes is a good minimum time. +- Be very clear about exercise expectations +- Keep HackMD updated as a log. +- Don't combine breaks and breakout times. +- The more people you have, the more diverse audience you have and the + more people overwhelmed and under whelmed. + + + +## Workshop collaborations + +Why limit ourselves to CodeRefinery workshop? Why not use our network +and techniquess for more + +- Case study: [Python for Scientific + Computing](https://aaltoscicomp.github.io/python-for-scicomp/) + - Started by Aalto + - Announced to CodeRefinery, five more instructors from three + countries joined. + - Rapid collaboration, taught course shortly later. + - Announced to all institutions. Some places had physical rooms, + some were pure online + - Also streamed + - It was much more fun and less stressful to work together + +- We want to continue this kind of collaboration in other workshops. + + 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..4e9a9f1f --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,900 @@ +/* + * 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; +} + +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; +} +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ +nav.contents, +aside.topic, +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, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::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; +} +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type: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 > 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/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 00000000..f1916ec7 --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 00000000..2ea7ff3e --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} 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( " + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

About the CodeRefinery project and CodeRefinery workshops

+
+

Keypoints

+
    +
  • Teaches intermediate-level software development tool lessons

  • +
  • Training network for other lessons, too

  • +
  • Publicly-funded discrete projects (3 projects actually) transitioning towards an open community project

  • +
  • We have online material, teaching, and exercise sessions

  • +
  • We want more people to work with us, and to work with more people

  • +
+
+

CodeRefinery is a +Nordic e-Infrastructure Collaboration (NeIC) +project that has started in October 2016 and is +funded until February 2025.

+

The funding from 2022-2025 is designed to keep this project active +beyond 2025 by forming a support network and building a community of +instructors and contributors.

+
+

History

+

The CodeRefinery project idea grew out of two SeSE courses given at KTH Stockholm in 2014 and 2016:

+ +

The project proposal was submitted to NeIC in 2015, accepted in 2015, and started in 2016.

+

We have started by porting own lessons to the Carpentries teaching style and +format, and collaboratively and iteratively grew and improved the material to +its present form.

+
+
+

Main goals

+
    +
  • Develop and maintain training material on software best practices for researchers that already write code. Our material addresses all academic disciplines and tries to be as programming language-independent as possible.

  • +
  • Provide a code repository hosting service that is open and free for all researchers based in universities and research institutes from Nordic countries.

  • +
  • Provide training opportunities in the Nordics using Carpentries and CodeRefinery training materials.

  • +
  • Articulate and implement the CodeRefinery sustainability plan.

  • +
+
+
+

Impact

+

We collect feedback and survey results to measure our impact.

+

3-6 months after attending a workshop, past participants are asked to complete a short post-workshop survey. +The survey questions aim to establish what impact CodeRefinery workshops have on how past participants develop +research software.

+

Pre- and post-workshop survey results

+
    +
  • Overall quality of research software has improved: more reusable, modular, reproducible and documented.

  • +
  • Collaboration on research software development has become easier

  • +
  • Past participants share their new knowledge with colleagues

  • +
  • Usage of several tools is improved, and new tools are adopted

  • +
+

Free-form answers +also suggest that workshops are having the intended effects on how people develop code. A common theme is:

+
+

I wish I had known this stuff already as a grad student 10+ years ago…

+
+

We would love to get suggestions on how we can better quantify our impact. This +would make it easier for us to convince institutions to partner with us and +also open up funding opportunities.

+
+
+

Target audience

+
+

Carpentries audience

+

The Carpentries aims to teach computational competence to learners through an applied approach, avoiding the theoretical and general in favor of the practical and specific.

+

Learners do not need to have any prior experience in programming. One major goal of a Carpentry workshop is to raise awareness on the tools researchers can learn/use to speed up their research.

+

By showing learners how to solve specific problems with specific tools and providing hands-on practice, learners develops confidence for future learning.

+
+

Novices

+

We often qualify Carpentry learners as novices: they do not know what they need to learn yet. A typical example is the usage of version control: the Carpentry git lesson aims to give a very high level conceptual overview of Git but it does not explain how it can be used in research projects.

+
+
+
+

CodeRefinery audience

+

In that sense, CodeRefinery workshops differ from Carpentry workshops as we assume our audience already writes code and scripts and we aim at teaching them best software practices.

+

Our learners usually do not have a good overview of best software practices but are aware of the need to learn them. Very often, they know the tools (Git, Jupyter, etc.) we are teaching but have difficulties to make the best use of them in their software development workflow.

+

Whenever we can, we should direct learners that do not have sufficient coding experience to Carpentries workshops.

+
+

Competent practitioners

+

We often qualify CodeRefinery learners as competent practitioners because they already have an understanding of their needs. +Novices and competent practitioners will be more clearly defined in the next section.

+
+
+

Best software practices for whom?

+

It can be useful to ask the question: best software practices for whom? +CodeRefinery teaches best software practices derived from producing and +shipping software. These practices are also very good for sharing software, +though our audience will probably not need to embrace all aspects of +software engineering.

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/backward-lesson-design/index.html b/backward-lesson-design/index.html new file mode 100644 index 00000000..4bdc5d91 --- /dev/null +++ b/backward-lesson-design/index.html @@ -0,0 +1,348 @@ + + + + + + + Backwards lesson design — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Backwards lesson design

+

It happens far too often: someone creates a lesson, but they think +about what is interesting to them, not what is important for the +learners. In fact, an earlier version of this instructor training had +this very issue.

+

It is critical to backwards design almost any piece of communication, +especially something as widespread as teaching.

+
+

The approach

+
    +
  • You don’t think about how to do something and try to explain it.

  • +
  • Avoid the typical approach “I want to show a number of things which I think are cool about +tool X - how do I press these into 90 minutes?”

  • +
  • Instead, you start defining your target audience by answering to questions +such What is the expected educational level of my audience?, Have they +been already exposed to the technologies I am planning to teach?, What +tools do they already use?, What are the main issues they are currently +experiencing?. It is important to discuss these points with a group of +colleagues, preferably from diverse backgrounds and institutions to reduce +biases. Once you clarified your target audience, it is useful to create +learner personas; that will help you during the development process by +providing concrete examples of potential learners showing up at your +workshops. For each learner personas, try to think of what is useful to +them: “What do they need to +remember/understand/apply/analyze/evaluate/create?”. +Asking and answering to these questions will allow you to define the +background knowledge (starting points) and goals (end points) of your +learners. Then, you create a sequence of exercises which test incrementally +progressing tasks and acquisition of the new skills (from starting to end +points).

  • +
  • Then, you write the minimum amount +of material to teach the gap between exercises.

  • +
+
+
+

The process

+

As described in “A lesson design process” in the book Teaching Tech +Together:

+
    +
  1. Understand your learners

  2. +
  3. Brainstorm rough ideas

  4. +
  5. Create an summative assessment to know your overall goal

    +
      +
    • CodeRefinery translation: think of the things your learners will +be able to do at the end of the lesson. Think simple! The +simpler the better. Think of three main points they will +remember, of which maybe one or two are a concrete skill.

    • +
    +
  6. +
  7. Create formative assessments to go from the starting point to this.

    +
      +
    • CodeRefinery translation: think of some engaging and active +exercises.

    • +
    +
  8. +
  9. Order the formative assessments (exercises) into a reasonable order.

  10. +
  11. Write just enough material to get from one assessment (exercise) to +another.

  12. +
  13. Describe the course so the learners know if it is relevant to them.

  14. +
+

We can’t emphasize enough how important it is to know your end +state and keep it simple.

+
+

Example: designing an HPC Carpentry lesson

+

Let’s take as an example the HPC Carpentry lesson

+

Target audience

+
    +
  • What is the expected educational level of my audience?

    +
      +
    • A PhD student, postdoc or young researcher.

    • +
    +
  • +
  • Have they been already exposed to the technologies I am planning to teach?

    +
      +
    • The word HPC is not new to them and they may have already used an HPC but are still not capable of giving a proper definition of HPC. In addition, we do not expect them to know much about parallelism and they cannot make any distinction between various available parallelism paradigms.

    • +
    +
  • +
  • What tools do they already use?

    +
      +
    • serial codes, multi-threaded codes, data parallelism; usually out-of-the-box tools.

    • +
    • they may have tried to “scale” their code (multiprocessing, threading, GPUs) with more or less success.

    • +
    +
  • +
  • What are the main issues they are currently experiencing?

    +
      +
    • they cannot solve their problems either because they would like to run the same code but with many different datasets or because their problem is larger (more computations/memory).

    • +
    • most of the time they know their codes can run on HPC (from the documentation) but never really had the opportunity to try it out.

    • +
    • Very few will have their own codes where they may have tried different things to speed it up (threading, task parallelism) but have no clear strategy.

    • +
    +
  • +
+

Learner persona

+
    +
  • Sonya is a 1st year PhD student: she recently moved to Oslo and joined the +Computational and Systems Neuroscience group. She will be using the +NEST, a simulator for spiking +neural network model. She used NEST during her master thesis but on her +small cluster: she never used an HPC resource and is really excited about it.

  • +
  • Robert is a field ecologist who obtained his PhD 6 months ago. He is now +working on a new project with Climate scientists and as a consequence will +need to run global climate models. He is not very familiar with command +line even though he attended a Software Carpentry workshop and the idea to +use HPC is a bit terrifying. He knows that he will get support from his +team who has extensive experience with HPC but would like to become more +independent and be able to run his own simulations (rather than copying +existing cases).

  • +
  • Jessica is a postdoc working on a project that investigates numerically the +complex dynamics arising at the tip of a fluid-driven rupture. Fluid +dynamics will be computed by a finite element method solving the +compressible Navier-Stokes equations on a moving mesh. She uses a code she +has developed during her PhD and that is based on existing libraries. She +has mostly ran it on a local desktop; her work during her PhD was very +limited due to the lack of computing resources and she is now very keen is +moving to HPC; she knows that it will requires some work, in particular to +parallelize her code. This HPC training will be her first experience with +HPC.

  • +
+

Learning outcomes

+
    +
  • Understand the difference between HPCs and other local/remote machines

  • +
  • Understand the notion of core, nodes, cluster, shared/distributed memory, etc.

  • +
  • Understand the notion of login nodes.

  • +
  • Understand the need for a scheduler and how to use it appropriately

  • +
  • Understand why optimising I/O is important on HPC and how to best use HPC filesystems

  • +
  • Understand the need to parallelize (or use existing parallel) codes and in which cases HPCs is a must (when communications is required)

  • +
  • Understand how to get your code ready to use on HPC (access to libraries, installation of your own libraries/software, etc.)

  • +
  • Understand that an HPC is an operational machine and is not meant for developing codes.

  • +
+

Exercises

+
    +
  • Get basic information such the number of CPUs, memory from your laptop and try to do the same on a HPC. Discuss outcomes.

  • +
  • Try to create files on the different filesystems on your HPC resource and access them.

  • +
  • Create different types of job scripts, submit and check outputs.

  • +
  • Make a concrete example to run a specific software on your HPC (something like GROMACS).

  • +
+
+
+
+

Exercises

+
+

Backwards-design a lesson/topic

+

Choose a simple lesson topic and apply backwards lesson design. You +won’t get all the way through, but come up with a logical +progression of exercises.

+

The section you pick should require screen sharing and be of some follow-along +task (preferably using a shell).

+

Some suggestions:

+
    +
  • Regular expressions

  • +
  • Making papers in LaTeX

  • +
  • Making figures in your favorite programming language

  • +
  • Linux shell basics

  • +
  • Something non-technical, such as painting a room

  • +
  • An instructor training for CodeRefinery

  • +
  • Some aspect from an already existing lesson

  • +
  • Introduction to high-performance computing (or an episode therein)

  • +
  • Unix shell in a HPC context (or an episode therein)

  • +
  • A lesson you always wanted to teach

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/.buildinfo b/branch/main/.buildinfo new file mode 100644 index 00000000..b68b3255 --- /dev/null +++ b/branch/main/.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: 8cb779779d660285ee14066343458a42 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/branch/main/.nojekyll b/branch/main/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/branch/main/00-preparation/index.html b/branch/main/00-preparation/index.html new file mode 100644 index 00000000..595eec98 --- /dev/null +++ b/branch/main/00-preparation/index.html @@ -0,0 +1,171 @@ + + + + + + Pre-workshop preparation — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Pre-workshop preparation

+
+

You don’t have to be a Carpentries instructor

+

Being a Carpentries instructor is not +required to attend CodeRefinery instructor training workshop.

+
+

Preparation before the workshop (takes ca. 1 hour)

+
    +
  • Complete our pre-workshop survey. Your responses will help us to customize the workshop appropriately.

  • +
  • Read this short paper The Science of Learning which provides a brief overview of some key evidence-based results in teaching. This paper is also used by The Carpentries for their Instructor Training workshops.

  • +
  • Watch at least two of recorded ca. 5-minute +lightning overview videos +introducing various +CodeRefinery lessons +to get an overview of what we teach in CodeRefinery and also to be +able to practice CodeRefinery teaching on day 2 of this course.

  • +
  • Watch at least two of recorded +“this is my training philosophy” videos +which we will +discuss in group discussions and which will form the basis for a group +exercise.

  • +
  • Please go through a CodeRefinery lesson and find one +topic/episode/aspect that you find interesting. During a group session you +will be asked to present a topic/episode/aspect of your choice for 5 +minutes and get constructive feedback.

  • +
+
+
+

Remark

+

Don’t worry if there are sections you do not understand. The main objective +is to have a baseline for our discussions, not to check your ability to teach +the lesson during the instructor training workshop.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/02-teaching-philosophies/index.html b/branch/main/02-teaching-philosophies/index.html new file mode 100644 index 00000000..dac1737f --- /dev/null +++ b/branch/main/02-teaching-philosophies/index.html @@ -0,0 +1,328 @@ + + + + + + CodeRefinery teaching philosophies — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery teaching philosophies

+
+

Ice-breaker in groups (20 minutes)

+
    +
  • Share your approach to teaching and your teaching philosophy with your group.

  • +
  • Please share your tricks and solutions in the live document for others.

  • +
+

Additional ice-breaker questions:

+
    +
  • What is your motivation for taking this training?

  • +
  • How structured or informal are your own teaching needs?

  • +
  • What difference do you notice between the teaching what we (also +Carpentries) do and traditional academic teaching?

  • +
  • What other skills need to be taught, but academic teaching isn’t the right setting?

  • +
+
+
+

Here CodeRefinery instructors share their training philosophy to show that we +all have different teaching styles and how these differences are beneficial to +CodeRefinery workshops.

+

It is important to explain how much we value individuals and that there is not +one way to teach but as many ways as individuals. We want to help each other to +find the way that is best for each of us.

+
+

Video recordings

+

Recently we have recorded some of the below as videos: +https://www.youtube.com/playlist?list=PLpLblYHCzJAAHF89P-GCjEXWC8CF-7nhX

+
+
+

Anne Fouilloux

+

I regularly teach Carpentries workshops so I try to apply what I have learnt to CodeRefinery workshops. However, I know our target audience is very much different and that I need to adapt my teaching style. I am still trying to find what works best in which situations and this is why I like so much CodeRefinery workshops. We usually have a wider range of skills and very mixed backgrounds so we usually have to be more careful with the pace and time given for exercises.

+

Some considerations:

+
    +
  • I spend quite a lot of time reading the CodeRefinery material and practising myself exercises. I particularly like to read the instructor notes just before teaching: they usually highlight important aspects both for preparing and teaching.

  • +
  • I usually do not show too much in advance the material as I think it prevents asking questions. If you have less competent practitioners in the classroom, they can easily copy-paste to avoid slowing down the entire classroom.

  • +
  • Ideally, I’d like to give several exercises so anyone can work at its own pace. I find it is important that everybody gets something different from the workshop.

  • +
  • I love breaks as it gives us an opportunity to discuss with attendees on their research topics. I am especially interested to understand what software they write and how they plan to use what they learn during our workshops.

  • +
+
+
+

Bjørn Lindi

+

My teaching style has changed a bit since I started with CodeRefinery. In the beginning I had this “BLOB” (Binary Large OBject) of knowledge and experience that I wanted to to convey to the participants. With experience and some help from the Carpentries Instructor training, I have realized I need to serialize the “BLOB”, to be able to share it with others.

+

In a similar fashion as you would do with a binary large object which you intend to send over the wire, you will need stop signals, check-sums and re-transmissions, when you give a lecture. I have come to appreciate the natural periods/breaks the lessons offers, the questions raised, the errors that appear during type-along and the re-transmission. Co-instructors are good to use for re-transmission or broadening a specific topic.

+

When I started with CodeRefinery my inclination was to give a lecture. Today I am trying to be a guide during a learning experience, a learning experience which includes me as well. That may sound a bit self-centric, but is in fact the opposite, as I have to be more sensitive to what is going on in the room. The more conscious I am of being a guide, the better lesson.

+

Tools that I find useful in preparing a lesson is concept maps and Learner Personas, though I have develop to few them.

+ +
+
+

Thor Wikfeldt

+

I never want to leave any learner behind and I really don’t like seeing confused, blank faces in the classroom. +At the same time I sometimes worry about some participants getting bored if a lesson is progressing slowly. +This is always a difficult compromise and something I struggle with!

+

I try to focus on making concepts intuitive, to “make sense” to the learners. Of course this is usually +based on how I learned the topic myself and how it makes sense to me.

+

I try to establish connections between topics: “this thing here is similar to what we saw in the previous +lesson where we learned about X…”.

+

Before mastering a lesson by teaching in many times I try to “follow the script”. After becoming very +familiar with a lesson I start to improvise more and react more dynamically to questions, e.g. by taking a +detour to explain a confusing topic more clearly.

+

What I think I do too often: copy-paste code/text from lesson material. This can leave learners behind - +typing out the code and describing it is slower, but more learning takes place. More advanced learners +will hopefully “be compensated” by interesting advanced exercises which follow.

+
+
+

Stefan Negru

+

A lesson is a conversation, it is useful if both the trainer and the trainee are engaged. +For that reason I try to have, most of the time, a conversation with the classroom and +after we finish parts of a lesson, step back and see how we might use what we learned.

+

That brings me to another point I follow throughout the lessons, answering questions like:

+
    +
  • How can we apply in practice what we just learned?

  • +
  • Do you see yourself (the trainee) using that in practice, why or why not?

  • +
+

Most of the times those seem like open-ended questions to the trainees that just learned +something new, so I try to find examples, most of the times from personal experience.

+

Last thing is that analogies are important when I teach, I try to find analogies in order +to simplify a convoluted part of a lesson.

+
+
+

Radovan Bast

+

My teaching changed by 180 degrees after taking the Carpentries instructor +training. Before that I used slides, 45 minute lecture blocks, and separate +exercise sessions. After the Carpentries instructor training I embraced the +interaction, exercises, demos, and typos.

+

My goal for a lesson is to spark curiosity to try things after the lesson, +both for the novices (“This looks like a useful tool, I want to try using it +after the workshop.”) and the more experienced participants (“Aha - I did not +know you could do this. I wonder whether I can make it work with X.”). I like +to start lessons with a question because this makes participants look up from +their browsers.

+

Keeping both the novices and the experts engaged during a lesson can be +difficult and offering additional exercises seems to be a good compromise.

+

For me it is a good sign if there are many questions. I like to encourage +questions by asking questions to the participants. But I also try not to go +into a rabbit hole when I get a question where only experts will appreciate +the answer.

+

I try to avoid jargon and “war stories” from the professional developers’ +perspective or the business world. Most researchers may not relate to them. +For examples I always try to use the research context. Avoid “customer”, +“production”, also a lot of Agile jargon is hard to relate to.

+

Less and clear is better than more and unclear. Simple examples are better +than complicated examples. Almost never I have felt or got the feedback that +something was too simple. I am repeating in my head to not use the words +“simply”, “just”, “easy”. If participants take home one or two points from +a lesson, that’s for me success.

+

I prepare for the lesson by reading the instructor guide and all issues and +open pull requests. I might not be able to solve issues, but I don’t want to +be surprised by known issues. I learn the material to a point where I know +precisely what comes next and am never surprised by the next episode or +slide. This allows me to skip and distill the essence and not read bullet +point by bullet point.

+

I try to never deviate from the script and if I do, be very explicit about +it.

+

A great exercise I can recommend is to watch a tutorial on a new programming +language/tool you have never used. It can feel very overwhelming and fast to +get all these new concepts and tools thrown at self. This can prepare me for +how a participant might feel.

+

I find it very helpful if there is somebody else in the room who helps me +detecting when I go too fast or become too confusing. I like when two +instructors complement each other during a lesson but when doing that to +others, I am often worried of interrupting their flow and timing too much.

+

A mistake I often do is to type too fast and in my mind I force myself +to slow down.

+
+
+

Sabry Razick

+

My approach is to show it is fun to demystify concepts. Once a concept is +not a mystery anymore, the learners will understand is what it means, where +it is coming from, why it is in place and what it could it offer for their future. +I try to relate concepts to real life with a twist of humour whenever possible if +the outcome is certain not be offensive to any one. I use diagrams whenever possible, +I have spent weeks creating diagrams that is sometime three or four sentences. That +effort I consider worthwhile as my intention is not to teach, but to demystify. +Once that is achieved, learners will learn the nitty gritty on their own easily +and with confidence, when they have the use-case.

+
+
+

Juho Lehtonen

+

I’m gradually realising the different ways to get a hint whether the workshop +participants are still following or perhaps bored. I assume it’s communicating +with the class, with exercises and simply by asking now and then. I also try +to remember to observe how people look like (puzzled, bored) while I teach, not +so obvious for me.

+

I believe that learners communicating with each other, in addition to with +instructors and helpers, really helps them to understand things faster. (At least +it helps me). So I try to make sure that no one sits or works alone at the workshops.

+
+
+

Richard Darst

+

Like many people, I’ve often been teaching, but rarely a teacher. I +tend to teach like I am doing an informal mentorship. +I’ve realized long ago that my most important lessons weren’t +learned in classes, but by a combination of seeing things done by +friends and independent study after that. I’ve realized that +teaching (the things I teach) is trying to correct these differences +in backgrounds.

+

My main job is supporting computing infrastructure, so my teaching +is very grounded in real-world problems. I’m often start at the +very basics, because this is what I see missing most often.

+

When teaching, I like lots of audience questions and don’t mind +going off-script a bit (even though I know it should be minimized). +I find that sufficient audience interest allows any lesson to be a +success - you don’t have to know everything perfectly, just show how +you’d approach a problem.

+
+
+

João M. da Silva

+

I started giving technical trainings twenty years ago, and hence my perspective +is perhaps more inclined towards the development of hands-on abilities and +capability to solve problems, independently or in a team.

+

But the development of hands-on practical skills, requires some essential +knowledge about the domain and some willingness to try different approaches +in case one gets stuck. Some call this the “KSA approach” +(“Knowledge-Skills-Attitude). Hence, I +try to impart the essential knowledge (and where to find out more) at my +trainings. And to encourage and challenge students in order to make them +overcome their self-perceived limits (e.g. “I’m a Humanist, I can’t use +Python virtualenv”).

+

I’ve been trying to study more about the Cognitive aspects of learning over the years, +and I should find out the time to return to that. There’s very interesting +research in Problem Solving, with Learning being a important component in that domain.

+

Storytelling: humans are neurologically made for paying attention to good +stories, and that’s something that I try to put into account: to give +a lesson like it would be a relevant narrative for the students, one that they +could relate to and help them in their work

+

I like to draw and be creative with that, but have to pay attention to +my handwriting during my trainings. I reckon that Architectural diagrams +help students to understand the big picture, so I should invest more on +those when development training material. I would also like to start looking into +Concept Maps and Semantic Trees in training.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/03-teaching-style/index.html b/branch/main/03-teaching-style/index.html new file mode 100644 index 00000000..907f20c8 --- /dev/null +++ b/branch/main/03-teaching-style/index.html @@ -0,0 +1,459 @@ + + + + + + Interactive teaching style — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interactive teaching style

+
+

What are the top issues new instructors face?

+ +
+
+
+

The Carpentries and CodeRefinery approaches to teaching

+

Here we will give you a very short overview of the Carpentries approach to teaching and highlight +parts that are most important for teaching CodeRefinery style lessons.

+

Most CodeRefinery instructors have completed the +Carpentry instructor training workshop, which +anyone can apply for

+
+

This material

+

This section is derived from the +Carpentries instructor training material. +We encourage you to further study this material later, and to sign up for a 2-day Carpentry +intructor training workshop.

+
+
+
+

Key principles

+

The “Carpentries” approach to teaching is based on:

+
    +
  • Applying research-based teaching principles, especially as they apply to the +Carpentries audience.

  • +
  • Understanding the importance of a respectful and inclusive classroom environment.

  • +
+
+

Carpentries teaching principles

+
    +
  • Learners need to practice what they are learning in real time and get feedback on what they +are doing. That is why the teaching approach relies on live coding.

  • +
  • Learners best learn in a respectful classroom environment, so the Carpentries use a +Code of Conduct.

  • +
  • Learners are encouraged to help each other during workshops as this improves their confidence +and reinforces concepts taught.

  • +
  • Carpentry instructors try to have learners do something that they think is useful in their +daily work within 15 minutes of starting each lesson.

  • +
+

What to Teach

+

In CodeRefinery, we follow The Carpentries teaching principles but in addition to live coding +we often use group discussions to put in context the concepts we are teaching.

+

Applying these teaching principles are not sufficient and in addition we need to be able to check +the effectiveness of our methods.

+
+
+
+
+

On the importance of feedback

+

Feedback is an essential part of effective learning. Feedback is bi-directional:

+
    +
  • To be effective, instructors need feedback on their learners’ progress. Learners can also check their progress and ask relevant questions to get clarification.

  • +
  • Instructors also need feedback on their teaching. For instance, this can help them to adapt the pace, add/skip optional exercises and improve their teaching.

  • +
+
+

Getting/giving feedback on learners’ progress

+

This feedback comes through what is called formative assessments (in contrast +to summative assessment).

+
+

Summative Assessment

+

Summative assessment is used +to judge whether a learner has reached an acceptable level of competence. +Usually at the end of a course +Learners either “pass” or “fail” a summative assessment. +One example is a driving exam, +which tells the rest of society whether someone can safely be allowed on the road. Most assessment done in university +courses is summative, and is used to assign course grades.

+
+
+

Formative assessment

+

Formative assessment takes place during teaching and learning. It sounds like +a fancy term, but it can be used to describe any interaction or activity +that provides feedback to both instructors and learners about learners’ level of understanding of the +material. For learners, this feedback can help focus their study efforts. For instructors, it allows them to refocus +their instruction to respond to challenges that learners are facing. +Used continuously

+
+

Learners don’t “pass” or “fail” formative assessments; they are simply a feedback mechanism. +For example, a music teacher might ask a learner to play a scale very slowly +in order to see whether they are breathing correctly, +and if not, what they should change.

+

Formative assessment is most useful when it happens frequently (we’ll talk about how frequently later) +and when the results are easily interpretable by the learner and instructor.

+

CodeRefinery uses different instruments to get feedback from learners:

+
    +
  • Surveys: we will discuss about CodeRefinery pre/post-surveys in the episode +Running a workshop: online.

  • +
  • Exercises: we have many exercises during CodeRefinery workshops and use polls too but not necessarily many multiple-choice questions. +This is something that we may change in the future but the initial reason was that we build on existing knowledge +(see below section on our target audience) and give recommendations for best software practices: +there is no unique solution and you would like our learners to choose the approach that is most suitable for them. +For the same reasons, we have many optional exercises to accommodate the different levels. +We would like everyone to get something useful out of the CodeRefinery workshops.

  • +
+
+
+

Getting/giving feedback on teaching

+

Teaching is a skill. One of the objective of the CodeRefinery Instructor training is to give you +the confidence in teaching CodeRefinery lessons. Later we will have group work where we will +practice teaching some lessons.

+

Before doing so, we will learn here to give feedback on teaching using the same +positive-vs-negative and content-vs-presentation rubric.

+
+

Give feedback on teaching (optional, 10 mn)

+

This exercise aims at learning to give feedback. It is optional as we have +similar exercises when practising teaching). +As a group, we will watch this video of teaching and +give feedback on two axes: positive vs. negative and content vs. presentation. Have each person in +the class add one point to a 2x2 grid on a whiteboard or in the shared notes (hackMD, etherpad, google doc) without duplicating any points. +For online instructor training event, use breakout room (4-5 persons per group) to facilitate discussion. Then each group reports to the shared notes. +You can use a rubric (used during The Carpentries teaching demos) to help you take notes. +What did other people see that you missed? What did they think that you strongly agree or disagree with?

+
+
+
+
+
+

Who are the learners

+

The first task in teaching is to figure out who your learners are. The Carpentries approach is +based on the work of researchers like Patricia Benner, +who applied the +Dreyfus model of skill acquisition +in her studies of +how nurses progress from novice to expert +(see also books by Benner). +This work indicates that through practice and formal instruction, learners acquire skills and advance +through distinct stages. In simplified form, the three stages of this model are:

+
+

Novices, competent practitioners and experts

+

Novice, Competent Practitioner, Expert

+
    +
  • Novice: someone who doesn’t know what they don’t know, i.e., +they don’t yet know what the key ideas in the domain are or how they relate. +One sign that someone is a novice is that their questions “aren’t even wrong”.

    +
      +
    • Example: A novice learner in a Carpentries workshop might never have heard of the bash +shell, and therefore may have no understanding of how it relates to their file system or +other programs on their computer.

    • +
    • Example HPC: A learner who has never executed a program on remote computer in headless mode

    • +
    • Example HPC: A learner who has no understanding about using a queue system and having a +hard time why a program can not be run directly after login in.

    • +
    +
  • +
  • Competent practitioner: someone who has enough understanding for everyday purposes. +They won’t know all the details of how something works and their understanding may not +be entirely accurate, but it is sufficient for completing normal tasks with normal +effort under normal circumstances.

    +
      +
    • Example: A competent practitioner in a Carpentries workshop might have used the shell +before and understand how to move around directories and use individual programs, but +they might not understand how they can fit these programs together to build scripts +and automate large tasks.

    • +
    • Example: A competent practitioner in a CodeRefinery workshop is someone that understands +the concepts of best software practices and its importance. He/she clearly sees the +benefits of applying best software practices but he/she does not fully know yet how and +what to use for their own projects.

    • +
    • Example HPC: Knows how to establish a connection to a cluster and have submitted jobs. +But may not know how to request optimal amount of resources in a job and how to setup +parallel jobs

    • +
    +
  • +
  • Expert: someone who can easily handle situations that are out of the ordinary.

    +
      +
    • Example: An expert in a Carpentries workshop may have experience writing and running shell +scripts and, when presented with a problem, immediately sees how these skills can be used +to solve the problem.

    • +
    • Example HPC: A learner who has a good understanding of the queue system, parallel processing +and understand how to interpret error reports when something goes wrong and knows how to +get help.

    • +
    +
  • +
+
+
+

Cognitive Development and Mental Models

+

Effective learning is facilitated by the creation of a well-founded mental model. A mental model +is a collection of concepts and facts, along with the relationships between those concepts, which +a person has about a topic. For example, a long-time resident of the United States may have an +advanced understanding of the location of US states, major cities and landmarks, weather patterns, +regional economies and demographic patterns, as well as the relationships among these, compared +with their understanding of these relationships for other countries. In other words, their mental +model of the United States is more complex compared with their mental model of other countries.

+

We can distinguish between a novice and a competent practitioner for a given domain based +on the complexity of their mental models.

+
    +
  • A novice is someone who has not yet built a mental model of the domain. +They therefore reason by analogy and guesswork, borrowing bits and pieces +of their mental models of other domains which seem superficially similar.

  • +
  • A competent practitioner is someone who has a mental model that’s good enough +for everyday purposes. This model does not have to be completely accurate in order +to be useful: for example, the average driver’s mental model of how a car works +probably doesn’t include most of the complexities that a mechanical engineer +would be concerned with.

  • +
+

We could expect a mixture of learners from novice and competent practitioner groups +in HPC training events.

+

Mental Models

+
+
+
+

How “knowledge” gets in the way

+

Mental models are hardly ever built from scratch. Every learner comes to a topic with +some amount of information, ideas and opinions about the topic. This is true even in +the case where a learner can’t articulate their prior knowledge and beliefs.

+

In many cases, this prior knowledge is incomplete or inaccurate. Inaccurate beliefs +can be termed “misconceptions” and can impede learning by making it more difficult for +learners to incorporate new, correct information into their mental models. +Correcting learners’ misconceptions is at least as important as presenting them with +correct information. Broadly speaking, misconceptions fall into three categories:

+
    +
  • Simple factual errors, such as believing that Vancouver is the capital of +British Columbia. These are the easiest to correct.

  • +
  • Broken models, such as believing that motion and acceleration must be in the +same direction. We can address these by having learners reason through examples to +see contradictions.

  • +
  • Fundamental beliefs, such as “the world is only a few thousand years old” or +“human beings cannot affect the planet’s climate”. These beliefs are deeply connected +to the learner’s social identity and are the hardest to change.

  • +
+

The current HPC carpentry workshop material are aimed at Novice of HPC

+

Among Novice learners there might be learners who are experts in their domain and very +competent in the program they are executing, but may not have used a HPC system before. +Then among the competent practitioners There might be learners who repeat some procedures +they have inherited but lack a in-depth understanding of what’s going on. That is why it is +important to get accurate feedback, before and during the workshops to understand the learner profiles.

+
+

Exercise: How to identify learner profiles?

+
    +
  1. How to identify leaner profiles from surveys and during the class

  2. +
  3. Which types of learners should the leassons focus on

  4. +
+
+
+
+
+
+

CodeRefinery Curriculum and Reverse Instructional Design (with recommendations for HPC carpentries)

+

When writing a CodeRefinery lesson, we take a “reverse” approach to instruction, +as described in Wiggins and McTighe’s +Understanding by Design, +that keeps the focus firmly on learning outcomes. The order of preparation in this case becomes

+
    +
  • Determine your learning objectives

  • +
  • Decide what constitutes evidence that objectives have been met, and design assessments +to target that evidence

  • +
  • Design instruction: Sort assessments in order of increasing complexity, +and write content that connects everything together

  • +
+
+

Working with learning objectives

+

Each CodeRefinery lesson (also the HPC capentries lessons) usually has a learning objectives section. +Good learning objectives are quite specific about the intended effect of a lesson on its learners. +We aim to create learning objectives that are specific, accurate, and informative for +both learners and instructors.

+
+
+

Using Bloom’s Taxonomy to write effective learning objectives

+

Bloom’s Taxonomy is a framework for thinking about learning that breaks progress down into discrete, hierarchical steps. +While many ideas have come and gone in education, Bloom’s has remained a useful tool for educators, in particular because the +hierarchy seems to be reasonably valid: outcomes at the top of the hierarchy cannot be achieved without mastery of outcomes at +the bottom. In the long term, everybody wants to be at the top. However, in aiming to meet learners where they are, we also +need to be mindful about helping them to “grow a level,” helping them to recognize when they have achieved that growth, and +guiding them to look ahead to where we might not be able to take them.

+

Bloom's Taxonomy

+

Image credit: Vanderbilt University Center for Teaching

+
+
+

Revisiting Learning objectives

+

When using existing teaching material, reverse instructional design principles might be applied as +follows:

+
    +
  1. Review the lesson’s learning objectives carefully, thinking about how they will work for your audience

  2. +
  3. Scan the lesson to identify promising points to check in with your learners, using formative assessment to verify that objectives have been met

  4. +
  5. Review the connecting content in detail to be sure everything works and you have anticipated likely problems and questions.

  6. +
+

We strongly encourage you to read them before teaching a lesson and to review whether they still match the content of the lesson:

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/_sources/00-preparation.md.txt b/branch/main/_sources/00-preparation.md.txt new file mode 100644 index 00000000..ebe5d586 --- /dev/null +++ b/branch/main/_sources/00-preparation.md.txt @@ -0,0 +1,50 @@ +--- +layout: episode +title: "Pre-workshop preparation" +teaching: 0 +exercises: 60 +questions: + - "What should I do before the CodeRefinery instructor training workshop?" + - "How long is the preparation work?" + - "Do I need to be Carpentries instructor to attend this workshop?" +--- + +# Pre-workshop preparation + + +## You don't have to be a [Carpentries instructor](https://carpentries.org/instructors/) + +Being a [Carpentries instructor](https://carpentries.org/instructors/) is not +required to attend CodeRefinery instructor training workshop. + +> ## Preparation before the workshop (takes ca. 1 hour) +> +> - Complete our pre-workshop survey. Your responses will help us to customize the workshop appropriately. +> +> - Read this short paper [The Science of Learning](https://carpentries.github.io/instructor-training/files/papers/science-of-learning-2015.pdf) which provides a brief overview of some key evidence-based results in teaching. This paper is also used by [The Carpentries](https://carpentries.org/) for their Instructor Training workshops. +> +> - Watch at least two of recorded ca. 5-minute +> [lightning overview videos](https://www.youtube.com/playlist?list=PLpLblYHCzJABvt25VY0wNIgbaQfTQaND7) +> introducing various +> [CodeRefinery lessons](https://coderefinery.org/lessons/) +> to get an overview of what we teach in CodeRefinery and also to be +> able to practice CodeRefinery teaching on day 2 of this course. +> +> - Watch at least two of recorded +> ["this is my training philosophy" videos](https://www.youtube.com/playlist?list=PLpLblYHCzJAAHF89P-GCjEXWC8CF-7nhX) +> which we will +> discuss in group discussions and which will form the basis for a group +> exercise. +> +> - Please go through a [CodeRefinery lesson](https://coderefinery.org/lessons/) and find one +> topic/episode/aspect that you find interesting. During a group session you +> will be asked to present a topic/episode/aspect of your choice for 5 +> minutes and get constructive feedback. +{: .prereq} + +> ## Remark +> +> Don't worry if there are sections you do not understand. The main objective +> is to have a baseline for our discussions, not to check your ability to teach +> the lesson during the instructor training workshop. +{: .callout} diff --git a/branch/main/_sources/02-teaching-philosophies.md.txt b/branch/main/_sources/02-teaching-philosophies.md.txt new file mode 100644 index 00000000..66bae95b --- /dev/null +++ b/branch/main/_sources/02-teaching-philosophies.md.txt @@ -0,0 +1,237 @@ +--- +layout: episode +title: "Our teaching philosophies" +teaching: 0 +exercises: 30 +questions: + - "What are our teaching philosophies?" +--- + +# CodeRefinery teaching philosophies + +> ## Ice-breaker in groups (20 minutes) +> +> - Share your approach to teaching and your teaching philosophy with your group. +> - Please share your tricks and solutions in the live document for others. +> +> Additional ice-breaker questions: +> - What is your motivation for taking this training? +> - How structured or informal are your own teaching needs? +> - What difference do you notice between the teaching what we (also +> Carpentries) do and traditional academic teaching? +> - What other skills need to be taught, but academic teaching isn't the right setting? +{: .challenge} + +--- + +Here CodeRefinery instructors share their training philosophy to show that we +all have different teaching styles and how these differences are beneficial to +CodeRefinery workshops. + +It is important to explain how much we value individuals and that there is not +one way to teach but as many ways as individuals. We want to help each other to +find the way that is best for each of us. + +> ## Video recordings +> +> Recently we have recorded some of the below as videos: +> +{: .prereq} + +> ## Anne Fouilloux +> +> I regularly teach Carpentries workshops so I try to apply what I have learnt to CodeRefinery workshops. However, I know our target audience is very much different and that I need to adapt my teaching style. I am still trying to find what works best in which situations and this is why I like so much CodeRefinery workshops. We usually have a wider range of skills and very mixed backgrounds so we usually have to be more careful with the pace and time given for exercises. +> +> Some considerations: +> - I spend quite a lot of time reading the CodeRefinery material and practising myself exercises. I particularly like to read the instructor notes just before teaching: they usually highlight important aspects both for preparing and teaching. +> - I usually do not show too much in advance the material as I think it prevents asking questions. If you have less competent practitioners in the classroom, they can easily copy-paste to avoid slowing down the entire classroom. +> - Ideally, I'd like to give several exercises so anyone can work at its own pace. I find it is important that everybody gets something different from the workshop. +> - I love breaks as it gives us an opportunity to discuss with attendees on their research topics. I am especially interested to understand what software they write and how they plan to use what they learn during our workshops. +{: .challenge} + +> ## Bjørn Lindi +> +> My teaching style has changed a bit since I started with CodeRefinery. In the beginning I had this "BLOB" (Binary Large OBject) of knowledge and experience that I wanted to to convey to the participants. With experience and some help from the Carpentries Instructor training, I have realized I need to serialize the "BLOB", to be able to share it with others. +> +>In a similar fashion as you would do with a binary large object which you intend to send over the wire, you will need stop signals, check-sums and re-transmissions, when you give a lecture. I have come to appreciate the natural periods/breaks the lessons offers, the questions raised, the errors that appear during type-along and the re-transmission. Co-instructors are good to use for re-transmission or broadening a specific topic. +> +>When I started with CodeRefinery my inclination was to give a lecture. Today I am trying to be a guide during a learning experience, a learning experience which includes me as well. That may sound a bit self-centric, but is in fact the opposite, as I have to be more sensitive to what is going on in the room. The more conscious I am of being a guide, the better lesson. +> +>Tools that I find useful in preparing a lesson is concept maps and Learner Personas, though I have develop to few them. +>- [Concept Maps](https://teachtogether.tech/#s:memory-concept-maps) +>- [Learner Personas](https://teachtogether.tech/#s:process-personas) +{: .challenge} + +> ## Thor Wikfeldt +> +> I never want to leave any learner behind and I really don't like seeing confused, blank faces in the classroom. +> At the same time I sometimes worry about some participants getting bored if a lesson is progressing slowly. +> This is always a difficult compromise and something I struggle with! +> +> I try to focus on making concepts intuitive, to "make sense" to the learners. Of course this is usually +> based on how I learned the topic myself and how it makes sense to me. +> +> I try to establish connections between topics: "this thing here is similar to what we saw in the previous +> lesson where we learned about X...". +> +> Before mastering a lesson by teaching in many times I try to "follow the script". After becoming very +> familiar with a lesson I start to improvise more and react more dynamically to questions, e.g. by taking a +> detour to explain a confusing topic more clearly. +> +> What I think I do too often: copy-paste code/text from lesson material. This can leave learners behind - +> typing out the code and describing it is slower, but more learning takes place. More advanced learners +> will hopefully "be compensated" by interesting advanced exercises which follow. +{: .challenge} + +> ## Stefan Negru +> +> A lesson is a conversation, it is useful if both the trainer and the trainee are engaged. +> For that reason I try to have, most of the time, a conversation with the classroom and +> after we finish parts of a lesson, step back and see how we might use what we learned. +> +> That brings me to another point I follow throughout the lessons, answering questions like: +> * How can we apply in practice what we just learned? +> * Do you see yourself (the trainee) using that in practice, why or why not? +> +> Most of the times those seem like open-ended questions to the trainees that just learned +> something new, so I try to find examples, most of the times from personal experience. +> +> Last thing is that analogies are important when I teach, I try to find analogies in order +> to simplify a convoluted part of a lesson. +{: .challenge} + +> ## Radovan Bast +> +> My teaching changed by 180 degrees after taking the Carpentries instructor +> training. Before that I used slides, 45 minute lecture blocks, and separate +> exercise sessions. After the Carpentries instructor training I embraced the +> interaction, exercises, demos, and typos. +> +> My goal for a lesson is to spark curiosity to try things after the lesson, +> both for the novices ("This looks like a useful tool, I want to try using it +> after the workshop.") and the more experienced participants ("Aha - I did not +> know you could do this. I wonder whether I can make it work with X."). I like +> to start lessons with a question because this makes participants look up from +> their browsers. +> +> Keeping both the novices and the experts engaged during a lesson can be +> difficult and offering additional exercises seems to be a good compromise. +> +> For me it is a good sign if there are many questions. I like to encourage +> questions by asking questions to the participants. But I also try not to go +> into a rabbit hole when I get a question where only experts will appreciate +> the answer. +> +> I try to avoid jargon and "war stories" from the professional developers' +> perspective or the business world. Most researchers may not relate to them. +> For examples I always try to use the research context. Avoid "customer", +> "production", also a lot of Agile jargon is hard to relate to. +> +> Less and clear is better than more and unclear. Simple examples are better +> than complicated examples. Almost never I have felt or got the feedback that +> something was too simple. I am repeating in my head to not use the words +> "simply", "just", "easy". If participants take home one or two points from +> a lesson, that's for me success. +> +> I prepare for the lesson by reading the instructor guide and all issues and +> open pull requests. I might not be able to solve issues, but I don't want to +> be surprised by known issues. I learn the material to a point where I know +> precisely what comes next and am never surprised by the next episode or +> slide. This allows me to skip and distill the essence and not read bullet +> point by bullet point. +> +> I try to never deviate from the script and if I do, be very explicit about +> it. +> +> A great exercise I can recommend is to watch a tutorial on a new programming +> language/tool you have never used. It can feel very overwhelming and fast to +> get all these new concepts and tools thrown at self. This can prepare me for +> how a participant might feel. +> +> I find it very helpful if there is somebody else in the room who helps me +> detecting when I go too fast or become too confusing. I like when two +> instructors complement each other during a lesson but when doing that to +> others, I am often worried of interrupting their flow and timing too much. +> +> A mistake I often do is to type too fast and in my mind I force myself +> to slow down. +{: .challenge} + +> ## Sabry Razick +> My approach is to show it is fun to demystify concepts. Once a concept is +> not a mystery anymore, the learners will understand is what it means, where +> it is coming from, why it is in place and what it could it offer for their future. +> I try to relate concepts to real life with a twist of humour whenever possible if +> the outcome is certain not be offensive to any one. I use diagrams whenever possible, +> I have spent weeks creating diagrams that is sometime three or four sentences. That +> effort I consider worthwhile as my intention is not to teach, but to demystify. +> Once that is achieved, learners will learn the nitty gritty on their own easily +> and with confidence, when they have the use-case. +> +> +{: .challenge} + +> ## Juho Lehtonen +> I'm gradually realising the different ways to get a hint whether the workshop +> participants are still following or perhaps bored. I assume it's communicating +> with the class, with exercises and simply by asking now and then. I also try +> to remember to observe how people look like (puzzled, bored) while I teach, not +> so obvious for me. +> +> I believe that learners communicating with each other, in addition to with +> instructors and helpers, really helps them to understand things faster. (At least +> it helps me). So I try to make sure that no one sits or works alone at the workshops. +{: .challenge} + +> ## Richard Darst +> +> Like many people, I've often been teaching, but rarely a teacher. I +> tend to teach like I am doing an informal mentorship. +> I've realized long ago that my most important lessons weren't +> learned in classes, but by a combination of seeing things done by +> friends and independent study after that. I've realized that +> teaching (the things I teach) is trying to correct these differences +> in backgrounds. +> +> My main job is supporting computing infrastructure, so my teaching +> is very grounded in real-world problems. I'm often start at the +> very basics, because this is what I see missing most often. +> +> When teaching, I like lots of audience questions and don't mind +> going off-script a bit (even though I know it should be minimized). +> I find that sufficient audience interest allows any lesson to be a +> success - you don't have to know everything perfectly, just show how +> you'd approach a problem. +> +{: .challenge} + +> ## João M. da Silva +> +> I started giving technical trainings twenty years ago, and hence my perspective +> is perhaps more inclined towards the development of hands-on abilities and +> capability to solve problems, independently or in a team. +> +> But the development of hands-on practical skills, requires some essential +> knowledge about the domain and some willingness to try different approaches +> in case one gets stuck. Some call this the "KSA approach" +> ("Knowledge-Skills-Attitude). Hence, I +> try to impart the essential knowledge (and where to find out more) at my +> trainings. And to encourage and challenge students in order to make them +> overcome their self-perceived limits (e.g. "I'm a Humanist, I can't use +> Python virtualenv"). +> +> I've been trying to study more about the Cognitive aspects of learning over the years, +> and I should find out the time to return to that. There's very interesting +> research in Problem Solving, with Learning being a important component in that domain. +> +> Storytelling: humans are neurologically made for paying attention to good +> stories, and that's something that I try to put into account: to give +> a lesson like it would be a relevant narrative for the students, one that they +> could relate to and help them in their work +> +> I like to draw and be creative with that, but have to pay attention to +> my handwriting during my trainings. I reckon that Architectural diagrams +> help students to understand the big picture, so I should invest more on +> those when development training material. I would also like to start looking into +> Concept Maps and Semantic Trees in training. +{: .challenge} diff --git a/branch/main/_sources/03-teaching-style.md.txt b/branch/main/_sources/03-teaching-style.md.txt new file mode 100644 index 00000000..8164130c --- /dev/null +++ b/branch/main/_sources/03-teaching-style.md.txt @@ -0,0 +1,336 @@ +--- +layout: episode +title: "Carpentries and CodeRefinery approach to teaching" +teaching: 30 +exercises: 30 +questions: + - "What pedagogical concepts underpin CodeRefinery and Carpentry workshops?" + - "How to get and give feedback?" + - "Who are the CodeRefinery learners?" + - "Why is it important to define learning objectives?" +objectives: + - "Explain The Carpentries and CodeRefinery approaches to teaching" + - "Understand what is meant by feedback, cognitive development, mental models and reverse instructional design" + - "Explain and practice important pedagogical concepts" +keypoints: + - "CodeRefinery lessons and teaching build on these principles" +--- +# Interactive teaching style + + +## What are the top issues new instructors face? + +```{solution} + - 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. + - Get the speed correct. Not too fast and not too slow. + - 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. + - 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. + - Special issues when lessons delivered online (discussed during Workshop preparation and organization) +``` + + +# The Carpentries and CodeRefinery approaches to teaching + +Here we will give you a very short overview of the Carpentries approach to teaching and highlight +parts that are most important for teaching CodeRefinery style lessons. + +Most CodeRefinery instructors have completed the +[Carpentry instructor training workshop](https://carpentries.github.io/instructor-training/), which +[anyone can apply for](https://carpentries.org/become-instructor/) + +> ## This material +> +> This section is derived from the +> [Carpentries instructor training material](https://carpentries.github.io/instructor-training/). +> We encourage you to further study this material later, and to sign up for a 2-day Carpentry +> intructor training workshop. +{: .callout} + +--- + +## Key principles + +The "Carpentries" approach to teaching is based on: + +- Applying research-based teaching principles, especially as they apply to the + Carpentries audience. +- Understanding the importance of a respectful and inclusive classroom environment. + + +### Carpentries teaching principles + +- Learners need to practice what they are learning in real time and get **feedback** on what they + are doing. That is why the teaching approach relies on **live coding**. +- Learners best learn in a respectful classroom environment, so the Carpentries use a + [Code of Conduct](https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html). +- Learners are encouraged to help each other during workshops as this improves their confidence + and reinforces concepts taught. +- Carpentry instructors try to have learners do something that they think is useful in their + daily work within **15 minutes of starting each lesson**. + +![What to Teach](https://carpentries.github.io/instructor-training/fig/what-to-teach.png) + +In CodeRefinery, we follow The Carpentries teaching principles but in addition to **live coding** +we often use **group discussions** to put in context the concepts we are teaching. + +Applying these teaching principles are not sufficient and in addition we need to be able to check +the effectiveness of our methods. + +--- + +## On the importance of feedback + +Feedback is an essential part of effective learning. Feedback is bi-directional: +- To be effective, instructors need feedback on their learners' progress. Learners can also check their progress and ask relevant questions to get clarification. +- Instructors also need feedback on their teaching. For instance, this can help them to adapt the pace, add/skip optional exercises and improve their teaching. + +### Getting/giving feedback on learners' progress + +This feedback comes through what is called *formative assessments* (in contrast + to *summative assessment*). + +> ## Summative Assessment +> *Summative assessment* is used +> to judge whether a learner has reached an acceptable level of competence. +> Usually at the end of a course +> Learners either "pass" or "fail" a summative assessment. +> One example is a driving exam, +> which tells the rest of society whether someone can safely be allowed on the road. Most assessment done in university +> courses is summative, and is used to assign course grades. +{: .callout} + +> ## Formative assessment +> *Formative assessment* takes place during teaching and learning. It sounds like +> a fancy term, but it can be used to describe any interaction or activity +> that provides feedback to both instructors and learners about learners' level of understanding of the +> material. For learners, this feedback can help focus their study efforts. For instructors, it allows them to refocus +> their instruction to respond to challenges that learners are facing. +> Used continuously +{: .callout} + +Learners don't "pass" or "fail" formative assessments; they are simply a feedback mechanism. +For example, a music teacher might ask a learner to play a scale very slowly +in order to see whether they are breathing correctly, +and if not, what they should change. + +Formative assessment is most useful when it happens frequently (we'll talk about how frequently later) +and when the results are easily interpretable by the learner and instructor. + + +CodeRefinery uses different instruments to get feedback from learners: + +- Surveys: we will discuss about CodeRefinery pre/post-surveys in the episode + {doc}`workshops-online`. +- Exercises: we have many exercises during CodeRefinery workshops and use polls too but not necessarily many multiple-choice questions. + This is something that we may change in the future but the initial reason was that we build on existing knowledge + (see below section on our target audience) and give recommendations for best software practices: + there is no unique solution and you would like our learners to choose the approach that is most suitable for them. + For the same reasons, we have many optional exercises to accommodate the different levels. + We would like everyone to get something useful out of the CodeRefinery workshops. + +### Getting/giving feedback on teaching + +Teaching is a skill. One of the objective of the CodeRefinery Instructor training is to give you +the confidence in teaching CodeRefinery lessons. Later we will have group work where we will +practice teaching some lessons. + +Before doing so, we will learn here to give feedback on teaching using the same +positive-vs-negative and content-vs-presentation rubric. + +> ## Give feedback on teaching (optional, 10 mn) +> This exercise aims at learning to give feedback. It is optional as we have +> similar exercises when {doc}`practising teaching `). +> As a group, we will watch [this video of teaching](https://www.youtube.com/watch?v=-ApVt04rB4U) and +> give feedback on two axes: positive vs. negative and content vs. presentation. Have each person in +> the class add one point to a 2x2 grid on a whiteboard or in the shared notes (hackMD, etherpad, google doc) without duplicating any points. +> For online instructor training event, use breakout room (4-5 persons per group) to facilitate discussion. Then each group reports to the shared notes. +> You can use a [rubric](http://carpentries.github.io/instructor-training/demos_rubric/) (used during The Carpentries teaching demos) to help you take notes. +> What did other people see that you missed? What did they think that you strongly agree or disagree with? +> +{: .challenge} + +--- + +## Who are the learners + +The first task in teaching is to figure out who your learners are. The Carpentries approach is +based on the work of researchers like [Patricia Benner](https://en.wikipedia.org/wiki/Patricia_Benner), +who applied the +[Dreyfus model of skill acquisition](https://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition) +in her studies of +[how nurses progress from novice to expert](http://journals.sagepub.com/doi/10.1177/0270467604265061) +([see also books by Benner](https://www.worldcat.org/search?q=au%3ABenner%2C+Patricia+E.&qt=hot_author)). +This work indicates that through practice and formal instruction, learners acquire skills and advance +through distinct stages. In simplified form, the three stages of this model are: + +### Novices, competent practitioners and experts + +![Novice, Competent Practitioner, Expert](https://carpentries.github.io/instructor-training/fig/skill-level.svg) + +* *Novice*: someone who doesn't know what they don't know, i.e., + they don't yet know what the key ideas in the domain are or how they relate. + One sign that someone is a novice is that their questions "aren't even wrong". + + - Example: A *novice* learner in a Carpentries workshop might never have heard of the bash + shell, and therefore may have no understanding of how it relates to their file system or + other programs on their computer. + + - Example HPC: A learner who has never executed a program on remote computer in headless mode + + - Example HPC: A learner who has no understanding about using a queue system and having a + hard time why a program can not be run directly after login in. + +* *Competent practitioner*: someone who has enough understanding for everyday purposes. + They won't know all the details of how something works and their understanding may not + be entirely accurate, but it is sufficient for completing normal tasks with normal + effort under normal circumstances. + + - Example: A *competent practitioner* in a Carpentries workshop might have used the shell + before and understand how to move around directories and use individual programs, but + they might not understand how they can fit these programs together to build scripts + and automate large tasks. + + - Example: A *competent practitioner* in a CodeRefinery workshop is someone that understands + the concepts of best software practices and its importance. He/she clearly sees the + benefits of applying best software practices but he/she does not fully know yet how and + what to use for their own projects. + + - Example HPC: Knows how to establish a connection to a cluster and have submitted jobs. + But may not know how to request optimal amount of resources in a job and how to setup + parallel jobs + + +* *Expert*: someone who can easily handle situations that are out of the ordinary. + + - Example: An *expert* in a Carpentries workshop may have experience writing and running shell + scripts and, when presented with a problem, immediately sees how these skills can be used + to solve the problem. + + - Example HPC: A learner who has a good understanding of the queue system, parallel processing + and understand how to interpret error reports when something goes wrong and knows how to + get help. + + +### Cognitive Development and Mental Models + +Effective learning is facilitated by the creation of a well-founded mental model. A mental model +is a collection of concepts and facts, along with the relationships between those concepts, which +a person has about a topic. For example, a long-time resident of the United States may have an +advanced understanding of the location of US states, major cities and landmarks, weather patterns, +regional economies and demographic patterns, as well as the relationships among these, compared +with their understanding of these relationships for other countries. In other words, their mental +model of the United States is more complex compared with their mental model of other countries. + +We can distinguish between a *novice* and a *competent practitioner* for a given domain based +on the complexity of their mental models. + +* A *novice* is someone who has not yet built a mental model of the domain. + They therefore reason by analogy and guesswork, borrowing bits and pieces + of their mental models of other domains which seem superficially similar. +* A *competent practitioner* is someone who has a mental model that's good enough + for everyday purposes. This model does not have to be completely accurate in order + to be useful: for example, the average driver's mental model of how a car works + probably doesn't include most of the complexities that a mechanical engineer + would be concerned with. + +We could expect a mixture of learners from *novice* and *competent practitioner* groups +in HPC training events. + +![Mental Models](https://carpentries.github.io/instructor-training/fig/mental_models.svg) + +--- + +### How “knowledge” gets in the way + +Mental models are hardly ever built from scratch. Every learner comes to a topic with +some amount of information, ideas and opinions about the topic. This is true even in +the case where a learner can’t articulate their prior knowledge and beliefs. + +In many cases, this prior knowledge is incomplete or inaccurate. Inaccurate beliefs +can be termed “misconceptions” and can impede learning by making it more difficult for +learners to incorporate new, correct information into their mental models. +Correcting learners’ misconceptions is at least as important as presenting them with +correct information. Broadly speaking, misconceptions fall into three categories: + +- **Simple factual errors**, such as believing that Vancouver is the capital of + British Columbia. These are the easiest to correct. +- **Broken models**, such as believing that motion and acceleration must be in the + same direction. We can address these by having learners reason through examples to + see contradictions. +- **Fundamental beliefs**, such as “the world is only a few thousand years old” or + “human beings cannot affect the planet’s climate”. These beliefs are deeply connected + to the learner’s social identity and are the hardest to change. + + +The current HPC carpentry workshop material are aimed at **Novice** of HPC + +Among *Novice* learners there might be learners who are experts in their domain and very +competent in the program they are executing, but may not have used a HPC system before. +Then among the **competent practitioners** There might be learners who repeat some procedures +they have inherited but lack a in-depth understanding of what's going on. That is why it is +important to get accurate feedback, before and during the workshops to understand the learner profiles. + + +> ## Exercise: How to identify learner profiles? +> +> 1. How to identify leaner profiles from surveys and during the class +> 2. Which types of learners should the leassons focus on +{: .challenge} + +--- + +## CodeRefinery Curriculum and Reverse Instructional Design (with recommendations for HPC carpentries) + +When writing a CodeRefinery lesson, we take a “reverse” approach to instruction, +as described in Wiggins and McTighe’s +[Understanding by Design](http://www.worldcat.org/title/understanding-by-design/oclc/56491025), +that keeps the focus firmly on learning outcomes. The order of preparation in this case becomes + +- Determine your learning objectives +- Decide what constitutes evidence that objectives have been met, and design assessments + to target that evidence +- Design instruction: Sort assessments in order of increasing complexity, + and write content that connects everything together + +### Working with learning objectives + +Each CodeRefinery lesson (also the HPC capentries lessons) usually has a *learning objectives* section. +Good learning objectives are quite specific about the intended effect of a lesson on its learners. +We aim to create learning objectives that are specific, accurate, and informative for +both learners and instructors. + + +### Using Bloom's Taxonomy to write effective learning objectives + +[Bloom's Taxonomy](https://cft.vanderbilt.edu/guides-sub-pages/blooms-taxonomy/) is a framework for thinking about learning that breaks progress down into discrete, hierarchical steps. +While many ideas have come and gone in education, Bloom's has remained a useful tool for educators, in particular because the +hierarchy seems to be reasonably valid: outcomes at the top of the hierarchy cannot be achieved without mastery of outcomes at +the bottom. In the long term, everybody wants to be at the top. However, in aiming to meet learners where they are, we also +need to be mindful about helping them to ["grow a level,"](https://software-carpentry.org/blog/2018/03/tractenberg-summary.html) helping them to recognize when they have achieved that growth, and +guiding them to look ahead to where we might not be able to take them. + +![Bloom's Taxonomy](https://carpentries.github.io/instructor-training/fig/Blooms.png) + +Image credit: Vanderbilt University Center for Teaching + +### Revisiting Learning objectives + +When using existing teaching material, *reverse instructional design* principles might be applied as +follows: + +1. Review the lesson's learning objectives carefully, thinking about how they will work for your audience +2. Scan the lesson to identify promising points to check in with your learners, using formative assessment to verify that objectives have been met +3. Review the connecting content in detail to be sure everything works and you have anticipated likely problems and questions. + + +We strongly encourage you to read them before teaching a lesson and to review whether they still match the content of the lesson: diff --git a/branch/main/_sources/about-coderefinery.md.txt b/branch/main/_sources/about-coderefinery.md.txt new file mode 100644 index 00000000..1c9ba2cb --- /dev/null +++ b/branch/main/_sources/about-coderefinery.md.txt @@ -0,0 +1,112 @@ +# About the CodeRefinery project + +CodeRefinery is a +[Nordic e-Infrastructure Collaboration (NeIC)](https://neic.no/) +project that has started in October 2016 and is +funded until October 2021. + +We hope to keep this project active beyond 2021 by forming a support network +and building a community of instructors and contributors. + +--- + +> ## History +> +> The CodeRefinery project idea grew out of two [SeSE](http://sese.nu) courses given at KTH Stockholm in 2014 and 2016: +> - [http://sese.nu/scientific-software-development-toolbox/](http://sese.nu/scientific-software-development-toolbox/) +> - [http://sese.nu/scientific-software-development-toolbox-2016/](http://sese.nu/scientific-software-development-toolbox-2016/) +> +> The project proposal was submitted to NeIC in 2015, accepted in 2015, and started in 2016. +> +> We have started by porting own lessons to the Carpentries teaching style and +> format, and collaboratively and iteratively grew and improved the material to +> its present form. +{: .discussion} + +--- + +## Main goals + +- Develop and maintain **training material on software best practices** for researchers that already write code. Our material addresses all academic disciplines and tries to be as programming language-independent as possible. +- Provide a [code repository hosting service](https://coderefinery.org/repository/) that is open and free for all researchers based in universities and research institutes from Nordic countries. +- Provide **training opportunities** in the Nordics using Carpentries and CodeRefinery training materials. +- Articulate and implement the CodeRefinery **sustainability plan**. + +--- + +## Impact + +We collect feedback and survey results to measure our impact. + +3-6 months after attending a workshop, past participants are asked to complete a short post-workshop survey. +The survey questions aim to establish what impact CodeRefinery workshops have on how past participants develop +research software. + +post-workshop survey results + +- Overall quality of research software has improved: more reusable, modular, reproducible and documented. +- Collaboration on research software development has become easier +- Past participants share their new knowledge with colleagues +- Usage of several tools is improved, and new tools are adopted + +[Free-form answers](https://coderefinery.org/#what-do-our-participants-say-after-attending-a-workshop) +also suggest that workshops are having the intended effects on how people develop code. A common theme is: +> *I wish I had known this stuff already as a grad student 10+ years ago...* + +We would love to get suggestions on how we can better quantify our impact. This +would make it easier for us to convince institutions to partner with us and +also open up funding opportunities. + +--- + +## Carpentries membership + +Since November 2018, [NeIC](https://neic.no) is a [Platinum Partner](https://carpentries.org/members/) to [The Carpentries](https://carpentries.org/). + +The Carpentries is an international project that comprises Software Carpentry and Data Carpentry, communities of instructors, trainers, maintainers, helpers, +and supporters who share a mission to teach foundational computational and data science skills to researchers. +The Carpentries teach foundational coding and data science skills to researchers worldwide and as such are complementary to CodeRefinery. + +Within the membership the Nordic research community has access to: + +- 6 Carpentries workshops in the Nordics each year. The workshop fee is covered by the membership, only the instructor travel is on the host institution. +- 15 seats in the Carpentries instructor training each year. Carpentries train the trainer program aims at building partnerships with Research Software Engineers and researchers who are willing to lead skill transfer within their local communities in the Nordics. + +--- + +## Target audience + +### Carpentries audience + + +The Carpentries aims to teach computational **competence** to learners through an applied approach, avoiding the theoretical and general in favor of the practical and specific. + +**Learners do not need to have any prior experience in programming.** One major goal of a Carpentry workshop is to raise awareness on the tools researchers can learn/use to speed up their research. + +By showing learners how to solve specific problems with specific tools and providing hands-on practice, learners develops confidence for future learning. + +> ## Novices +> We often qualify Carpentry learners as **novices**: they do not know what they need to learn yet. A typical example is the usage of version control: the Carpentry `git` lesson aims to give a very high level conceptual overview of Git but it does not explain how it can be used in research projects. +{: .callout} + + +### CodeRefinery audience + +In that sense, CodeRefinery workshops differ from Carpentry workshops as we assume our audience already writes code and scripts and we aim at teaching them **best software practices**. + +Our learners usually do not have a good overview of **best software practices** but are aware of the need to learn them. Very often, they know the tools (Git, Jupyter, etc.) we are teaching but have difficulties to make the best use of them in their software development workflow. + +Whenever we can, we should direct learners that do not have sufficient coding experience to Carpentries workshops. + +> ## Competent practitioners +> We often qualify CodeRefinery learners as **competent practitioners** because they already have an understanding of their needs. +> *Novices* and *competent practitioners* will be more clearly defined in the {doc}`next section <03-teaching-style>`. +{: .callout} + +> ## Best software practices for whom? +> It can be useful to ask the question: *best software practices for whom*? +> CodeRefinery teaches *best software practices* derived from producing and +> shipping software. These practices are also very good for sharing software, +> though our audience will probably not need to embrace *all* aspects of +> software engineering. +{: .callout} diff --git a/branch/main/_sources/coderefinery-workshops.md.txt b/branch/main/_sources/coderefinery-workshops.md.txt new file mode 100644 index 00000000..4979f540 --- /dev/null +++ b/branch/main/_sources/coderefinery-workshops.md.txt @@ -0,0 +1,37 @@ +# Organize a CodeRefinery workshop + +You or us? +- Historically, most workshops are CodeRefinery workshops were + organized centrally with a local host. +- Now, we want to transition to locally-invited workshops, so we know + we have a audience and advertisement. +- In the future, we need to transition to "independently run". + +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. + +## Centrally organized workshops + +- CodeRefinery staff organize, we try to reach as many people as + possible. +- Workshops in our own institutions tend to be best-attended, going to + a new institution sometimes has low attendance. +- We started this way. + + +## Locally invited workshops + +- A local team requests CodeRefinery (usually with a known audience). +- There is usually pretty good attendance. +- CodeRefinery staff travels to site and teaches - at least with local + helpers, ideally with a local instructor. + +## Independently organized workshops + +- In the future, we want to encourage independently organized + workshops: a site can organize the workshops without needing to go + through the core team. +- We don't yet know exactly how this will work, but this instructor + training is part of it. diff --git a/branch/main/_sources/future.md.txt b/branch/main/_sources/future.md.txt new file mode 100644 index 00000000..4a52d121 --- /dev/null +++ b/branch/main/_sources/future.md.txt @@ -0,0 +1,69 @@ +# Future + +## Activities + +### What is CodeRefinery? +- Teaching tools and best practices for version control and reproducibility in modern research software development +- Over 30 workshops to almost 1000 participants +- Typical workshop: +- Lessons: +- Carpentries membership + +### This workshop +- Was it a useful format and useful content? Please give us feedback. +- Should we collaborate on HPC Carpentry workshops? +- Who will end up teaching HPC Carpentry? What do you need from us/somebody as support? + +### Nordic-RSE (research software engineers) +- [Nordic-RSE Get together online event, Nov 30 - Dec 2, 2020](https://nordic-rse.org/events/2020-online-get-together/) +- [Conference May 2021](https://nordic-rse.org/conference/) +- [Map](https://nordic-rse.org/map/) +- Bi-weekly meetings + +### Collaborative workshops +- Example: +- Ideas for more of this? + +--- + +## How to get involved in CodeRefinery + +There are many ways to get involved: + +- Become a workshop helper +- Become a CodeRefinery workshop instructor +- Become a Carpentries workshop instructor +- Contribute to teaching material: +- Create your own teaching material in our constellation of teaching. +- Reuse our material +- Become an institutional partner as a training hub +- Participate in our chat and shape the project and lessons with us: +- Start a study group + +--- + +## Biggest open problems + +- How to give helpers and contributors more credit and visibility +- How to promote/engage new members +- We don't know how we should be in relation with Carpentries +- What are we? Non-profit? Institution collaboration network? Selling services? +- Funding and sustainability (but we have ideas: collaboration network) +- Scalability and marketing question: How to reach more people? + ([Research Software Hour](https://researchsoftwarehour.github.io/), Twitch, streaming-only + workshops, recording, post-processing videos) + +--- + +## Certification for CodeRefinery instructors + +We will set up a more formal process soon but for now you would need to: + +- Attend an instructor training (this workshop). +- Contribute to a lesson, either via pull request, issue, discussion, or as a helper. +- Share a short teaching demo or teach a lesson at a CodeRefinery workshop where you will get some feedback on your teaching. +- Participate in a call with other instructors and helpers either preparing a workshop or during a workshop debrief session. + +There are many ways to learn how to teach well. We and carpentries provide one way and basic material, but we want to find a way for everyone to be a part of us. + +See also https://coderefinery.github.io/manuals/instructor-intro/#from-helper-to-more. diff --git a/branch/main/_sources/guide.rst.txt b/branch/main/_sources/guide.rst.txt new file mode 100644 index 00000000..bb15781e --- /dev/null +++ b/branch/main/_sources/guide.rst.txt @@ -0,0 +1,2 @@ +Instructor's guide +------------------ diff --git a/branch/main/_sources/index.rst.txt b/branch/main/_sources/index.rst.txt new file mode 100644 index 00000000..4bd32ecf --- /dev/null +++ b/branch/main/_sources/index.rst.txt @@ -0,0 +1,141 @@ +Community teaching training +=========================== + +In 2020, we got farther from our offices but closer to each other. If +you could adapt to the circumstances, a huge number of possibilities +were opened - in particular with collaborative teaching. In this +training, you will learn how to use them. Teaching from 2019 is +almost obsolete - join us to learn more. + +Teaching is a profession, but also something that everyone needs to be +able to do to some degree, since everyone has their own personal +specialties they will either teach or mentor. + +Broadly, this covers: + +- **Tools of teaching**: how to make the most out of online (and + other) teaching +- **Workshop organization, collaboratively**: our vision of teaching + together outside of our silos. +- **Socio-technical factors**: social and technical barriers to + learning, why you need to care, and what you can do about them. +- **Lesson development, collaboratively**: how to design lessons and + teaching materials so that they can be open and shared. + +.. prereq:: + + This course has no strict prerequisites, but + + * It is helpful if you have attended CodeRefinery or Carpentries + workshops, which teach in an interactive and hands-on way. + + * We assume you already have competence in the technical tools you + want to teach. Many of our concepts use examples from + CodeRefinery lessons, such as version control or other software + development tools. + + * While not a prerequisite for this course, version control (git) + is necessary to contribute to lessons development the way we show + here (but the lesson design concepts are applicable to other + styles, too). + + +.. toctree:: + :maxdepth: 1 + :caption: Introduction + +.. toctree:: + :maxdepth: 1 + :caption: Teaching tools + +.. toctree:: + :maxdepth: 1 + :caption: Workshop organization + +.. toctree:: + :maxdepth: 1 + :caption: Sociol-technical considerations + +.. toctree:: + :maxdepth: 1 + :caption: Lesson development + +.. toctree:: + :maxdepth: 1 + :caption: Outro + + + +.. toctree:: + :maxdepth: 1 + :caption: Old TOC + + 00-preparation.md + welcome.md + about-coderefinery.md + 02-teaching-philosophies.md + 03-teaching-style.md + workshops-online.md + lesson-design.md + lesson-development.md + teaching-strategies + teaching-practice.md + future.md + coderefinery-workshops + + +.. toctree:: + :maxdepth: 1 + :caption: Reference + + quick-reference + guide + + +.. _learner-personas: + +Who is the course for? +---------------------- + +You are interested in teaching CodeRefinery lessons, and would like a +comprehensive kickstart to how CodeRefinery works either to join us, +or teach its lessons with us or independently. + +You are a technical specialist who is frustrated with the way you +currently try to teach others who need to use your software or +infrastructure. You can't spend too much time to become a +professional, but you know you need something more than what you've +been doing. Thus, you would like to adopt some of the best practices of +designing and teaching interactive, hands-on workshops. + +You've been teaching alone, but would like to join a collaboration +network for more co-teaching and to reduce the amount of duplication +of effort. + +You run a practical teaching program at your institution (for example +as part of a research computing group) and would like to learn best +practices for collaborative teaching, so that you aren't re-inventing +the same thing over and over again. + + + +See also +-------- + +* `The old "CodeRefinery instructor training" program + `__ - this is + replaced by what you are reading now. +* `CodeRefinery manuals `__ +* Our gradual pathway to instructor from the manuals: `helper intro + `__ and + `instructor intro + `__. +* `Carpentries instructor training + `__ - more + intensive, but focused only on teaching. +* `Carpentries curriculum development handbook + `__ +* `Teaching Tech Together `__, a book + about similar topics by someone involved in Carpentries. +* `Carpentries general organizational documentation + `__ diff --git a/branch/main/_sources/lesson-design.md.txt b/branch/main/_sources/lesson-design.md.txt new file mode 100644 index 00000000..a9f6ec75 --- /dev/null +++ b/branch/main/_sources/lesson-design.md.txt @@ -0,0 +1,183 @@ +# Lesson design + +```{prereq} Recommended reading +- CodeRefinery [lesson-design](https://coderefinery.github.io/manuals/lesson-design/) manual +- [The Carpentries Curriculum Development Handbook](https://cdh.carpentries.org) +- [Teaching Tech Together](http://teachtogether.tech/) +- Our [summary](https://coderefinery.github.io/manuals/teaching-tech-together/) of "Teaching Tech Together" +- [Ten quick tips for creating an effective lesson](https://doi.org/10.1371/journal.pcbi.1006915) +``` + +--- + +## How do you design? + +```{discussion} +Discuss either in groups or via collaborative document: +- How do you start when you design a new lesson/presentation? +- Has your approach changed over the years? If yes, how? +``` + +--- + +## Backwards lesson design + +### The approach + +- You don't think about how to do something and try to explain it. +- Avoid the typical approach *"I want to show a number of things which I think are cool about + tool X - how do I press these into 90 minutes?"* +- Instead, you start defining your target audience by answering to questions + such **What is the expected educational level of my audience?**, **Have they + been already exposed to the technologies I am planning to teach?**, **What + tools do they already use?**, **What are the main issues they are currently + experiencing?**. It is important to discuss these points with a group of + colleagues, preferably from diverse backgrounds and institutions to reduce + biases. Once you clarified your target audience, it is useful to create + **learner personas**; that will help you during the development process by + providing concrete examples of potential learners showing up at your + workshops. For each **learner personas**, try to think of what is **useful to + them**: *"What do they **need** to + [remember/understand/apply/analyze/evaluate/create](https://coderefinery.github.io/instructor-training/03-teaching-style/#using-bloom-s-taxonomy-to-write-effective-learning-objectives)?"*. + Asking and answering to these questions will allow you to define the + background knowledge (starting points) and goals (end points) of your + learners. Then, you create a sequence of exercises which test incrementally + progressing tasks and acquisition of the new skills (from starting to end + points). +- Then, you write the minimum amount + of material to teach the gap between exercises. + +### The process + +For the whole process, see [our +manual](https://coderefinery.github.io/manuals/lesson-design/#backwards-lesson-design) +(instructor discusses these points briefly). + + +### Why is it good to have a process?: + +- Having a semi-rigid design process can **save time** to start drafting. +- It allows collaborative development of teaching material. +- It will probably **increase quality and relevance** of lessons for learners. +- **We aren't perfect yet.** CodeRefinery is still striving to get + better at this, and we are more ad-hoc than you might think. + A number of our lessons have not been designed this way but we are now improving + these lessons with the backwards lesson design in mind. + + +### Designing exercises + + +The goal of exercises is twofold: +- instructors can assess the progress of learners. +- learners put in practice the skills that you have included in your skills list. + +When designing exercises, consider that some participants will get stuck +and may want to re-join at a later exercise. In other words it is nice +if exercises build up on each other but not at the cost that if participants +get stuck at exercise 2, they will not be able to do exercises 3 to N. + +--- + +## Practice backwards design + + +```{discussion} The goal here is to discuss and provide examples on backwards-design of a lesson. + +Let's take as an example the *[HPC Carpentry lesson](https://hpc-carpentry.github.io/hpc-intro/)* + +**Target audience** + - What is the expected educational level of my audience? + - A PhD student, postdoc or young researcher. + - Have they been already exposed to the technologies I am planning to teach? + - The word **HPC** is not new to them and they may have already used an HPC but are still not capable of giving a proper definition of HPC. In addition, we do not expect them to know much about parallelism and they cannot make any distinction between various available parallelism paradigms. + - What tools do they already use? + - serial codes, multi-threaded codes, data parallelism; usually out-of-the-box tools. + - they may have tried to "scale" their code (multiprocessing, threading, GPUs) with more or less success. + - What are the main issues they are currently experiencing? + - they cannot solve their problems either because they would like to run the same code but with many different datasets or because their problem is larger (more computations/memory). + - most of the time they know their codes can run on HPC (from the documentation) but never really had the opportunity to try it out. + - Very few will have their own codes where they may have tried different things to speed it up (threading, task parallelism) but have no clear strategy. + +**Learner persona** + - Sonya is a 1st year PhD student: she recently moved to Oslo and joined the + Computational and Systems Neuroscience group. She will be using the + [NEST](https://nest-simulator.readthedocs.io/), a simulator for spiking + neural network model. She used NEST during her master thesis but on her + small cluster: **she never used an HPC resource** and is really excited about it. + - Robert is a field ecologist who obtained his PhD 6 months ago. He is now + working on a new project with Climate scientists and as a consequence will + need to run global climate models. He is **not very familiar with command + line** even though he attended a Software Carpentry workshop and the idea to + use HPC is a bit terrifying. He knows that he will get support from his + team who has extensive experience with HPC but would like to become more + independent and be able to **run his own simulations** (rather than copying + existing cases). + - Jessica is a postdoc working on a project that investigates numerically the + complex dynamics arising at the tip of a fluid-driven rupture. Fluid + dynamics will be computed by a finite element method solving the + compressible Navier-Stokes equations on a moving mesh. She **uses a code she + has developed** during her PhD and that is based on existing libraries. She + has mostly ran it on a local desktop; her work during her PhD was very + limited due to the lack of computing resources and she is now very keen is + **moving to HPC**; she knows that it will requires some work, in particular to + parallelize her code. This HPC training will be her first experience with + HPC. + +**Learning outcomes** + - Understand the difference between HPCs and other local/remote machines + - Understand the notion of core, nodes, cluster, shared/distributed memory, etc. + - Understand the notion of login nodes. + - Understand the need for a scheduler and how to use it appropriately + - Understand why optimising I/O is important on HPC and how to best use HPC filesystems + - Understand the need to parallelize (or use existing parallel) codes and in which cases HPCs is a must (when communications is required) + - Understand how to get your code ready to use on HPC (access to libraries, installation of your own libraries/software, etc.) + - Understand that an HPC is an operational machine and is not meant for developing codes. + +**Exercises** + - Get basic information such the number of CPUs, memory from your laptop and try to do the same on a HPC. Discuss outcomes. + - Try to create files on the different filesystems on your HPC resource and access them. + - Create different types of job scripts, submit and check outputs. + - Make a concrete example to run a specific software on your HPC (something like GROMACS). +``` + +```{challenge} Demo +Before we let participants present to their groups, one of the instructors +presents a 5-minute segment and we practice together giving feedback. + +The section we demo should require screen sharing and be of some follow-along +task. + +If there is time, we present one demo on the day before, and one demo just +before the group exercise. +``` + +```{challenge} Exercise +Choose a simple lesson topic and apply backwards lesson design. You +won't get all the way through, but come up with a logical +progression of exercises. + +The section you pick should require **screen sharing** and be of some **follow-along +task** (preferably using a shell). + +Some suggestions: +- Regular expressions +- Making papers in LaTeX +- Making figures in your favorite programming language +- Linux shell basics +- Something non-technical, such as painting a room +- An instructor training for CodeRefinery +- Some aspect from an already existing lesson +- [Introduction to high-performance computing](https://hpc-carpentry.github.io/hpc-intro/) (or an episode therein) +- [Unix shell in a HPC context](https://hpc-carpentry.github.io/hpc-shell/) (or an episode therein) +- A lesson you always wanted to teach + +Exercise (30 minutes): +- Collect notes in a shared document. +- Start with learner personas and learning outcomes. +- Come up with a logical progression of exercises. + +Discussion (15 minutes): +- How does this approach compare to other lessons or courses you have designed? +- We read, compare, and discuss our notes. +``` diff --git a/branch/main/_sources/lesson-development.md.txt b/branch/main/_sources/lesson-development.md.txt new file mode 100644 index 00000000..5371312e --- /dev/null +++ b/branch/main/_sources/lesson-development.md.txt @@ -0,0 +1,95 @@ +# Collaborative lesson development + +This session focuses on **organizational** and **technical aspects** +of collaborative lesson development. + +```{discussion} +This session is about **collaborative** lesson development. What advantages do +you see in developing lessons collaboratively and sharing lessons (making +material accessible)? What difficulties are there? +``` + +--- + +## Lesson templates for static sites + +- [Jekyll](https://jekyllrb.com/)-based + - Example: [Introduction to version control with Git](https://coderefinery.github.io/git-intro/) + - [Lesson template](https://github.com/coderefinery/example-lesson) + - Common styling implemented as Git submodule: [jekyll-common](https://github.com/coderefinery/jekyll-common) + - Based on a past version of the [Carpentries lesson style](https://github.com/carpentries/styles/) + - A new Carpentries lesson template is in the works +- [Sphinx](ttps://www.sphinx-doc.org)-based + - Example: this lesson + - Starting point: [sphinx-lesson](https://github.com/coderefinery/sphinx-lesson) + - [Documentation](https://coderefinery.github.io/sphinx-lesson/) +- Templates can be freely re-used + +Why static sites? +- Decentralized (in terms of organization/namespace) +- Forkable +- Anybody can suggest changes + +--- + +## Creating new teaching material + +Creating new teaching material is a longer process, because you should +go through the whole +[backwards lesson design process](/lesson-design/) +and get extensive comments. +Still, don't feel afraid: nothing is perfect (or even good) +the first time. In fact, **it may be an advantage to share an imperfect +lesson with others early** to collect feedback and suggestions before the lesson +"solidifies" too much. Draft it and collect feedback. The result will probably +be better than working in isolation towards a "perfect" lesson. + +```{discussion} +How can we share unfinished work/ideas? +- Draft pull requests (GitHub) or WIP (work in progress) merge requests (GitLab). +- Open an issue and discuss your idea before implementing it. +``` + +--- + +## Contributing to existing lessons + +Our lessons are **collaboratively developed**. They are made by many +people, and there is no single fixed master plan (but there should be, +in the instructors or maintainer's guide). We encourage +everyone to contribute to the lessons. + +Lessons are reviewed very often - essentially, before each workshop by +the instructor of that workshop. This can be a quick review, looking +at issues and fixing easy things, or more thorough. + +Every so often (such as at this training), there is an extensive +hackathon period of fully revising a lesson and making major improvements. + +We've made the [lesson-review](https://coderefinery.github.io/manuals/lesson-review/) checklist +to guide the review process. + +```{discussion} +We now go to the +[lesson-review](https://coderefinery.github.io/manuals/lesson-review/) +checklist and discuss it, instead of duplicating things here. +``` + +--- + +## Recommendations and lessons learned + +- Convert feedback about lessons and suggestions for improvements into *issues* + so that these don't get lost. +- Make your lesson citable: get a DOI. +- Credit contributors (not only Git commits). +- Instructor guide is essential for new instructors. +- Lesson changes should be accompanied with instructor guide changes (it's like + a documentation for the lesson material). +- Apply and validate backwards lesson design again and again. +- Make it possible to try out new ideas (by making the lesson branch-able). +- Before making larger changes, talk with somebody and discuss these changes. +- For substantial changes we recommend to first open an issue and describe your + idea and collect feedback before you start with an extensive rewrite. +- For things still under construction, open a draft pull request to collect + feedback and to signal to others what you are working on. diff --git a/branch/main/_sources/quick-reference.rst.txt b/branch/main/_sources/quick-reference.rst.txt new file mode 100644 index 00000000..dab20157 --- /dev/null +++ b/branch/main/_sources/quick-reference.rst.txt @@ -0,0 +1,2 @@ +Quick Reference +--------------- diff --git a/branch/main/_sources/teaching-practice.md.txt b/branch/main/_sources/teaching-practice.md.txt new file mode 100644 index 00000000..1323c867 --- /dev/null +++ b/branch/main/_sources/teaching-practice.md.txt @@ -0,0 +1,76 @@ +# Teaching practice and feedback + +Goals of the teaching practice: + +- In groups of 4-5 persons we will practice teaching a **5-minute segment + of a lesson of your choice**. +- The section you pick should require **screen sharing** and be of some + **demonstration or follow-along task** (preferably using a shell) to also + practice having a good screen-sharing setup. +- We will practice giving **constructive feedback**. +- We will practice improving our 5-minute segment by taking the feedback into account. +- In both session you can teach the same topic/segment but if you prefer you can also + change the topic/aspect for the second session. + +--- + +## Instructor demo + +- In order to demonstrate the goals of this section, the instructor + will make a 5-minute demo for your evaluation. +- It is designed to include some good and bad practices for you to + notice. + +--- + +## Teaching demos part 1 + +In group rooms, 50 minutes. + +```{challenge} +- We organize the breakout rooms to not only discuss one lesson/topic so that it is more interesting + to listen and also probably we will all get more useful feedback. +- Give each other **constructive verbal feedback** on the teaching demos, for example + using [this demo rubric](https://carpentries.github.io/instructor-training/demos_rubric/). +- Write down questions (in the collaborative document) that you would like to + discuss in the main room or interesting conclusions which you would like to + share with others. +``` + +## Teaching demos, part 2 + +In group rooms, 50 minutes. + +```{challenge} +- In the second round we distribute the rooms differently so that you can + present it to a **new group of workshop participants** and can receive new + feedback. +- Ask for feedback and one/few point(s) you want to improve. +- In your second trial check whether you feel the demonstration improved. +- Share your lessons learned in the collaborative document. +- Give us also feedback on this exercise format. Was it useful? What can we improve? +``` + +--- + +## Discussion + +```{discussion} Main room discussion + - We discuss questions and conclusions which came up during the group work session. +``` + +--- + +## Optional: feedback for two live-coding examples + +```{challenge} +Teaching by live coding is a +[performance art which requires practice](https://teachtogether.tech/#s:performance-exercises). +This exercise highlights some typical pitfalls that most instructors +fall into sooner or later, and also shows how to avoid them. +Watch closely since we will be giving feedback! +- Watch these two videos: [video 1](https://youtu.be/bXxBeNkKmJE) and + [video 2](https://youtu.be/SkPmwe_WjeY) +- What was better in video 1 and what was better in video 2? +- Please give feedback in the shared workshop document. +``` diff --git a/branch/main/_sources/teaching-strategies.md.txt b/branch/main/_sources/teaching-strategies.md.txt new file mode 100644 index 00000000..2e93a217 --- /dev/null +++ b/branch/main/_sources/teaching-strategies.md.txt @@ -0,0 +1,220 @@ +# How to teach online + +```{objectives} +- Understand the benefits and disadvantage of online teaching, + compared to in-person + +- Set up a good screen share + +- Understand the benefits and disadvantages of team teaching + +- Prepare for the teaching practice +``` + + +## Why teaching mechanics matter + +- When you teach, you are mainly showing a basic example for the + learner to follow along +- The learner has a *lot* more to think about than you do, so you need + to minimize the possible distractions and unnecessary weirdness. +- A learner will often only one small screen, limiting the number of + things that they can think about. +- You are must faster than learners (5 times possibly?) You have to + do things to slow yourself down. +- It's easy to save these mechanics until the end, and then you run + out of time. + + + + +## Shell sharing + +```{discussion} Discussion: what goes into a good shell share or demonstration? + +When you are following along with a type-along demonstration, what +things: + +- Are useful to make it easy to follow along +- Make it harder to follow along + +Answer in the collaborative notes +``` + +When doing any demonstration, there are difficulties: + +- If one misses something, you can't rewind to see it - is there any + way to catch up? +- The learner must get oriented with the whole picture, while + instructor knows precisely where to focus. + +A good **shell share** has some of the following properties: + +- Large font +- Shell history, available separately from the main shell window +- Closely matches the type-along instructions + +We have a collection of shell sharing systems: +- We will look over [lesson presentation +hints](https://coderefinery.github.io/manuals/instructor-tech-setup/#terminal-history-window). +- There are other things you can copy +- Whatever you do, do *something*. + +```{discussion} +The instructor will demonstrate several shell-sharing systems. You +will use this in the teaching practice. +``` + + + +## Screen sharing + +`````{discussion} + +Look at the various [screen layouts in the CodeRefinery +manuals](https://coderefinery.github.io/manuals/instructor-tech-setup/#screen-sharing). +Use the HackMD to comment about what which are better or worse. + +````{output} HackMD prototype +:class: dropdown +``` +- S1 + - good: + - bad: +- S2 + - good: + - bad: +- S3 + - good: + - bad: +- S4 + - good: + - bad: +- Student layouts: + - ... +- Instructor layouts: + - ... +``` +```` +````` + +- Many learners will have a smaller screen than you. +- You should plan for learners with only one small screen. +- A learner will **need to focus on both your screen share and their + work**. +- Sharing your a whole screen is almost always a bad idea, if you want + the learners to do anything at the same time. +- If you constrict yourself, then your experience is more similar to + that of a learner. + +Vertical sharing: +- CodeRefinery has recently started trialing a **vertical share** + system, where you share a vertical half of your screen. +- This allows learners with one screen to display your screen + side-by-side with their learn +- Zoom provides a "Share a part of screen" that is good for this. + + + +## Meta-talk + +Don't just teach, also make sure you guide the learners through the +course. + +- You know what you just discussed, and what is coming next, but + learners are often stuck thinking about now. +- Give a lot of "meta-talk" that is not just about the topic you are + teaching, but how you are teaching it. +- Examples + - **Why** you are doing each episode + - What is the purpose of each exercise + - Clearly state what someone should accomplish in each exercise and + how long it will take - don't assume this is obvious. + - What is the point of each lesson. How much should people expect + to get from it? Should you follow everything, or are some things + advanced and optional? Make that clear. + + + +## Teach teaching + +- Demonstration-based teaching require two different types of focus: + - Doing the mechanical steps as a demonstration + - Explaining why you are doing it +- This is a lot for one person to keep in mind, so can multiple people + work together for this? +- Team teaching idea: + - One person is doing the demonstrations + - One person is giving the commentary about what they are doing + - The lecture becomes a discussion between two people instead. + +Advantages: +- This reduces the pressure on each person (reduces demo effect) +- You are less likely to forget things +- It slows you down in teaching +- It makes the lesson more interesting to listen to +- One person can follow questions +- Great for introducing new instructors (which half is easier to start + with?) + +Disadvantage: +- Requires two people's time +- Requires coordination when preparing (slows you down in preparation) +- Unfamiliar concept to most people + + + +## Questions + +- Questions are great, and important for any practical and interactive + class +- But questions in main room doesn't scale to very large rooms. +- CodeRefinery strategy: HackMD for questions + - Chat is not good enough, you can't reply to old things + - HackMD allows threaded replies and follow up later + - You need some other helpers to watch HackMD and answer, and bring + things up to you. And let you know how things are going. + - Learners can ask anonymously + - Learners don't have to worry about interrupting the flow. + - Disadvantage: can produce information overload, warn people to not + follow too closely + - With too few people, it can turn out to be very quiet. +- We will learn more about HackMD questions tomorrow in + {doc}`workshops-online`. + +```{seealso} +* {doc}`workshops-online` +* [HackMD +mechanics](https://coderefinery.github.io/manuals/hackmd-mechanics/) +and [HackMD +helpers](https://coderefinery.github.io/manuals/hackmd-helper/) on +CodeRefinery manulas. +``` + + + +## Teaching practice + +In {doc}`teaching-practice`, you will break into groups and try to +apply these strategies to a five-minute example session. + + + +## See also + +In this lesson: + +* {doc}`workshops-online` + +CodeRefinery manuals: + +* [Instructor tech + setup](https://coderefinery.github.io/manuals/instructor-tech-setup/) +* [Lesson preparation + hints](https://coderefinery.github.io/manuals/presenting/) (more + focused on in-person) +* [Instructor + introduction](https://coderefinery.github.io/manuals/presenting/) - + has a lot of tips for new instructors, but also more things about + the workshop. +* [Workshop prep call](https://coderefinery.github.io/manuals/workshop-prep-call/) diff --git a/branch/main/_sources/welcome.md.txt b/branch/main/_sources/welcome.md.txt new file mode 100644 index 00000000..ec9af20f --- /dev/null +++ b/branch/main/_sources/welcome.md.txt @@ -0,0 +1,88 @@ +# Welcome and introduction + +```{discussion} What do we want to get out of this workshop +- Introduction of instructors and helpers +- Each instructor can say what we want to get out of the instructor training +- But we want to know from everybody and collect these in the live notes +``` + +--- + +## Goals for this workshop + +```{discussion} Goals for this instructor training +- Give future instructors the **tools and confidence** to teach best software practices and tools. +- **Motivate new instructors** to take up lessons, remix them, and to contribute. +- **Get feedback** to improve the material as well as our collaboration model. +- For us to **learn how we can support** related efforts and collaborate. +- **Catalyze and form new networks** and collaborations of teachers and trainers of + practical scientific computing. +``` + + +### Giving confidence + +> *Goal number one should be that we give participants the confidence to +> independently apply the tools or knowledge learnt. This is more important +> that giving a "complete" overview.* [Lucy Whalley gave this great comment at one of our workshops] + +- You don't have to know everything to use (or teach) something. +- For the large majority of topics we teach, there are many resources online + which provide how-to guides or tutorials. And the Stack Overflow answer bank + isn't getting any smaller. So we need to ask why do people attend in-person + sessions if there is information freely available? Our impression is that + it is for confidence building, identity formation, perhaps signposting to + resources. +- This also links with building a welcoming/inclusive environment: for example, + imposter syndrome, which disproportionately affects under-represented groups + ([link](https://www.ncda.org/aws/NCDA/pt/sd/news_article/245005/_PARENT/CC_layout_details/false)), + can manifest as low self-confidence --> building the confidence of + students in the classroom may lead to a more diverse community. + +--- + +## Tools for this workshop + +We always start workshops with these: +- [HackMD mechanics and controls](https://coderefinery.github.io/manuals/hackmd-mechanics/) +- [Zoom mechanics and controls](https://coderefinery.github.io/manuals/zoom-mechanics/) + +--- + +## Code of Conduct + +- We follow [The Carpentries Code of Conduct](https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html). +- This is a hands-on, interactive workshop. + - Be kind to each other and help each other as best you can. + - If you can't help someone or there is some problem, let someone know. + - If you notice something that prevents you from learning as well as you can, let us know and don't suffer silently. +- It's also about the little things: + - volume + - font size + - generally confusing instructor + - **not enough breaks** + +--- + +## Overview of the lessons and a typical workshop + +Here the instructor gives an overview of the lessons and a typical workshop. + +--- + +```{discussion} What we do differently? +- Planing, teaching material available in advance and not PDF slides +- Different roles (instructor, host, hackmd, ...) +- GitHub projects board so all boxes are checked +- Helper recruitment and breakout room planning + - Designing for this as soon as you open registration +- Less is more +- Welcome session and "outro" session +- Clearly defining learning outcomes +- Asking for feedback, encouraging feedback +- Manual +- Screen-sharing +- Using lesson templates +- Lesson review on GitHub +- Sharing material instead of being protective +``` diff --git a/branch/main/_sources/workshops-online.md.txt b/branch/main/_sources/workshops-online.md.txt new file mode 100644 index 00000000..abf5222c --- /dev/null +++ b/branch/main/_sources/workshops-online.md.txt @@ -0,0 +1,256 @@ +--- +layout: episode +title: "Lessons learned from running online and in-person workshops" +teaching: 20 +exercises: 10 +questions: + - "What are the steps for organizing a CodeRefinery workshop?" + - "What can I learn about running my own workshop?" + - "What have we learned from running large online workshops?" +objectives: + - "Learn how to use the manuals to organize and teach a workshop." +keypoints: + - "There are many aspects to consider to deliver a successful workshop." + - "CodeRefinery maintains a number of manuals - use them when preparing a workshop." +--- + +> ## Workshop manuals +> CodeRefinery maintains a number of [workshop manuals](https://github.com/coderefinery/manuals/) +> with most of the "primary" information. This episode condenses this +> into a quick overview. +{: .callout} + + +# Running a workshop: online + + +## Online teaching discussion + +```{discussion} Discussion: Online vs in-person + +In notes: +- Compare and contrast the benefits of online teaching with + in-person: {advantage, disadvantage} × {content, presentation} +- How do you have to prepare differently? +- What are your own experiences? +``` + + + +## Case study: Mega-CodeRefinery and Finland HPC Kickstart + +- Mega-CodeRefinery + - Audience of around 90-100 + - "bring your own breakout room" (see below) + - 3 days/week, 6 days total + - Lessons as normal in CodeRefinery +- HPC Kickstart + - 250 registered, ~180 max participants + - Multi-university: local differences made this much harder to manage. + - Breakout rooms not pre-planned. + +Mega-CodeRefinery worked very well, HPC kickstart didn't - but not +because of the size. + + + +## General workshop arrangements + +> ## Manuals link +> - [before the +> workshop](https://github.com/coderefinery/manuals/blob/master/workshop-administration.md#before-the-workshop) +{: .callout} + +- Select a coordinator, recruit instructors (at least 3 is important), + find helpers +- Find a good lecture room: + [requirements](https://github.com/coderefinery/manuals/blob/master/workshop-requirements-inperson.md) +- Set up workshop webpage using the [Github, template + repository](https://github.com/coderefinery/template-workshop-webpage]: + [see + manuals](https://github.com/coderefinery/manuals/blob/master/workshop-administration.md#set-up-workshop-page) +- Advertising the workshop +- Communication with registered participants + + + +## CodeRefinery online scaling strategy + +- We started online workshops in 2020 March, for the obvious reasons. +- First, we started with two "normal size" (20 people) practice + workshops +- Then we did a 100 person workshop. It went well, but there is less + tolerance for problems. + + +### Basic preparation + +- You need more breaks are needed +- People have a way of doing too many things and not focusing. +- "[How to attend an online + workshop](https://coderefinery.github.io/manuals/how-to-attend-online/)" + guide to prepare learners + +### Basic platform: Zoom + +- Zoom (not the most ethical, but worked well and was available) +- [Zoom mechanics: instructions for + students](https://coderefinery.github.io/manuals/zoom-mechanics/). + - Mostly things that are known + - We don't use Zoom interaction features much anymore + (faster/slower/etc), but breakout rooms and HackMD instead +- See also: [Online training + manual](https://coderefinery.github.io/manuals/online-training/) + (which is getting a bit old compared to what is below). + +### Breakout rooms, bring your own team + +- Breakout rooms are + - Static: same people across whole workshop + - Contain one helper per room (see below) +- Team registration: accept a "team" field when registering, people on the + same team are put together. + - Gives motivations for learners to bring their colleagues and + learn together. + - More than one person learning together greatly increases update +- You need a powerful enough registration system to assign rooms and + email them to people! +- We ask people to name themselves "(N) Firstname Lastname" or "(N,H) + Firstname Lastname" for helpers. Then it is fast to assign them to + their designated breakout rooms. +- See also: [Breakout room + mechanics](https://coderefinery.github.io/manuals/breakout-rooms-helping/) + + +### Helper training + +- Each breakout room has a helper +- Helper should be a little bit familiar, but not expected to be able + to answer all questions. +- Special, custom [helper + training](https://coderefinery.github.io/manuals/helper-intro/) + since helpers make or break the workshop +- Helper recruitment: + - Our networks + - Team registration: if a team registers with their own helper, then + they are guaranteed to get in together. "bring your own breakout + room" + - Former learners, ask them to come back. +- Two helper trainings the week before the workshop. + +### Staff roles + +To reduce stress on any one person, we clearly define the different +roles and try to avoid overlap. We actually have enough people for +all of these, so it works well. + +- Workshop coordinator + - Registration, etc. +- Zoom host + - Handles registration, breakout rooms, recording, Zoom chat. +- HackMD helper + - Dedicated to watching HackMD and answering questions quickly. + - [Host on manuals](https://coderefinery.github.io/manuals/host/) +- Expert helpers + - "Spare hands" who rotate between breakout rooms and make sure + helpers are doing well. + - Give feedback to instructor about how breakout rooms are going. + - Take the place of missing helpers. + - Easy way for any people with a bit of spare time to help out. + - [Expert helpers in workshop](https://coderefinery.github.io/manuals/expert-helpers/) +- Instructors + - Teach, they shouldn't overlap with the above roles (but serve as + expert helpers other times). + - Usually also improve the lesson a bit before teaching + - [General staff intro in manuals](https://coderefinery.github.io/manuals/instructor-intro/) +- Workshop preparation meeting + - Get together, introduce roles, kickstart instructors + - [Workshop prep meeting in manuals](https://coderefinery.github.io/manuals/workshop-prep-call/) + + +### HackMD + +- We've been using it here +- Chat doesn't work wen large, written + document does. +- HackMD can just about scale to ~100 person workshop. Recommend + learners keep it in view mode while not editing. +- Voice questions are still allowed, but will be recorded. Staff + raise important questions from HackMD to the instructor immediately. +- HackMD also allows communication when in breakout rooms. +- You can get multiple answers, and answers can be improved over + time. +- [HackMD + mechanics](https://coderefinery.github.io/manuals/hackmd-mechanics/) + and [HackMD + helpers](https://coderefinery.github.io/manuals/hackmd-helper/). + +### Recording and streaming + +- When you have 100 people, main room is quiet anyway: you don't lose + much by recording. + - Questions anonymously in HackMD, privacy loss is not so bad +- Breakout rooms are never recorded +- Streaming + - We streamed via Twitch: https://twitch.tv/coderefinery + - We typically get 5-40 viewers. + - Zoom can directly send the stream to Twitch: no extra software + needed. + - Twitch archives videos for 14 days, which allows learners to get + an instant reply (we get hundreds of views in the next days). + - So while possibly not useful for new people to learn, the instant + reply *is* very useful. Instructor can also work on problems in + main stream during breakout rooms, which learners can watch + later. + - Streamers also have access to HackMD to ask questions. +- Certain tricks needed to keep learners from appearing in recording + or stream + - "Spotlight video", host does not go to gallery view, uses dual + monitor mode. We are still figuring this out. + +### Installation time + +- People *have* to be ready once we start, or else everything fails. +- Two installation help times the week before. +- Every email emphasizes that you have to be prepared, and "requires" + you to attend workshops (but really it's only) +- Installation instructions include *steps to verify* +- Installation instructions also include *video demonstrations* of + installation and verification. +- We haven't had that many installation problems, but also we keep the + requirements simple. +- Helper introduction is right before software install time, so + helpers can stay and help with install if they want. +- *Design to be easy to install and get set up.* + +### Other notes + +- Make breakout sessions as long as possible: 10 minutes is really too + short. 20 minutes is a good minimum time. +- Be very clear about exercise expectations +- Keep HackMD updated as a log. +- Don't combine breaks and breakout times. +- The more people you have, the more diverse audience you have and the + more people overwhelmed and under whelmed. + + + +## Workshop collaborations + +Why limit ourselves to CodeRefinery workshop? Why not use our network +and techniquess for more + +- Case study: [Python for Scientific + Computing](https://aaltoscicomp.github.io/python-for-scicomp/) + - Started by Aalto + - Announced to CodeRefinery, five more instructors from three + countries joined. + - Rapid collaboration, taught course shortly later. + - Announced to all institutions. Some places had physical rooms, + some were pure online + - Also streamed + - It was much more fun and less stressful to work together + +- We want to continue this kind of collaboration in other workshops. + + diff --git a/branch/main/_static/basic.css b/branch/main/_static/basic.css new file mode 100644 index 00000000..bf18350b --- /dev/null +++ b/branch/main/_static/basic.css @@ -0,0 +1,906 @@ +/* + * 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: 450px; + 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; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +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/branch/main/_static/check-solid.svg b/branch/main/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/branch/main/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/main/_static/clipboard.min.js b/branch/main/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/branch/main/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/branch/main/_static/copybutton.css b/branch/main/_static/copybutton.css new file mode 100644 index 00000000..40eafe5f --- /dev/null +++ b/branch/main/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/branch/main/_static/copybutton.js b/branch/main/_static/copybutton.js new file mode 100644 index 00000000..40ac3310 --- /dev/null +++ b/branch/main/_static/copybutton.js @@ -0,0 +1,220 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const codeCells = document.querySelectorAll('div.highlight pre') + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + return formatCopyText(target.innerText, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/branch/main/_static/copybutton_funcs.js b/branch/main/_static/copybutton_funcs.js new file mode 100644 index 00000000..b9168c55 --- /dev/null +++ b/branch/main/_static/copybutton_funcs.js @@ -0,0 +1,58 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/branch/main/_static/css/badge_only.css b/branch/main/_static/css/badge_only.css new file mode 100644 index 00000000..e380325b --- /dev/null +++ b/branch/main/_static/css/badge_only.css @@ -0,0 +1 @@ +.fa:before{-webkit-font-smoothing:antialiased}.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/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff2 b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff2 b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.eot b/branch/main/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.svg b/branch/main/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/branch/main/_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/branch/main/_static/css/fonts/fontawesome-webfont.ttf b/branch/main/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.woff b/branch/main/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.woff2 b/branch/main/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-bold-italic.woff b/branch/main/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold-italic.woff differ diff --git a/branch/main/_static/css/fonts/lato-bold-italic.woff2 b/branch/main/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-bold.woff b/branch/main/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold.woff differ diff --git a/branch/main/_static/css/fonts/lato-bold.woff2 b/branch/main/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-normal-italic.woff b/branch/main/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal-italic.woff differ diff --git a/branch/main/_static/css/fonts/lato-normal-italic.woff2 b/branch/main/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-normal.woff b/branch/main/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal.woff differ diff --git a/branch/main/_static/css/fonts/lato-normal.woff2 b/branch/main/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal.woff2 differ diff --git a/branch/main/_static/css/theme.css b/branch/main/_static/css/theme.css new file mode 100644 index 00000000..0d9ae7e1 --- /dev/null +++ b/branch/main/_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,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,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}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.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 .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 .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.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}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.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}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.footnote{font-size:.9rem}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.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,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 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 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{font-size:inherit;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}.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}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):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(.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(.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(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>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(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>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(.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(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):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(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):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(.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(.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(.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(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):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{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.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/branch/main/_static/doctools.js b/branch/main/_static/doctools.js new file mode 100644 index 00000000..e509e483 --- /dev/null +++ b/branch/main/_static/doctools.js @@ -0,0 +1,326 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * 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; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return 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 : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + var url = new URL(window.location); + url.searchParams.delete('highlight'); + window.history.replaceState({}, '', url); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/branch/main/_static/documentation_options.js b/branch/main/_static/documentation_options.js new file mode 100644 index 00000000..79d8db80 --- /dev/null +++ b/branch/main/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/branch/main/_static/file.png b/branch/main/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/branch/main/_static/file.png differ diff --git a/branch/main/_static/jquery-3.5.1.js b/branch/main/_static/jquery-3.5.1.js new file mode 100644 index 00000000..50937333 --- /dev/null +++ b/branch/main/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( 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. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +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.5.1", + + // 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.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( 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.namespaceURI, + docElem = ( 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 master Deferred + master = 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 ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.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 + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + 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(); + return 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: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, 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; + }, + + 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! + 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"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + 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; + 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 ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + 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 + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + 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( " + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

About the CodeRefinery project

+

CodeRefinery is a +Nordic e-Infrastructure Collaboration (NeIC) +project that has started in October 2016 and is +funded until October 2021.

+

We hope to keep this project active beyond 2021 by forming a support network +and building a community of instructors and contributors.

+
+
+

History

+

The CodeRefinery project idea grew out of two SeSE courses given at KTH Stockholm in 2014 and 2016:

+ +

The project proposal was submitted to NeIC in 2015, accepted in 2015, and started in 2016.

+

We have started by porting own lessons to the Carpentries teaching style and +format, and collaboratively and iteratively grew and improved the material to +its present form.

+
+
+
+

Main goals

+
    +
  • Develop and maintain training material on software best practices for researchers that already write code. Our material addresses all academic disciplines and tries to be as programming language-independent as possible.

  • +
  • Provide a code repository hosting service that is open and free for all researchers based in universities and research institutes from Nordic countries.

  • +
  • Provide training opportunities in the Nordics using Carpentries and CodeRefinery training materials.

  • +
  • Articulate and implement the CodeRefinery sustainability plan.

  • +
+
+
+
+

Impact

+

We collect feedback and survey results to measure our impact.

+

3-6 months after attending a workshop, past participants are asked to complete a short post-workshop survey. +The survey questions aim to establish what impact CodeRefinery workshops have on how past participants develop +research software.

+
+https://coderefinery.org/assets/img/heatmap_yesno.png +
+
    +
  • Overall quality of research software has improved: more reusable, modular, reproducible and documented.

  • +
  • Collaboration on research software development has become easier

  • +
  • Past participants share their new knowledge with colleagues

  • +
  • Usage of several tools is improved, and new tools are adopted

  • +
+

Free-form answers +also suggest that workshops are having the intended effects on how people develop code. A common theme is:

+
+

I wish I had known this stuff already as a grad student 10+ years ago…

+
+

We would love to get suggestions on how we can better quantify our impact. This +would make it easier for us to convince institutions to partner with us and +also open up funding opportunities.

+
+
+
+

Carpentries membership

+

Since November 2018, NeIC is a Platinum Partner to The Carpentries.

+

The Carpentries is an international project that comprises Software Carpentry and Data Carpentry, communities of instructors, trainers, maintainers, helpers, +and supporters who share a mission to teach foundational computational and data science skills to researchers. +The Carpentries teach foundational coding and data science skills to researchers worldwide and as such are complementary to CodeRefinery.

+

Within the membership the Nordic research community has access to:

+
    +
  • 6 Carpentries workshops in the Nordics each year. The workshop fee is covered by the membership, only the instructor travel is on the host institution.

  • +
  • 15 seats in the Carpentries instructor training each year. Carpentries train the trainer program aims at building partnerships with Research Software Engineers and researchers who are willing to lead skill transfer within their local communities in the Nordics.

  • +
+
+
+
+

Target audience

+
+

Carpentries audience

+

The Carpentries aims to teach computational competence to learners through an applied approach, avoiding the theoretical and general in favor of the practical and specific.

+

Learners do not need to have any prior experience in programming. One major goal of a Carpentry workshop is to raise awareness on the tools researchers can learn/use to speed up their research.

+

By showing learners how to solve specific problems with specific tools and providing hands-on practice, learners develops confidence for future learning.

+
+

Novices

+

We often qualify Carpentry learners as novices: they do not know what they need to learn yet. A typical example is the usage of version control: the Carpentry git lesson aims to give a very high level conceptual overview of Git but it does not explain how it can be used in research projects.

+
+
+
+

CodeRefinery audience

+

In that sense, CodeRefinery workshops differ from Carpentry workshops as we assume our audience already writes code and scripts and we aim at teaching them best software practices.

+

Our learners usually do not have a good overview of best software practices but are aware of the need to learn them. Very often, they know the tools (Git, Jupyter, etc.) we are teaching but have difficulties to make the best use of them in their software development workflow.

+

Whenever we can, we should direct learners that do not have sufficient coding experience to Carpentries workshops.

+
+

Competent practitioners

+

We often qualify CodeRefinery learners as competent practitioners because they already have an understanding of their needs. +Novices and competent practitioners will be more clearly defined in the next section.

+
+
+

Best software practices for whom?

+

It can be useful to ask the question: best software practices for whom? +CodeRefinery teaches best software practices derived from producing and +shipping software. These practices are also very good for sharing software, +though our audience will probably not need to embrace all aspects of +software engineering.

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/coderefinery-workshops/index.html b/branch/main/coderefinery-workshops/index.html new file mode 100644 index 00000000..3ed2b4c1 --- /dev/null +++ b/branch/main/coderefinery-workshops/index.html @@ -0,0 +1,181 @@ + + + + + + Organize a CodeRefinery workshop — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Organize a CodeRefinery workshop

+

You or us?

+
    +
  • Historically, most workshops are CodeRefinery workshops were +organized centrally with a local host.

  • +
  • Now, we want to transition to locally-invited workshops, so we know +we have a audience and advertisement.

  • +
  • In the future, we need to transition to “independently run”.

  • +
+

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.

+
+

Centrally organized workshops

+
    +
  • CodeRefinery staff organize, we try to reach as many people as +possible.

  • +
  • Workshops in our own institutions tend to be best-attended, going to +a new institution sometimes has low attendance.

  • +
  • We started this way.

  • +
+
+
+

Locally invited workshops

+
    +
  • A local team requests CodeRefinery (usually with a known audience).

  • +
  • There is usually pretty good attendance.

  • +
  • CodeRefinery staff travels to site and teaches - at least with local +helpers, ideally with a local instructor.

  • +
+
+
+

Independently organized workshops

+
    +
  • In the future, we want to encourage independently organized +workshops: a site can organize the workshops without needing to go +through the core team.

  • +
  • We don’t yet know exactly how this will work, but this instructor +training is part of it.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/future/index.html b/branch/main/future/index.html new file mode 100644 index 00000000..e2d0cf98 --- /dev/null +++ b/branch/main/future/index.html @@ -0,0 +1,227 @@ + + + + + + Future — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Future

+
+

Activities

+
+

What is CodeRefinery?

+ +
+
+

This workshop

+
    +
  • Was it a useful format and useful content? Please give us feedback.

  • +
  • Should we collaborate on HPC Carpentry workshops?

  • +
  • Who will end up teaching HPC Carpentry? What do you need from us/somebody as support?

  • +
+
+
+

Nordic-RSE (research software engineers)

+ +
+
+

Collaborative workshops

+ +
+
+
+
+

How to get involved in CodeRefinery

+

There are many ways to get involved: https://coderefinery.org/get-involved/

+
    +
  • Become a workshop helper

  • +
  • Become a CodeRefinery workshop instructor

  • +
  • Become a Carpentries workshop instructor

  • +
  • Contribute to teaching material: https://github.com/coderefinery/

  • +
  • Create your own teaching material in our constellation of teaching.

  • +
  • Reuse our material

  • +
  • Become an institutional partner as a training hub

  • +
  • Participate in our chat and shape the project and lessons with us: https://coderefinery.zulipchat.com

  • +
  • Start a study group

  • +
+
+
+
+

Biggest open problems

+
    +
  • How to give helpers and contributors more credit and visibility

  • +
  • How to promote/engage new members

  • +
  • We don’t know how we should be in relation with Carpentries

  • +
  • What are we? Non-profit? Institution collaboration network? Selling services?

  • +
  • Funding and sustainability (but we have ideas: collaboration network)

  • +
  • Scalability and marketing question: How to reach more people? +(Research Software Hour, Twitch, streaming-only +workshops, recording, post-processing videos)

  • +
+
+
+
+

Certification for CodeRefinery instructors

+

We will set up a more formal process soon but for now you would need to:

+
    +
  • Attend an instructor training (this workshop).

  • +
  • Contribute to a lesson, either via pull request, issue, discussion, or as a helper.

  • +
  • Share a short teaching demo or teach a lesson at a CodeRefinery workshop where you will get some feedback on your teaching.

  • +
  • Participate in a call with other instructors and helpers either preparing a workshop or during a workshop debrief session.

  • +
+

There are many ways to learn how to teach well. We and carpentries provide one way and basic material, but we want to find a way for everyone to be a part of us.

+

See also https://coderefinery.github.io/manuals/instructor-intro/#from-helper-to-more.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/genindex/index.html b/branch/main/genindex/index.html new file mode 100644 index 00000000..8d998b45 --- /dev/null +++ b/branch/main/genindex/index.html @@ -0,0 +1,134 @@ + + + + + + Index — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/branch/main/guide/index.html b/branch/main/guide/index.html new file mode 100644 index 00000000..69c8a566 --- /dev/null +++ b/branch/main/guide/index.html @@ -0,0 +1,133 @@ + + + + + + Instructor’s guide — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/branch/main/index.html b/branch/main/index.html new file mode 100644 index 00000000..fc08c676 --- /dev/null +++ b/branch/main/index.html @@ -0,0 +1,240 @@ + + + + + + Community teaching training — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Community teaching training

+

In 2020, we got farther from our offices but closer to each other. If +you could adapt to the circumstances, a huge number of possibilities +were opened - in particular with collaborative teaching. In this +training, you will learn how to use them. Teaching from 2019 is +almost obsolete - join us to learn more.

+

Teaching is a profession, but also something that everyone needs to be +able to do to some degree, since everyone has their own personal +specialties they will either teach or mentor.

+

Broadly, this covers:

+
    +
  • Tools of teaching: how to make the most out of online (and +other) teaching

  • +
  • Workshop organization, collaboratively: our vision of teaching +together outside of our silos.

  • +
  • Socio-technical factors: social and technical barriers to +learning, why you need to care, and what you can do about them.

  • +
  • Lesson development, collaboratively: how to design lessons and +teaching materials so that they can be open and shared.

  • +
+
+

Prerequisites

+

This course has no strict prerequisites, but

+
    +
  • It is helpful if you have attended CodeRefinery or Carpentries +workshops, which teach in an interactive and hands-on way.

  • +
  • We assume you already have competence in the technical tools you +want to teach. Many of our concepts use examples from +CodeRefinery lessons, such as version control or other software +development tools.

  • +
  • While not a prerequisite for this course, version control (git) +is necessary to contribute to lessons development the way we show +here (but the lesson design concepts are applicable to other +styles, too).

  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+

Who is the course for?

+

You are interested in teaching CodeRefinery lessons, and would like a +comprehensive kickstart to how CodeRefinery works either to join us, +or teach its lessons with us or independently.

+

You are a technical specialist who is frustrated with the way you +currently try to teach others who need to use your software or +infrastructure. You can’t spend too much time to become a +professional, but you know you need something more than what you’ve +been doing. Thus, you would like to adopt some of the best practices of +designing and teaching interactive, hands-on workshops.

+

You’ve been teaching alone, but would like to join a collaboration +network for more co-teaching and to reduce the amount of duplication +of effort.

+

You run a practical teaching program at your institution (for example +as part of a research computing group) and would like to learn best +practices for collaborative teaching, so that you aren’t re-inventing +the same thing over and over again.

+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/lesson-design/index.html b/branch/main/lesson-design/index.html new file mode 100644 index 00000000..c3e86caf --- /dev/null +++ b/branch/main/lesson-design/index.html @@ -0,0 +1,348 @@ + + + + + + Lesson design — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lesson design

+ +
+
+

How do you design?

+
+

Discussion

+

Discuss either in groups or via collaborative document:

+
    +
  • How do you start when you design a new lesson/presentation?

  • +
  • Has your approach changed over the years? If yes, how?

  • +
+
+
+
+
+

Backwards lesson design

+
+

The approach

+
    +
  • You don’t think about how to do something and try to explain it.

  • +
  • Avoid the typical approach “I want to show a number of things which I think are cool about +tool X - how do I press these into 90 minutes?”

  • +
  • Instead, you start defining your target audience by answering to questions +such What is the expected educational level of my audience?, Have they +been already exposed to the technologies I am planning to teach?, What +tools do they already use?, What are the main issues they are currently +experiencing?. It is important to discuss these points with a group of +colleagues, preferably from diverse backgrounds and institutions to reduce +biases. Once you clarified your target audience, it is useful to create +learner personas; that will help you during the development process by +providing concrete examples of potential learners showing up at your +workshops. For each learner personas, try to think of what is useful to +them: “What do they need to +remember/understand/apply/analyze/evaluate/create?”. +Asking and answering to these questions will allow you to define the +background knowledge (starting points) and goals (end points) of your +learners. Then, you create a sequence of exercises which test incrementally +progressing tasks and acquisition of the new skills (from starting to end +points).

  • +
  • Then, you write the minimum amount +of material to teach the gap between exercises.

  • +
+
+
+

The process

+

For the whole process, see our +manual +(instructor discusses these points briefly).

+
+
+

Why is it good to have a process?:

+
    +
  • Having a semi-rigid design process can save time to start drafting.

  • +
  • It allows collaborative development of teaching material.

  • +
  • It will probably increase quality and relevance of lessons for learners.

  • +
  • We aren’t perfect yet. CodeRefinery is still striving to get +better at this, and we are more ad-hoc than you might think. +A number of our lessons have not been designed this way but we are now improving +these lessons with the backwards lesson design in mind.

  • +
+
+
+

Designing exercises

+

The goal of exercises is twofold:

+
    +
  • instructors can assess the progress of learners.

  • +
  • learners put in practice the skills that you have included in your skills list.

  • +
+

When designing exercises, consider that some participants will get stuck +and may want to re-join at a later exercise. In other words it is nice +if exercises build up on each other but not at the cost that if participants +get stuck at exercise 2, they will not be able to do exercises 3 to N.

+
+
+
+
+

Practice backwards design

+
+

The goal here is to discuss and provide examples on backwards-design of a lesson.

+

Let’s take as an example the HPC Carpentry lesson

+

Target audience

+
    +
  • What is the expected educational level of my audience?

    +
      +
    • A PhD student, postdoc or young researcher.

    • +
    +
  • +
  • Have they been already exposed to the technologies I am planning to teach?

    +
      +
    • The word HPC is not new to them and they may have already used an HPC but are still not capable of giving a proper definition of HPC. In addition, we do not expect them to know much about parallelism and they cannot make any distinction between various available parallelism paradigms.

    • +
    +
  • +
  • What tools do they already use?

    +
      +
    • serial codes, multi-threaded codes, data parallelism; usually out-of-the-box tools.

    • +
    • they may have tried to “scale” their code (multiprocessing, threading, GPUs) with more or less success.

    • +
    +
  • +
  • What are the main issues they are currently experiencing?

    +
      +
    • they cannot solve their problems either because they would like to run the same code but with many different datasets or because their problem is larger (more computations/memory).

    • +
    • most of the time they know their codes can run on HPC (from the documentation) but never really had the opportunity to try it out.

    • +
    • Very few will have their own codes where they may have tried different things to speed it up (threading, task parallelism) but have no clear strategy.

    • +
    +
  • +
+

Learner persona

+
    +
  • Sonya is a 1st year PhD student: she recently moved to Oslo and joined the +Computational and Systems Neuroscience group. She will be using the +NEST, a simulator for spiking +neural network model. She used NEST during her master thesis but on her +small cluster: she never used an HPC resource and is really excited about it.

  • +
  • Robert is a field ecologist who obtained his PhD 6 months ago. He is now +working on a new project with Climate scientists and as a consequence will +need to run global climate models. He is not very familiar with command +line even though he attended a Software Carpentry workshop and the idea to +use HPC is a bit terrifying. He knows that he will get support from his +team who has extensive experience with HPC but would like to become more +independent and be able to run his own simulations (rather than copying +existing cases).

  • +
  • Jessica is a postdoc working on a project that investigates numerically the +complex dynamics arising at the tip of a fluid-driven rupture. Fluid +dynamics will be computed by a finite element method solving the +compressible Navier-Stokes equations on a moving mesh. She uses a code she +has developed during her PhD and that is based on existing libraries. She +has mostly ran it on a local desktop; her work during her PhD was very +limited due to the lack of computing resources and she is now very keen is +moving to HPC; she knows that it will requires some work, in particular to +parallelize her code. This HPC training will be her first experience with +HPC.

  • +
+

Learning outcomes

+
    +
  • Understand the difference between HPCs and other local/remote machines

  • +
  • Understand the notion of core, nodes, cluster, shared/distributed memory, etc.

  • +
  • Understand the notion of login nodes.

  • +
  • Understand the need for a scheduler and how to use it appropriately

  • +
  • Understand why optimising I/O is important on HPC and how to best use HPC filesystems

  • +
  • Understand the need to parallelize (or use existing parallel) codes and in which cases HPCs is a must (when communications is required)

  • +
  • Understand how to get your code ready to use on HPC (access to libraries, installation of your own libraries/software, etc.)

  • +
  • Understand that an HPC is an operational machine and is not meant for developing codes.

  • +
+

Exercises

+
    +
  • Get basic information such the number of CPUs, memory from your laptop and try to do the same on a HPC. Discuss outcomes.

  • +
  • Try to create files on the different filesystems on your HPC resource and access them.

  • +
  • Create different types of job scripts, submit and check outputs.

  • +
  • Make a concrete example to run a specific software on your HPC (something like GROMACS).

  • +
+
+
+

Demo

+

Before we let participants present to their groups, one of the instructors +presents a 5-minute segment and we practice together giving feedback.

+

The section we demo should require screen sharing and be of some follow-along +task.

+

If there is time, we present one demo on the day before, and one demo just +before the group exercise.

+
+
+

Exercise

+

Choose a simple lesson topic and apply backwards lesson design. You +won’t get all the way through, but come up with a logical +progression of exercises.

+

The section you pick should require screen sharing and be of some follow-along +task (preferably using a shell).

+

Some suggestions:

+
    +
  • Regular expressions

  • +
  • Making papers in LaTeX

  • +
  • Making figures in your favorite programming language

  • +
  • Linux shell basics

  • +
  • Something non-technical, such as painting a room

  • +
  • An instructor training for CodeRefinery

  • +
  • Some aspect from an already existing lesson

  • +
  • Introduction to high-performance computing (or an episode therein)

  • +
  • Unix shell in a HPC context (or an episode therein)

  • +
  • A lesson you always wanted to teach

  • +
+

Exercise (30 minutes):

+
    +
  • Collect notes in a shared document.

  • +
  • Start with learner personas and learning outcomes.

  • +
  • Come up with a logical progression of exercises.

  • +
+

Discussion (15 minutes):

+
    +
  • How does this approach compare to other lessons or courses you have designed?

  • +
  • We read, compare, and discuss our notes.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/lesson-development/index.html b/branch/main/lesson-development/index.html new file mode 100644 index 00000000..7b0ba005 --- /dev/null +++ b/branch/main/lesson-development/index.html @@ -0,0 +1,240 @@ + + + + + + Collaborative lesson development — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Collaborative lesson development

+

This session focuses on organizational and technical aspects +of collaborative lesson development.

+
+

Discussion

+

This session is about collaborative lesson development. What advantages do +you see in developing lessons collaboratively and sharing lessons (making +material accessible)? What difficulties are there?

+
+
+
+

Lesson templates for static sites

+ +

Why static sites?

+
    +
  • Decentralized (in terms of organization/namespace)

  • +
  • Forkable

  • +
  • Anybody can suggest changes

  • +
+
+
+
+

Creating new teaching material

+

Creating new teaching material is a longer process, because you should +go through the whole +backwards lesson design process +and get extensive comments. +Still, don’t feel afraid: nothing is perfect (or even good) +the first time. In fact, it may be an advantage to share an imperfect +lesson with others early to collect feedback and suggestions before the lesson +“solidifies” too much. Draft it and collect feedback. The result will probably +be better than working in isolation towards a “perfect” lesson.

+
+

Discussion

+

How can we share unfinished work/ideas?

+
    +
  • Draft pull requests (GitHub) or WIP (work in progress) merge requests (GitLab).

  • +
  • Open an issue and discuss your idea before implementing it.

  • +
+
+
+
+
+

Contributing to existing lessons

+

Our lessons are collaboratively developed. They are made by many +people, and there is no single fixed master plan (but there should be, +in the instructors or maintainer’s guide). We encourage +everyone to contribute to the lessons.

+

Lessons are reviewed very often - essentially, before each workshop by +the instructor of that workshop. This can be a quick review, looking +at issues and fixing easy things, or more thorough.

+

Every so often (such as at this training), there is an extensive +hackathon period of fully revising a lesson and making major improvements.

+

We’ve made the lesson-review checklist +to guide the review process.

+
+

Discussion

+

We now go to the +lesson-review +checklist and discuss it, instead of duplicating things here.

+
+
+
+
+

Recommendations and lessons learned

+
    +
  • Convert feedback about lessons and suggestions for improvements into issues +so that these don’t get lost.

  • +
  • Make your lesson citable: get a DOI.

  • +
  • Credit contributors (not only Git commits).

  • +
  • Instructor guide is essential for new instructors.

  • +
  • Lesson changes should be accompanied with instructor guide changes (it’s like +a documentation for the lesson material).

  • +
  • Apply and validate backwards lesson design again and again.

  • +
  • Make it possible to try out new ideas (by making the lesson branch-able).

  • +
  • Before making larger changes, talk with somebody and discuss these changes.

  • +
  • For substantial changes we recommend to first open an issue and describe your +idea and collect feedback before you start with an extensive rewrite.

  • +
  • For things still under construction, open a draft pull request to collect +feedback and to signal to others what you are working on.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/objects.inv b/branch/main/objects.inv new file mode 100644 index 00000000..e527d01e Binary files /dev/null and b/branch/main/objects.inv differ diff --git a/branch/main/quick-reference/index.html b/branch/main/quick-reference/index.html new file mode 100644 index 00000000..7319f9e4 --- /dev/null +++ b/branch/main/quick-reference/index.html @@ -0,0 +1,135 @@ + + + + + + Quick Reference — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/branch/main/search/index.html b/branch/main/search/index.html new file mode 100644 index 00000000..8f8897a1 --- /dev/null +++ b/branch/main/search/index.html @@ -0,0 +1,148 @@ + + + + + + Search — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • »
  • +
  • Search
  • +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2020, The contributors.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/branch/main/searchindex.js b/branch/main/searchindex.js new file mode 100644 index 00000000..6b4f260c --- /dev/null +++ b/branch/main/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["00-preparation","02-teaching-philosophies","03-teaching-style","about-coderefinery","coderefinery-workshops","future","guide","index","lesson-design","lesson-development","quick-reference","teaching-practice","teaching-strategies","welcome","workshops-online"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"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:56},filenames:["00-preparation.md","02-teaching-philosophies.md","03-teaching-style.md","about-coderefinery.md","coderefinery-workshops.md","future.md","guide.rst","index.rst","lesson-design.md","lesson-development.md","quick-reference.rst","teaching-practice.md","teaching-strategies.md","welcome.md","workshops-online.md"],objects:{},objnames:{},objtypes:{},terms:{"10":[3,5,14],"100":14,"1000":5,"14":14,"15":[2,3,8],"180":[1,14],"1st":8,"2":[0,2,5,8],"20":[5,14],"2014":3,"2015":3,"2016":3,"2018":3,"2019":7,"2020":[5,7,14],"2021":[3,5],"250":14,"2x2":2,"3":[3,8,14],"30":[5,8],"4":[2,11],"40":14,"45":1,"5":[0,2,8,11,12,14],"50":11,"6":[3,8,14],"7nhx":1,"90":[8,14],"break":[1,2,12,13,14],"case":[1,2,8],"catch":12,"class":[1,2,12],"do":[0,1,2,3,5,7,9,12,14],"import":[1,8,12,13,14],"long":[1,2,12,14],"new":[1,3,4,5,8,11,12,13,14],"return":1,"short":[0,2,3,5,14],"static":14,"true":2,"try":[1,2,4,7,8,9,12,14],"while":[1,2,7,12,14],A:[1,2,3,4,8,9,12],And:[1,12,13],As:2,At:1,BY:4,Be:[13,14],Being:0,But:[1,2,12,13],By:3,For:[1,2,8,9,13],If:[1,7,8,12,13],In:[1,2,3,4,7,8,9,11,12,14],It:[1,2,3,7,8,11,12,13,14],Not:2,Of:1,One:[2,3,12],Or:2,That:[1,2],The:[0,1,3,7,9,11,12,13,14],Then:[2,8,14],There:[1,2,4,5,12],These:[2,3],To:[2,14],With:[1,12],aalto:14,aaltoscicomp:5,abil:[0,1],abl:[0,1,2,7,8,9,14],about:[1,2,7,8,9,12,13,14],abov:14,academ:[1,3],acceler:2,accept:[2,3,14],access:[3,8,9,14],accommod:2,accompani:9,accomplish:[2,12],account:[1,11],accur:2,achiev:[1,2],acquir:2,acquisit:[2,8],across:14,activ:[2,3],actual:14,ad:8,adapt:[1,2,7],add:2,addit:[1,2,8],address:[2,3],adopt:[3,7],advanc:[1,2,12,13],advantag:[9,12,14],advertis:[4,14],affect:[2,13],afraid:9,after:[1,2,3],again:[7,9],agil:1,ago:[1,3,8],agre:2,aha:1,ahead:2,aim:[2,3],all:[1,2,3,8,11,13,14],allow:[1,2,8,12,14],almost:[1,5,7,12],alon:[1,7],along:[1,2,8,11,12],alreadi:[2,3,7,8],also:[0,1,2,3,5,11,13,14],alwai:[1,8,12,13],am:[1,8],among:2,amount:[2,7,8],an:[0,1,2,3,5,7,8,9,13,14],analog:[1,2],analyz:8,ani:[1,2,3,8,12,13,14],announc:14,anonym:[12,14],anoth:1,answer:[1,3,8,12,13,14],anticip:2,anybodi:9,anymor:[1,14],anyon:[1,2,4],anyth:12,anywai:14,appear:[1,14],appli:[1,2,3,8,9,12,13],applic:7,appreci:1,approach:[1,3,7],appropri:[0,8],ar:[0,1,3,4,5,7,8,9,12,13,14],architectur:1,archiv:14,aren:[2,7,8],aris:8,around:[2,14],art:11,articul:[2,3],ask:[0,1,2,3,8,11,12,13,14],aspect:[0,1,3,4,8,9,11],assess:8,assign:[2,14],assum:[1,2,3,7,12],attend:[0,3,4,5,7,8,13,14],attende:1,attent:1,attitud:1,audienc:[1,2,4,8,14],autom:2,avail:[8,12,13,14],averag:2,avoid:[1,3,8,11,14],awar:3,ax:2,back:[1,2,14],background:[1,8],backward:9,bad:[11,12,14],bank:13,barrier:7,base:[0,1,2,3,8,9,12],baselin:0,bash:2,basi:0,basic:[1,5,8,12],becaus:[1,2,3,8,9,14],becom:[1,2,3,5,7,8,12],been:[1,2,7,8,14],befor:[1,2,8,9,14],begin:1,behind:1,being:[1,13],beings:2,belief:2,believ:[1,2],below:[1,2,14],benefici:1,benefit:[2,12,14],benner:2,best:[1,2,4,5,7,8,13],better:[1,3,8,9,11,12],between:[1,2,8,12,14],beyond:3,bi:[2,5],bias:8,big:1,binari:1,bit:[1,2,8,14],blank:1,blob:1,block:1,board:13,book:[2,7],bore:1,borrow:2,both:[1,2,11,12],bottom:2,box:[8,13],branch:9,breakout:[2,11,13],breath:2,brief:0,briefli:8,bring:[1,2,12],british:2,broaden:1,broadli:[2,7],broken:2,browser:1,build:[2,3,8,13],built:2,bullet:1,busi:1,call:[1,2,5,12],came:11,can:[1,2,3,4,7,8,9,11,12,13,14],cannot:[2,8],capabl:[1,8],capentri:2,capit:2,car:2,care:[1,4,7],carefulli:2,carpentri:[1,5,7,8,9,13],catalyz:13,categori:2,cc:4,center:2,centric:1,certain:[1,14],challeng:[1,2],chang:[1,2,8,9,11],chat:[5,12,14],check:[0,1,2,8,11,13],checklist:9,choic:[0,2,11],choos:[2,8],circumst:[2,7],citabl:9,citi:2,clarif:2,clarifi:8,classroom:[1,2,13],clear:[1,8,12,14],clearli:[1,2,3,12,13,14],climat:[2,8],close:[11,12],closer:7,cluster:[2,8],co:[1,7],code:[1,2,3,8],coderefineri:[0,7,8,12],cognit:1,collabor:[3,7,8,11,12,13],colleagu:[3,8,14],collect:[2,3,8,9,12,13],columbia:2,com:[1,5,14],combin:[1,14],come:[1,2,8,12,14],command:8,comment:[9,12,13],commentari:12,commit:9,common:[3,9],commun:[1,3,8,13,14],compar:[2,8,12,14],compens:1,compet:[1,7],complement:1,complementari:3,complet:[0,2,3,13],complex:[2,8],complic:1,compon:1,comprehens:7,compress:8,compris:3,compromis:1,comput:[1,2,3,7,8,13,14],concept:[1,2,7,12],conceptu:3,concern:2,conclus:11,concret:8,condens:14,conduct:2,confer:5,confid:[1,2,3],configur:2,confus:[1,13],connect:[1,2],consciou:1,consequ:8,consid:[1,8],consider:1,constel:5,constitut:2,constrict:12,construct:[0,9,11],contain:14,content:[2,5,14],context:[1,2,8],continu:[2,14],contradict:2,contrast:[2,14],contribut:[5,7,13],contributor:[3,5,9],control:[3,5,7,9,13],convei:1,convers:1,convert:9,convinc:3,convolut:1,cool:8,coordin:[12,14],copi:[1,8,12],core:[4,8],correct:[1,2],correctli:2,cost:8,could:[1,2,7],countri:[2,3,14],cours:[0,1,2,3,8,12,14],cover:[3,7],cpu:8,creat:[1,2,5,8],creation:2,creativ:1,credit:[2,5,9],curios:1,current:[2,7,8],curriculum:[7,8],custom:[0,1,14],cut:2,d:1,dai:[0,2,8,14],daili:2,data:[3,8],dataset:8,debrief:5,dec:5,decentr:9,decid:2,dedic:14,deepli:2,defin:[3,8,13,14],definit:8,degre:[1,7],deliv:2,demo:[1,2,5,12],demograph:2,demonstr:[11,14],demystifi:1,depend:2,depth:2,deriv:[2,3],describ:[1,2,9],design:[7,9,11,13,14],desktop:8,detail:2,detect:1,determin:2,detour:1,develop:[1,3,5,7,8],deviat:1,diagram:1,did:[1,2,14],didn:14,differ:[1,2,3,8,11,12,14],difficult:[1,2],difficulti:[3,9,12],direct:[2,3],directli:[2,14],directori:2,disadvantag:[12,14],disagre:2,disciplin:3,discret:2,discuss:[0,1,2,5],displai:12,disproportion:13,distil:1,distinct:[2,8],distinguish:2,distract:12,distribut:[8,11],divers:[8,13,14],doc:2,document:[1,3,7,8,9,11,14],doe:[2,3,8,14],doesn:[2,12,14],doi:9,domain:[1,2],don:[1,2,4,5,8,9,12,13,14],done:[1,2],down:[1,2,11,12],draft:[8,9],draw:1,dreyfu:2,drive:2,driven:8,driver:2,dual:14,due:8,duplic:[2,7,9],dure:[0,1,2,5,8,11,14],dynam:[1,8],e:[1,2,3],each:[1,2,3,7,8,9,11,12,13,14],earli:9,easi:[1,9,12,14],easier:[3,12],easiest:2,easili:[1,2],ecologist:8,economi:2,edit:14,educ:[2,8],effect:[3,8,12],effort:[1,2,7,13],either:[2,5,7,8],element:8,els:[1,14],email:14,embrac:[1,3],emphas:14,encourag:[1,2,4,9,13],end:[1,2,5,8,12],engag:[1,5],engin:[2,3],enough:[2,12,13,14],entir:[1,2],environ:[2,13],episod:[0,1,2,8,12,14],equat:8,error:[1,2],especi:[1,2],essenc:1,essenti:[1,2,9],establish:[1,2,3],etc:[3,8,14],etherpad:2,ethic:14,evalu:[8,11],even:[1,2,8,9],event:[2,5],ever:2,everi:[2,9,14],everybodi:[1,2,13],everydai:2,everyon:[2,5,7,9],everyth:[1,2,12,13,14],evid:[0,2],exactli:4,exam:2,exampl:[1,2,3,5,7,9,12,13],excit:8,execut:2,exercis:[0,1,12,14],exist:[2,8],expect:[2,8,12,14],experi:[1,2,3,8,12,14],experienc:[1,8],expert:[1,14],explain:[1,2,3,8,12],explicit:1,expos:8,express:8,extens:[8,9],extra:14,face:1,facilit:2,fact:[1,2,9],factor:7,factual:2,fail:[2,14],fall:[2,11],familiar:[1,8,14],fanci:2,farther:7,fashion:1,fast:[1,2,14],faster:[1,12,14],favor:3,favorit:8,featur:14,fee:3,feedback:[0,1,3,5,7,8,9,12,13,14],feel:[1,2,9,11],felt:1,few:[1,2,8,11,12],field:[8,14],figur:[2,8,14],file:[2,8],filesystem:8,find:[0,1,5,14],finish:1,finit:8,firmli:2,first:[2,8,9,14],firstnam:14,fit:2,five:[12,14],fix:9,flow:[1,12],fluid:8,focu:[1,2,12],focus:[7,9,12,14],follow:[1,2,8,11,12,13],font:[12,13],forc:1,forget:12,forkabl:9,form:[0,3,13],formal:[2,5],format:[3,5,11,13],former:14,found:2,foundat:3,four:1,framework:2,free:3,freeli:[9,13],frequent:2,friend:1,from:[1,2,3,5,7,8,12,13,14],frustrat:7,fulli:[2,9],fun:[1,14],fund:[3,5],fundament:2,further:2,futur:[1,2,3,4,7,13],g:1,galleri:14,gap:8,gave:13,gcjexwc8cf:1,gener:[3,7,13],get:[0,1,3,8,9,11,12,14],git:[3,7,9],github:[5,9,13,14],gitlab:9,give:[1,3,5,8,11,12,14],given:[1,2,3],global:8,go:[0,1,2,4,9,12,14],goal:[1,11],goe:2,gone:2,good:[1,2,3,4,9,11,14],googl:2,got:[1,7],gpu:8,grad:3,grade:2,gradual:[1,7],great:[1,12,13],greatli:14,grew:3,grid:2,gritti:1,gromac:8,ground:1,group:[0,2,5,7,8,11,12,13],grow:2,growth:2,guarante:14,guesswork:2,guid:[1,2,7,9,12,13,14],h:14,ha:[1,2,3,4,7,8,12,14],hackathon:9,hackmd:[2,13],had:[1,3,8,14],half:12,hand:[1,3,7,13,14],handbook:[7,8],handl:[2,14],handwrit:1,happen:2,hard:[1,2],harder:[12,14],hardest:2,hardli:2,have:[1,2,3,4,5,7,11,12,13,14],haven:14,he:[2,8],head:1,headless:2,heard:2,help:[0,1,2,7,8,13,14],helper:[1,3,4,5,7,12,13],henc:1,her:[2,8],here:[1,2,4,7,9,13,14],hi:8,hierarch:2,hierarchi:2,high:[3,8],highlight:[1,2,11],hint:[1,12],histor:4,histori:[2,12],hoc:8,hole:1,home:1,hope:3,hopefulli:1,host:[3,4,13,14],hour:5,how:[1,3,4,7,9,11,13,14],howev:[1,2,4],hpc:[5,8],http:[1,3,5,14],hub:5,huge:7,human:[1,2],humanist:1,humour:1,hundr:14,i:[1,2,3,8],idea:[2,3,5,8,9,12],ideal:[1,4],ident:[2,13],imag:2,immedi:[2,14],impart:1,imped:2,imperfect:9,implement:[3,9],impost:13,impress:13,improv:[2,3,8,9,11,13,14],improvis:1,inaccur:2,inclin:1,includ:[1,2,8,11,14],inclus:[2,13],incomplet:2,incorpor:2,increas:[2,8,14],increment:8,independ:[1,3,7,8,13],indic:2,individu:[1,2],inform:[1,2,8,12,13,14],infrastructur:[1,3,7],inherit:2,initi:2,instal:[2,8],instanc:2,instant:14,instead:[8,9,12,13,14],institut:[3,4,5,7,8,14],instruct:[12,14],instructor:[1,3,4,7,8,9,12,14],instrument:2,intend:[1,2,3],intens:7,intent:1,interact:[1,7,12,13,14],interest:[0,1,7,11,12],intern:3,interpret:2,interrupt:[1,12],intro:[2,5,7,14],introduc:[0,12,14],introduct:[7,8,9,12,14],intructor:2,intuit:1,invent:7,invest:1,investig:8,involv:7,io:5,isn:[1,13],isol:9,issu:[1,5,8,9],iter:3,its:[1,2,3,7],jargon:1,jekyl:9,jessica:8,job:[1,2,8],join:[7,8,14],judg:2,jupyt:3,just:[1,8,12,14],keen:8,keep:[1,2,3,12,14],kei:0,kickstart:7,kind:[13,14],know:[1,2,3,4,5,7,8,12,13],knowledg:[1,3,8,13],known:[1,3,4,14],ksa:1,kth:3,lack:[2,8],landmark:2,languag:[1,3,8],laptop:8,larg:[1,2,12,13,14],larger:[8,9],last:1,lastnam:14,later:[2,8,11,12,14],latex:8,layout:12,lead:[3,13],leaner:2,learn:[0,1,3,5,7,8,11,12,13,14],learner:[1,3,8,12,14],learnt:[1,13],leasson:2,least:[0,1,2,4,14],leav:1,lectur:[1,12,14],less:[1,2,8,12,13,14],lesson:[0,1,2,3,4,5,7,11,12,14],let:[8,12,13],level:[2,3,8],librari:8,licens:4,life:1,lightn:0,like:[1,2,7,8,9,11,12],limit:[1,8,12,14],line:8,link:13,linux:8,list:[1,8],listen:[11,12],littl:[13,14],live:[1,2,13],ll:2,local:[3,8,14],locat:2,log:14,logic:8,login:[2,8],longer:9,look:[1,2,9,12],lose:14,loss:14,lost:9,lot:[1,12],love:[1,3],low:[4,13],luci:13,machin:8,made:[1,9,14],mai:[1,2,5,8,9,13],main:[0,1,8,12,14],mainli:12,maintain:[3,9,14],major:[2,3,9,13],make:[1,2,3,4,7,8,9,11,12,14],manag:[2,14],mani:[1,2,4,5,7,8,9,12,13,14],manifest:13,manual:[5,7,8,12,13],manula:12,map:[1,5],march:14,market:5,master:[1,8,9],masteri:2,match:[2,12],materi:[1,3,5,7,8,13],max:14,mctigh:2,me:1,mean:1,meant:8,measur:3,mechan:[2,13,14],meet:[2,5,14],member:5,membership:5,memori:8,mentor:7,mentorship:1,merg:9,mesh:8,met:2,method:[2,8],might:[1,2,8],mind:[1,2,8,12],minim:[1,12],minimum:[2,8,14],minut:[0,2,8,11,12,14],misconcept:2,miss:[1,2,12,14],mission:3,mistak:1,mix:1,mixtur:2,mode:[2,14],model:[8,13],modern:5,modular:3,monitor:14,month:[3,8],more:[1,2,3,5,7,8,9,11,12,13,14],most:[1,2,4,7,8,11,12,14],mostli:[8,14],motion:2,motiv:[1,13,14],move:[2,8],much:[1,2,7,8,9,12,14],multi:[8,14],multipl:[2,12,14],multiprocess:8,music:2,must:[2,8,12],my:[0,1,8],myself:1,mysteri:1,n:[8,14],name:14,namespac:9,narr:1,natur:1,navier:8,necessari:7,necessarili:2,need:[1,2,3,4,5,7,8,12,13,14],neg:2,negoti:2,neic:3,nest:8,network:[3,5,7,8,13,14],neural:8,neurolog:1,neurosci:8,never:[1,2,8,14],next:[1,3,12,14],nice:8,nitti:1,node:8,non:[5,8],nordic:3,normal:[2,14],note:[1,2,8,12,13],noth:9,notic:[1,11,13],notion:8,nov:5,novemb:3,novic:1,now:[1,4,5,7,8,9,12],nu:3,number:[7,8,12,13,14],numer:8,nurs:2,o:8,object:[0,1],observ:1,obsolet:7,obtain:8,obviou:[1,12,14],octob:3,off:1,offens:1,offer:1,offic:7,often:[1,2,3,9,12],ok:2,old:[2,12,14],onc:[1,8,14],one:[0,1,2,5,8,11,12,13,14],onli:[1,2,3,5,7,9,11,12,14],onlin:[2,5,7,13],open:[1,3,7,9,13],oper:8,opinion:2,opportun:[1,3,8],opposit:1,optim:2,optimis:8,option:12,order:[1,2,11],ordinari:2,org:5,organ:[2,7,9,11],organiz:[7,9],orient:12,oslo:8,other:[1,2,5,7,8,9,11,12,13],our:[0,1,2,3,4,5,7,8,9,11,13,14],ourselv:14,out:[1,2,3,7,8,9,12,14],outcom:[1,2,8,13],output:8,outro:13,outsid:7,over:[1,5,7,8,12,14],overal:3,overcom:1,overflow:13,overlap:14,overload:12,overview:[0,2,3,14],overwhelm:[1,14],own:[1,2,3,4,5,7,8],pace:[1,2],pai:1,paint:8,paper:[0,8],paradigm:8,parallel:[2,8],part:[1,2,4,5,7,12],particip:[1,3,5,8,11,13,14],particular:[2,7,8],particularli:1,partner:[3,5],partnership:3,pass:2,past:[1,3,9],pathwai:7,patricia:2,pattern:2,pdf:13,peopl:[1,2,3,4,5,9,12,13,14],per:[2,14],perceiv:1,perfect:[8,9],perfectli:1,perform:[8,11],perhap:[1,13],period:[1,9],person:[1,2,7,11,12,13],persona:[1,8],perspect:1,phd:8,philosophi:[0,7],physic:14,pick:[8,11],pictur:[1,12],piec:2,pitfal:11,place:[1,2,14],plai:2,plan:[1,3,4,8,9,12,13,14],plane:13,planet:2,platinum:3,playlist:1,pleas:[0,1,5,11],plplblyhczjaahf89p:1,point:[1,2,8,9,11,12],poll:2,port:3,portion:2,posit:2,possibl:[1,2,3,4,7,9,12,14],post:[2,3,5],postdoc:8,potenti:8,power:14,practic:[0,1,2,4,5,7,13,14],practis:[1,2],practition:1,pre:[2,7,14],precis:[1,12],prefer:[8,11],prep:[12,14],prepar:[1,2,4,5,7,12],prerequisit:2,present:[0,2,3,8,11,12,14],press:8,pressur:12,pretti:4,prevent:[1,13],previou:1,primari:14,prior:[2,3],privaci:14,probabl:[2,3,8,9,11],problem:[1,2,3,8,13,14],procedur:2,process:[2,5,9],produc:[3,12],product:1,profess:7,profession:[1,7],profit:5,program:[1,2,3,7,8],progress:[1,8,9],project:[2,5,7,8,13],promis:2,promot:5,proper:8,properti:12,propos:3,protect:13,provid:[0,2,3,5,12,13],pull:[1,5,9],pure:14,purpos:[2,12],put:[1,2,8,14],puzzl:1,python:[1,5,14],qualifi:3,qualiti:[3,8],quantifi:3,question:[1,2,3,5,8,11,14],queue:2,quick:[7,8,9,14],quickli:14,quiet:[12,14],quit:[1,2],rabbit:1,rais:[1,3,14],ran:8,rang:1,rapid:14,rare:1,rather:8,re:[1,7,8,9],reach:[2,4,5],react:1,read:[0,1,2,7],readi:[2,8,14],real:[1,2],realis:1,realiz:1,realli:[1,8,14],reason:[1,2,14],receiv:11,recent:[1,8,12],reckon:1,recogn:2,recommend:[1,14],record:[0,5],recruit:[13,14],reduc:[7,8,12,14],refocu:2,region:2,regist:14,registr:[13,14],regular:8,regularli:1,reinforc:2,relat:[1,2,5,13],relationship:2,relev:[1,2,8],reli:2,remain:2,rememb:[1,2,8],remix:13,remot:[2,8],repeat:[1,2],replac:7,repli:[12,14],report:2,repositori:[3,14],repres:13,reproduc:[3,5],request:[1,2,4,5,9],requir:[0,1,4,8,11,12,14],research:[1,2,3,7,8],reserv:2,resid:2,resourc:[2,8,13],respect:2,respond:2,respons:0,rest:2,result:[0,2,3,9],reus:5,reusabl:3,review:[2,9,13],revis:9,rewind:12,rewrit:9,right:[1,14],rigid:8,road:2,robert:8,role:13,room:[1,2,8,12,13],rotat:14,round:11,rubric:[2,11],run:[2,4,7,8,12],ruptur:8,s1:12,s2:12,s3:12,s4:12,s:[1,7,8,9,11,12,13,14],sad:2,safe:2,sai:13,same:[1,2,7,8,11,12,14],save:[8,12],saw:1,scalabl:5,scale:[2,8,12],scan:2,schedul:[5,8],scicomp:5,scienc:[0,3],scientif:[3,13,14],scientist:8,scratch:2,screen:[2,8,11,13],script:[1,2,3,8],seat:3,second:11,section:[0,2,3,8,11],see:[1,2,5,8,9,14],seem:[1,2],segment:[8,11],select:14,self:[1,13],sell:5,semant:1,semi:8,send:[1,14],sens:[1,3],sensit:1,sentenc:1,separ:[1,12],sequenc:8,serial:[1,8],serv:14,servic:[3,5],sese:3,session:[0,1,2,5,9,11,12,13,14],set:[1,2,5,12,14],setup:[2,11,12],sever:[1,3,12],shape:5,share:[1,2,3,5,7,8,9,11,13],she:[2,8],shell:[2,8,11],ship:3,shortli:14,should:[1,2,3,5,8,9,11,12,13,14],shouldn:14,show:[1,3,7,8,11,12],side:12,sign:[1,2],signal:[1,9],signpost:13,silent:13,silo:7,similar:[1,2,7,12],simpl:[1,2,8,14],simpli:[1,2],simplifi:[1,2],simul:8,sinc:[1,3,7,11,14],singl:9,sit:1,site:4,situat:[1,2],size:[13,14],skill:[1,2,3,8],skip:[1,2],slide:[1,13],slow:[1,2,12],slower:[1,2,14],slowli:[1,2],small:[8,12],smaller:[12,13],so:[1,2,4,7,9,11,12,13,14],social:[2,7],societi:2,socio:7,softwar:[1,2,7,8,13,14],solidifi:9,solut:1,solv:[1,2,3,8],some:[0,1,2,5,7,8,11,12,13,14],somebodi:[1,5,9],someon:[2,7,12,13],someth:[1,2,7,8,12,13],sometim:[1,4],sonya:8,soon:[5,13],sooner:11,sort:2,sound:[1,2],spare:14,spark:1,speak:2,special:[2,14],specialist:7,specialti:7,specif:[1,2,3,8],speed:[2,3,8],spend:[1,7],spent:1,sphinx:9,spike:8,spotlight:14,stack:13,staff:4,stage:2,stai:14,start:[1,2,3,4,5,8,9,12,13,14],state:[2,12],step:[1,2,12,14],still:[1,2,8,9,14],stockholm:3,stoke:8,stop:1,stori:1,storytel:1,strategi:[8,12],stream:5,streamer:14,stress:14,strict:7,strive:8,strongli:2,structur:1,struggl:1,stuck:[1,8,12],student:[1,3,8,12,13,14],studi:[1,2,5],stuff:[2,3],style:[1,3,7,9],submit:[2,3,8],submodul:9,substanti:9,success:[1,4,8],suffer:13,suffici:[1,2,3],suggest:[3,8,9],suitabl:2,sum:1,summari:8,superfici:2,support:[1,3,5,8,13],sure:[1,2,12,14],surpris:1,survei:[0,2,3],sustain:[3,5],syndrom:13,system:[2,8,12,14],t:[1,2,4,5,7,8,9,12,13,14],take:[1,2,8,11,12,13,14],talk:[2,9],target:[1,2,8],task:[2,8,11],taught:[1,2,14],teach:[0,3,4,5,8,13],teacher:[1,2,13],team:[1,4,8,12],tech:[7,8,12],technic:[1,7,8,9],techniquess:14,technolog:8,tell:2,templat:[13,14],ten:8,tend:[1,4],term:[2,9],termin:2,terrifi:8,test:8,text:1,than:[1,2,7,8,9,12,14],thei:[1,2,3,7,8,9,12,14],them:[1,2,3,7,8,11,13,14],theme:3,themselv:14,theoret:3,therefor:2,therein:8,thesi:8,thi:[0,1,3,4,7,8,9,11,12,14],thing:[1,7,8,9,12,13,14],think:[1,2,8,12],thorough:9,those:[1,2],though:[1,3,8],thousand:2,thread:[8,12],three:[1,2,14],through:[0,2,3,4,8,9,12],throughout:1,thrown:1,thu:7,time:[1,2,7,8,9,12],tip:[8,12],todai:1,togeth:[2,5,7,8,12,14],toler:14,tomorrow:12,too:[1,2,7,9,12,14],tool:[1,2,3,5,7,8],toolbox:3,topic:[0,1,2,7,8,11,12,13],total:14,toward:[1,9],tradit:1,train:[0,1,2,3,4,5,8,9],traine:1,trainer:[1,3,13],transfer:3,transit:4,transmiss:1,travel:[3,4],tree:1,tri:[3,8],trial:[11,12],trick:[1,14],turn:12,tutori:[1,13],tv:14,twenti:1,twist:1,twitch:[5,14],two:[0,1,2,3,12,14],twofold:8,type:[1,2,8,12],typic:[3,5,8,11,14],typo:1,unclear:1,under:[2,4,9,13,14],understand:[0,1,2,3,8,12],unfamiliar:12,unfinish:9,uniqu:2,unit:2,univers:[2,3,14],unix:8,unnecessari:12,until:[3,12],up:[1,2,3,5,8,11,12,13,14],updat:14,us:[0,1,3,4,5,7,8,9,11,12,13,14],usag:3,usual:[1,2,3,4,8,14],valid:[2,9],valu:1,vancouv:2,vanderbilt:2,variou:[0,8,12],ve:[1,7,9,14],verbal:11,veri:[1,2,3,8,9,12,14],verif:14,verifi:[2,14],version:[3,5,7,9],vertic:12,via:[5,8,14],video:[0,2,5,11,14],view:14,viewer:14,virtualenv:1,visibl:5,vision:7,voic:14,volum:13,vs:2,wa:[1,2,3,5,8,11,14],wai:[1,4,5,7,8,12,14],want:[1,2,4,5,7,8,11,12,14],war:1,warn:12,watch:[0,1,2,11,12,14],we:[0,1,2,3,4,5,7,8,9,11,12,14],weather:2,webpag:14,week:[1,14],weekli:5,weird:12,welcom:7,well:[1,2,5,13,14],wen:14,went:14,were:[4,7,14],weren:1,whallei:13,what:[0,1,3,7,8,9,11,14],whatev:12,whelm:14,when:[1,2,8,12,14],whenev:[1,3],where:[1,2,5,8,12],whether:[1,2,11],which:[0,1,2,4,7,8,11,12,13,14],whiteboard:2,who:[1,3,5,8,14],whole:[8,9,12,14],why:[1,2,7,9,13,14],wider:1,wiggin:2,willing:[1,3],window:12,wip:9,wire:1,wish:3,within:[2,3],without:[2,4],won:[2,8],wonder:1,word:[1,2,8],work:[1,4,7,8,9,11,12,14],workflow:3,workshop:[1,2,3,7,8,9,11,12],world:[1,2],worldwid:3,worri:[0,1,12],wors:12,worthwhil:1,would:[1,2,3,5,7,8,11],write:[1,3,8,11],written:14,wrong:2,www:1,x:[1,8],ye:8,year:[1,2,3,8],yet:[2,3,4,8],you:[1,2,4,5,7,9,11,12,13,14],young:8,your:[0,1,2,5,7,8,9,11,12],yourself:[1,12],youtub:1,zoom:[12,13],zulipchat:5},titles:["Pre-workshop preparation","CodeRefinery teaching philosophies","Interactive teaching style","About the CodeRefinery project","Organize a CodeRefinery workshop","Future","Instructor\u2019s guide","Community teaching training","Lesson design","Collaborative lesson development","Quick Reference","Teaching practice and feedback","How to teach online","Welcome and introduction","Running a workshop: online"],titleterms:{"1":[0,11],"10":2,"2":11,"20":1,"bj\u00f8rn":1,"case":14,"do":[8,13],"import":2,"jo\u00e3o":1,"new":[2,9],"static":9,On:2,The:[2,8],about:3,activ:5,also:[7,12],ann:1,approach:[2,8],ar:2,arrang:14,assess:2,audienc:3,backward:8,basic:14,bast:1,befor:0,best:3,biggest:5,bloom:2,breaker:1,breakout:14,bring:14,ca:0,carpentri:[0,2,3],central:4,certif:5,code:[11,13],coderefineri:[1,2,3,4,5,14],cognit:2,collabor:[5,9,14],commun:7,compet:[2,3],conduct:13,confid:13,contribut:9,cours:7,creat:9,curriculum:2,da:1,darst:1,demo:[8,11],demonstr:12,design:[2,8],develop:[2,9],differ:13,discuss:[8,9,11,12,14],don:0,effect:2,engin:5,exampl:[8,11],exercis:[2,8,11],exist:9,expert:2,face:2,feedback:[2,11],finland:14,form:2,fouilloux:1,futur:5,gener:14,get:[2,5,13],give:[2,13],goal:[3,8,13],goe:12,good:[8,12],group:1,guid:6,hackmd:[12,14],have:[0,8],helper:14,here:8,histori:3,hour:0,how:[2,5,8,12],hpc:[2,14],ic:1,identifi:2,impact:3,independ:4,instal:14,instruct:2,instructor:[0,2,5,6,11,13],interact:2,introduct:13,invit:4,involv:5,issu:2,juho:1,kei:2,kickstart:14,knowledg:2,learn:[2,9],learner:2,lehtonen:1,lesson:[8,9,13],lindi:1,link:14,live:11,local:4,m:1,main:[3,11],manual:14,materi:[2,9],matter:12,mechan:12,mega:14,membership:3,mental:2,meta:12,minut:1,mn:2,model:2,negru:1,nordic:5,note:14,novic:[2,3],object:[2,12],old:7,onlin:[12,14],open:5,option:[2,11],organ:4,other:14,out:13,overview:13,own:14,part:11,person:14,philosophi:1,platform:14,practic:[3,8,11,12],practition:[2,3],pre:0,prepar:[0,14],prerequisit:7,principl:2,problem:5,process:8,profil:2,progress:2,project:3,prototyp:12,provid:8,question:12,quick:10,radovan:1,razick:1,read:8,recommend:[2,8,9],record:[1,14],refer:[7,10],remark:0,research:5,revers:2,revisit:2,richard:1,role:14,room:[11,14],rse:5,run:14,s:[2,6],sabri:1,scale:14,screen:12,see:[7,12],share:12,shell:12,silva:1,site:9,softwar:[3,5],solut:2,staff:14,stefan:1,strategi:14,stream:14,studi:14,style:2,summ:2,t:0,take:0,talk:12,target:3,taxonomi:2,teach:[1,2,7,9,11,12,14],team:14,templat:9,thi:[2,5,13],thor:1,time:14,toc:7,tool:13,top:2,train:[7,13,14],two:11,typic:13,us:2,video:1,vs:14,wai:2,want:13,we:13,welcom:13,what:[2,5,12,13],who:[2,7],whom:3,why:[8,12],wikfeldt:1,work:2,workshop:[0,4,5,13,14],write:2,you:[0,8],your:14,zoom:14}}) \ No newline at end of file diff --git a/branch/main/teaching-practice/index.html b/branch/main/teaching-practice/index.html new file mode 100644 index 00000000..911e636f --- /dev/null +++ b/branch/main/teaching-practice/index.html @@ -0,0 +1,225 @@ + + + + + + Teaching practice and feedback — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Teaching practice and feedback

+

Goals of the teaching practice:

+
    +
  • In groups of 4-5 persons we will practice teaching a 5-minute segment +of a lesson of your choice.

  • +
  • The section you pick should require screen sharing and be of some +demonstration or follow-along task (preferably using a shell) to also +practice having a good screen-sharing setup.

  • +
  • We will practice giving constructive feedback.

  • +
  • We will practice improving our 5-minute segment by taking the feedback into account.

  • +
  • In both session you can teach the same topic/segment but if you prefer you can also +change the topic/aspect for the second session.

  • +
+
+
+

Instructor demo

+
    +
  • In order to demonstrate the goals of this section, the instructor +will make a 5-minute demo for your evaluation.

  • +
  • It is designed to include some good and bad practices for you to +notice.

  • +
+
+
+
+

Teaching demos part 1

+

In group rooms, 50 minutes.

+
+

Exercise

+
    +
  • We organize the breakout rooms to not only discuss one lesson/topic so that it is more interesting +to listen and also probably we will all get more useful feedback.

  • +
  • Give each other constructive verbal feedback on the teaching demos, for example +using this demo rubric.

  • +
  • Write down questions (in the collaborative document) that you would like to +discuss in the main room or interesting conclusions which you would like to +share with others.

  • +
+
+
+
+

Teaching demos, part 2

+

In group rooms, 50 minutes.

+
+

Exercise

+
    +
  • In the second round we distribute the rooms differently so that you can +present it to a new group of workshop participants and can receive new +feedback.

  • +
  • Ask for feedback and one/few point(s) you want to improve.

  • +
  • In your second trial check whether you feel the demonstration improved.

  • +
  • Share your lessons learned in the collaborative document.

  • +
  • Give us also feedback on this exercise format. Was it useful? What can we improve?

  • +
+
+
+
+
+

Discussion

+
+

Main room discussion

+
    +
  • We discuss questions and conclusions which came up during the group work session.

  • +
+
+
+
+
+

Optional: feedback for two live-coding examples

+
+

Exercise

+

Teaching by live coding is a +performance art which requires practice. +This exercise highlights some typical pitfalls that most instructors +fall into sooner or later, and also shows how to avoid them. +Watch closely since we will be giving feedback!

+
    +
  • Watch these two videos: video 1 and +video 2

  • +
  • What was better in video 1 and what was better in video 2?

  • +
  • Please give feedback in the shared workshop document.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/teaching-strategies/index.html b/branch/main/teaching-strategies/index.html new file mode 100644 index 00000000..bb67e63e --- /dev/null +++ b/branch/main/teaching-strategies/index.html @@ -0,0 +1,373 @@ + + + + + + How to teach online — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

How to teach online

+
+

Objectives

+
    +
  • Understand the benefits and disadvantage of online teaching, +compared to in-person

  • +
  • Set up a good screen share

  • +
  • Understand the benefits and disadvantages of team teaching

  • +
  • Prepare for the teaching practice

  • +
+
+
+

Why teaching mechanics matter

+
    +
  • When you teach, you are mainly showing a basic example for the +learner to follow along

  • +
  • The learner has a lot more to think about than you do, so you need +to minimize the possible distractions and unnecessary weirdness.

  • +
  • A learner will often only one small screen, limiting the number of +things that they can think about.

  • +
  • You are must faster than learners (5 times possibly?) You have to +do things to slow yourself down.

  • +
  • It’s easy to save these mechanics until the end, and then you run +out of time.

  • +
+
+
+

Shell sharing

+ +

When doing any demonstration, there are difficulties:

+
    +
  • If one misses something, you can’t rewind to see it - is there any +way to catch up?

  • +
  • The learner must get oriented with the whole picture, while +instructor knows precisely where to focus.

  • +
+

A good shell share has some of the following properties:

+
    +
  • Large font

  • +
  • Shell history, available separately from the main shell window

  • +
  • Closely matches the type-along instructions

  • +
+

We have a collection of shell sharing systems:

+ +
+

Discussion

+

The instructor will demonstrate several shell-sharing systems. You +will use this in the teaching practice.

+
+
+
+

Screen sharing

+
+

Discussion

+

Look at the various screen layouts in the CodeRefinery +manuals. +Use the HackMD to comment about what which are better or worse.

+ +
+
    +
  • Many learners will have a smaller screen than you.

  • +
  • You should plan for learners with only one small screen.

  • +
  • A learner will need to focus on both your screen share and their +work.

  • +
  • Sharing your a whole screen is almost always a bad idea, if you want +the learners to do anything at the same time.

  • +
  • If you constrict yourself, then your experience is more similar to +that of a learner.

  • +
+

Vertical sharing:

+
    +
  • CodeRefinery has recently started trialing a vertical share +system, where you share a vertical half of your screen.

  • +
  • This allows learners with one screen to display your screen +side-by-side with their learn

  • +
  • Zoom provides a “Share a part of screen” that is good for this.

  • +
+
+
+

Meta-talk

+

Don’t just teach, also make sure you guide the learners through the +course.

+
    +
  • You know what you just discussed, and what is coming next, but +learners are often stuck thinking about now.

  • +
  • Give a lot of “meta-talk” that is not just about the topic you are +teaching, but how you are teaching it.

  • +
  • Examples

    +
      +
    • Why you are doing each episode

    • +
    • What is the purpose of each exercise

    • +
    • Clearly state what someone should accomplish in each exercise and +how long it will take - don’t assume this is obvious.

    • +
    • What is the point of each lesson. How much should people expect +to get from it? Should you follow everything, or are some things +advanced and optional? Make that clear.

    • +
    +
  • +
+
+
+

Teach teaching

+
    +
  • Demonstration-based teaching require two different types of focus:

    +
      +
    • Doing the mechanical steps as a demonstration

    • +
    • Explaining why you are doing it

    • +
    +
  • +
  • This is a lot for one person to keep in mind, so can multiple people +work together for this?

  • +
  • Team teaching idea:

    +
      +
    • One person is doing the demonstrations

    • +
    • One person is giving the commentary about what they are doing

    • +
    • The lecture becomes a discussion between two people instead.

    • +
    +
  • +
+

Advantages:

+
    +
  • This reduces the pressure on each person (reduces demo effect)

  • +
  • You are less likely to forget things

  • +
  • It slows you down in teaching

  • +
  • It makes the lesson more interesting to listen to

  • +
  • One person can follow questions

  • +
  • Great for introducing new instructors (which half is easier to start +with?)

  • +
+

Disadvantage:

+
    +
  • Requires two people’s time

  • +
  • Requires coordination when preparing (slows you down in preparation)

  • +
  • Unfamiliar concept to most people

  • +
+
+
+

Questions

+
    +
  • Questions are great, and important for any practical and interactive +class

  • +
  • But questions in main room doesn’t scale to very large rooms.

  • +
  • CodeRefinery strategy: HackMD for questions

    +
      +
    • Chat is not good enough, you can’t reply to old things

    • +
    • HackMD allows threaded replies and follow up later

    • +
    • You need some other helpers to watch HackMD and answer, and bring +things up to you. And let you know how things are going.

    • +
    • Learners can ask anonymously

    • +
    • Learners don’t have to worry about interrupting the flow.

    • +
    • Disadvantage: can produce information overload, warn people to not +follow too closely

    • +
    • With too few people, it can turn out to be very quiet.

    • +
    +
  • +
  • We will learn more about HackMD questions tomorrow in +Running a workshop: online.

  • +
+
+

See also

+ +
+
+
+

Teaching practice

+

In Teaching practice and feedback, you will break into groups and try to +apply these strategies to a five-minute example session.

+
+
+

See also

+

In this lesson:

+ +

CodeRefinery manuals:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/welcome/index.html b/branch/main/welcome/index.html new file mode 100644 index 00000000..bcdecea5 --- /dev/null +++ b/branch/main/welcome/index.html @@ -0,0 +1,248 @@ + + + + + + Welcome and introduction — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Welcome and introduction

+
+

What do we want to get out of this workshop

+
    +
  • Introduction of instructors and helpers

  • +
  • Each instructor can say what we want to get out of the instructor training

  • +
  • But we want to know from everybody and collect these in the live notes

  • +
+
+
+
+

Goals for this workshop

+
+

Goals for this instructor training

+
    +
  • Give future instructors the tools and confidence to teach best software practices and tools.

  • +
  • Motivate new instructors to take up lessons, remix them, and to contribute.

  • +
  • Get feedback to improve the material as well as our collaboration model.

  • +
  • For us to learn how we can support related efforts and collaborate.

  • +
  • Catalyze and form new networks and collaborations of teachers and trainers of +practical scientific computing.

  • +
+
+
+

Giving confidence

+
+

Goal number one should be that we give participants the confidence to +independently apply the tools or knowledge learnt. This is more important +that giving a “complete” overview. [Lucy Whalley gave this great comment at one of our workshops]

+
+
    +
  • You don’t have to know everything to use (or teach) something.

  • +
  • For the large majority of topics we teach, there are many resources online +which provide how-to guides or tutorials. And the Stack Overflow answer bank +isn’t getting any smaller. So we need to ask why do people attend in-person +sessions if there is information freely available? Our impression is that +it is for confidence building, identity formation, perhaps signposting to +resources.

  • +
  • This also links with building a welcoming/inclusive environment: for example, +imposter syndrome, which disproportionately affects under-represented groups +(link), +can manifest as low self-confidence –> building the confidence of +students in the classroom may lead to a more diverse community.

  • +
+
+
+
+
+

Tools for this workshop

+

We always start workshops with these:

+ +
+
+
+

Code of Conduct

+
    +
  • We follow The Carpentries Code of Conduct.

  • +
  • This is a hands-on, interactive workshop.

    +
      +
    • Be kind to each other and help each other as best you can.

    • +
    • If you can’t help someone or there is some problem, let someone know.

    • +
    • If you notice something that prevents you from learning as well as you can, let us know and don’t suffer silently.

    • +
    +
  • +
  • It’s also about the little things:

    +
      +
    • volume

    • +
    • font size

    • +
    • generally confusing instructor

    • +
    • not enough breaks

    • +
    +
  • +
+
+
+
+

Overview of the lessons and a typical workshop

+

Here the instructor gives an overview of the lessons and a typical workshop.

+
+
+

What we do differently?

+
    +
  • Planing, teaching material available in advance and not PDF slides

  • +
  • Different roles (instructor, host, hackmd, …)

  • +
  • GitHub projects board so all boxes are checked

  • +
  • Helper recruitment and breakout room planning

    +
      +
    • Designing for this as soon as you open registration

    • +
    +
  • +
  • Less is more

  • +
  • Welcome session and “outro” session

  • +
  • Clearly defining learning outcomes

  • +
  • Asking for feedback, encouraging feedback

  • +
  • Manual

  • +
  • Screen-sharing

  • +
  • Using lesson templates

  • +
  • Lesson review on GitHub

  • +
  • Sharing material instead of being protective

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/workshops-online/index.html b/branch/main/workshops-online/index.html new file mode 100644 index 00000000..12397869 --- /dev/null +++ b/branch/main/workshops-online/index.html @@ -0,0 +1,451 @@ + + + + + + Running a workshop: online — CodeRefinery instructor training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop manuals

+

CodeRefinery maintains a number of workshop manuals +with most of the “primary” information. This episode condenses this +into a quick overview.

+
+
+

Running a workshop: online

+
+

Online teaching discussion

+
+

Discussion: Online vs in-person

+

In notes:

+
    +
  • Compare and contrast the benefits of online teaching with +in-person: {advantage, disadvantage} × {content, presentation}

  • +
  • How do you have to prepare differently?

  • +
  • What are your own experiences?

  • +
+
+
+
+

Case study: Mega-CodeRefinery and Finland HPC Kickstart

+
    +
  • Mega-CodeRefinery

    +
      +
    • Audience of around 90-100

    • +
    • “bring your own breakout room” (see below)

    • +
    • 3 days/week, 6 days total

    • +
    • Lessons as normal in CodeRefinery

    • +
    +
  • +
  • HPC Kickstart

    +
      +
    • 250 registered, ~180 max participants

    • +
    • Multi-university: local differences made this much harder to manage.

    • +
    • Breakout rooms not pre-planned.

    • +
    +
  • +
+

Mega-CodeRefinery worked very well, HPC kickstart didn’t - but not +because of the size.

+
+
+

General workshop arrangements

+ +
    +
  • Select a coordinator, recruit instructors (at least 3 is important), +find helpers

  • +
  • Find a good lecture room: +requirements

  • +
  • Set up workshop webpage using the [Github, template +repository](https://github.com/coderefinery/template-workshop-webpage]: +see +manuals

  • +
  • Advertising the workshop

  • +
  • Communication with registered participants

  • +
+
+
+

CodeRefinery online scaling strategy

+
    +
  • We started online workshops in 2020 March, for the obvious reasons.

  • +
  • First, we started with two “normal size” (20 people) practice +workshops

  • +
  • Then we did a 100 person workshop. It went well, but there is less +tolerance for problems.

  • +
+
+

Basic preparation

+
    +
  • You need more breaks are needed

  • +
  • People have a way of doing too many things and not focusing.

  • +
  • How to attend an online +workshop” +guide to prepare learners

  • +
+
+
+

Basic platform: Zoom

+
    +
  • Zoom (not the most ethical, but worked well and was available)

  • +
  • Zoom mechanics: instructions for +students.

    +
      +
    • Mostly things that are known

    • +
    • We don’t use Zoom interaction features much anymore +(faster/slower/etc), but breakout rooms and HackMD instead

    • +
    +
  • +
  • See also: Online training +manual +(which is getting a bit old compared to what is below).

  • +
+
+
+

Breakout rooms, bring your own team

+
    +
  • Breakout rooms are

    +
      +
    • Static: same people across whole workshop

    • +
    • Contain one helper per room (see below)

    • +
    +
  • +
  • Team registration: accept a “team” field when registering, people on the +same team are put together.

    +
      +
    • Gives motivations for learners to bring their colleagues and +learn together.

    • +
    • More than one person learning together greatly increases update

    • +
    +
  • +
  • You need a powerful enough registration system to assign rooms and +email them to people!

  • +
  • We ask people to name themselves “(N) Firstname Lastname” or “(N,H) +Firstname Lastname” for helpers. Then it is fast to assign them to +their designated breakout rooms.

  • +
  • See also: Breakout room +mechanics

  • +
+
+
+

Helper training

+
    +
  • Each breakout room has a helper

  • +
  • Helper should be a little bit familiar, but not expected to be able +to answer all questions.

  • +
  • Special, custom helper +training +since helpers make or break the workshop

  • +
  • Helper recruitment:

    +
      +
    • Our networks

    • +
    • Team registration: if a team registers with their own helper, then +they are guaranteed to get in together. “bring your own breakout +room”

    • +
    • Former learners, ask them to come back.

    • +
    +
  • +
  • Two helper trainings the week before the workshop.

  • +
+
+
+

Staff roles

+

To reduce stress on any one person, we clearly define the different +roles and try to avoid overlap. We actually have enough people for +all of these, so it works well.

+
    +
  • Workshop coordinator

    +
      +
    • Registration, etc.

    • +
    +
  • +
  • Zoom host

    +
      +
    • Handles registration, breakout rooms, recording, Zoom chat.

    • +
    +
  • +
  • HackMD helper

    +
      +
    • Dedicated to watching HackMD and answering questions quickly.

    • +
    • Host on manuals

    • +
    +
  • +
  • Expert helpers

    +
      +
    • “Spare hands” who rotate between breakout rooms and make sure +helpers are doing well.

    • +
    • Give feedback to instructor about how breakout rooms are going.

    • +
    • Take the place of missing helpers.

    • +
    • Easy way for any people with a bit of spare time to help out.

    • +
    • Expert helpers in workshop

    • +
    +
  • +
  • Instructors

    +
      +
    • Teach, they shouldn’t overlap with the above roles (but serve as +expert helpers other times).

    • +
    • Usually also improve the lesson a bit before teaching

    • +
    • General staff intro in manuals

    • +
    +
  • +
  • Workshop preparation meeting

    + +
  • +
+
+
+

HackMD

+
    +
  • We’ve been using it here

  • +
  • Chat doesn’t work wen large, written +document does.

  • +
  • HackMD can just about scale to ~100 person workshop. Recommend +learners keep it in view mode while not editing.

  • +
  • Voice questions are still allowed, but will be recorded. Staff +raise important questions from HackMD to the instructor immediately.

  • +
  • HackMD also allows communication when in breakout rooms.

  • +
  • You can get multiple answers, and answers can be improved over +time.

  • +
  • HackMD +mechanics +and HackMD +helpers.

  • +
+
+
+

Recording and streaming

+
    +
  • When you have 100 people, main room is quiet anyway: you don’t lose +much by recording.

    +
      +
    • Questions anonymously in HackMD, privacy loss is not so bad

    • +
    +
  • +
  • Breakout rooms are never recorded

  • +
  • Streaming

    +
      +
    • We streamed via Twitch: https://twitch.tv/coderefinery

    • +
    • We typically get 5-40 viewers.

    • +
    • Zoom can directly send the stream to Twitch: no extra software +needed.

    • +
    • Twitch archives videos for 14 days, which allows learners to get +an instant reply (we get hundreds of views in the next days).

    • +
    • So while possibly not useful for new people to learn, the instant +reply is very useful. Instructor can also work on problems in +main stream during breakout rooms, which learners can watch +later.

    • +
    • Streamers also have access to HackMD to ask questions.

    • +
    +
  • +
  • Certain tricks needed to keep learners from appearing in recording +or stream

    +
      +
    • “Spotlight video”, host does not go to gallery view, uses dual +monitor mode. We are still figuring this out.

    • +
    +
  • +
+
+
+

Installation time

+
    +
  • People have to be ready once we start, or else everything fails.

  • +
  • Two installation help times the week before.

  • +
  • Every email emphasizes that you have to be prepared, and “requires” +you to attend workshops (but really it’s only)

  • +
  • Installation instructions include steps to verify

  • +
  • Installation instructions also include video demonstrations of +installation and verification.

  • +
  • We haven’t had that many installation problems, but also we keep the +requirements simple.

  • +
  • Helper introduction is right before software install time, so +helpers can stay and help with install if they want.

  • +
  • Design to be easy to install and get set up.

  • +
+
+
+

Other notes

+
    +
  • Make breakout sessions as long as possible: 10 minutes is really too +short. 20 minutes is a good minimum time.

  • +
  • Be very clear about exercise expectations

  • +
  • Keep HackMD updated as a log.

  • +
  • Don’t combine breaks and breakout times.

  • +
  • The more people you have, the more diverse audience you have and the +more people overwhelmed and under whelmed.

  • +
+
+
+
+

Workshop collaborations

+

Why limit ourselves to CodeRefinery workshop? Why not use our network +and techniquess for more

+
    +
  • Case study: Python for Scientific +Computing

    +
      +
    • Started by Aalto

    • +
    • Announced to CodeRefinery, five more instructors from three +countries joined.

    • +
    • Rapid collaboration, taught course shortly later.

    • +
    • Announced to all institutions. Some places had physical rooms, +some were pure online

    • +
    • Also streamed

    • +
    • It was much more fun and less stressful to work together

    • +
    +
  • +
  • We want to continue this kind of collaboration in other workshops.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/collaboration-models/index.html b/collaboration-models/index.html new file mode 100644 index 00000000..0a71acc9 --- /dev/null +++ b/collaboration-models/index.html @@ -0,0 +1,251 @@ + + + + + + + Collaboration models — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Collaboration models

+
+

Model: CodeRefinery

+
    +
  • Before Covid-19, workshops were physically around the Nordics, +instructors would travel (or already be there).

    +
      +
    • Maximum size: ~40 people

    • +
    • High workload per person

    • +
    +
  • +
  • After several small scaling attempts, now we have:

    +
      +
    • Two large workshops per year - livestream format

    • +
    • Combined organization efforts

    • +
    • Instructors from each location - on average two lessons taught.

    • +
    • Locations with staff can have local breakout rooms: physical +place to help during exercises.

    • +
    +
  • +
  • Others in the world can register and interact using HackMD, but no +promises of help.

  • +
  • Content still available to anyone in the world: live + instant +replay.

  • +
  • Course page and material: +https://coderefinery.github.io/2022-03-22-workshop/

  • +
+
+
+

Model: Python for Scientific Computing

+
    +
  • Aalto Scientific Computing wanted to host a course, Python for +Scientific Computing

  • +
  • ASC came up with initial vision and announced it

  • +
  • ASC hosted an open initial meeting, inviting any interested +organizers or instructors

  • +
  • We went over the plan and refined the topics and schedule. We also +decided things such as the date, organizers, and instructors for +each lesson.

  • +
  • Registration was open to everyone in the world, non-Nordic +participants could watch via livestream.

  • +
  • People prepared their parts and came together and presented. +Organizers kept everything on track.

  • +
  • Compared to the amount of effort each person put in, the results +were great.

  • +
  • A 2021 version also happened and was even larger.

  • +
  • Course page: https://scicomp.aalto.fi/training/scip/python-for-scicomp/

  • +
  • Material: https://aaltoscicomp.github.io/python-for-scicomp/

  • +
+
+
+

Exercises

+
+

List successes and failures in collaborative teaching

+

Using HackMD, list some successes and failures in collaborative +teaching that you have experienced.

+
+
+

Recommendations for co-teaching

+

If you have experience with co-teaching, what approach/technique/trick +can you recommend a colleague who would like to try co-teaching for the +first time?

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/distributed/index.html b/distributed/index.html new file mode 100644 index 00000000..c4487616 --- /dev/null +++ b/distributed/index.html @@ -0,0 +1,220 @@ + + + + + + + Distributed workshop organization — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Distributed workshop organization

+
+

Keypoints

+
    +
  • If another university/organization wants to run the course, they can easily join our existing course at little cost/risk to them and to us.

  • +
  • Each organization that joins provides a great benefit to us (helpers, instructors).

  • +
  • They can reserve an in-person breakout room and provide mentors while watching the livestream: A great experience for their audience.

  • +
+
+
+

It is easier to join and follow than to start or lead

+

Organizing a course is time intensive and so is developing a course. Many +courses given in country A are also relevant in other countries and instead of +developing and possibly re-inventing courses independently in different places, +it is so much more rewarding to collaborate and share.

+

In our courses we wish and try to make it easier for teams and organizations +and universities to join, at little risk and cost to them, possibly for a short +period of time, possibly only as observer. Later observers can progress to +exercise leads, expert helpers, instructors, and co-organizers.

+

One model that we have successfully tried is that the course is delivered via +live-stream to all partners and all the partner needs to do is to reserve a +room and motivate few people to help local learners as exercise leads during +exercise sessions which can happen in-person.

+
+

Lessons learned from organizing larger workshops

+
    +
  • One person is needed to coordinate the registration process and this person should +not have teaching duties in addition to this role.

  • +
  • Generally it helps to have well-defined roles (see Workshop roles).

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/diversity-and-inclusion/index.html b/diversity-and-inclusion/index.html new file mode 100644 index 00000000..e3936330 --- /dev/null +++ b/diversity-and-inclusion/index.html @@ -0,0 +1,232 @@ + + + + + + + Diversity and inclusion — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Diversity and inclusion

+

When we are teaching, we fill a critical role in between people and +technology. We are not un-involved technical staff teaching asocial +topics, but we are very connected to the social context of the tools. +Unfortunately, there are major demographic imbalances in most +computing.

+
+

Primary articles

+ +
+
+

Support services vs diversity

+

Study this presentation by Richard Darst:

+ +

Summary:

+
    +
  • Computing is hard and quite often our ability to learn quickly is +connected to our social group.

  • +
  • Good technical services serve the role of mentors

  • +
  • This mentorship helps to equalize

  • +
  • Our entire system of research should be configured for more +equality. Modernization usually takes it the other way.

  • +
+
+
+

Exercises

+
+

Reflect on how your job can be defined to promote diversity.

+

What are some (possibly surprising) ways that your job promote +diversity and equality among people of different backgrounds?

+
+
+
+

See also

+

(none yet)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/exercises/index.html b/exercises/index.html new file mode 100644 index 00000000..ef09a22b --- /dev/null +++ b/exercises/index.html @@ -0,0 +1,947 @@ + + + + + + + Exercise list — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Exercise list

+

This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests.

+
+

Teaching online

+

In teaching-online.md:

+
+

Exercise

+

Using HackMD, brainstorm advantages and disadvantages of online and +in-person teaching. For each disadvantage of each, think of ways to compensate.

+
+
+
+

Team teaching

+

In team-teaching.rst:

+
+

Exercise

+

Divide into groups of two or three. Choose one of the two models +in the team-teaching page, and quickly (5 min) prepare a short +topic (3-5 min) to team teach. You can quickly scan the +“preparation” section at the bottom.

+

The challenge is not just to give the lesson, but to prepare the +lesson quickly and rely on each other to give a good lesson anyway.

+
+
+
+

HackMD

+

In hackmd.rst:

+
+

Exercise

+
    +
  • Actively use HackMD during this course.

  • +
  • Observe how the instructors integrate it during the course +itself, and can immediately respond to the questions.

  • +
  • Observe how instructors occasionally mention and screenshare +HackMD to validate to the audience that it is being watched.

  • +
  • Keep HackMD open. Can you balance it and watching. Does it +increase or decrease engagement?

  • +
+
+
+
+

Teams

+

In teams.rst:

+
+

Teams

+

Consider these questions:

+
    +
  • Should teams have similar or different people in them?

  • +
+
+
+
+

Livestreaming

+

In livestreaming.rst:

+
+

(advanced) Set up and install OBS as a livestreaming tool.

+

This exercise is open-ended.

+
+
+
+

Instructor tech setup

+

In instructor-tech-setup.md:

+
+

Evaluate screen captures

+

Evaluate screenshots within the instructor tech +setup lesson. +Use the collaborative document to make a list of the trade-offs of each one. +Which one do you prefer? Which are useful in each situation?

+
+

In instructor-tech-setup.md:

+
+

Set up your own environment

+

Set up your screen to teach something. Get some feedback from +another learner. We will discuss among the class.

+
+
+
+

Video editing

+

In video-editing.rst:

+
+

Editing-1: Get your sample video

+

Download a sample video:

+
+
+
+

In video-editing.rst:

+
+

Editing-2: Run Whisper to generate raw subtitles and test video.

+

First off, install Whisper and generate the base subtitles, based +on the. Since this is probably too much to expect for a short +lesson, they are provided for you (above), but if you want you can +try using Whisper, or generating the subtitles some other way.

+

You can start generating subtitles now, while you do the next +steps, so that they are ready by the time you are ready to apply +the editlist. ffmpeg-editlist can also slice up the subtitles from +the main video to make subtitles for each segment you cut out.

+

Whisper is left as an exercise to the reader.

+ +
+

In video-editing.rst:

+
+

Editing-3: Create the basic editlist.yaml file

+

Install ffmpeg-editlist and try to +follow its instructions, to create an edit with these features:

+
    +
  • The input definition.

  • +
  • Two output sections: the “Intro to the course”, and “From data +storage to your science” talks (Remember it said the recording +started at 11:35… look at the schedule for hints on when it +might start!). This should have a start/end timestamp from the +original video.

  • +
+

A basic example:

+
- input: day1-raw.mkv
+
+# This is the output from one section.  Your result should have two of these sections.
+- output: part1.mkv
+  title: something
+  description: >-
+    some long
+    description of the
+    segment
+  editlist:
+    - start: 10:00    # start timestamp of the section, in *original* video
+    - end: 20:00      # end timestamp of the section, in the *original* video
+
+
+ +
+

In video-editing.rst:

+
+

Editing-4: Run ffmpeg-editlist

+

Install ffmpeg-editlist: pip install ffmpeg-editlist[srt] (you +may want to use a virtual environment, but these are very minimal +dependencies).

+

The ffmpeg command line tool must be available in your +PATH.

+ +
+

In video-editing.rst:

+
+

Editing-5: Add more features

+
    +
  • Several chapter definitions.(re-run and you should see a +.info.txt file also generated). Video chapter definitions +are timestamps of the original video, that get translated to +timestamps of the output video.

    +
    - output: part1.mkv
    +  editlist:
    +  - start: 10:00
    +  - -: Introduction    #  <-- New, `-` means "at start time"
    +  - 10:45: Part 1      #  <-- New
    +  - 15:00: Part 2      #  <-- New
    +  - end: 20:00
    +
    +
    +

    Look at the .info.txt files that come out now. What is new in it?

    +
  • +
  • Add in “workshop title”, “workshop description”, and see the +.info.txt files that come out now. This is ready for +copy-pasting into a YouTube description (first line is the title, +rest is the description).

    +

    Look at the new .info.txt files. What is new?

    +
  • +
+ +
+

In video-editing.rst:

+
+

Editing-6: Subtitles

+

Re-run ffmpeg-editlist with the --srt option (you have to +install it with pip install ffmpeg-editlist[srt] to pull in the +necessary dependency). Notice how .srt files come out now.

+

Use some subtitle editor to edit the original subtitle file, to +fix up any transcription mistakes you may find. You could edit +directly, use subtitle-editor on Linux, or find some other +tool.

+

What do you learn from editing the subtitles?

+ +
+

In video-editing.rst:

+
+

Editing-6: Subtitles

+

Re-run ffmpeg-editlist with the --srt option (you have to +install it with pip install ffmpeg-editlist[srt] to pull in the +necessary dependency). Notice how .srt files come out now.

+

Use some subtitle editor to edit the original subtitle file, to +fix up any transcription mistakes you may find. You could edit +directly, use subtitle-editor on Linux, or find some other +tool.

+

What do you learn from editing the subtitles?

+
+

In video-editing.rst:

+
+

Editing-7: Generate the final output file.

+
    +
  • Run ffmpeg-editlist with the --reencode option: this +re-encodes the video and makes sure that there is no black point +at the start.

  • +
  • If you re-run with --check, it won’t output a new video file, +but it will re-output the .info.txt and .srt files. +This is useful when you adjust descriptions or chapters.

  • +
+
+

In video-editing.rst:

+
+

Use ffmpeg-editlist to edit this sample video

+

Prerequisites: ffmpeg must be installed on your computer +outside of Python. Be able to install ffmpeg-editlist. This is +simple in a Python virtual environment, but if not the only +dependency is PyYAML.

+ +
+

In video-editing.rst:

+ +
+
+

Why teach together?

+

In why-teach-together.rst:

+
+

What similarities do we have?

+

Using HackMD, make two lists:

+
    +
  • What courses do you think your local community would benefit +from, which you don’t currently have? +1 other people’s items +which are also relevant to you.

  • +
  • Which courses are you thinking of preparing for your local +community? +1 other people’s items which you would be +interested in helping out with.

  • +
+
+
+
+

Collaboration models

+

In collaboration-models.rst:

+
+

List successes and failures in collaborative teaching

+

Using HackMD, list some successes and failures in collaborative +teaching that you have experienced.

+
+

In collaboration-models.rst:

+
+

Recommendations for co-teaching

+

If you have experience with co-teaching, what approach/technique/trick +can you recommend a colleague who would like to try co-teaching for the +first time?

+
+
+
+

Workshop roles

+

In workshop-roles.rst:

+
+

How many people teach in your workshops?

+
    +
  • Using HackMD, make a histogram of how many (instructors + +organizers) you typically have in your workshops.

  • +
  • List some of the common roles you have used.

  • +
+
+
+
+

Why are computers hard?

+

In why-are-computers-hard.rst:

+
+

Exercise

+

Think of a tool or technology that is easy to understand and use if +you understand the underlying abstraction layers, but is almost +impossible otherwise.

+
+
+
+

Diversity and inclusion

+

In diversity-and-inclusion.rst:

+
+

Reflect on how your job can be defined to promote diversity.

+

What are some (possibly surprising) ways that your job promote +diversity and equality among people of different backgrounds?

+
+
+
+

Lesson development with version control

+

In lessons-with-version-control.md:

+
+

Contribute to a sample lesson

+
    +
  • Open this very lesson in GitHub (it uses the same format as +typical CodeRefinery lessons): +https://github.com/coderefinery/community-teaching/

  • +
  • Browse the files and understand the general idea. Check out at +least these and use HackMD to record their functions:

    +
      +
    • .github/workflows/sphinx.yml

    • +
    • content/conf.py

    • +
    • content/index.rst

    • +
    • content/lessons-with-version-control.rst

    • +
    +
  • +
  • If you want, try to make a pull request to this lesson. It +doesn’t have to have any significant content, it can be a pure +test pull request.

  • +
+
+

In lessons-with-version-control.md:

+
+

(advanced) Create your own lesson

+

Use the +sphinx-lesson-template +to create a new lesson of your choice. Alternatively, use the current +Carpentries system, or some other system of your choice.

+
+
+
+

Backwards lesson design

+

In backward-lesson-design.md:

+
+

Backwards-design a lesson/topic

+

Choose a simple lesson topic and apply backwards lesson design. You +won’t get all the way through, but come up with a logical +progression of exercises.

+

The section you pick should require screen sharing and be of some follow-along +task (preferably using a shell).

+

Some suggestions:

+
    +
  • Regular expressions

  • +
  • Making papers in LaTeX

  • +
  • Making figures in your favorite programming language

  • +
  • Linux shell basics

  • +
  • Something non-technical, such as painting a room

  • +
  • An instructor training for CodeRefinery

  • +
  • Some aspect from an already existing lesson

  • +
  • Introduction to high-performance computing (or an episode therein)

  • +
  • Unix shell in a HPC context (or an episode therein)

  • +
  • A lesson you always wanted to teach

  • +
+
+
+
+

CodeRefinery teaching philosophies

+

In 02-teaching-philosophies.md:

+
+

Ice-breaker in groups (20 minutes)

+
    +
  • Share your approach to teaching and your teaching philosophy with your group.

  • +
  • Please share your tricks and solutions in the live document for others.

  • +
+

Additional ice-breaker questions:

+
    +
  • What is your motivation for taking this training?

  • +
  • How structured or informal are your own teaching needs?

  • +
  • What difference do you notice between the teaching what we (also +Carpentries) do and traditional academic teaching?

  • +
  • What other skills need to be taught, but academic teaching isn’t the right setting?

  • +
+
+

In 02-teaching-philosophies.md:

+
+

Anne Fouilloux

+

I regularly teach Carpentries workshops so I try to apply what I have learnt to CodeRefinery workshops. However, I know our target audience is very much different and that I need to adapt my teaching style. I am still trying to find what works best in which situations and this is why I like so much CodeRefinery workshops. We usually have a wider range of skills and very mixed backgrounds so we usually have to be more careful with the pace and time given for exercises.

+

Some considerations:

+
    +
  • I spend quite a lot of time reading the CodeRefinery material and practising myself exercises. I particularly like to read the instructor notes just before teaching: they usually highlight important aspects both for preparing and teaching.

  • +
  • I usually do not show too much in advance the material as I think it prevents asking questions. If you have less competent practitioners in the classroom, they can easily copy-paste to avoid slowing down the entire classroom.

  • +
  • Ideally, I’d like to give several exercises so anyone can work at its own pace. I find it is important that everybody gets something different from the workshop.

  • +
  • I love breaks as it gives us an opportunity to discuss with attendees on their research topics. I am especially interested to understand what software they write and how they plan to use what they learn during our workshops.

  • +
+
+

In 02-teaching-philosophies.md:

+
+

Bjørn Lindi

+

My teaching style has changed a bit since I started with CodeRefinery. In the beginning I had this “BLOB” (Binary Large OBject) of knowledge and experience that I wanted to to convey to the participants. With experience and some help from the Carpentries Instructor training, I have realized I need to serialize the “BLOB”, to be able to share it with others.

+

In a similar fashion as you would do with a binary large object which you intend to send over the wire, you will need stop signals, check-sums and re-transmissions, when you give a lecture. I have come to appreciate the natural periods/breaks the lessons offers, the questions raised, the errors that appear during type-along and the re-transmission. Co-instructors are good to use for re-transmission or broadening a specific topic.

+

When I started with CodeRefinery my inclination was to give a lecture. Today I am trying to be a guide during a learning experience, a learning experience which includes me as well. That may sound a bit self-centric, but is in fact the opposite, as I have to be more sensitive to what is going on in the room. The more conscious I am of being a guide, the better lesson.

+

Tools that I find useful in preparing a lesson is concept maps and Learner Personas, though I have develop to few them.

+ +
+

In 02-teaching-philosophies.md:

+
+

Thor Wikfeldt

+

I never want to leave any learner behind and I really don’t like seeing confused, blank faces in the classroom. +At the same time I sometimes worry about some participants getting bored if a lesson is progressing slowly. +This is always a difficult compromise and something I struggle with!

+

I try to focus on making concepts intuitive, to “make sense” to the learners. Of course this is usually +based on how I learned the topic myself and how it makes sense to me.

+

I try to establish connections between topics: “this thing here is similar to what we saw in the previous +lesson where we learned about X…”.

+

Before mastering a lesson by teaching in many times I try to “follow the script”. After becoming very +familiar with a lesson I start to improvise more and react more dynamically to questions, e.g. by taking a +detour to explain a confusing topic more clearly.

+

What I think I do too often: copy-paste code/text from lesson material. This can leave learners behind - +typing out the code and describing it is slower, but more learning takes place. More advanced learners +will hopefully “be compensated” by interesting advanced exercises which follow.

+
+

In 02-teaching-philosophies.md:

+
+

Stefan Negru

+

A lesson is a conversation, it is useful if both the trainer and the trainee are engaged. +For that reason I try to have, most of the time, a conversation with the classroom and +after we finish parts of a lesson, step back and see how we might use what we learned.

+

That brings me to another point I follow throughout the lessons, answering questions like:

+
    +
  • How can we apply in practice what we just learned?

  • +
  • Do you see yourself (the trainee) using that in practice, why or why not?

  • +
+

Most of the times those seem like open-ended questions to the trainees that just learned +something new, so I try to find examples, most of the times from personal experience.

+

Last thing is that analogies are important when I teach, I try to find analogies in order +to simplify a convoluted part of a lesson.

+
+

In 02-teaching-philosophies.md:

+
+

Radovan Bast

+

My teaching changed by 180 degrees after taking the Carpentries instructor +training. Before that I used slides, 45 minute lecture blocks, and separate +exercise sessions. After the Carpentries instructor training I embraced the +interaction, exercises, demos, and typos.

+

My goal for a lesson is to spark curiosity to try things after the lesson, +both for the novices (“This looks like a useful tool, I want to try using it +after the workshop.”) and the more experienced participants (“Aha - I did not +know you could do this. I wonder whether I can make it work with X.”). I like +to start lessons with a question because this makes participants look up from +their browsers.

+

Keeping both the novices and the experts engaged during a lesson can be +difficult and offering additional exercises seems to be a good compromise.

+

For me it is a good sign if there are many questions. I like to encourage +questions by asking questions to the participants. But I also try not to go +into a rabbit hole when I get a question where only experts will appreciate +the answer.

+

I try to avoid jargon and “war stories” from the professional developers’ +perspective or the business world. Most researchers may not relate to them. +For examples I always try to use the research context. Avoid “customer”, +“production”, also a lot of Agile jargon is hard to relate to.

+

Less and clear is better than more and unclear. Simple examples are better +than complicated examples. Almost never I have felt or got the feedback that +something was too simple. I am repeating in my head to not use the words +“simply”, “just”, “easy”. If participants take home one or two points from +a lesson, that’s for me success.

+

I prepare for the lesson by reading the instructor guide and all issues and +open pull requests. I might not be able to solve issues, but I don’t want to +be surprised by known issues. I learn the material to a point where I know +precisely what comes next and am never surprised by the next episode or +slide. This allows me to skip and distill the essence and not read bullet +point by bullet point.

+

I try to never deviate from the script and if I do, be very explicit about +it.

+

A great exercise I can recommend is to watch a tutorial on a new programming +language/tool you have never used. It can feel very overwhelming and fast to +get all these new concepts and tools thrown at self. This can prepare me for +how a participant might feel.

+

I find it very helpful if there is somebody else in the room who helps me +detecting when I go too fast or become too confusing. I like when two +instructors complement each other during a lesson but when doing that to +others, I am often worried of interrupting their flow and timing too much.

+

A mistake I often do is to type too fast and in my mind I force myself +to slow down.

+
+

In 02-teaching-philosophies.md:

+
+

Sabry Razick

+

My approach is to show it is fun to demystify concepts. Once a concept is +not a mystery anymore, the learners will understand is what it means, where +it is coming from, why it is in place and what it could it offer for their future. +I try to relate concepts to real life with a twist of humour whenever possible if +the outcome is certain not be offensive to any one. I use diagrams whenever possible, +I have spent weeks creating diagrams that is sometime three or four sentences. That +effort I consider worthwhile as my intention is not to teach, but to demystify. +Once that is achieved, learners will learn the nitty gritty on their own easily +and with confidence, when they have the use-case.

+
+

In 02-teaching-philosophies.md:

+
+

Juho Lehtonen

+

I’m gradually realising the different ways to get a hint whether the workshop +participants are still following or perhaps bored. I assume it’s communicating +with the class, with exercises and simply by asking now and then. I also try +to remember to observe how people look like (puzzled, bored) while I teach, not +so obvious for me.

+

I believe that learners communicating with each other, in addition to with +instructors and helpers, really helps them to understand things faster. (At least +it helps me). So I try to make sure that no one sits or works alone at the workshops.

+
+

In 02-teaching-philosophies.md:

+
+

Richard Darst

+

Like many people, I’ve often been teaching, but rarely a teacher. I +tend to teach like I am doing an informal mentorship. +I’ve realized long ago that my most important lessons weren’t +learned in classes, but by a combination of seeing things done by +friends and independent study after that. I’ve realized that +teaching (the things I teach) is trying to correct these differences +in backgrounds.

+

My main job is supporting computing infrastructure, so my teaching +is very grounded in real-world problems. I’m often start at the +very basics, because this is what I see missing most often.

+

When teaching, I like lots of audience questions and don’t mind +going off-script a bit (even though I know it should be minimized). +I find that sufficient audience interest allows any lesson to be a +success - you don’t have to know everything perfectly, just show how +you’d approach a problem.

+
+

In 02-teaching-philosophies.md:

+
+

João M. da Silva

+

I started giving technical trainings twenty years ago, and hence my perspective +is perhaps more inclined towards the development of hands-on abilities and +capability to solve problems, independently or in a team.

+

But the development of hands-on practical skills, requires some essential +knowledge about the domain and some willingness to try different approaches +in case one gets stuck. Some call this the “KSA approach” +(“Knowledge-Skills-Attitude). Hence, I +try to impart the essential knowledge (and where to find out more) at my +trainings. And to encourage and challenge students in order to make them +overcome their self-perceived limits (e.g. “I’m a Humanist, I can’t use +Python virtualenv”).

+

I’ve been trying to study more about the Cognitive aspects of learning over the years, +and I should find out the time to return to that. There’s very interesting +research in Problem Solving, with Learning being a important component in that domain.

+

Storytelling: humans are neurologically made for paying attention to good +stories, and that’s something that I try to put into account: to give +a lesson like it would be a relevant narrative for the students, one that they +could relate to and help them in their work

+

I like to draw and be creative with that, but have to pay attention to +my handwriting during my trainings. I reckon that Architectural diagrams +help students to understand the big picture, so I should invest more on +those when development training material. I would also like to start looking into +Concept Maps and Semantic Trees in training.

+
+
+
+

Interactive teaching style

+

In 03-teaching-style.md:

+ +

In 03-teaching-style.md:

+
+

Give feedback on teaching (optional, 10 mn)

+

This exercise aims at learning to give feedback. It is optional as we have +similar exercises when practising teaching). +As a group, we will watch this video of teaching and +give feedback on two axes: positive vs. negative and content vs. presentation. Have each person in +the class add one point to a 2x2 grid on a whiteboard or in the shared notes (hackMD, etherpad, google doc) without duplicating any points. +For online instructor training event, use breakout room (4-5 persons per group) to facilitate discussion. Then each group reports to the shared notes. +You can use a rubric (used during The Carpentries teaching demos) to help you take notes. +What did other people see that you missed? What did they think that you strongly agree or disagree with?

+
+

In 03-teaching-style.md:

+
+

Exercise: How to identify learner profiles?

+
    +
  1. How to identify leaner profiles from surveys and during the class

  2. +
  3. Which types of learners should the leassons focus on

  4. +
+
+
+
+

Teaching practice and feedback

+

In teaching-practice.md:

+
+

Exercise

+
    +
  • We organize the breakout rooms to not only discuss one lesson/topic so that it is more interesting +to listen and also probably we will all get more useful feedback.

  • +
  • Give each other constructive verbal feedback on the teaching demos, for example +using this demo rubric.

  • +
  • Write down questions (in the collaborative document) that you would like to +discuss in the main room or interesting conclusions which you would like to +share with others.

  • +
+
+

In teaching-practice.md:

+
+

Exercise

+
    +
  • In the second round we distribute the rooms differently so that you can +present it to a new group of workshop participants and can receive new +feedback.

  • +
  • Ask for feedback and one/few point(s) you want to improve.

  • +
  • In your second trial check whether you feel the demonstration improved.

  • +
  • Share your lessons learned in the collaborative document.

  • +
  • Give us also feedback on this exercise format. Was it useful? What can we improve?

  • +
+
+

In teaching-practice.md:

+
+

Exercise

+

Teaching by live coding is a +performance art which requires practice. +This exercise highlights some typical pitfalls that most instructors +fall into sooner or later, and also shows how to avoid them. +Watch closely since we will be giving feedback!

+
    +
  • Watch these two videos: video 1 and +video 2

  • +
  • What was better in video 1 and what was better in video 2?

  • +
  • Please give feedback in the shared workshop document.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/future/index.html b/future/index.html new file mode 100644 index 00000000..2b6b3f91 --- /dev/null +++ b/future/index.html @@ -0,0 +1,247 @@ + + + + + + + Possibilities for Carpentries — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Possibilities for Carpentries

+
+

Keypoints

+
    +
  • Carpentries is currently designed around small workshops, so many of these ideas can’t directly apply

  • +
  • Yet many of these tools and also team teaching can still be used

  • +
  • You can run your own breakout room for any of our workshops

  • +
  • Join as observer if you want to see our workshop organization and tools in action

  • +
+
+

CodeRefinery workshops can be a good progression step after taking a +Carpentries workshop.

+

Helping out at a CodeRefinery workshop as exercise lead can be a good +progression step for those who have helped out at a Carpentries workshop or who +have taken the Carpentries instructor training.

+
+
+

CodeRefinery’s plans

+
+

Keypoints

+
    +
  • We are continuing to focus on online-first with local breakout rooms

  • +
  • We welcome people joining us, either individually or as an organization

  • +
  • Still interested in collaboration with Carpentries

  • +
  • We need to become better at marketing and outreach

  • +
+
+
+

Biggest open problems

+
    +
  • How to give helpers and contributors more credit and visibility

  • +
  • How to promote/engage new members

  • +
  • What are we? Non-profit? Institution collaboration network? Selling services?

  • +
  • Funding and sustainability (but we have ideas: collaboration network)

  • +
+
+
+

How you can join

+

Individual level:

+
    +
  • Join CodeRefinery +chat

  • +
  • Lead a team, co-teach, or help organize a workshop

  • +
  • Generally provide marketing and outreach

  • +
+

Organization level:

+
    +
  • Have your organization join CodeRefinery

  • +
  • Officially co-advertise and co-teach workshops

  • +
  • Run local breakout rooms and join a workshop as a team

  • +
  • Send an observer to a workshop

  • +
+
+
+

Aside: Nordic-RSE (research software engineers)

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/genindex/index.html b/genindex/index.html new file mode 100644 index 00000000..f5fa3e3d --- /dev/null +++ b/genindex/index.html @@ -0,0 +1,181 @@ + + + + + + Index — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guide/index.html b/guide/index.html new file mode 100644 index 00000000..46652ba0 --- /dev/null +++ b/guide/index.html @@ -0,0 +1,193 @@ + + + + + + + Instructor’s guide — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor’s guide

+

In a lesson that was further developed, this would include an +instructor’s guide that mentioned:

+
    +
  • Background of why the course is how it is

  • +
  • Recommendations of teaching it

  • +
  • Known pitfalls of teaching it, so that other instructors can avoid +them

  • +
  • Possibly how to contribute, long-term plans, etc.

  • +
+

For example, see git-intro’s instructor guide.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/hackmd/index.html b/hackmd/index.html new file mode 100644 index 00000000..8bfdf909 --- /dev/null +++ b/hackmd/index.html @@ -0,0 +1,251 @@ + + + + + + + HackMD — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

HackMD

+

The name “HackMD” doesn’t do this concept justice, nor do the more +common descriptions of “shared notes” or “collaborative document”. It +is a full replacement for chat: perhaps it could be called random +access chat or parallel 2D chat ?

+

HackMD itself is a web service for collaborative documents in +Markdown. This isn’t special to HackMD, but we have used it for its +scalability, markdown support, and privacy in the “view” mode.

+
+

Primary articles

+ +
+
+

Advantages

+
    +
  • Synchronous questions, no disadvantage for quiet people.

  • +
  • Anonymous questions.

  • +
  • Parallel answers by a large number of helpers.

  • +
  • Easier to go back and review past questions during Q&A sessions +(compared to scrolling through chat), for example finding important +or unanswered questions.

  • +
  • The above can make a course feel much more interactive than it would +otherwise.

  • +
+
+
+

Disadvantages

+
    +
  • Overwhelming flood of information

    +
      +
    • But you wanted more interaction, right?

    • +
    • Co-teaching helps here, one person can focus on watching.

    • +
    • Students must be warned to be deliberate about where they focus +their attention (different learners have different interests).

    • +
    +
  • +
  • It is another tool to use

    +
      +
    • Not required for basic learners, learners can begin using when +they are comfortable.

    • +
    +
  • +
+
+
+

Exercise

+
+

Exercise

+
    +
  • Actively use HackMD during this course.

  • +
  • Observe how the instructors integrate it during the course +itself, and can immediately respond to the questions.

  • +
  • Observe how instructors occasionally mention and screenshare +HackMD to validate to the audience that it is being watched.

  • +
  • Keep HackMD open. Can you balance it and watching. Does it +increase or decrease engagement?

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..42414557 --- /dev/null +++ b/index.html @@ -0,0 +1,310 @@ + + + + + + + Community teaching training — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Community teaching training

+
+

Under development (mid 2022)

+

As of mid-2022, this material has been reworked for our summer workshop and +for the CarpentryCon 2022 workshop. The material will continue to be +improved before a longer training session in the autumn.

+

This material is the new version of our previous Instructor +training.

+
+
+

What this course covers

+

In 2020, we got farther from our offices but closer to each other. If +you could adapt to the circumstances, a huge number of possibilities +were opened - in particular with collaborative teaching. In this +training, you will learn how we use them. Teaching from 2019 is +almost obsolete - join us to learn more.

+
    +
  • Tools of teaching: how to make the most out of online (and +other) teaching.

  • +
  • Workshop organization, collaboratively: our vision of teaching +together outside of our silos.

  • +
  • Socio-technical factors: social and technical barriers to +learning, why you need to care, and what you can do about them.

  • +
  • Lesson development, collaboratively: how to design lessons and +teaching materials so that they can be open and shared.

  • +
+
+
+

Who is the course for?

+

Teaching is a profession, but also something that everyone needs to be +able to do to some degree, since everyone has their own personal +specialties they will either teach or mentor.

+

This course can be relevant for different learner personas:

+
    +
  • You run a practical teaching program at your institution (for example +as part of a research computing group) and would like to learn best +practices for collaborative teaching, so that you aren’t re-inventing +the same thing over and over again.

  • +
  • You are a technical specialist who is frustrated with the way you +currently try to teach others who need to use your software or +infrastructure. You can’t spend too much time to become a +professional, but you know you need something more than what you’ve +been doing. Thus, you would like to adopt some of the best practices of +designing and teaching interactive, hands-on workshops.

  • +
  • You’ve been teaching alone, but would like to join a collaboration +network for more co-teaching and to reduce the amount of duplication +of effort.

  • +
  • You are interested in teaching CodeRefinery lessons, and would like a +comprehensive kick-start to how CodeRefinery works, either to join us, +or teach its lessons with us or independently.

  • +
+
+

Preparation

+ +
+ + + + + +
+

Wrap-up, future, and getting involved

+ +
+ + +
+
+ + +
+
+ +
+
+
+
+ + + + \ 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..6bacc7f8 --- /dev/null +++ b/instructor-tech-setup/index.html @@ -0,0 +1,278 @@ + + + + + + + Instructor tech setup — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor tech setup

+
+

Keypoints

+
    +
  • Screenshare: portrait layout instead of sharing entire screen

  • +
  • Prompt: adjust your prompt to make commands easy to read

  • +
  • Readability and beauty is important: adjust your setup for your audience

  • +
  • Share the history of your commands

  • +
  • Get set up a few days in advance and get an outside reviewer

  • +
+
+
+

Screenshare

+

Compare the following two screen-shares (you can find many more in +the coderefinery manuals:

+
+https://coderefinery.github.io/manuals/_images/screenshare-fullhd.png +
+

FullHD.

+
+
+
+https://coderefinery.github.io/manuals/_images/s10-kickstart-prompt-log.png +
+

Portrait, latest proposed best practices.

+
+
+

Share a portrait layout (left or right half of your screen) +instead of sharing entire screen.

+

Motivation:

+
    +
  • This makes it easier for you to look at some other notes or to coordinate +with other instructors at the same time +without distracting with too much information.

  • +
  • This makes it possible for participants to have something else open in the +other screen half: terminal or browser or notebook.

  • +
+
+
+

Adjust your prompt/configuration/colors

+

Adjust your prompt to make commands easy to read. What looks good for your own +work (many terminals, small font, extensions, shortcuts, color scheme) is +usually not the best for other people watching you. Adjust your setup for your +audience. Remove distractions.

+

You need to spend some time getting set up before you teach. 10 minutes +before the session starts is typically too late. Get set up a few days in +advance and get an outside reviewer.

+
+

Should instructors be forced to have a consistent screenshare?

+

There are pros and cons to all instructors using the same screenshare and prompt.

+
    +
  • What are the advantages?

  • +
  • What are the opportunities of instructors showing different setups?

  • +
  • How does it depend on the lesson and the experience of learners?

  • +
+
+
+
+

Share the history of your commands

+

Even if you type slowly it is almost impossible to follow every command. We +all get distracted or want to read up on something or while following a command +fails on the learner laptop while instructor gets no error.

+

Add pauses and share the commands that you have typed so that one can catch up.

+
+
+

More examples and how to set it up

+ +
+
+

Exercises

+
+

Evaluate screen captures

+

Evaluate screenshots within the instructor tech +setup lesson. +Use the collaborative document to make a list of the trade-offs of each one. +Which one do you prefer? Which are useful in each situation?

+
+
+

Set up your own environment

+

Set up your screen to teach something. Get some feedback from +another learner. We will discuss among the class.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/lessons-with-version-control/index.html b/lessons-with-version-control/index.html new file mode 100644 index 00000000..5a1e2aee --- /dev/null +++ b/lessons-with-version-control/index.html @@ -0,0 +1,293 @@ + + + + + + + Lesson development with version control — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lesson development with version control

+

So, we want to practically share. We have these minimum requirements:

+
    +
  • Someone can get the preferred form of modification, to improve +without limitation.

  • +
  • It is trivial to track differences and send the changes back to the +source, with little cost to the original maintainer.

  • +
+

Especially with the second of these, version control in an online +platform seems to be the only reasonable option.

+
+

Version control and static site generators

+

CodeRefinery and the Carpentries use git and Github to develop +lessons. The general procedure is this:

+
    +
  • Version control to store the raw files in text format

  • +
  • A static website compiler to convert them to HTML files

  • +
  • Serving to the public via Github Pages (but this could be replaced +with other systems)

  • +
+

This allows for true collaborative development and community +contributions.

+

Carpentries uses a custom website complierer based on R, CodeRefinery +uses the Sphinx documentation engine which is used in many different +projects for documentation. CodeRefinery’s use of a standard tool +allows us to build on a huge and growing ecosystem of extensions and +themes, and promotes local reuse.

+

The exact static website generator used isn’t so important, as long as +some form of version control is used.

+

A open-source license is the last bit to consider: without a license, +it can’t be reused and passed on, and there is little incentive for +someone to contribute.

+
+
+

CodeRefinery lesson tools

+

CodeRefinery uses the following tools to actually make its lessons +right now:

+
    +
  • Sphinx (a common documentation +generator, widely used in open source projects in general)

  • +
  • The sphinx-lesson, which is more of +a small collection of other extensions than new development itself.

  • +
  • Github for hosting lessons: https://github.com/coderefinery/

  • +
  • Github Actions and Github Pages for building and web serving our +lessons.

  • +
+
+
+

Exercises

+
+

Contribute to a sample lesson

+
    +
  • Open this very lesson in GitHub (it uses the same format as +typical CodeRefinery lessons): +https://github.com/coderefinery/community-teaching/

  • +
  • Browse the files and understand the general idea. Check out at +least these and use HackMD to record their functions:

    +
      +
    • .github/workflows/sphinx.yml

    • +
    • content/conf.py

    • +
    • content/index.rst

    • +
    • content/lessons-with-version-control.rst

    • +
    +
  • +
  • If you want, try to make a pull request to this lesson. It +doesn’t have to have any significant content, it can be a pure +test pull request.

  • +
+
+
+

(advanced) Create your own lesson

+

Use the +sphinx-lesson-template +to create a new lesson of your choice. Alternatively, use the current +Carpentries system, or some other system of your choice.

+
+
+
+

Recommendations and lessons learned

+
    +
  • Convert feedback about lessons and suggestions for improvements into issues +so that these don’t get lost.

  • +
  • Make your lesson citable: get a DOI.

  • +
  • Credit contributors (not only Git commits).

  • +
  • Instructor guide is essential for new instructors.

  • +
  • Lesson changes should be accompanied with instructor guide changes (it’s like +a documentation for the lesson material).

  • +
  • Apply and validate Backwards lesson design again and again.

  • +
  • Make it possible to try out new ideas (by making the lesson branch-able).

  • +
  • Before making larger changes, talk with somebody and discuss these changes.

  • +
  • For substantial changes we recommend to first open an issue and describe your +idea and collect feedback before you start with an extensive rewrite.

  • +
  • For things still under construction, open a draft pull request to collect +feedback and to signal to others what you are working on.

  • +
+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/livestreaming/index.html b/livestreaming/index.html new file mode 100644 index 00000000..0907884f --- /dev/null +++ b/livestreaming/index.html @@ -0,0 +1,273 @@ + + + + + + + Livestreaming — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Livestreaming

+

In a large lecture, in effect, you don’t interact with most people - +not even close. Yet, trying to force this limited interaction greatly +limits our possible reach, and keeps us in an awkward state of +expecting live interaction yet usually receiving minimal. When we try +this online, it forces a closed

+

Teaching via livestreaming allows us to:

+
    +
  • Reach a near-unlimited number of people

  • +
  • Fully embrace online tools for interaction, instead of asking people +to speak up. This equalizes the participation for shy or passive +participants.

  • +
  • By being large, be more efficient and use the extra resources for +meaningful interactions in small groups.

  • +
+
+

Primary articles

+ +
+
+

Summary

+
    +
  • There are actually three levels here.

    +
      +
    • In-person

    • +
    • Online meeting

    • +
    • Online livestream

    • +
    +
  • +
+
+https://coderefinery.github.io/manuals/_images/mooc-diagram.png +
+

The general presence and information flow within the MOOC strategy.

+
+
+
    +
  • CodeRefinery livestreams via Twitch, but Twitch is not an essential +aspect.

  • +
  • We can invite anyone in the world, no risk of disruptions from +trolls.

  • +
  • This has enabled us to fully embrace strategies such as HackMD and +co-teaching.

    +
      +
    • While we tried these in-person, they didn’t work well since the +loud, extroverted people would dominate.

    • +
    +
  • +
+
+

Tech details

+
    +
  • We stream by using OBS to capture a Zoom meeting. We can switch +between a gallery view, screenshare, and mixed.

  • +
  • Dedicated instructor Zoom meeting - no learners. Thus, no chance of +privacy violations.

    +
      +
    • Learners can attend different ways: a) independently online b) +in-person breakout room c) Zoom breakout rooms.

    • +
    +
  • +
  • We don’t have time to get into details here… see the linked +documents and also join us for in-person experience while we improve +our materials more.

  • +
+
+
+
+

Exercises

+
+

(advanced) Set up and install OBS as a livestreaming tool.

+

This exercise is open-ended.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..e6a41e7a Binary files /dev/null and b/objects.inv differ diff --git a/other-resources/index.html b/other-resources/index.html new file mode 100644 index 00000000..514d74d8 --- /dev/null +++ b/other-resources/index.html @@ -0,0 +1,206 @@ + + + + + + + Other resources — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Other resources

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/placeholder/index.html b/placeholder/index.html new file mode 100644 index 00000000..b8e51daa --- /dev/null +++ b/placeholder/index.html @@ -0,0 +1,183 @@ + + + + + + + Placeholder — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/preparation/index.html b/preparation/index.html new file mode 100644 index 00000000..565d4950 --- /dev/null +++ b/preparation/index.html @@ -0,0 +1,228 @@ + + + + + + + Pre-workshop preparation — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Pre-workshop preparation

+

These things will help you get the most out of this workshop, by +giving you a broad overview at the beginning that you might only get +later on in the lesson.

+

Don’t worry if you don’t have time to do everything here. The most +important ones are listed first.

+
+

Read “How to help someone use a computer” (5 min)

+

How to help someone use a computer, by Phil +Agre. +Summary: Most of our teaching challenge is helping people to overcome bad user +interface design.

+
+
+

Browse a CodeRefinery lesson (5 min)

+

Please take 5 minutes and go through a CodeRefinery +lesson and understand the general +layout. Don’t go in-depth to any of the material (unless you want, +obviously). We would recommend +git-intro if you don’t +have a preference.

+
+
+

(optional) Watch “The future of teaching” (35 min content only, 45 min with Q&A, or 15 min reading)

+

The “The Future of Teaching” talk is a summary of many things in this +course. You could watch it as a preparation (or if you are reading on +your own, as a summary). This is low priority, since we will cover +most of these things in the course itself. +Watch it on YouTube +or read it if you prefer.

+
+
+

(optional) Read “The science of learning” (20 min)

+

Read this short paper The Science of +Learning +which provides a brief overview of some key evidence-based results in +teaching. This paper is also used by The +Carpentries for their Instructor Training +workshops.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/search/index.html b/search/index.html new file mode 100644 index 00000000..815bc291 --- /dev/null +++ b/search/index.html @@ -0,0 +1,195 @@ + + + + + + Search — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2020-, The contributors.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..4b491fed --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["02-teaching-philosophies", "03-teaching-style", "about-coderefinery", "backward-lesson-design", "collaboration-models", "distributed", "diversity-and-inclusion", "exercises", "future", "guide", "hackmd", "index", "instructor-tech-setup", "lessons-with-version-control", "livestreaming", "other-resources", "placeholder", "preparation", "teaching-online", "teaching-practice", "teaching-strategies", "team-teaching", "teams", "video-editing", "video-recording", "welcome", "why-are-computers-hard", "why-teach-together", "workshop-roles", "workshops-online"], "filenames": ["02-teaching-philosophies.md", "03-teaching-style.md", "about-coderefinery.md", "backward-lesson-design.md", "collaboration-models.rst", "distributed.md", "diversity-and-inclusion.rst", "exercises.rst", "future.md", "guide.rst", "hackmd.rst", "index.rst", "instructor-tech-setup.md", "lessons-with-version-control.md", "livestreaming.rst", "other-resources.md", "placeholder.rst", "preparation.md", "teaching-online.md", "teaching-practice.md", "teaching-strategies.md", "team-teaching.rst", "teams.rst", "video-editing.rst", "video-recording.md", "welcome.md", "why-are-computers-hard.rst", "why-teach-together.rst", "workshop-roles.rst", "workshops-online.md"], "titles": ["CodeRefinery teaching philosophies", "Interactive teaching style", "About the CodeRefinery project and CodeRefinery workshops", "Backwards lesson design", "Collaboration models", "Distributed workshop organization", "Diversity and inclusion", "Exercise list", "Possibilities for Carpentries", "Instructor\u2019s guide", "HackMD", "Community teaching training", "Instructor tech setup", "Lesson development with version control", "Livestreaming", "Other resources", "Placeholder", "Pre-workshop preparation", "Teaching online", "Teaching practice and feedback", "How to teach online", "Team teaching", "Teams", "Video editing", "Video recording", "Welcome and introduction", "Why are computers hard?", "Why teach together?", "Workshop roles", "Running a workshop: online"], "terms": {"share": [0, 1, 2, 3, 5, 7, 10, 11, 13, 19, 23, 24, 25], "your": [0, 1, 3, 8, 11, 17, 19, 20, 22, 24, 27], "approach": [0, 2, 4, 7, 11], "pleas": [0, 7, 17, 19], "trick": [0, 4, 7, 29], "solut": 0, "live": [0, 1, 4, 5, 7, 14, 24, 25], "document": [0, 2, 3, 7, 10, 12, 13, 14, 15, 19, 24, 29], "other": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 18, 19, 20, 21, 22, 23, 25, 27], "addit": [0, 1, 3, 5, 7], "question": [0, 1, 2, 3, 7, 10, 18, 19, 21, 22, 28, 29], "what": [0, 2, 3, 4, 6, 8, 12, 13, 15, 19, 29], "i": [0, 1, 2, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29], "motiv": [0, 5, 6, 7, 12, 29], "take": [0, 1, 3, 6, 7, 8, 17, 19, 20, 21, 23, 24, 29], "thi": [0, 2, 3, 5, 6, 9, 10, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 24, 27, 29], "train": [0, 1, 2, 3, 4, 6, 7, 8, 15, 17, 21, 23, 28], "how": [0, 2, 3, 9, 10, 11, 15, 19, 25, 27, 29], "structur": [0, 7], "inform": [0, 1, 3, 7, 10, 12, 14, 20, 22, 23, 25, 28, 29], "ar": [0, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29], "own": [0, 1, 2, 3, 8, 11, 17, 22, 24, 27], "need": [0, 1, 2, 3, 5, 7, 8, 12, 20, 21, 22, 23, 24, 25, 27, 29], "differ": [0, 1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 14, 19, 20, 21, 22, 24, 28, 29], "do": [0, 1, 2, 3, 5, 10, 11, 12, 17, 20, 21, 23, 24, 26, 29], "you": [0, 1, 3, 4, 7, 10, 11, 12, 13, 14, 15, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "notic": [0, 7, 19, 23, 25], "between": [0, 1, 3, 6, 7, 14, 20, 21, 29], "we": [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14, 17, 18, 19, 20, 23, 28, 29], "also": [0, 1, 2, 4, 5, 7, 8, 11, 14, 17, 19, 24, 25, 29], "carpentri": [0, 6, 7, 11, 13, 15, 17], "tradit": [0, 7], "academ": [0, 2, 7], "skill": [0, 1, 3, 7, 21, 22], "taught": [0, 1, 4, 7, 27, 29], "isn": [0, 7, 10, 13, 25], "t": [0, 1, 3, 7, 8, 10, 11, 13, 14, 17, 18, 20, 21, 22, 23, 24, 25, 27, 29], "right": [0, 7, 10, 12, 13, 18, 23, 27, 29], "set": [0, 1, 20, 22, 29], "here": [0, 1, 7, 10, 14, 17, 18, 23, 29], "instructor": [0, 2, 3, 4, 5, 6, 8, 10, 11, 13, 14, 15, 17, 20, 21, 24, 27, 28, 29], "show": [0, 2, 3, 7, 12, 19, 20], "all": [0, 1, 2, 3, 5, 7, 12, 18, 19, 22, 23, 24, 29], "have": [0, 1, 2, 3, 4, 5, 8, 10, 13, 14, 17, 19, 20, 21, 22, 23, 25, 28, 29], "style": [0, 2, 11], "benefici": 0, "workshop": [0, 1, 3, 4, 6, 8, 10, 18, 19, 20, 22, 23, 24], "It": [0, 1, 2, 3, 7, 10, 13, 19, 20, 23, 25, 27, 29], "import": [0, 3, 7, 10, 12, 13, 17, 20, 23, 25, 28, 29], "explain": [0, 1, 2, 3, 7, 20], "much": [0, 1, 3, 5, 7, 10, 11, 12, 18, 20, 21, 22, 23, 27, 29], "valu": [0, 27], "individu": [0, 1, 8], "one": [0, 1, 3, 7, 10, 12, 19, 20, 21, 22, 23, 24, 25, 29], "wai": [0, 3, 6, 7, 11, 14, 18, 20, 21, 23, 26, 29], "mani": [0, 1, 3, 5, 8, 12, 13, 17, 18, 20, 21, 24, 25, 26, 27, 29], "want": [0, 1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 17, 19, 20, 22, 23, 24, 29], "help": [0, 1, 3, 4, 5, 6, 7, 8, 10, 15, 22, 23, 24, 25, 27, 29], "each": [0, 1, 3, 4, 5, 7, 11, 12, 18, 19, 20, 21, 22, 23, 25, 26, 28, 29], "find": [0, 7, 10, 12, 23, 27, 29], "best": [0, 1, 3, 7, 11, 12, 22, 25, 27], "u": [0, 1, 2, 5, 7, 8, 11, 13, 14, 19, 23, 24, 25, 27], "recent": [0, 3, 20], "some": [0, 1, 3, 4, 6, 7, 11, 12, 13, 15, 17, 18, 19, 20, 23, 24, 25, 28, 29], "below": [0, 1, 24, 29], "http": [0, 2, 4, 6, 7, 10, 12, 13, 14, 18, 21, 22, 23, 24, 26, 28, 29], "www": [0, 6, 7, 23, 26], "youtub": [0, 6, 7, 15, 17, 23], "com": [0, 6, 7, 13, 23, 29], "playlist": [0, 7, 23], "list": [0, 11, 12, 17, 23, 27, 28], "plplblyhczjaahf89p": 0, "gcjexwc8cf": 0, "7nhx": 0, "regularli": [0, 7], "so": [0, 1, 3, 5, 7, 8, 9, 11, 12, 13, 19, 20, 21, 22, 23, 25, 27, 29], "try": [0, 1, 3, 4, 5, 7, 11, 13, 14, 20, 22, 23, 29], "appli": [0, 1, 2, 3, 7, 8, 13, 20, 23, 25], "learnt": [0, 7, 25], "howev": [0, 1, 7, 21], "know": [0, 1, 2, 3, 7, 11, 20, 22, 24, 25], "our": [0, 1, 2, 5, 6, 7, 8, 11, 13, 14, 15, 17, 19, 21, 22, 23, 24, 25, 26, 27, 29], "target": [0, 1, 3, 7], "audienc": [0, 1, 3, 5, 7, 10, 12, 21, 23, 24, 26, 27, 29], "veri": [0, 1, 2, 3, 6, 7, 13, 20, 21, 23, 27, 29], "adapt": [0, 1, 7, 11, 26], "my": [0, 3, 7], "am": [0, 3, 7], "still": [0, 1, 3, 4, 7, 8, 13, 27, 29], "work": [0, 2, 3, 7, 11, 12, 13, 14, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29], "which": [0, 1, 3, 5, 7, 12, 13, 17, 18, 19, 20, 23, 25, 27, 29], "situat": [0, 1, 7, 12, 21], "why": [0, 1, 3, 9, 11, 25, 29], "like": [0, 1, 3, 4, 7, 11, 13, 19, 20, 23], "usual": [0, 1, 2, 3, 6, 7, 12, 14, 18, 21, 26, 27, 28, 29], "wider": [0, 7], "rang": [0, 7], "mix": [0, 7, 14, 21], "background": [0, 3, 6, 7, 9], "more": [0, 1, 2, 3, 5, 6, 8, 10, 11, 13, 14, 15, 18, 19, 20, 21, 22, 25, 26, 27, 29], "care": [0, 7, 11, 27], "pace": [0, 1, 7], "time": [0, 1, 3, 4, 5, 7, 11, 12, 14, 17, 20, 21, 23, 26], "given": [0, 1, 2, 5, 7], "exercis": [0, 2, 5, 8, 11, 20, 29], "consider": [0, 7], "spend": [0, 7, 11, 12], "quit": [0, 1, 6, 7, 22], "lot": [0, 7, 20, 22, 28], "read": [0, 1, 6, 7, 12, 15, 24], "materi": [0, 2, 3, 4, 7, 11, 13, 14, 17, 27], "practis": [0, 1, 7], "myself": [0, 7], "particularli": [0, 7], "note": [0, 1, 7, 10, 12, 20, 25], "just": [0, 3, 7, 20, 21, 23, 29], "befor": [0, 1, 4, 7, 11, 12, 13, 23, 28, 29], "thei": [0, 1, 2, 3, 5, 7, 10, 11, 14, 20, 22, 23, 24, 26, 29], "highlight": [0, 1, 7, 19, 22], "aspect": [0, 2, 3, 7, 14, 19], "both": [0, 1, 7, 19, 20, 27, 28], "prepar": [0, 1, 4, 7, 20, 21, 24, 27], "too": [0, 1, 2, 3, 7, 11, 12, 20, 22, 23, 24, 27, 29], "advanc": [0, 1, 12, 20], "think": [0, 1, 3, 7, 18, 20, 26, 27], "prevent": [0, 7, 25], "ask": [0, 1, 2, 3, 7, 14, 19, 20, 21, 25, 29], "If": [0, 4, 5, 7, 11, 13, 20, 23, 24, 25, 27], "less": [0, 1, 3, 7, 20, 21, 25, 27, 29], "compet": [0, 7], "practition": [0, 7], "classroom": [0, 1, 7, 21, 25], "can": [0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 14, 19, 20, 21, 22, 23, 24, 25, 27, 29], "easili": [0, 1, 5, 7], "copi": [0, 3, 7, 20, 23], "past": [0, 2, 7, 10, 23], "avoid": [0, 2, 3, 7, 9, 19, 27, 29], "slow": [0, 1, 7, 20, 23], "down": [0, 1, 7, 19, 20], "entir": [0, 1, 6, 7, 12], "ideal": [0, 7], "d": [0, 6, 7], "give": [0, 2, 3, 8, 17, 19, 20, 21, 29], "sever": [0, 2, 4, 6, 7, 20, 23], "anyon": [0, 1, 4, 7, 14, 23], "its": [0, 1, 2, 7, 10, 11, 13, 23], "everybodi": [0, 1, 7, 25], "get": [0, 2, 3, 12, 13, 14, 17, 19, 20, 22, 24, 27, 29], "someth": [0, 1, 3, 7, 11, 12, 20, 23, 25, 26], "from": [0, 1, 2, 3, 4, 6, 7, 11, 12, 14, 15, 20, 22, 23, 24, 25, 27, 29], "love": [0, 2, 7], "break": [0, 1, 7, 20, 23, 25, 29], "an": [0, 1, 2, 4, 5, 7, 8, 9, 12, 13, 14, 18, 21, 23, 24, 29], "opportun": [0, 2, 3, 7, 12, 18], "discuss": [0, 1, 3, 7, 12, 13, 18], "attende": [0, 7, 22], "research": [0, 1, 2, 3, 6, 7, 11], "topic": [0, 1, 4, 6, 15, 19, 20, 21, 23, 25], "especi": [0, 1, 3, 7, 13, 23, 24, 25], "interest": [0, 3, 4, 7, 8, 10, 11, 19, 20, 27], "understand": [0, 1, 2, 3, 7, 13, 17, 20, 26, 27], "softwar": [0, 1, 3, 7, 11, 14, 29], "write": [0, 2, 3, 7, 19], "plan": [0, 2, 3, 4, 7, 9, 11, 20, 21, 28, 29], "us": [0, 2, 3, 4, 8, 10, 11, 12, 13, 14, 15, 18, 19, 20, 22, 24, 25, 27, 28, 29], "learn": [0, 2, 3, 6, 7, 11, 15, 19, 20, 21, 22, 23, 25, 26, 28, 29], "dure": [0, 1, 3, 4, 5, 6, 7, 10, 19, 21, 22, 28, 29], "ha": [0, 1, 2, 3, 7, 11, 14, 20, 21, 29], "chang": [0, 1, 7, 13, 19, 27], "bit": [0, 1, 3, 7, 13, 22, 29], "sinc": [0, 7, 11, 14, 17, 19, 21, 23, 24, 25, 29], "start": [0, 1, 2, 3, 7, 11, 12, 13, 20, 23, 25, 29], "In": [0, 1, 2, 3, 5, 7, 9, 11, 14, 18, 19, 20, 21, 24, 29], "begin": [0, 7, 10, 17, 23], "had": [0, 2, 3, 7, 29], "blob": [0, 7], "binari": [0, 7], "larg": [0, 1, 4, 7, 10, 14, 20, 22, 24, 25, 27, 29], "object": [0, 7, 24], "knowledg": [0, 2, 3, 7, 25], "experi": [0, 1, 2, 3, 4, 5, 7, 12, 14, 20, 29], "convei": [0, 7], "particip": [0, 2, 4, 7, 12, 14, 19, 23, 24, 25, 29], "With": [0, 7, 20], "realiz": [0, 7], "serial": [0, 3, 7], "abl": [0, 1, 3, 7, 11, 13, 21, 23, 26, 29], "similar": [0, 1, 15, 20, 22, 23], "fashion": [0, 7], "would": [0, 1, 2, 3, 4, 7, 9, 10, 11, 14, 17, 19, 22, 24, 26, 27], "intend": [0, 1, 2, 7], "send": [0, 7, 8, 13, 29], "over": [0, 4, 7, 11, 20, 23, 29], "wire": [0, 7], "stop": [0, 7, 23], "signal": [0, 7, 13], "check": [0, 1, 3, 7, 13, 19, 23], "sum": [0, 7], "re": [0, 5, 7, 11, 22, 23], "transmiss": [0, 7], "when": [0, 1, 3, 6, 7, 10, 14, 20, 22, 23, 24, 26, 29], "lectur": [0, 7, 14, 20, 21, 29], "come": [0, 1, 3, 7, 20, 22, 23, 24, 29], "appreci": [0, 7], "natur": [0, 7, 22], "period": [0, 5, 7], "lesson": [0, 1, 2, 4, 9, 12, 19, 20, 21, 23, 28, 29], "offer": [0, 7], "rais": [0, 2, 7, 29], "error": [0, 1, 7, 12], "appear": [0, 7, 23, 24, 29], "type": [0, 1, 3, 7, 12, 20, 21], "along": [0, 1, 3, 7, 19, 20, 22, 23, 28], "co": [0, 5, 8, 10, 11, 14, 27, 28], "good": [0, 1, 2, 6, 7, 8, 12, 19, 21, 23, 24, 26, 29], "broaden": [0, 7], "specif": [0, 1, 2, 3, 7], "inclin": [0, 7], "wa": [0, 1, 2, 3, 4, 7, 9, 19, 23, 29], "todai": [0, 7], "guid": [0, 1, 7, 11, 13, 20, 21, 25, 28, 29], "includ": [0, 1, 7, 9, 19, 23, 29], "me": [0, 7], "well": [0, 1, 5, 7, 14, 25, 29], "That": [0, 1, 7], "mai": [0, 1, 3, 7, 22, 23, 25, 27], "sound": [0, 1, 7], "self": [0, 7, 22, 25], "centric": [0, 7], "fact": [0, 1, 3, 7, 22], "opposit": [0, 7], "sensit": [0, 7], "go": [0, 1, 3, 7, 10, 17, 20, 23, 25, 29], "room": [0, 1, 3, 4, 5, 7, 8, 14, 20, 22, 23, 24, 28], "The": [0, 2, 7, 10, 11, 13, 14, 15, 18, 19, 20, 21, 22, 23, 25, 26, 29], "consciou": [0, 7], "being": [0, 7, 10, 14, 22], "better": [0, 2, 3, 7, 8, 18, 19, 20, 21], "tool": [0, 1, 2, 3, 6, 8, 10, 18, 23, 26], "concept": [0, 1, 7, 10, 20, 21], "map": [0, 7], "learner": [0, 2, 3, 5, 10, 11, 12, 14, 20, 21, 22, 23, 24, 28, 29], "persona": [0, 3, 7, 11], "though": [0, 2, 3, 7], "develop": [0, 2, 3, 5, 9, 15, 27], "few": [0, 1, 3, 5, 7, 12, 19, 20, 23, 24], "them": [0, 1, 2, 3, 5, 7, 9, 11, 13, 19, 22, 29], "never": [0, 1, 3, 7, 23, 29], "leav": [0, 7, 23, 24], "ani": [0, 1, 2, 3, 4, 7, 8, 13, 17, 20, 21, 23, 25, 29], "behind": [0, 7], "realli": [0, 3, 7, 29], "don": [0, 1, 3, 7, 13, 14, 17, 20, 21, 22, 23, 24, 25, 27, 29], "see": [0, 1, 5, 7, 8, 9, 14, 24, 29], "confus": [0, 7, 25], "blank": [0, 7], "face": [0, 7], "At": [0, 7], "same": [0, 1, 3, 7, 11, 12, 13, 19, 20, 21, 22, 23, 27, 28, 29], "sometim": [0, 7, 28], "worri": [0, 7, 17, 20], "about": [0, 1, 3, 7, 10, 11, 13, 15, 20, 23, 24, 25, 27, 29], "bore": [0, 7], "progress": [0, 3, 5, 7, 8], "slowli": [0, 1, 7, 12], "alwai": [0, 3, 7, 20, 24, 28], "difficult": [0, 1, 7, 24], "compromis": [0, 7], "struggl": [0, 7], "focu": [0, 1, 7, 8, 10, 20, 21], "make": [0, 1, 2, 3, 5, 7, 10, 11, 12, 13, 19, 20, 21, 22, 24, 26, 27, 28, 29], "intuit": [0, 7], "sens": [0, 2, 7], "Of": [0, 7, 26], "cours": [0, 1, 2, 3, 4, 5, 7, 9, 10, 14, 17, 18, 20, 21, 22, 23, 24, 27, 29], "base": [0, 1, 2, 3, 7, 13, 15, 17, 20, 22, 23], "establish": [0, 1, 2, 7], "connect": [0, 1, 6, 7], "thing": [0, 3, 4, 7, 11, 13, 17, 20, 21, 23, 25, 26, 27, 29], "saw": [0, 7], "previou": [0, 7, 11], "where": [0, 1, 3, 7, 10, 20, 23, 25], "x": [0, 3, 7], "master": [0, 3, 7], "follow": [0, 1, 3, 7, 12, 13, 19, 20, 22, 23, 25, 26], "script": [0, 1, 2, 3, 7], "after": [0, 1, 2, 4, 7, 8, 10, 22, 23, 24], "becom": [0, 1, 2, 3, 7, 8, 11, 20, 23], "familiar": [0, 3, 7, 29], "improvis": [0, 7], "react": [0, 7, 21], "dynam": [0, 3, 7], "e": [0, 1, 2, 6, 7, 23], "g": [0, 7, 23], "detour": [0, 7], "clearli": [0, 1, 2, 7, 20, 23, 29], "often": [0, 1, 2, 3, 6, 7, 20, 21, 22, 25, 28], "code": [0, 1, 2, 3, 7, 23], "text": [0, 7, 13, 23, 26], "out": [0, 1, 2, 3, 7, 8, 11, 13, 17, 20, 22, 23, 27, 29], "describ": [0, 1, 3, 7, 13], "slower": [0, 1, 7, 29], "place": [0, 1, 4, 5, 7, 23, 29], "hopefulli": [0, 7], "compens": [0, 7, 18], "A": [0, 1, 2, 3, 4, 5, 7, 10, 13, 15, 20, 22], "convers": [0, 7], "trainer": [0, 7], "traine": [0, 7], "engag": [0, 3, 7, 8, 10, 27], "For": [0, 1, 3, 7, 9, 13, 18, 22, 23, 24, 25], "reason": [0, 1, 3, 7, 13, 26, 29], "most": [0, 1, 3, 6, 7, 11, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 26, 29], "finish": [0, 7], "part": [0, 1, 4, 7, 11, 20, 21, 23, 25], "step": [0, 1, 7, 8, 20, 23, 29], "back": [0, 1, 7, 10, 13, 23, 24, 29], "might": [0, 1, 7, 17, 23, 24, 27], "bring": [0, 1, 7, 20, 22], "anoth": [0, 3, 5, 7, 10, 12, 21], "point": [0, 1, 3, 7, 19, 20, 22, 23, 26], "throughout": [0, 7], "answer": [0, 2, 3, 7, 10, 20, 21, 25, 27, 29], "practic": [0, 1, 11, 12, 13, 21, 25, 29], "yourself": [0, 7, 20], "those": [0, 1, 7, 8, 21], "seem": [0, 1, 7, 13, 21], "open": [0, 2, 4, 7, 10, 11, 12, 13, 14, 27], "end": [0, 1, 3, 7, 14, 20, 23], "new": [0, 2, 3, 7, 8, 11, 13, 18, 19, 20, 21, 23, 27, 29], "exampl": [0, 1, 2, 7, 9, 10, 11, 20, 23, 25], "person": [0, 1, 4, 5, 7, 10, 11, 14, 18, 19, 20, 21, 25, 28], "last": [0, 7, 13, 27], "analogi": [0, 1, 7], "order": [0, 1, 3, 7, 19, 24], "simplifi": [0, 1, 7, 26], "convolut": [0, 7], "180": [0, 7, 29], "degre": [0, 7, 11], "slide": [0, 7], "45": [0, 7, 15, 23], "block": [0, 7, 23], "separ": [0, 7, 20, 23, 24], "session": [0, 1, 2, 5, 7, 10, 11, 12, 19, 20, 23, 25, 29], "embrac": [0, 2, 7, 14], "interact": [0, 4, 10, 11, 14, 18, 20, 21, 22, 23, 24, 25, 27, 29], "demo": [0, 1, 7, 20, 21, 23], "typo": [0, 7], "goal": [0, 3, 7, 19], "spark": [0, 7], "curios": [0, 7], "novic": [0, 7], "look": [0, 1, 7, 12, 20, 23, 24], "experienc": [0, 3, 4, 7], "aha": [0, 7], "did": [0, 1, 7, 29], "could": [0, 1, 4, 7, 10, 11, 13, 17, 22, 23, 24], "wonder": [0, 7], "whether": [0, 1, 7, 19, 23], "becaus": [0, 1, 2, 3, 7, 23, 29], "up": [0, 1, 2, 3, 4, 19, 20, 21, 22, 23, 24, 29], "browser": [0, 7, 12], "keep": [0, 1, 2, 3, 7, 10, 14, 20, 29], "expert": [0, 5, 7, 28, 29], "sign": [0, 1, 7, 22], "encourag": [0, 1, 7, 22], "But": [0, 1, 7, 10, 20, 22, 25, 27], "rabbit": [0, 7], "hole": [0, 7], "onli": [0, 1, 5, 7, 13, 15, 19, 20, 23, 24, 25, 29], "jargon": [0, 7], "war": [0, 7], "stori": [0, 7], "profession": [0, 7, 11], "perspect": [0, 7], "busi": [0, 7], "world": [0, 1, 4, 7, 14, 25], "relat": [0, 1, 7, 18, 26], "context": [0, 1, 3, 6, 7], "custom": [0, 7, 13, 29], "product": [0, 7], "agil": [0, 7], "hard": [0, 1, 6, 11, 23], "clear": [0, 3, 7, 20, 23, 29], "than": [0, 1, 3, 7, 10, 11, 13, 18, 20, 21, 23, 26, 27, 29], "unclear": [0, 7], "simpl": [0, 1, 3, 7, 23, 24, 29], "complic": [0, 7], "almost": [0, 3, 7, 11, 12, 20, 22, 26], "felt": [0, 7], "got": [0, 7, 11, 25], "feedback": [0, 2, 11, 12, 13, 20, 21, 29], "repeat": [0, 1, 7], "head": [0, 7], "word": [0, 1, 3, 7, 23], "simpli": [0, 1, 7], "easi": [0, 7, 12, 20, 24, 26, 29], "home": [0, 7], "two": [0, 1, 2, 3, 4, 7, 12, 20, 21, 22, 23, 27, 29], "": [0, 3, 7, 11, 13, 18, 19, 20, 21, 23, 25, 26, 27, 29], "success": [0, 3], "issu": [0, 3, 7, 13], "pull": [0, 7, 13, 23], "request": [0, 1, 7, 13, 22], "solv": [0, 1, 2, 3, 7, 24], "surpris": [0, 6, 7], "known": [0, 2, 7, 9, 29], "precis": [0, 7, 20], "next": [0, 2, 7, 20, 23, 29], "episod": [0, 1, 3, 7, 20, 23, 29], "allow": [0, 1, 3, 7, 13, 14, 20, 22, 23, 29], "skip": [0, 1, 7], "distil": [0, 7], "essenc": [0, 7], "bullet": [0, 7], "deviat": [0, 7], "explicit": [0, 7, 22], "great": [0, 4, 5, 7, 20, 21, 24, 25], "recommend": [0, 9, 17, 29], "watch": [0, 1, 4, 5, 6, 7, 10, 12, 15, 19, 20, 21, 22, 23, 24, 28, 29], "tutori": [0, 7, 25], "program": [0, 1, 2, 3, 7, 11, 15], "languag": [0, 2, 3, 7], "feel": [0, 1, 7, 10, 19], "overwhelm": [0, 7, 10, 29], "fast": [0, 1, 7, 23, 27, 29], "thrown": [0, 7], "somebodi": [0, 7, 13], "els": [0, 7, 12, 22, 23, 26, 29], "who": [0, 3, 4, 7, 8, 22, 23, 25, 29], "detect": [0, 7], "complement": [0, 7, 21], "interrupt": [0, 7, 20], "flow": [0, 7, 14, 20, 28], "mistak": [0, 7, 23, 24, 26], "mind": [0, 1, 7, 20, 21], "forc": [0, 7, 14], "fun": [0, 7, 29], "demystifi": [0, 7], "onc": [0, 3, 7, 26, 29], "mysteri": [0, 7], "anymor": [0, 7, 29], "mean": [0, 7, 21, 23, 28], "futur": [0, 1, 2, 7, 15, 23], "real": [0, 1, 7, 23], "life": [0, 7], "twist": [0, 7], "humour": [0, 7], "whenev": [0, 2, 7], "possibl": [0, 1, 2, 7, 11, 12, 13, 14, 20, 24, 29], "outcom": [0, 1, 3, 7], "certain": [0, 7, 29], "offens": [0, 7], "diagram": [0, 7], "spent": [0, 7], "week": [0, 7, 29], "creat": [0, 1, 3, 22, 24], "three": [0, 1, 3, 7, 14, 21, 29], "four": [0, 7, 23], "sentenc": [0, 7, 23], "effort": [0, 1, 4, 7, 11, 24, 27], "consid": [0, 7, 13, 22], "worthwhil": [0, 7], "intent": [0, 7], "achiev": [0, 1, 7], "nitti": [0, 7], "gritti": [0, 7], "confid": [0, 1, 2, 7], "case": [0, 1, 3, 7, 24], "gradual": [0, 7, 15], "realis": [0, 7], "hint": [0, 7, 14, 20, 23], "perhap": [0, 7, 10, 23, 24, 25], "assum": [0, 1, 2, 7, 20, 26], "commun": [0, 2, 3, 7, 13, 25, 27, 28, 29], "class": [0, 1, 7, 12, 20], "now": [0, 3, 4, 7, 13, 15, 18, 20, 22, 23], "rememb": [0, 1, 3, 7, 23], "observ": [0, 5, 7, 8, 10], "peopl": [0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 15, 17, 18, 20, 22, 23, 24, 25, 26, 27, 29], "puzzl": [0, 7], "while": [0, 1, 5, 7, 12, 14, 20, 23, 29], "obviou": [0, 7, 20, 23, 29], "believ": [0, 1, 7, 18], "helper": [0, 5, 7, 8, 10, 15, 20, 22, 25, 27, 28], "faster": [0, 7, 20, 29], "least": [0, 1, 7, 13, 29], "sure": [0, 1, 7, 20, 23, 24, 29], "sit": [0, 7, 22], "alon": [0, 7, 11, 22, 25, 27], "ve": [0, 7, 11, 26, 29], "been": [0, 1, 3, 7, 11, 21, 23, 29], "rare": [0, 7], "teacher": [0, 1, 7, 21, 25, 26, 27, 28], "tend": [0, 7], "mentorship": [0, 6, 7], "long": [0, 1, 7, 9, 13, 20, 23, 24, 29], "ago": [0, 2, 3, 7], "weren": [0, 7], "combin": [0, 4, 7, 27, 29], "done": [0, 1, 7, 22, 23, 27], "friend": [0, 7], "independ": [0, 2, 3, 5, 7, 11, 14, 21, 25, 27], "studi": [0, 1, 6, 7], "correct": [0, 1, 7], "main": [0, 3, 7, 20, 22, 23, 29], "job": [0, 1, 3, 25], "support": [0, 2, 3, 7, 10, 28], "comput": [0, 1, 2, 3, 6, 11, 15, 23, 29], "infrastructur": [0, 2, 7, 11], "ground": [0, 7, 28], "problem": [0, 1, 2, 3, 7, 25, 29], "basic": [0, 3, 10, 20], "miss": [0, 1, 7, 20, 23, 24, 29], "off": [0, 7, 12, 18, 23, 24], "even": [0, 1, 3, 4, 7, 12, 14, 18, 21, 23], "should": [0, 1, 2, 3, 5, 6, 7, 13, 19, 20, 22, 23, 25, 29], "minim": [0, 7, 14, 20, 23, 27], "suffici": [0, 1, 2, 7], "everyth": [0, 1, 4, 7, 17, 20, 23, 25, 29], "perfectli": [0, 7, 21, 27], "technic": [0, 3, 6, 7], "twenti": [0, 7], "year": [0, 1, 2, 3, 4, 7], "henc": [0, 7], "toward": [0, 2, 7], "hand": [0, 2, 7, 11, 25, 29], "abil": [0, 6, 7, 26], "capabl": [0, 3, 7, 22], "team": [0, 3, 5, 8, 11, 20, 27, 28], "requir": [0, 3, 7, 10, 13, 19, 20, 27, 28, 29], "essenti": [0, 1, 7, 13, 14], "domain": [0, 1, 7], "willing": [0, 7], "stuck": [0, 7, 20], "call": [0, 1, 7, 10, 20], "ksa": [0, 7], "attitud": [0, 7], "impart": [0, 7], "And": [0, 7, 20, 23, 25], "challeng": [0, 1, 7, 15, 17, 21], "student": [0, 2, 3, 7, 10, 20, 21, 25, 27, 29], "overcom": [0, 7, 15, 17], "perceiv": [0, 7], "limit": [0, 3, 7, 13, 14, 20, 22, 29], "humanist": [0, 7], "python": [0, 7, 23, 29], "virtualenv": [0, 7], "cognit": [0, 7], "return": [0, 7], "There": [0, 1, 7, 12, 14, 20, 23], "compon": [0, 7], "storytel": [0, 7], "human": [0, 1, 7], "neurolog": [0, 7], "made": [0, 7, 22, 26, 28, 29], "pai": [0, 7], "attent": [0, 7, 10], "put": [0, 1, 4, 7, 29], "account": [0, 7, 19], "relev": [0, 1, 3, 5, 7, 11, 25, 27], "narr": [0, 7], "draw": [0, 7], "creativ": [0, 7], "handwrit": [0, 7], "reckon": [0, 7], "architectur": [0, 7], "big": [0, 7], "pictur": [0, 7, 20], "invest": [0, 7], "semant": [0, 7], "tree": [0, 7], "negoti": [1, 7], "minimum": [1, 3, 7, 13, 29], "minut": [1, 3, 12, 17, 19, 20, 29], "breakout": [1, 4, 5, 7, 8, 14, 19, 22, 23, 24, 28], "short": [1, 2, 5, 7, 17, 21, 23, 29], "expect": [1, 3, 7, 14, 20, 21, 23, 24, 26, 29], "intro": [1, 7, 9, 13, 14, 15, 17, 23, 29], "speed": [1, 2, 3, 7], "Not": [1, 7, 10], "accomplish": [1, 7, 20], "5": [1, 19, 20, 21, 22, 29], "stuff": [1, 2, 7], "wrong": [1, 7], "depend": [1, 7, 12, 23], "ok": [1, 7, 23], "cut": [1, 7, 23], "reserv": [1, 5, 7], "readi": [1, 3, 7, 23, 29], "run": [1, 3, 5, 8, 11, 20, 28], "environ": [1, 23, 25, 26], "match": [1, 7, 20, 21], "screen": [1, 3, 19, 23], "termin": [1, 7, 12], "histori": [1, 7, 20], "portion": [1, 7], "remot": [1, 3, 7, 23], "alreadi": [1, 2, 3, 4, 7], "prerequisit": [1, 7, 23], "Or": [1, 6, 7], "instal": [1, 3, 23], "configur": [1, 6, 7], "manag": [1, 7, 10, 22, 28, 29], "sad": [1, 7], "special": [1, 7, 10, 29], "deliv": [1, 5, 7], "onlin": [1, 2, 8, 11, 12, 13, 14, 21, 25], "organ": [1, 4, 7, 8, 18, 19, 21, 22, 28], "overview": [1, 2, 15, 17, 25, 28, 29], "complet": [1, 2, 25], "section": [1, 2, 3, 6, 7, 18, 19, 21, 23], "deriv": [1, 2], "further": [1, 9], "later": [1, 5, 7, 17, 19, 20, 23, 24, 29], "2": 1, "dai": [1, 7, 12, 22, 23, 27, 28, 29], "intructor": 1, "respect": 1, "inclus": [1, 11, 25], "reli": [1, 7, 21], "conduct": 1, "improv": [1, 2, 7, 11, 13, 14, 19, 29], "reinforc": 1, "daili": 1, "within": [1, 7, 12, 14, 21, 22, 23, 24], "15": [1, 7, 15, 23], "group": [1, 3, 6, 11, 14, 19, 20, 21, 22, 25], "method": [1, 3], "bi": [1, 8], "direct": [1, 2], "To": [1, 23, 29], "clarif": 1, "instanc": 1, "add": [1, 12, 24, 27], "through": [1, 2, 3, 7, 10, 17, 20, 22, 23], "contrast": [1, 29], "judg": 1, "reach": [1, 14], "accept": [1, 2, 29], "level": [1, 2, 3, 8, 14, 28], "either": [1, 3, 8, 11, 21, 22], "pass": [1, 13], "fail": [1, 12, 29], "One": [1, 2, 5, 20, 21, 22], "drive": 1, "exam": 1, "tell": 1, "rest": [1, 7, 18, 23], "societi": 1, "someon": [1, 3, 7, 13, 15, 20, 23, 25], "safe": 1, "road": 1, "univers": [1, 2, 5, 29], "assign": [1, 22, 29], "grade": 1, "fanci": 1, "term": [1, 9], "activ": [1, 2, 3, 7, 10, 21], "provid": [1, 2, 3, 5, 7, 8, 15, 17, 20, 23, 24, 25], "refocu": 1, "respond": [1, 7, 10], "continu": [1, 8, 11, 29], "mechan": [1, 10, 25, 29], "music": 1, "plai": 1, "scale": [1, 3, 4, 20, 21], "breath": 1, "correctli": 1, "happen": [1, 3, 4, 5, 22, 23, 24], "frequent": 1, "ll": 1, "talk": [1, 7, 13, 17, 23], "result": [1, 2, 4, 7, 15, 17, 23], "interpret": 1, "instrument": 1, "survei": [1, 2, 7], "pre": [1, 2, 11, 22, 29], "post": [1, 2], "poll": 1, "necessarili": 1, "multipl": [1, 20, 29], "choic": [1, 7, 13, 19, 23], "initi": [1, 4, 7, 23], "build": [1, 2, 13, 25], "exist": [1, 3, 5, 7], "uniqu": 1, "choos": [1, 3, 7, 21], "suitabl": [1, 27], "accommod": 1, "everyon": [1, 4, 7, 11, 22, 23], "posit": [1, 7], "v": [1, 7, 23, 24], "neg": [1, 7], "content": [1, 4, 7, 13, 15, 23, 29], "present": [1, 2, 4, 6, 7, 19, 20, 23, 27, 29], "rubric": [1, 7, 19], "aim": [1, 2, 7], "As": [1, 3, 7, 11, 18, 26, 28], "video": [1, 11, 19, 28, 29], "ax": [1, 7], "2x2": [1, 7], "grid": [1, 7], "whiteboard": [1, 7], "hackmd": [1, 4, 11, 13, 14, 18, 21, 23, 25, 27, 28], "etherpad": [1, 7], "googl": [1, 6, 7], "doc": [1, 6, 7], "without": [1, 7, 12, 13, 22], "duplic": [1, 7, 11, 27], "event": [1, 7, 22, 24, 27], "4": [1, 19], "per": [1, 4, 7, 22, 23, 29], "facilit": [1, 7], "Then": [1, 3, 7, 29], "report": [1, 7], "strongli": [1, 7, 22], "agre": [1, 7], "disagre": [1, 7], "first": [1, 3, 4, 7, 8, 13, 17, 23, 29], "task": [1, 3, 7, 19], "figur": [1, 3, 7, 29], "patricia": 1, "benner": 1, "dreyfu": 1, "acquisit": [1, 3], "her": [1, 3], "nurs": 1, "book": [1, 3, 15, 24], "indic": [1, 23], "formal": 1, "acquir": 1, "distinct": [1, 3], "stage": 1, "doesn": [1, 7, 10, 13, 20, 22, 29], "yet": [1, 2, 6, 7, 8, 14, 21, 22, 23, 26, 28], "idea": [1, 2, 3, 7, 8, 13, 20, 24], "aren": [1, 7, 11, 23, 27], "heard": 1, "bash": 1, "shell": [1, 3, 7, 19], "therefor": 1, "file": [1, 3, 13], "system": [1, 3, 6, 7, 13, 20, 22, 29], "execut": 1, "headless": 1, "mode": [1, 10, 23, 29], "queue": 1, "directli": [1, 7, 8, 18, 23, 24, 29], "login": [1, 3], "enough": [1, 3, 20, 22, 23, 25, 29], "everydai": 1, "purpos": [1, 20], "won": [1, 3, 7, 18, 23], "detail": 1, "accur": [1, 23], "normal": [1, 29], "under": [1, 13, 25, 28, 29], "circumst": [1, 11], "move": [1, 3, 21, 23], "around": [1, 4, 8, 29], "directori": [1, 7, 23], "fit": 1, "togeth": [1, 3, 4, 11, 15, 20, 22, 25, 29], "autom": 1, "he": [1, 3], "she": [1, 3], "benefit": [1, 5, 7, 20, 25, 27, 29], "doe": [1, 2, 7, 10, 12, 21, 29], "fulli": [1, 14], "project": [1, 3, 11, 13], "cluster": [1, 3], "submit": [1, 2, 3], "optim": 1, "amount": [1, 3, 4, 11, 28], "resourc": [1, 3, 11, 14, 25], "setup": [1, 11, 19, 20], "parallel": [1, 3, 10, 23, 27], "handl": [1, 29], "ordinari": 1, "immedi": [1, 7, 10, 23, 24, 29], "process": [1, 5, 7, 23], "goe": 1, "creation": 1, "found": 1, "collect": [1, 2, 7, 13, 20, 23, 25], "relationship": 1, "resid": 1, "unit": 1, "state": [1, 3, 14, 20], "locat": [1, 4, 22], "major": [1, 2, 6, 25], "citi": 1, "landmark": 1, "weather": 1, "pattern": 1, "region": 1, "economi": 1, "demograph": [1, 6], "among": [1, 6, 7, 12, 27, 28], "compar": [1, 4, 10, 12, 20, 29], "countri": [1, 2, 5, 29], "complex": [1, 3], "distinguish": 1, "built": [1, 26], "guesswork": 1, "borrow": 1, "piec": [1, 3, 24], "superfici": 1, "averag": [1, 4], "driver": 1, "car": 1, "probabl": [1, 2, 7, 19, 23], "engin": [1, 2, 13], "concern": 1, "mixtur": 1, "hardli": 1, "ever": 1, "scratch": [1, 24], "everi": [1, 12, 29], "opinion": 1, "true": [1, 13], "articul": [1, 2], "prior": [1, 2], "belief": 1, "incomplet": 1, "inaccur": 1, "misconcept": 1, "imped": 1, "incorpor": 1, "broadli": 1, "speak": [1, 14, 21, 23], "fall": [1, 7, 19], "categori": 1, "factual": 1, "vancouv": 1, "capit": 1, "british": 1, "columbia": 1, "These": [1, 2, 17, 23], "easiest": 1, "broken": 1, "motion": 1, "acceler": 1, "must": [1, 3, 7, 10, 20, 23], "address": [1, 2], "contradict": 1, "fundament": 1, "thousand": 1, "old": [1, 15, 20, 29], "beings": 1, "cannot": [1, 3], "affect": [1, 25], "planet": 1, "climat": [1, 3], "deepli": 1, "social": [1, 6], "ident": [1, 25], "hardest": 1, "current": [1, 3, 7, 8, 11, 13, 23, 27], "procedur": [1, 13], "inherit": 1, "lack": [1, 3], "depth": [1, 17], "leaner": [1, 7], "leasson": [1, 7], "wiggin": 1, "mctigh": 1, "firmli": 1, "determin": [1, 26], "decid": [1, 4], "constitut": 1, "evid": [1, 15, 17], "met": 1, "sort": 1, "increas": [1, 7, 10, 29], "capentri": 1, "framework": 1, "discret": [1, 2], "hierarch": 1, "gone": 1, "educ": [1, 3, 21], "remain": 1, "particular": [1, 3, 11, 21], "hierarchi": 1, "valid": [1, 7, 10, 13], "masteri": 1, "bottom": [1, 7, 21], "meet": [1, 4, 8, 14, 24, 29], "grow": [1, 13], "recogn": 1, "growth": 1, "ahead": 1, "imag": 1, "credit": [1, 8, 13], "vanderbilt": 1, "center": 1, "review": [1, 7, 10, 12, 23, 24], "carefulli": 1, "scan": [1, 7, 21], "promis": [1, 4], "verifi": [1, 29], "anticip": 1, "teach": [2, 3, 5, 6, 8, 9, 10, 12, 13, 14, 15, 23, 25], "intermedi": 2, "network": [2, 3, 8, 11, 25, 29], "publicli": 2, "fund": [2, 8], "3": [2, 10, 21, 29], "actual": [2, 7, 13, 14, 23, 29], "transit": [2, 22, 23], "nordic": [2, 4], "collabor": [2, 5, 8, 10, 11, 12, 13, 18, 19, 20, 25, 27], "neic": 2, "octob": 2, "2016": 2, "until": [2, 20], "februari": 2, "2025": 2, "2022": [2, 4, 8, 10], "design": [2, 8, 13, 15, 17, 19, 29], "beyond": 2, "form": [2, 3, 13, 22, 25], "contributor": [2, 8, 13], "grew": 2, "sese": 2, "kth": 2, "stockholm": 2, "2014": 2, "nu": 2, "scientif": [2, 7, 23, 29], "toolbox": 2, "propos": [2, 12], "2015": 2, "port": 2, "format": [2, 4, 7, 13, 19, 25, 28], "iter": [2, 27], "maintain": [2, 13, 27, 29], "disciplin": 2, "tri": [2, 3, 5, 14, 18], "repositori": [2, 29], "host": [2, 4, 13, 28, 29], "servic": [2, 8, 10], "free": 2, "institut": [2, 3, 8, 11, 29], "implement": [2, 22, 26], "sustain": [2, 8, 25], "measur": 2, "6": [2, 3, 29], "month": [2, 3], "attend": [2, 3, 7, 14, 23, 24, 25, 28, 29], "overal": [2, 3, 23], "qualiti": [2, 23], "reusabl": 2, "modular": 2, "reproduc": 2, "easier": [2, 10, 12, 20, 24, 27], "colleagu": [2, 3, 4, 7, 29], "usag": 2, "adopt": [2, 11], "suggest": [2, 3, 7, 13], "effect": [2, 14, 20, 21], "common": [2, 7, 10, 13, 21, 28], "theme": [2, 13], "wish": [2, 5], "grad": 2, "10": [2, 12, 23, 29], "quantifi": 2, "convinc": 2, "partner": [2, 5, 27], "theoret": 2, "gener": [2, 5, 8, 12, 14, 15, 17, 21, 25], "favor": 2, "awar": 2, "By": [2, 14, 23, 24], "qualifi": 2, "typic": [2, 3, 7, 12, 13, 19, 28, 29], "version": [2, 3, 4, 11], "control": [2, 11, 25], "git": [2, 9, 13, 17], "high": [2, 3, 4, 7, 23], "conceptu": 2, "jupyt": 2, "etc": [2, 3, 9, 12, 23, 28, 29], "difficulti": [2, 20, 22, 26, 27], "workflow": [2, 7, 13, 23], "defin": [2, 3, 5, 23, 29], "produc": [2, 7, 20, 23], "ship": 2, "far": [3, 27], "earlier": 3, "critic": [3, 6, 26], "widespread": 3, "number": [3, 10, 11, 14, 20, 21, 22, 25, 29], "cool": 3, "press": 3, "90": [3, 29], "instead": [3, 5, 7, 12, 14, 20, 23, 27, 29], "expos": 3, "technologi": [3, 6, 7, 26], "prefer": [3, 7, 12, 13, 15, 17, 19, 24], "divers": [3, 11, 25, 29], "reduc": [3, 11, 20, 27, 29], "bias": 3, "clarifi": 3, "concret": 3, "potenti": 3, "analyz": 3, "evalu": [3, 19], "sequenc": [3, 23], "test": [3, 13], "increment": 3, "gap": 3, "tech": [3, 11, 15, 20], "brainstorm": [3, 7, 18], "rough": 3, "summ": 3, "assess": [3, 21], "coderefineri": [3, 10, 11, 12, 14, 15, 18, 20, 21, 22, 23, 24, 25, 28], "translat": [3, 7, 18, 23], "simpler": 3, "mayb": 3, "emphas": [3, 29], "let": [3, 20, 22, 23, 25, 27], "phd": 3, "postdoc": 3, "young": 3, "proper": 3, "definit": [3, 7, 23], "variou": [3, 20], "avail": [3, 4, 7, 20, 23, 25, 29], "paradigm": 3, "multi": [3, 29], "thread": [3, 20], "data": [3, 7, 23, 27], "box": 3, "multiprocess": 3, "gpu": 3, "dataset": 3, "larger": [3, 4, 13, 21], "memori": 3, "strategi": [3, 14, 18, 20, 27], "sonya": 3, "1st": 3, "oslo": 3, "join": [3, 11, 14, 29], "neurosci": 3, "nest": 3, "simul": [3, 7, 23], "spike": 3, "neural": 3, "model": [3, 5, 11, 21, 27], "thesi": 3, "small": [3, 4, 8, 12, 13, 14, 20, 27, 28], "excit": 3, "robert": 3, "field": [3, 22, 29], "ecologist": 3, "obtain": 3, "hi": 3, "scientist": 3, "consequ": 3, "global": 3, "command": [3, 7, 23], "line": [3, 7, 12, 23], "terrifi": 3, "extens": [3, 12, 13, 21, 27], "rather": 3, "jessica": 3, "investig": 3, "numer": 3, "aris": 3, "tip": [3, 20], "fluid": 3, "driven": 3, "ruptur": 3, "finit": 3, "element": 3, "compress": 3, "navier": 3, "stoke": 3, "equat": 3, "mesh": 3, "librari": 3, "mostli": [3, 29], "ran": 3, "local": [3, 4, 5, 7, 8, 13, 22, 27, 29], "desktop": 3, "due": 3, "keen": 3, "machin": 3, "notion": 3, "core": 3, "node": 3, "distribut": [3, 7, 11, 19], "schedul": [3, 4, 7, 23, 28], "appropri": 3, "optimis": 3, "o": [3, 6, 7, 23], "filesystem": 3, "access": [3, 6, 10, 11, 29], "oper": 3, "meant": 3, "cpu": 3, "laptop": [3, 12], "output": 3, "gromac": 3, "logic": [3, 7], "pick": [3, 7, 19], "regular": [3, 7], "express": [3, 7], "paper": [3, 7, 17], "latex": [3, 7], "favorit": [3, 7], "linux": [3, 7, 23], "non": [3, 4, 7, 8], "paint": [3, 7], "introduct": [3, 7, 20, 23, 29], "perform": [3, 7, 19], "therein": [3, 7], "unix": [3, 7], "covid": [4, 27], "19": [4, 27], "were": [4, 11, 23, 29], "physic": [4, 22, 29], "travel": 4, "maximum": 4, "size": [4, 22, 25, 29], "40": [4, 29], "workload": [4, 21], "attempt": 4, "livestream": [4, 5, 11, 22, 23, 24, 28], "staff": [4, 6, 22, 23, 25, 27], "regist": [4, 29], "instant": [4, 24, 29], "replai": [4, 24], "page": [4, 7, 13, 21, 23], "github": [4, 7, 10, 12, 13, 14, 18, 21, 22, 23, 24, 28, 29], "io": [4, 7, 10, 12, 14, 18, 21, 22, 23, 24, 28], "03": [4, 7, 10, 23], "22": [4, 10], "aalto": [4, 7, 23, 29], "asc": [4, 23], "came": [4, 19], "vision": [4, 11, 27], "announc": [4, 29], "invit": [4, 14], "went": [4, 29], "refin": 4, "date": 4, "registr": [4, 5, 22, 28, 29], "via": [4, 5, 13, 14, 25, 28, 29], "kept": 4, "track": [4, 13], "2021": 4, "scicomp": [4, 7, 23], "fi": [4, 7, 23], "scip": [4, 7, 23], "aaltoscicomp": [4, 7, 23], "techniqu": [4, 7, 18], "littl": [5, 13, 25, 29], "cost": [5, 13, 24], "risk": [5, 14, 23, 24], "mentor": [5, 6, 11], "intens": [5, 15], "possibli": [5, 6, 7, 9, 20, 27, 29], "invent": [5, 7, 11, 23], "reward": 5, "successfulli": 5, "stream": [5, 7, 14, 23, 24, 25], "coordin": [5, 12, 20, 22, 27, 28, 29], "duti": 5, "role": [5, 6, 10, 11, 14, 22, 23, 26], "fill": [6, 26], "un": 6, "involv": [6, 15, 22], "asoci": 6, "unfortun": 6, "imbal": 6, "demotiv": 6, "equiti": 6, "leader": [6, 22, 27, 28], "richard": 6, "darst": 6, "z1vs1wlen": 6, "2pacx": 6, "1vqkzomfi5sfnx69d4qrq_3n": 6, "mtcv7gubpzd4a6uypekzumgk0fl5w0rsse6alzxv1ne635yl1gpyckk": 6, "pub": 6, "summari": [6, 15, 17], "quickli": [6, 7, 21, 22, 23, 28, 29], "serv": [6, 13, 28, 29], "equal": [6, 7, 14, 23], "modern": [6, 25], "none": [6, 21, 26, 28], "mainli": [7, 20], "refer": 7, "automat": 7, "singl": 7, "cover": [7, 17], "subset": 7, "md": 7, "advantag": [7, 12, 18, 20, 29], "disadvantag": [7, 18, 20, 22, 29], "rst": [7, 13], "divid": [7, 21], "min": [7, 15, 21], "anywai": [7, 21, 27, 29], "integr": [7, 10], "itself": [7, 10, 13, 17, 26], "occasion": [7, 10], "mention": [7, 9, 10], "screenshar": [7, 10, 14], "balanc": [7, 10], "decreas": [7, 10], "screenshot": [7, 12], "trade": [7, 12, 18], "download": [7, 23], "user": [7, 15, 17, 23, 26], "darstr1": [7, 23], "kickstart": [7, 23], "2023": [7, 23], "mkv": [7, 23], "srt": [7, 23], "11": [7, 23], "35": [7, 15, 23], "12": [7, 23], "25": [7, 23], "descript": [7, 10, 14, 22, 23, 24], "abov": [7, 10, 23, 26, 29], "slice": [7, 23], "segment": [7, 19, 23], "left": [7, 12, 18, 22, 23], "reader": [7, 23], "devic": [7, 23], "cuda": [7, 23], "output_format": [7, 23], "initial_prompt": [7, 23], "welcom": [7, 8, 11, 23], "lang": [7, 23], "en": [7, 23], "condition_on_previous_text": [7, 23], "fals": [7, 23], "input": [7, 23], "prompt": [7, 23], "full": [7, 10, 23], "punctuat": [7, 23], "instruct": [7, 20, 21, 23, 24, 28, 29], "storag": [7, 23], "scienc": [7, 15, 23, 27], "said": [7, 23, 26], "record": [7, 11, 13, 23], "timestamp": [7, 23], "origin": [7, 13, 23], "day1": [7, 23], "part1": [7, 23], "titl": [7, 23], "00": [7, 23], "excerpt": [7, 23], "24": [7, 23], "37": [7, 23], "31": [7, 23], "extern": [7, 23], "lead": [7, 8, 23, 25, 27], "scicompintro": [7, 23], "43": [7, 23], "50": [7, 19, 23], "05": [7, 23], "pip": [7, 23], "virtual": [7, 21, 23], "path": [7, 23], "contain": [7, 23, 29], "quick": [7, 23, 29], "garbl": [7, 23], "second": [7, 13, 19, 23], "kei": [7, 15, 17, 23], "frame": [7, 23], "fix": [7, 23], "reencod": [7, 23], "encod": [7, 23], "info": [7, 18, 23], "txt": [7, 23], "chapter": [7, 23], "didn": [7, 14, 23, 29], "hpc": [7, 23], "summer": [7, 11, 23], "07": [7, 23], "lost": [7, 13, 23, 24], "plzlvms9rf3nmkr2jmglan4su3ojwtwmvw": [7, 23], "webpag": [7, 23, 29], "necessari": [7, 23], "editor": [7, 23, 28], "transcript": [7, 23], "align": [7, 23], "black": [7, 23], "adjust": [7, 22, 23], "outsid": [7, 11, 12, 23], "Be": [7, 23, 25, 29], "pyyaml": [7, 23], "modifi": [7, 23], "dead": [7, 23], "desir": [7, 23], "tabl": [7, 22, 23], "16": [7, 23], "demonstr": [7, 19, 23, 29], "04": [7, 23], "item": [7, 27], "histogram": [7, 28], "underli": [7, 26], "abstract": 7, "layer": 7, "imposs": [7, 12, 22, 26], "otherwis": [7, 10, 23, 26], "brows": [7, 13], "function": [7, 13], "sphinx": [7, 13], "yml": [7, 13], "conf": [7, 13], "py": [7, 13], "index": [7, 13], "signific": [7, 13, 21], "pure": [7, 13, 29], "templat": [7, 13, 29], "altern": [7, 13], "02": 7, "listen": [7, 19, 20], "construct": [7, 13, 19], "verbal": [7, 19], "conclus": [7, 19], "round": [7, 19], "receiv": [7, 14, 19, 27, 28], "trial": [7, 19, 20], "art": [7, 19], "pitfal": [7, 9, 19], "sooner": [7, 19], "close": [7, 14, 19, 20], "action": [8, 13], "taken": 8, "market": 8, "outreach": [8, 28], "visibl": 8, "promot": [8, 13, 25], "member": 8, "profit": 8, "sell": 8, "chat": [8, 10, 20, 21, 28, 29], "offici": 8, "advertis": [8, 28, 29], "unconfer": 8, "weekli": 8, "contribut": 9, "name": [10, 22, 23, 29], "justic": 10, "nor": 10, "replac": [10, 13, 15], "random": 10, "2d": 10, "web": [10, 13], "markdown": 10, "scalabl": 10, "privaci": [10, 14, 23, 29], "view": [10, 14, 29], "manual": [10, 12, 14, 15, 18, 20, 21, 22, 23, 24, 28], "publish": [10, 28], "six": 10, "hour": [10, 23, 24], "synchron": 10, "quiet": [10, 20, 29], "anonym": [10, 20, 29], "q": [10, 15], "scroll": [10, 23], "unansw": 10, "flood": 10, "warn": [10, 20], "deliber": 10, "comfort": 10, "rework": 11, "carpentrycon": 11, "longer": [11, 21], "autumn": 11, "2020": [11, 29], "farther": 11, "offic": 11, "closer": 11, "huge": [11, 13], "2019": 11, "obsolet": 11, "silo": 11, "socio": 11, "factor": [11, 23], "barrier": [11, 27], "profess": 11, "specialti": 11, "again": [11, 13], "specialist": 11, "frustrat": 11, "thu": [11, 14, 21, 22], "comprehens": 11, "kick": [11, 27], "edit": [11, 24, 28, 29], "usabl": 11, "placehold": 11, "backward": [11, 13], "philosophi": 11, "portrait": 12, "layout": [12, 17, 20], "readabl": 12, "beauti": 12, "fullhd": 12, "latest": 12, "half": [12, 20], "distract": [12, 20], "notebook": 12, "font": [12, 20, 25], "shortcut": 12, "scheme": 12, "remov": [12, 18, 23, 24], "late": [12, 23], "pro": 12, "con": 12, "paus": 12, "catch": [12, 20, 23, 24], "modif": 13, "trivial": 13, "sourc": 13, "platform": [13, 24], "option": [13, 20, 22, 23], "store": 13, "raw": [13, 24], "websit": 13, "compil": 13, "convert": 13, "html": 13, "public": [13, 27], "complier": 13, "r": 13, "standard": 13, "ecosystem": 13, "reus": 13, "exact": 13, "licens": 13, "incent": [13, 23, 24], "wide": [13, 21], "citabl": 13, "doi": 13, "commit": 13, "accompani": 13, "branch": 13, "substanti": 13, "rewrit": 13, "draft": 13, "greatli": [14, 29], "awkward": 14, "unlimit": 14, "shy": 14, "passiv": 14, "effici": 14, "extra": [14, 27, 29], "meaning": 14, "mooc": 14, "broadcast": [14, 28], "crash": 14, "presenc": 14, "twitch": [14, 29], "disrupt": 14, "troll": 14, "enabl": 14, "loud": 14, "extrovert": 14, "domin": 14, "captur": 14, "zoom": [14, 20, 22, 24, 25], "switch": 14, "galleri": [14, 29], "dedic": [14, 29], "chanc": 14, "violat": 14, "b": 14, "c": [14, 27], "link": [14, 25], "pathwai": 15, "focus": [15, 20, 29], "curriculum": 15, "handbook": 15, "organiz": 15, "phil": [15, 17], "agr": [15, 17], "bad": [15, 17, 19, 20, 26, 29], "interfac": [15, 17, 26], "brief": [15, 17, 23], "broad": 17, "ones": 17, "unless": 17, "obvious": 17, "low": [17, 24, 25], "prioriti": [17, 23], "wors": [18, 20], "suffer": [18, 25], "reveal": 18, "flaw": 18, "pedagogi": 18, "dump": 18, "elabor": 18, "somehow": [18, 22], "unnecessari": 20, "weird": 20, "save": 20, "harder": [20, 22, 29], "rewind": 20, "orient": 20, "whole": [20, 22, 23, 24, 29], "properti": [20, 22], "window": 20, "whatev": 20, "comment": [20, 25], "s1": 20, "s2": 20, "s3": 20, "s4": 20, "smaller": [20, 25], "anyth": [20, 23, 24], "constrict": 20, "vertic": 20, "displai": 20, "side": 20, "commentari": 20, "pressur": [20, 24], "forget": [20, 23], "introduc": [20, 28, 29], "unfamiliar": 20, "repli": [20, 29], "overload": [20, 27], "turn": 20, "tomorrow": 20, "manula": 20, "five": [20, 29], "prep": [20, 29], "improvemest": 21, "wikipedia": 21, "divis": 21, "labor": 21, "1": [21, 27], "strong": 21, "strength": 21, "strictli": 21, "voic": [21, 24, 29], "quicker": 21, "unexpect": 21, "act": 21, "onboard": [21, 28], "uncertainti": 21, "realiti": 21, "interview": 21, "primarili": 21, "space": 22, "nearbi": 22, "aka": 22, "stai": [22, 29], "uptak": 22, "higher": 22, "renam": 22, "n": [22, 29], "select": [22, 29], "indico": 22, "mail": 22, "messag": 22, "drop": 22, "partwai": 22, "natuar": 22, "arrang": 22, "manner": 22, "explicitli": 22, "ensur": 22, "crowd": 22, "deal": 22, "themselv": [22, 29], "deleg": 22, "releas": [23, 27], "hypothesi": 23, "perfect": 23, "principl": 23, "guarante": [23, 24, 29], "disclaim": [23, 24], "sai": [23, 24, 25, 27], "accid": [23, 24], "audio": [23, 24], "unprocess": [23, 24], "No": 23, "split": [23, 24, 28], "chunk": 23, "jump": 23, "spot": 23, "crowdsourc": 23, "20": [23, 29], "ob": 23, "cleanli": 23, "hover": 23, "mous": 23, "cursor": 23, "area": 23, "stick": 23, "advoc": 23, "flowchat": 23, "worth": 23, "thvmntbjg2y": 23, "_cobn": 23, "n2ak": 23, "afterward": 24, "cmp": 24, "ing": 24, "sth": 24, "soon": 24, "central": 24, "inspir": 25, "indirectli": 25, "luci": 25, "whallei": 25, "gave": [25, 27], "stack": 25, "overflow": 25, "bank": 25, "freeli": 25, "impress": 25, "signpost": 25, "impost": 25, "syndrom": 25, "disproportion": 25, "repres": 25, "manifest": 25, "kind": [25, 29], "silent": 25, "volum": 25, "librarian": 26, "net": 26, "stax": 26, "4965": 26, "terribl": 26, "fault": 26, "forgotten": 26, "despit": 27, "led": 27, "eventu": 27, "fair": 27, "heavili": 27, "emphazis": 27, "mass": 27, "previous": 27, "board": 27, "scari": 27, "tune": 27, "sync": 27, "revert": 27, "massiv": 28, "varieti": 28, "updat": [28, 29], "lower": 28, "top": 28, "sub": 28, "spare": [28, 29], "rotat": [28, 29], "director": 28, "ey": 28, "primari": 29, "condens": 29, "100": 29, "total": 29, "250": 29, "max": 29, "recruit": 29, "march": 29, "toler": 29, "ethic": 29, "featur": 29, "static": 29, "across": 29, "power": 29, "email": 29, "firstnam": 29, "lastnam": 29, "h": 29, "former": 29, "stress": 29, "overlap": 29, "shouldn": 29, "wen": 29, "written": 29, "lose": 29, "loss": 29, "tv": 29, "viewer": 29, "archiv": 29, "14": 29, "hundr": 29, "streamer": 29, "spotlight": 29, "dual": 29, "monitor": 29, "verif": 29, "haven": 29, "log": 29, "whelm": 29, "ourselv": 29, "techniquess": 29, "rapid": 29, "shortli": 29}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"coderefineri": [0, 1, 2, 4, 7, 8, 13, 17, 29], "teach": [0, 1, 4, 7, 11, 17, 18, 19, 20, 21, 26, 27, 28, 29], "philosophi": [0, 7], "ic": [0, 7], "breaker": [0, 7], "group": [0, 7], "20": [0, 7, 17], "minut": [0, 7], "video": [0, 7, 23, 24], "record": [0, 24, 29], "ann": [0, 7], "fouilloux": [0, 7], "bj\u00f8rn": [0, 7], "lindi": [0, 7], "thor": [0, 7], "wikfeldt": [0, 7], "stefan": [0, 7], "negru": [0, 7], "radovan": [0, 7], "bast": [0, 7], "sabri": [0, 7], "razick": [0, 7], "juho": [0, 7], "lehtonen": [0, 7], "richard": [0, 7], "darst": [0, 7], "jo\u00e3o": [0, 7], "m": [0, 7], "da": [0, 7], "silva": [0, 7], "interact": [1, 7], "style": [1, 7], "what": [1, 7, 11, 20, 22, 23, 25, 26, 27], "ar": [1, 7, 26], "top": 1, "issu": 1, "new": 1, "instructor": [1, 7, 9, 12, 19, 25], "face": 1, "solut": [1, 7, 23], "The": [1, 3, 17], "carpentri": [1, 2, 3, 8], "approach": [1, 3], "thi": [1, 7, 11, 23, 25], "materi": 1, "kei": 1, "principl": 1, "On": 1, "import": [1, 24], "feedback": [1, 7, 19], "get": [1, 7, 11, 23, 25], "give": [1, 7, 25], "learner": [1, 7], "progress": 1, "summ": 1, "assess": 1, "form": 1, "option": [1, 7, 17, 19], "10": [1, 7], "mn": [1, 7], "who": [1, 11], "novic": [1, 2], "compet": [1, 2], "practition": [1, 2], "expert": 1, "cognit": 1, "develop": [1, 7, 11, 13], "mental": 1, "model": [1, 4, 7], "how": [1, 6, 7, 8, 12, 17, 20, 23, 26, 28], "knowledg": 1, "wai": [1, 27], "exercis": [1, 3, 4, 6, 7, 10, 12, 13, 14, 18, 19, 21, 22, 23, 26, 27, 28], "identifi": [1, 7], "profil": [1, 7], "curriculum": 1, "revers": 1, "instruct": 1, "design": [1, 3, 7, 11], "recommend": [1, 4, 7, 13], "hpc": [1, 3, 29], "work": 1, "learn": [1, 5, 13, 17], "object": [1, 20], "us": [1, 7, 17, 23, 26], "bloom": 1, "": [1, 8, 9], "taxonomi": 1, "write": 1, "effect": 1, "revisit": 1, "about": 2, "project": 2, "workshop": [2, 5, 7, 11, 17, 25, 28, 29], "keypoint": [2, 5, 8, 12, 24], "histori": [2, 12], "main": [2, 19], "goal": [2, 25], "impact": 2, "target": 2, "audienc": 2, "best": 2, "softwar": [2, 8], "practic": [2, 7, 19, 20], "whom": 2, "backward": [3, 7], "lesson": [3, 5, 7, 11, 13, 17], "process": 3, "exampl": [3, 12, 19], "an": 3, "topic": [3, 7], "collabor": [4, 7, 29], "python": 4, "scientif": 4, "comput": [4, 7, 17, 26], "list": [4, 7], "success": [4, 7], "failur": [4, 7], "co": [4, 7, 21], "distribut": [5, 23], "organ": [5, 11], "It": 5, "i": [5, 11, 24], "easier": 5, "join": [5, 8], "follow": 5, "than": [5, 24], "start": 5, "lead": 5, "from": 5, "larger": 5, "divers": [6, 7], "inclus": [6, 7], "primari": [6, 10, 14, 21, 22, 23, 28], "articl": [6, 10, 14, 21, 22, 23, 28], "support": 6, "servic": 6, "v": [6, 29], "reflect": [6, 7], "your": [6, 7, 12, 13, 23, 28, 29], "job": [6, 7], "can": [6, 7, 8], "defin": [6, 7], "promot": [6, 7], "see": [6, 13, 18, 20, 21, 23, 26, 27, 28], "also": [6, 13, 18, 20, 21, 23, 26, 27, 28], "onlin": [7, 18, 20, 22, 29], "team": [7, 21, 22, 29], "hackmd": [7, 10, 20, 29], "livestream": [7, 14], "advanc": [7, 13, 14], "set": [7, 12, 14], "up": [7, 11, 12, 14], "instal": [7, 14, 29], "ob": [7, 14], "tool": [7, 11, 13, 14, 25], "tech": [7, 12, 14], "setup": [7, 12, 24], "evalu": [7, 12], "screen": [7, 12, 20], "captur": [7, 12], "own": [7, 12, 13, 29], "environ": [7, 12], "edit": [7, 23], "1": [7, 19, 23], "sampl": [7, 13, 23], "2": [7, 19, 23], "run": [7, 23, 29], "whisper": [7, 23], "gener": [7, 13, 23, 29], "raw": [7, 23], "subtitl": [7, 23], "test": [7, 23], "3": [7, 23], "creat": [7, 13, 23], "basic": [7, 22, 23, 29], "editlist": [7, 23], "yaml": [7, 23], "file": [7, 23], "4": [7, 23], "ffmpeg": [7, 23], "5": [7, 17, 23], "add": [7, 23], "more": [7, 12, 23, 24], "featur": [7, 23], "6": [7, 23], "7": [7, 23], "final": [7, 23], "output": [7, 23], "why": [7, 20, 26, 27], "togeth": [7, 27], "similar": [7, 27], "do": [7, 22, 25, 27], "we": [7, 11, 22, 24, 25, 26, 27], "have": [7, 12, 27], "role": [7, 24, 28, 29], "mani": [7, 28], "peopl": [7, 28], "hard": [7, 26], "version": [7, 13], "control": [7, 13], "contribut": [7, 13], "possibl": 8, "plan": 8, "biggest": 8, "open": 8, "problem": 8, "you": 8, "asid": 8, "nordic": 8, "rse": 8, "research": 8, "engin": 8, "guid": 9, "advantag": [10, 27], "disadvantag": [10, 27], "commun": 11, "train": [11, 25, 29], "under": 11, "mid": 11, "2022": 11, "cours": 11, "cover": 11, "prepar": [11, 17, 29], "introduct": [11, 25], "social": 11, "technic": 11, "consider": 11, "wrap": 11, "futur": [11, 17], "involv": 11, "refer": 11, "old": 11, "content": [11, 17], "need": 11, "move": 11, "merg": 11, "screenshar": 12, "adjust": 12, "prompt": 12, "configur": 12, "color": 12, "should": 12, "forc": 12, "consist": 12, "share": [12, 20], "command": 12, "static": 13, "site": 13, "summari": [14, 23, 28], "detail": 14, "other": [15, 24, 29], "resourc": 15, "placehold": 16, "pre": 17, "read": [17, 26], "help": [17, 26], "someon": [17, 26], "min": 17, "brows": 17, "watch": 17, "35": 17, "onli": 17, "45": 17, "q": 17, "A": [17, 23], "15": 17, "scienc": 17, "demo": 19, "part": 19, "discuss": [19, 20, 22, 23, 29], "room": [19, 29], "two": 19, "live": 19, "code": [19, 25], "mechan": 20, "matter": 20, "shell": 20, "goe": 20, "good": 20, "demonstr": 20, "prototyp": 20, "meta": 20, "talk": 20, "question": 20, "benefit": 21, "strategi": [21, 29], "concept": 22, "In": 22, "person": [22, 29], "actual": 22, "make": 23, "easi": 23, "b": 23, "try": 24, "releas": 24, "same": 24, "dai": 24, "privaci": 24, "ani": 24, "factor": 24, "broadcast": 24, "welcom": 25, "want": 25, "out": 25, "confid": 25, "conduct": 25, "initi": 26, "phil": 26, "agr": 26, "usabl": 26, "deep": 26, "abstract": 26, "layer": 26, "conclus": 26, "challeng": 27, "manual": 29, "case": 29, "studi": 29, "mega": 29, "finland": 29, "kickstart": 29, "arrang": 29, "link": 29, "scale": 29, "platform": 29, "zoom": 29, "breakout": 29, "bring": 29, "helper": 29, "staff": 29, "stream": 29, "time": 29, "note": 29}, "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": {"CodeRefinery teaching philosophies": [[0, "coderefinery-teaching-philosophies"], [7, "coderefinery-teaching-philosophies"]], "Ice-breaker in groups (20 minutes)": [[0, "exercise-0"], [7, "exercise-0"]], "Video recordings": [[0, "prerequisites-0"]], "Anne Fouilloux": [[0, "exercise-1"], [7, "exercise-1"]], "Bj\u00f8rn Lindi": [[0, "exercise-2"], [7, "exercise-2"]], "Thor Wikfeldt": [[0, "exercise-3"], [7, "exercise-3"]], "Stefan Negru": [[0, "exercise-4"], [7, "exercise-4"]], "Radovan Bast": [[0, "exercise-5"], [7, "exercise-5"]], "Sabry Razick": [[0, "exercise-6"], [7, "exercise-6"]], "Juho Lehtonen": [[0, "exercise-7"], [7, "exercise-7"]], "Richard Darst": [[0, "exercise-8"], [7, "exercise-8"]], "Jo\u00e3o M. da Silva": [[0, "exercise-9"], [7, "exercise-9"]], "Interactive teaching style": [[1, "interactive-teaching-style"], [7, "interactive-teaching-style"]], "What are the top issues new instructors face?": [[1, "what-are-the-top-issues-new-instructors-face"]], "Solution": [[1, "solution-0"], [7, "solution-0"], [7, "solution-1"], [7, "solution-2"], [7, "solution-3"], [7, "solution-4"], [7, "solution-5"], [7, "solution-0"], [23, "solution-0"], [23, "solution-1"], [23, "solution-2"], [23, "solution-3"], [23, "solution-4"], [23, "solution-5"]], "The Carpentries and CodeRefinery approaches to teaching": [[1, "the-carpentries-and-coderefinery-approaches-to-teaching"]], "This material": [[1, "callout-0"]], "Key principles": [[1, "key-principles"]], "Carpentries teaching principles": [[1, "carpentries-teaching-principles"]], "On the importance of feedback": [[1, "on-the-importance-of-feedback"]], "Getting/giving feedback on learners\u2019 progress": [[1, "getting-giving-feedback-on-learners-progress"]], "Summative Assessment": [[1, "callout-1"]], "Formative assessment": [[1, "callout-2"]], "Getting/giving feedback on teaching": [[1, "getting-giving-feedback-on-teaching"]], "Give feedback on teaching (optional, 10 mn)": [[1, "exercise-0"], [7, "exercise-0"]], "Who are the learners": [[1, "who-are-the-learners"]], "Novices, competent practitioners and experts": [[1, "novices-competent-practitioners-and-experts"]], "Cognitive Development and Mental Models": [[1, "cognitive-development-and-mental-models"]], "How \u201cknowledge\u201d gets in the way": [[1, "how-knowledge-gets-in-the-way"]], "Exercise: How to identify learner profiles?": [[1, "exercise-1"], [7, "exercise-1"]], "CodeRefinery Curriculum and Reverse Instructional Design (with recommendations for HPC carpentries)": [[1, "coderefinery-curriculum-and-reverse-instructional-design-with-recommendations-for-hpc-carpentries"]], "Working with learning objectives": [[1, "working-with-learning-objectives"]], "Using Bloom\u2019s Taxonomy to write effective learning objectives": [[1, "using-bloom-s-taxonomy-to-write-effective-learning-objectives"]], "Revisiting Learning objectives": [[1, "revisiting-learning-objectives"]], "About the CodeRefinery project and CodeRefinery workshops": [[2, "about-the-coderefinery-project-and-coderefinery-workshops"]], "Keypoints": [[2, "keypoints-0"], [5, "keypoints-0"], [8, "keypoints-0"], [8, "keypoints-1"], [12, "keypoints-0"], [24, "keypoints-0"]], "History": [[2, "discussion-0"]], "Main goals": [[2, "main-goals"]], "Impact": [[2, "impact"]], "Target audience": [[2, "target-audience"]], "Carpentries audience": [[2, "carpentries-audience"]], "Novices": [[2, "callout-0"]], "CodeRefinery audience": [[2, "coderefinery-audience"]], "Competent practitioners": [[2, "callout-1"]], "Best software practices for whom?": [[2, "callout-2"]], "Backwards lesson design": [[3, "backwards-lesson-design"], [7, "backwards-lesson-design"]], "The approach": [[3, "the-approach"]], "The process": [[3, "the-process"]], "Example: designing an HPC Carpentry lesson": [[3, "discussion-0"]], "Exercises": [[3, "exercises"], [4, "exercises"], [6, "exercises"], [12, "exercises"], [13, "exercises"], [14, "exercises"], [21, "exercises"], [22, "exercises"], [23, "exercises"], [27, "exercises"], [28, "exercises"]], "Backwards-design a lesson/topic": [[3, "exercise-0"], [7, "exercise-0"]], "Collaboration models": [[4, "collaboration-models"], [7, "collaboration-models"]], "Model: CodeRefinery": [[4, "model-coderefinery"]], "Model: Python for Scientific Computing": [[4, "model-python-for-scientific-computing"]], "List successes and failures in collaborative teaching": [[4, "exercise-0"], [7, "exercise-0"]], "Recommendations for co-teaching": [[4, "exercise-1"], [7, "exercise-1"]], "Distributed workshop organization": [[5, "distributed-workshop-organization"]], "It is easier to join and follow than to start or lead": [[5, "it-is-easier-to-join-and-follow-than-to-start-or-lead"]], "Lessons learned from organizing larger workshops": [[5, "discussion-0"]], "Diversity and inclusion": [[6, "diversity-and-inclusion"], [7, "diversity-and-inclusion"]], "Primary articles": [[6, "primary-articles"], [10, "primary-articles"], [14, "primary-articles"], [22, "primary-articles"], [23, "primary-articles"], [28, "primary-articles"]], "Support services vs diversity": [[6, "support-services-vs-diversity"]], "Reflect on how your job can be defined to promote diversity.": [[6, "exercise-0"], [7, "exercise-0"]], "See also": [[6, "see-also"], [13, "see-also"], [18, "see-also"], [20, "see-also"], [21, "see-also"], [23, "see-also"], [26, "see-also"], [27, "see-also"], [28, "see-also"]], "Exercise list": [[7, "exercise-list"]], "Teaching online": [[7, "teaching-online"], [18, "teaching-online"]], "Exercise": [[7, "exercise-0"], [7, "exercise-0"], [7, "exercise-0"], [7, "exercise-0"], [7, "exercise-0"], [7, "exercise-1"], [7, "exercise-2"], [10, "exercise"], [10, "exercise-0"], [18, "exercise-0"], [19, "exercise-0"], [19, "exercise-1"], [19, "exercise-2"], [21, "exercise-0"], [26, "exercise-0"]], "Team teaching": [[7, "team-teaching"], [21, "team-teaching"]], "HackMD": [[7, "hackmd"], [10, "hackmd"], [29, "hackmd"]], "Teams": [[7, "teams"], [7, "exercise-0"], [22, "teams"], [22, "exercise-0"]], "Livestreaming": [[7, "livestreaming"], [14, "livestreaming"]], "(advanced) Set up and install OBS as a livestreaming tool.": [[7, "exercise-0"], [14, "exercise-0"]], "Instructor tech setup": [[7, "instructor-tech-setup"], [12, "instructor-tech-setup"]], "Evaluate screen captures": [[7, "exercise-0"], [12, "exercise-0"]], "Set up your own environment": [[7, "exercise-1"], [12, "exercise-1"]], "Video editing": [[7, "video-editing"], [23, "video-editing"]], "Editing-1: Get your sample video": [[7, "exercise-0"], [23, "exercise-0"]], "Editing-2: Run Whisper to generate raw subtitles and test video.": [[7, "exercise-1"], [23, "exercise-1"]], "Editing-3: Create the basic editlist.yaml file": [[7, "exercise-2"], [23, "exercise-2"]], "Editing-4: Run ffmpeg-editlist": [[7, "exercise-3"], [23, "exercise-3"]], "Editing-5: Add more features": [[7, "exercise-4"], [23, "exercise-4"]], "Editing-6: Subtitles": [[7, "exercise-5"], [7, "exercise-6"], [23, "exercise-5"], [23, "exercise-6"]], "Editing-7: Generate the final output file.": [[7, "exercise-7"], [23, "exercise-7"]], "Use ffmpeg-editlist to edit this sample video": [[7, "exercise-8"], [23, "exercise-8"]], "Why teach together?": [[7, "why-teach-together"], [27, "why-teach-together"]], "What similarities do we have?": [[7, "exercise-0"], [27, "exercise-0"]], "Workshop roles": [[7, "workshop-roles"], [28, "workshop-roles"]], "How many people teach in your workshops?": [[7, "exercise-0"], [28, "exercise-0"]], "Why are computers hard?": [[7, "why-are-computers-hard"], [26, "why-are-computers-hard"]], "Lesson development with version control": [[7, "lesson-development-with-version-control"], [13, "lesson-development-with-version-control"]], "Contribute to a sample lesson": [[7, "exercise-0"], [13, "exercise-0"]], "(advanced) Create your own lesson": [[7, "exercise-1"], [13, "exercise-1"]], "Teaching practice and feedback": [[7, "teaching-practice-and-feedback"], [19, "teaching-practice-and-feedback"]], "Possibilities for Carpentries": [[8, "possibilities-for-carpentries"]], "CodeRefinery\u2019s plans": [[8, "coderefinery-s-plans"]], "Biggest open problems": [[8, "biggest-open-problems"]], "How you can join": [[8, "how-you-can-join"]], "Aside: Nordic-RSE (research software engineers)": [[8, "aside-nordic-rse-research-software-engineers"]], "Instructor\u2019s guide": [[9, "instructor-s-guide"]], "Advantages": [[10, "advantages"], [27, "advantages"]], "Disadvantages": [[10, "disadvantages"]], "Community teaching training": [[11, "community-teaching-training"]], "Under development (mid 2022)": [[11, null]], "What this course covers": [[11, "what-this-course-covers"]], "Who is the course for?": [[11, "who-is-the-course-for"]], "Preparation": [[11, null]], "Introduction": [[11, null]], "Teaching tools": [[11, null]], "Workshop organization": [[11, null]], "Social-technical considerations": [[11, null]], "Lesson design and development": [[11, null]], "Wrap-up, future, and getting involved": [[11, null]], "Reference": [[11, null]], "Old contents - we need to move/merge": [[11, null]], "Screenshare": [[12, "screenshare"]], "Adjust your prompt/configuration/colors": [[12, "adjust-your-prompt-configuration-colors"]], "Should instructors be forced to have a consistent screenshare?": [[12, "discussion-0"]], "Share the history of your commands": [[12, "share-the-history-of-your-commands"]], "More examples and how to set it up": [[12, "more-examples-and-how-to-set-it-up"]], "Version control and static site generators": [[13, "version-control-and-static-site-generators"]], "CodeRefinery lesson tools": [[13, "coderefinery-lesson-tools"]], "Recommendations and lessons learned": [[13, "recommendations-and-lessons-learned"]], "Summary": [[14, "summary"], [23, "summary"], [28, "summary"]], "Tech details": [[14, "tech-details"]], "Other resources": [[15, "other-resources"]], "Placeholder": [[16, "placeholder"]], "Pre-workshop preparation": [[17, "pre-workshop-preparation"]], "Read \u201cHow to help someone use a computer\u201d (5 min)": [[17, "read-how-to-help-someone-use-a-computer-5-min"]], "Browse a CodeRefinery lesson (5 min)": [[17, "browse-a-coderefinery-lesson-5-min"]], "(optional) Watch \u201cThe future of teaching\u201d (35 min content only, 45 min with Q&A, or 15 min reading)": [[17, "optional-watch-the-future-of-teaching-35-min-content-only-45-min-with-q-a-or-15-min-reading"]], "(optional) Read \u201cThe science of learning\u201d (20 min)": [[17, "optional-read-the-science-of-learning-20-min"]], "Instructor demo": [[19, "instructor-demo"]], "Teaching demos part 1": [[19, "teaching-demos-part-1"]], "Teaching demos, part 2": [[19, "teaching-demos-part-2"]], "Discussion": [[19, "discussion"], [20, "discussion-1"], [20, "discussion-2"]], "Main room discussion": [[19, "discussion-0"]], "Optional: feedback for two live-coding examples": [[19, "optional-feedback-for-two-live-coding-examples"]], "How to teach online": [[20, "how-to-teach-online"]], "Objectives": [[20, "objectives-0"]], "Why teaching mechanics matter": [[20, "why-teaching-mechanics-matter"]], "Shell sharing": [[20, "shell-sharing"]], "Discussion: what goes into a good shell share or demonstration?": [[20, "discussion-0"]], "Screen sharing": [[20, "screen-sharing"]], "HackMD prototype": [[20, "output-0"]], "Meta-talk": [[20, "meta-talk"]], "Teach teaching": [[20, "teach-teaching"]], "Questions": [[20, "questions"]], "Teaching practice": [[20, "teaching-practice"]], "Co-teaching": [[21, null]], "Primary article": [[21, "primary-article"]], "Benefits": [[21, "benefits"]], "Strategies": [[21, "strategies"]], "Basic concepts": [[22, "basic-concepts"]], "Online": [[22, "online"]], "In-person": [[22, "in-person"]], "Discussion: what we actually do": [[22, "discussion-what-we-actually-do"]], "Exercise A": [[23, "exercise-a"]], "Discussion: what makes a video easy to edit?": [[23, null]], "Discussion: how to distribute this?": [[23, null]], "Exercise B": [[23, "exercise-b"]], "Video recording": [[24, "video-recording"]], "We try to release videos on the same day": [[24, "we-try-to-release-videos-on-the-same-day"]], "Privacy is more important than any other factor": [[24, "privacy-is-more-important-than-any-other-factor"]], "Broadcasting role and setup": [[24, "broadcasting-role-and-setup"]], "Welcome and introduction": [[25, "welcome-and-introduction"]], "What do we want to get out of this workshop": [[25, "discussion-0"]], "Goals for this workshop": [[25, "goals-for-this-workshop"]], "Goals for this instructor training": [[25, "discussion-1"]], "Giving confidence": [[25, "giving-confidence"]], "Tools for this workshop": [[25, "tools-for-this-workshop"]], "Code of Conduct": [[25, "code-of-conduct"]], "Initial reading": [[26, "initial-reading"]], "How to help someone use a computer, by Phil Agre": [[26, null]], "Usability": [[26, "usability"]], "Deep abstraction layers": [[26, "deep-abstraction-layers"]], "Conclusion: what are we teaching, then?": [[26, "conclusion-what-are-we-teaching-then"]], "Ways to teach together": [[27, "ways-to-teach-together"]], "Challenges and disadvantages": [[27, "challenges-and-disadvantages"]], "Workshop manuals": [[29, "callout-0"]], "Running a workshop: online": [[29, "running-a-workshop-online"]], "Online teaching discussion": [[29, "online-teaching-discussion"]], "Discussion: Online vs in-person": [[29, "discussion-0"]], "Case study: Mega-CodeRefinery and Finland HPC Kickstart": [[29, "case-study-mega-coderefinery-and-finland-hpc-kickstart"]], "General workshop arrangements": [[29, "general-workshop-arrangements"]], "Manuals link": [[29, "callout-1"]], "CodeRefinery online scaling strategy": [[29, "coderefinery-online-scaling-strategy"]], "Basic preparation": [[29, "basic-preparation"]], "Basic platform: Zoom": [[29, "basic-platform-zoom"]], "Breakout rooms, bring your own team": [[29, "breakout-rooms-bring-your-own-team"]], "Helper training": [[29, "helper-training"]], "Staff roles": [[29, "staff-roles"]], "Recording and streaming": [[29, "recording-and-streaming"]], "Installation time": [[29, "installation-time"]], "Other notes": [[29, "other-notes"]], "Workshop collaborations": [[29, "workshop-collaborations"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/teaching-online/index.html b/teaching-online/index.html new file mode 100644 index 00000000..5c7cf43a --- /dev/null +++ b/teaching-online/index.html @@ -0,0 +1,211 @@ + + + + + + + Teaching online — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Teaching online

+

Is online teaching better or worse? As usual for that question, “it’s +all a trade-off”. We believe that many people tried to directly +translate in-person strategies to online, and teaching suffered. In +some ways, this even revealed the flaws of in-person pedagogy (remove +some interaction and not much is left other than an info-dump).

+
+

Exercise

+

Using HackMD, brainstorm advantages and disadvantages of online and +in-person teaching. For each disadvantage of each, think of ways to compensate.

+
+
    +
  • We won’t elaborate more here right now - most of the rest of the +course somehow relates to online teaching!

  • +
  • We will see many techniques which compensate for some of the +disadvantages in the section tools of teaching.

  • +
  • Workshop organization will discuss new collaborative +opportunities with online teaching.

  • +
+
+

See also

+
    +
  • The rest of this course

  • +
  • CodeRefinery manuals: https://coderefinery.github.io/manuals/

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/teaching-practice/index.html b/teaching-practice/index.html new file mode 100644 index 00000000..02aff98b --- /dev/null +++ b/teaching-practice/index.html @@ -0,0 +1,271 @@ + + + + + + + Teaching practice and feedback — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Teaching practice and feedback

+

Goals of the teaching practice:

+
    +
  • In groups of 4-5 persons we will practice teaching a 5-minute segment +of a lesson of your choice.

  • +
  • The section you pick should require screen sharing and be of some +demonstration or follow-along task (preferably using a shell) to also +practice having a good screen-sharing setup.

  • +
  • We will practice giving constructive feedback.

  • +
  • We will practice improving our 5-minute segment by taking the feedback into account.

  • +
  • In both session you can teach the same topic/segment but if you prefer you can also +change the topic/aspect for the second session.

  • +
+
+
+

Instructor demo

+
    +
  • In order to demonstrate the goals of this section, the instructor +will make a 5-minute demo for your evaluation.

  • +
  • It is designed to include some good and bad practices for you to +notice.

  • +
+
+
+
+

Teaching demos part 1

+

In group rooms, 50 minutes.

+
+

Exercise

+
    +
  • We organize the breakout rooms to not only discuss one lesson/topic so that it is more interesting +to listen and also probably we will all get more useful feedback.

  • +
  • Give each other constructive verbal feedback on the teaching demos, for example +using this demo rubric.

  • +
  • Write down questions (in the collaborative document) that you would like to +discuss in the main room or interesting conclusions which you would like to +share with others.

  • +
+
+
+
+

Teaching demos, part 2

+

In group rooms, 50 minutes.

+
+

Exercise

+
    +
  • In the second round we distribute the rooms differently so that you can +present it to a new group of workshop participants and can receive new +feedback.

  • +
  • Ask for feedback and one/few point(s) you want to improve.

  • +
  • In your second trial check whether you feel the demonstration improved.

  • +
  • Share your lessons learned in the collaborative document.

  • +
  • Give us also feedback on this exercise format. Was it useful? What can we improve?

  • +
+
+
+
+
+

Discussion

+
+

Main room discussion

+
    +
  • We discuss questions and conclusions which came up during the group work session.

  • +
+
+
+
+
+

Optional: feedback for two live-coding examples

+
+

Exercise

+

Teaching by live coding is a +performance art which requires practice. +This exercise highlights some typical pitfalls that most instructors +fall into sooner or later, and also shows how to avoid them. +Watch closely since we will be giving feedback!

+
    +
  • Watch these two videos: video 1 and +video 2

  • +
  • What was better in video 1 and what was better in video 2?

  • +
  • Please give feedback in the shared workshop document.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/teaching-strategies/index.html b/teaching-strategies/index.html new file mode 100644 index 00000000..d3e1bbc5 --- /dev/null +++ b/teaching-strategies/index.html @@ -0,0 +1,421 @@ + + + + + + + How to teach online — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

How to teach online

+
+

Objectives

+
    +
  • Understand the benefits and disadvantage of online teaching, +compared to in-person

  • +
  • Set up a good screen share

  • +
  • Understand the benefits and disadvantages of team teaching

  • +
  • Prepare for the teaching practice

  • +
+
+
+

Why teaching mechanics matter

+
    +
  • When you teach, you are mainly showing a basic example for the +learner to follow along

  • +
  • The learner has a lot more to think about than you do, so you need +to minimize the possible distractions and unnecessary weirdness.

  • +
  • A learner will often only one small screen, limiting the number of +things that they can think about.

  • +
  • You are must faster than learners (5 times possibly?) You have to +do things to slow yourself down.

  • +
  • It’s easy to save these mechanics until the end, and then you run +out of time.

  • +
+
+
+

Shell sharing

+ +

When doing any demonstration, there are difficulties:

+
    +
  • If one misses something, you can’t rewind to see it - is there any +way to catch up?

  • +
  • The learner must get oriented with the whole picture, while +instructor knows precisely where to focus.

  • +
+

A good shell share has some of the following properties:

+
    +
  • Large font

  • +
  • Shell history, available separately from the main shell window

  • +
  • Closely matches the type-along instructions

  • +
+

We have a collection of shell sharing systems:

+ +
+

Discussion

+

The instructor will demonstrate several shell-sharing systems. You +will use this in the teaching practice.

+
+
+
+

Screen sharing

+
+

Discussion

+

Look at the various screen layouts in the CodeRefinery +manuals. +Use the HackMD to comment about what which are better or worse.

+ +
+
    +
  • Many learners will have a smaller screen than you.

  • +
  • You should plan for learners with only one small screen.

  • +
  • A learner will need to focus on both your screen share and their +work.

  • +
  • Sharing your a whole screen is almost always a bad idea, if you want +the learners to do anything at the same time.

  • +
  • If you constrict yourself, then your experience is more similar to +that of a learner.

  • +
+

Vertical sharing:

+
    +
  • CodeRefinery has recently started trialing a vertical share +system, where you share a vertical half of your screen.

  • +
  • This allows learners with one screen to display your screen +side-by-side with their learn

  • +
  • Zoom provides a “Share a part of screen” that is good for this.

  • +
+
+
+

Meta-talk

+

Don’t just teach, also make sure you guide the learners through the +course.

+
    +
  • You know what you just discussed, and what is coming next, but +learners are often stuck thinking about now.

  • +
  • Give a lot of “meta-talk” that is not just about the topic you are +teaching, but how you are teaching it.

  • +
  • Examples

    +
      +
    • Why you are doing each episode

    • +
    • What is the purpose of each exercise

    • +
    • Clearly state what someone should accomplish in each exercise and +how long it will take - don’t assume this is obvious.

    • +
    • What is the point of each lesson. How much should people expect +to get from it? Should you follow everything, or are some things +advanced and optional? Make that clear.

    • +
    +
  • +
+
+
+

Teach teaching

+
    +
  • Demonstration-based teaching require two different types of focus:

    +
      +
    • Doing the mechanical steps as a demonstration

    • +
    • Explaining why you are doing it

    • +
    +
  • +
  • This is a lot for one person to keep in mind, so can multiple people +work together for this?

  • +
  • Team teaching idea:

    +
      +
    • One person is doing the demonstrations

    • +
    • One person is giving the commentary about what they are doing

    • +
    • The lecture becomes a discussion between two people instead.

    • +
    +
  • +
+

Advantages:

+
    +
  • This reduces the pressure on each person (reduces demo effect)

  • +
  • You are less likely to forget things

  • +
  • It slows you down in teaching

  • +
  • It makes the lesson more interesting to listen to

  • +
  • One person can follow questions

  • +
  • Great for introducing new instructors (which half is easier to start +with?)

  • +
+

Disadvantage:

+
    +
  • Requires two people’s time

  • +
  • Requires coordination when preparing (slows you down in preparation)

  • +
  • Unfamiliar concept to most people

  • +
+
+
+

Questions

+
    +
  • Questions are great, and important for any practical and interactive +class

  • +
  • But questions in main room doesn’t scale to very large rooms.

  • +
  • CodeRefinery strategy: HackMD for questions

    +
      +
    • Chat is not good enough, you can’t reply to old things

    • +
    • HackMD allows threaded replies and follow up later

    • +
    • You need some other helpers to watch HackMD and answer, and bring +things up to you. And let you know how things are going.

    • +
    • Learners can ask anonymously

    • +
    • Learners don’t have to worry about interrupting the flow.

    • +
    • Disadvantage: can produce information overload, warn people to not +follow too closely

    • +
    • With too few people, it can turn out to be very quiet.

    • +
    +
  • +
  • We will learn more about HackMD questions tomorrow in +Running a workshop: online.

  • +
+
+

See also

+ +
+
+
+

Teaching practice

+

In Teaching practice and feedback, you will break into groups and try to +apply these strategies to a five-minute example session.

+
+
+

See also

+

In this lesson:

+ +

CodeRefinery manuals:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/team-teaching/index.html b/team-teaching/index.html new file mode 100644 index 00000000..3c800258 --- /dev/null +++ b/team-teaching/index.html @@ -0,0 +1,257 @@ + + + + + + + Team teaching — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Team teaching

+

One of the most significant improvemest of our teaching has been the +concept of co-teaching.

+
+

Co-teaching

+

Wikipedia: Co-teaching or team teaching is the division of labor +between educators to plan, organize, instruct and make assessments +on the same group of students, generally in the a common +classroom,[1] and often with a strong focus on those teaching as a +team complementing one another’s particular skills or other +strengths.

+
+

This is not strictly an effect of moving online. However, the +larger number of instructors and larger audiences make this practical +on a wide scale.

+
+

Primary article

+

https://coderefinery.github.io/manuals/team-teaching/

+
+
+

Benefits

+
    +
  • The course seems very interactive, much more so than expecting +students to speak up. The co-teacher can take on the “voice of the +audience”.

  • +
  • Quicker preparation time since co-teachers can rely on each other in +unexpected situations.

  • +
  • One co-teacher can be effectively learning at the same time and thus +acting as the “voice of the audience” in another way.

  • +
  • Great way to onboard new instructors - extensive training and +preparation no longer needed.

  • +
  • More active minds means better able to watch and react to other +feedback, such as HackMD or chat.

  • +
  • Less workload - one person does not have to prepare perfectly, any +uncertainty can usually be quickly answered by the other.

  • +
+
+
+

Strategies

+

In reality, these strategies are mixed and matched even within a +lesson, and there are many things between these:

+
    +
  • One person gives lectures, one does the typing during demos.

  • +
  • “Interview”: One primarily doing the “teaching”, one guiding by +asking questions - either as an interviewer or as a virtual learner.

  • +
+

Things that don’t work (are not team teaching):

+
    +
  • Dividing up a lesson into parts, each person gives different parts +independently.

  • +
+
+
+

Exercises

+
+

Exercise

+

Divide into groups of two or three. Choose one of the two models +in the team-teaching page, and quickly (5 min) prepare a short +topic (3-5 min) to team teach. You can quickly scan the +“preparation” section at the bottom.

+

The challenge is not just to give the lesson, but to prepare the +lesson quickly and rely on each other to give a good lesson anyway.

+
+
+
+

See also

+

(none yet)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/teams/index.html b/teams/index.html new file mode 100644 index 00000000..2dd023e2 --- /dev/null +++ b/teams/index.html @@ -0,0 +1,287 @@ + + + + + + + Teams — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Teams

+

Everyone wants interaction in courses, yet when a group size gets too +large, it doesn’t have much interaction. A event in a physical space +naturally makes teams based on who is nearby. When done online, this +needs to be more explicit.

+
+

Primary articles

+ +
+
+

Basic concepts

+
    +
  • Teams are pre-assigned

  • +
  • Exercise leaders (aka helpers) assigned per team

  • +
  • Teams stay together during the whole workshop.

  • +
  • Learners can sign up either alone…

  • +
  • … or they can sign up with a pre-made team: people who know +each. “bring your own breakout room”:

    +
      +
    • When two people in a work group learn a skill, uptake within the +group is often much higher. Thus, we strongly encourage pre-made +teams that know each other.

    • +
    • Teams that all come from the same group or field, with a helper +from that field, can transition to help

    • +
    +
  • +
+
+
+

Online

+

In the best online implementations, our teams have these properties:

+
    +
  • Coordination of breakout rooms is a lot of work.

  • +
  • In zoom, we could request learners to rename to (N) Learner +Name, and then quickly assign people. Now, you can have learners +self-select their rooms. But will they actually do this, or stay in +main room?

  • +
  • One helper is assigned per team.

    +
      +
    • In fact, we would limit the number of registrations to 5× the +number of helpers so that all teams have a helper

    • +
    +
  • +
  • Our registration system (indico) is capable of mailing personalized +messages per person with their team information. This is quite a +bit of work to manage.

  • +
+

But they have these disadvantages:

+
    +
  • Much, much harder registration coordination, almost to the point of +being impossible.

  • +
  • Number of attendees.

  • +
  • Difficulties when attendees drop out partway through a course.

  • +
+
+
+

In-person

+

Teams may natuarally form based on setting location, but

+
    +
  • Teams may happen naturally by sitting at the same table

  • +
  • Do teams stay the same day after day?

  • +
  • Do teams get arranged in a manner useful for learning?

  • +
  • Do you have one helper per team?

  • +
  • Do you encourage people to interact explicitly enough?

  • +
  • Do you ensure that no one gets left out in the crowd? Are the teams +explicit enough?

  • +
+
+
+

Discussion: what we actually do

+
    +
  • For large enough CodeRefinery workshops, assign teams with one +helper each. Deal with re-adjustment

  • +
  • The livestream option allows everyone else to follow along.

  • +
  • In other workshops, create breakout rooms but somehow try let people +self-assign. Most don’t.

  • +
  • For large workshops without enough staff help, livestream and +encourage people to form their own teams and watch themselves - we +don’t actually need to be involved.

  • +
  • Teams can be delegated to a local organizer.

  • +
+
+
+

Exercises

+
+

Teams

+

Consider these questions:

+
    +
  • Should teams have similar or different people in them?

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/video-editing/index.html b/video-editing/index.html new file mode 100644 index 00000000..479a551b --- /dev/null +++ b/video-editing/index.html @@ -0,0 +1,564 @@ + + + + + + + Video editing — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Video editing

+

Video recordings could be useful for people attending a course later, +but also are (perhaps more) useful for immediate review and catching +up after missing a day in a workshop. For this, they need to be +released immediately, within a few hours of the workshop. +CodeRefinery can do this.

+

Hypothesis: videos must be processed the same evening as they were +recorded, otherwise (it may never happen) or (it’s too late to be +useful). To do that, we have to make processing good enough (not +perfect) and fast and distributeable

+
+

Primary articles

+ +
+
+

Summary

+
    +
  • Basic principle: privacy is more important than any other factor. +If we can’t guarantee privacy, we can’t release videos at all.

    +
      +
    • Disclaimers such as “if you don’t want to appear in a recording, +leave your video off and don’t say anything”, since a) accidents +happen especially when coming back from breakout rooms. b) it +creates an incentive to not interact or participate in the course.

    • +
    +
  • +
  • Livestreaming is important here: by separating the instruction from +the audience audio/video, there is no privacy risk in the raw +recording. They could be released or shared unprocessed.

  • +
  • Our 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. +
    +
  • +
  • ffmpeg-editlist allows us to +define an edit in a text file (crowdsourceable on Github), and then +generate videos very quickly.

  • +
+
+
+

Exercises

+
+

Exercise A

+

These exercises will take you through the whole sequence.

+
+

Editing-1: Get your sample video

+

Download a sample video:

+
+
+
+
+

Editing-2: Run Whisper to generate raw subtitles and test video.

+

First off, install Whisper and generate the base subtitles, based +on the. Since this is probably too much to expect for a short +lesson, they are provided for you (above), but if you want you can +try using Whisper, or generating the subtitles some other way.

+

You can start generating subtitles now, while you do the next +steps, so that they are ready by the time you are ready to apply +the editlist. ffmpeg-editlist can also slice up the subtitles from +the main video to make subtitles for each segment you cut out.

+

Whisper is left as an exercise to the reader.

+ +
+
+

Editing-3: Create the basic editlist.yaml file

+

Install ffmpeg-editlist and try to +follow its instructions, to create an edit with these features:

+
    +
  • The input definition.

  • +
  • Two output sections: the “Intro to the course”, and “From data +storage to your science” talks (Remember it said the recording +started at 11:35… look at the schedule for hints on when it +might start!). This should have a start/end timestamp from the +original video.

  • +
+

A basic example:

+
- input: day1-raw.mkv
+
+# This is the output from one section.  Your result should have two of these sections.
+- output: part1.mkv
+  title: something
+  description: >-
+    some long
+    description of the
+    segment
+  editlist:
+    - start: 10:00    # start timestamp of the section, in *original* video
+    - end: 20:00      # end timestamp of the section, in the *original* video
+
+
+ +
+
+

Discussion: what makes a video easy to edit?

+
    +
  • Clear speaking and have high audio quality.

  • +
  • For subtitle generation: Separate sentences cleanly, otherwise it +gets in a “stream of words” instead of “punctuated sentences” +mode.

  • +
  • Clearly screen-sharing the place you are at, including section +name.

  • +
  • Clear transitions, “OK, now let’s move on to the next lesson, +LESSON-NAME. Going back to the main page, we see it here.”

  • +
  • Clearly indicate where the transitions are

  • +
  • Hover mouse cursor over the area you are currently talking about.

  • +
  • Scroll screen when you move on to a new topic.

  • +
  • Accurate course webpage and sticking to the schedule

  • +
+

All of these are also good for learners. By editing videos, you +become an advocate for good teaching overall.

+
+
+

Editing-4: Run ffmpeg-editlist

+

Install ffmpeg-editlist: pip install ffmpeg-editlist[srt] (you +may want to use a virtual environment, but these are very minimal +dependencies).

+

The ffmpeg command line tool must be available in your +PATH.

+ +
+
+

Editing-5: Add more features

+
    +
  • Several chapter definitions.(re-run and you should see a +.info.txt file also generated). Video chapter definitions +are timestamps of the original video, that get translated to +timestamps of the output video.

    +
    - output: part1.mkv
    +  editlist:
    +  - start: 10:00
    +  - -: Introduction    #  <-- New, `-` means "at start time"
    +  - 10:45: Part 1      #  <-- New
    +  - 15:00: Part 2      #  <-- New
    +  - end: 20:00
    +
    +
    +

    Look at the .info.txt files that come out now. What is new in it?

    +
  • +
  • Add in “workshop title”, “workshop description”, and see the +.info.txt files that come out now. This is ready for +copy-pasting into a YouTube description (first line is the title, +rest is the description).

    +

    Look at the new .info.txt files. What is new?

    +
  • +
+ +
+
+

Editing-6: Subtitles

+

Re-run ffmpeg-editlist with the --srt option (you have to +install it with pip install ffmpeg-editlist[srt] to pull in the +necessary dependency). Notice how .srt files come out now.

+

Use some subtitle editor to edit the original subtitle file, to +fix up any transcription mistakes you may find. You could edit +directly, use subtitle-editor on Linux, or find some other +tool.

+

What do you learn from editing the subtitles?

+ +
+
+

Editing-6: Subtitles

+

Re-run ffmpeg-editlist with the --srt option (you have to +install it with pip install ffmpeg-editlist[srt] to pull in the +necessary dependency). Notice how .srt files come out now.

+

Use some subtitle editor to edit the original subtitle file, to +fix up any transcription mistakes you may find. You could edit +directly, use subtitle-editor on Linux, or find some other +tool.

+

What do you learn from editing the subtitles?

+
+
+

Editing-7: Generate the final output file.

+
    +
  • Run ffmpeg-editlist with the --reencode option: this +re-encodes the video and makes sure that there is no black point +at the start.

  • +
  • If you re-run with --check, it won’t output a new video file, +but it will re-output the .info.txt and .srt files. +This is useful when you adjust descriptions or chapters.

  • +
+
+
+

Discussion: how to distribute this?

+

Create a flowchat of all the parts that need to be done, and which +parts can be done in parallel. Don’t forget things that you might +need to do before the workshop starts.

+

How hard was this editing? Was it worth it?

+
+
+
+

Exercise B

+

This is similar to the above but more brief and not on a real example +video.

+
+

Use ffmpeg-editlist to edit this sample video

+

Prerequisites: ffmpeg must be installed on your computer +outside of Python. Be able to install ffmpeg-editlist. This is +simple in a Python virtual environment, but if not the only +dependency is PyYAML.

+ +
+ +
+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/video-recording/index.html b/video-recording/index.html new file mode 100644 index 00000000..055e9b9b --- /dev/null +++ b/video-recording/index.html @@ -0,0 +1,245 @@ + + + + + + + Video recording — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Video recording

+
+

Keypoints

+
    +
  • We don’t expect many people to watch the recording from scratch later (but +some do) (some might look afterwards a few pieces, cmp. reading a book vs +look ing sth up from a book)

  • +
  • Learners getting an “instant replay” to review, or to make up for a lost day, is great.

  • +
  • Privacy is more important than any other factor

  • +
  • Recording only works if privacy is guaranteed and effort is low. +This is only possible with the instructor-audience split setup of livestreaming.

  • +
+
+
+

We try to release videos on the same day

+

Video recordings could be useful for people attending a course later, but also +are (perhaps more) useful for immediate review and catching up after missing +a day in a workshop.

+

For this, they need to be released immediately, within a few hours of the +workshop (see Video editing). CodeRefinery can do this.

+

For the videos to be released soon we need to make sure we guarantee privacy of +learners (see below). Our livestream setup makes the privacy guarantee easy at +the cost of separating instructors and learners into different video rooms.

+

Good preparation and documentation helps to make video recording and video +editing easier.

+
+
+

Privacy is more important than any other factor

+

If we can’t guarantee privacy, we can’t release videos at all.

+

Some events add a disclaimers such as “if you don’t want to appear +in a recording, leave your video off and don’t say anything”. We +would prefer not to do this, since:

+
    +
  • we know accidents happen (especially when coming back from breakout rooms)

  • +
  • it creates an incentive to not interact by voice/video

  • +
  • it could pressure participants to not object in order “to not be difficult”

  • +
+

Livestreaming solves this for us:

+
    +
  • By separating the instruction from +the audience audio/video, there is no privacy risk in the raw +recording. They could be released or shared unprocessed.

  • +
  • Recording with Zoom in a large meeting with all the instructors and +learners is simple, but not good for privacy: there are always +mistakes, reviewing takes too long.

  • +
  • Livestream platforms also provide instant recordings of the whole +stream, and some make instant replays possible. This could remove +the need for making our own videos, since one of the most important +cases is this instant replay idea.

  • +
+
+
+

Broadcasting role and setup

+

In the live-streaming setup, the Broadcasting role is central to video +recording.

+

Broadcaster description (most is not directly about recording): +https://coderefinery.github.io/manuals/broadcaster/

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/welcome/index.html b/welcome/index.html new file mode 100644 index 00000000..02290c8c --- /dev/null +++ b/welcome/index.html @@ -0,0 +1,269 @@ + + + + + + + Welcome and introduction — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Welcome and introduction

+
+

What do we want to get out of this workshop

+
    +
  • Introduction of instructors and helpers

  • +
  • Each instructor can say what we want to get out of the instructor training

  • +
  • But we want to know from everybody and collect these in the live notes

  • +
+
+
+
+

Goals for this workshop

+
+

Goals for this instructor training

+
    +
  • Inspire teachers and staff who have to teach indirectly as part of +their job: use best practices for the modern world, especially +for online teaching.

  • +
  • Promote collaboration in teaching: less going alone.

  • +
  • Promote CodeRefinery sustainability: form a network that can +work together to share the work and benefits.

  • +
+
+
+

Giving confidence

+
+

Goal number one should be that we give participants the confidence to +independently apply the tools or knowledge learnt. This is more important +that giving a “complete” overview. [Lucy Whalley gave this great comment at one of our workshops]

+
+
    +
  • You don’t have to know everything to use (or teach) something.

  • +
  • For the large majority of topics we teach, there are many resources online +which provide how-to guides or tutorials. And the Stack Overflow answer bank +isn’t getting any smaller. So we need to ask why do people attend in-person +sessions if there is information freely available? Our impression is that +it is for confidence building, identity formation, perhaps signposting to +resources.

  • +
  • This also links with building a welcoming/inclusive environment: for example, +imposter syndrome, which disproportionately affects under-represented groups +(link), +can manifest as low self-confidence –> building the confidence of +students in the classroom may lead to a more diverse community.

  • +
+
+
+
+
+

Tools for this workshop

+

We often start workshops with these:

+ +
+
+
+

Code of Conduct

+
    +
  • We follow The CodeRefinery Code of +Conduct.

  • +
  • This is a hands-on, interactive workshop.

    +
      +
    • Be kind to each other and help each other as best you can.

    • +
    • If you can’t help someone or there is some problem, let someone know.

    • +
    • If you notice something that prevents you from learning as well as you can, let us know and don’t suffer silently.

    • +
    +
  • +
  • It’s also about the little things:

    +
      +
    • volume

    • +
    • font size

    • +
    • generally confusing instructor

    • +
    • not enough breaks

    • +
    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/why-are-computers-hard/index.html b/why-are-computers-hard/index.html new file mode 100644 index 00000000..c083c840 --- /dev/null +++ b/why-are-computers-hard/index.html @@ -0,0 +1,237 @@ + + + + + + + Why are computers hard? — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Why are computers hard?

+

Most of the time, when teaching, our difficulty is not what you expect.

+
+

Initial reading

+

Read the following:

+ +

Of each of the points made, how many are related to:

+
    +
  • The computing itself

  • +
  • The user interface

  • +
  • The ability of the user to work in the computing environment

  • +
  • Something else

  • +
+
+
+

Usability

+

As said in the text above:

+
+

Most user interfaces are terrible. When people make mistakes it’s +usually the fault of the interface. You’ve forgotten how many ways +you’ve learned to adapt to bad interfaces. You’ve forgotten how +many things you once assumed that the interface would be able to +do for you.

+
+
+
+

Deep abstraction layers

+

Most technology is built on abstraction layers, for good reason. They +help simplify implementation and understanding.

+
+

Exercise

+

Think of a tool or technology that is easy to understand and use if +you understand the underlying abstraction layers, but is almost +impossible otherwise.

+
+
+
+

Conclusion: what are we teaching, then?

+

As teachers of computing, we fill a critical role that is more +determined by our audience, than the technology we are teaching.

+
+
+

See also

+

(none yet)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/why-teach-together/index.html b/why-teach-together/index.html new file mode 100644 index 00000000..885a6b1b --- /dev/null +++ b/why-teach-together/index.html @@ -0,0 +1,270 @@ + + + + + + + Why teach together? — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Why teach together?

+

We usually say so much about the value of collaboration. Despite us +saying this, our teaching is still far too alone. Covid-19 gave us a +kick that reduced our barriers and led to lasting changes in how we +taught (eventually leading to this very course).

+

Open Science / FAIR data is heavily emphazised these days. But let’s +add a “C” to FAIR: “collaborative”. Instead of people doing their own +thing and releasing, develop, iterate, and maintain collaboratively.

+
+

Ways to teach together

+
    +
  • Develop materials together - avoid duplication.

  • +
  • Team teaching

  • +
  • Extensive use of helpers and team leaders.

  • +
  • HackMD for parallel and mass answers.

  • +
+
+
+

Advantages

+
    +
  • You need to teach anyway, less effort if you combine.

  • +
  • If done right, minimal extra effort for others to receive benefit (+ +you get publicity).

  • +
  • Many of the previously presented teaching strategies work best in +large courses - this makes the course more engaging than a small +event with minimal interaction.

  • +
  • More engaging for the audience.

  • +
  • Easier on-boarding of new instructors (less “scary” to teach a new course +with other instructors).

  • +
+
+
+

Challenges and disadvantages

+
    +
  • Coordination

    +
      +
    • Finding suitable partners with the same vision

    • +
    • Coordination efforts (if others don’t understand the vision).

    • +
    +
  • +
  • Materials

    +
      +
    • May not be perfectly tuned to your own audience

    • +
    • May not iterate as fast as you need

    • +
    +
  • +
  • Co-teaching

    +
      +
    • Difficulty in finding co-teachers

    • +
    • Required effort of syncing among staff

    • +
    • It might revert to independent teaching if you aren’t careful.

    • +
    +
  • +
  • HackMD

    +
      +
    • Can possibly overload both student and teacher.

    • +
    +
  • +
+
+
+

Exercises

+
+

What similarities do we have?

+

Using HackMD, make two lists:

+
    +
  • What courses do you think your local community would benefit +from, which you don’t currently have? +1 other people’s items +which are also relevant to you.

  • +
  • Which courses are you thinking of preparing for your local +community? +1 other people’s items which you would be +interested in helping out with.

  • +
+
+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-roles/index.html b/workshop-roles/index.html new file mode 100644 index 00000000..b36c8bed --- /dev/null +++ b/workshop-roles/index.html @@ -0,0 +1,259 @@ + + + + + + + Workshop roles — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop roles

+

Running massive workshops requires a lot of people. We have a variety +of roles with different levels of support.

+

As usual, roles are a plan, and a plans are made to be updated.

+
+

Primary articles

+ +
+
+

Summary

+

Lower levels mean “top level sometimes split into some of these +sub-roles”.

+
    +
  • Instructor coordinator: coordinates schedule and instructors

    +
      +
    • Instructor: Teaches along with a co-teacher.

    • +
    • Expert helper: Spare person, usually watching HackMD but also +rotates among breakout rooms. Often instructs some lessons.

    • +
    • Director: Manages the flow of the schedule during the +workshop, introduces each lesson, etc. (often the instructor +coordinator)

      +
        +
      • Broadcaster: Manages the livestreaming

        +
          +
        • Video editor: Edits and publishes videos the day of the +workshop.

        • +
        +
      • +
      +
    • +
    +
  • +
  • Registration coordinator: coordinates registration, helpers, and +breakout rooms.

    +
      +
    • Exercise leader coordinator: Onboards exercise leaders

    • +
    • Host: Manages the learner breakout rooms, learner questions, +etc. (often the registration coordinator)

    • +
    • Advertisement coordinator: Advertises and outreaches

    • +
    +
  • +
  • Under both registration coordinator and instructor coordinator

    +
      +
    • HackMD manager: always watches and formats HackMD and +publishes it same-day. “Eyes on the ground” via HackMD and chat +and quickly communicates important information to instructor and +registration coordinators.

    • +
    +
  • +
  • Learner: attends and learns

  • +
  • Exercise leader: serves as a guide to the team, receives small +amount of training before the workshop.

  • +
+
+
+

Exercises

+
+

How many people teach in your workshops?

+
    +
  • Using HackMD, make a histogram of how many (instructors + +organizers) you typically have in your workshops.

  • +
  • List some of the common roles you have used.

  • +
+
+
+
+

See also

+

(none yet)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshops-online/index.html b/workshops-online/index.html new file mode 100644 index 00000000..e4f5bf0a --- /dev/null +++ b/workshops-online/index.html @@ -0,0 +1,499 @@ + + + + + + + Running a workshop: online — Community teaching training documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop manuals

+

CodeRefinery maintains a number of workshop manuals +with most of the “primary” information. This episode condenses this +into a quick overview.

+
+
+

Running a workshop: online

+
+

Online teaching discussion

+
+

Discussion: Online vs in-person

+

In notes:

+
    +
  • Compare and contrast the benefits of online teaching with +in-person: {advantage, disadvantage} × {content, presentation}

  • +
  • How do you have to prepare differently?

  • +
  • What are your own experiences?

  • +
+
+
+
+

Case study: Mega-CodeRefinery and Finland HPC Kickstart

+
    +
  • Mega-CodeRefinery

    +
      +
    • Audience of around 90-100

    • +
    • “bring your own breakout room” (see below)

    • +
    • 3 days/week, 6 days total

    • +
    • Lessons as normal in CodeRefinery

    • +
    +
  • +
  • HPC Kickstart

    +
      +
    • 250 registered, ~180 max participants

    • +
    • Multi-university: local differences made this much harder to manage.

    • +
    • Breakout rooms not pre-planned.

    • +
    +
  • +
+

Mega-CodeRefinery worked very well, HPC kickstart didn’t - but not +because of the size.

+
+
+

General workshop arrangements

+ +
    +
  • Select a coordinator, recruit instructors (at least 3 is important), +find helpers

  • +
  • Find a good lecture room: +requirements

  • +
  • Set up workshop webpage using the [Github, template +repository](https://github.com/coderefinery/template-workshop-webpage]: +see +manuals

  • +
  • Advertising the workshop

  • +
  • Communication with registered participants

  • +
+
+
+

CodeRefinery online scaling strategy

+
    +
  • We started online workshops in 2020 March, for the obvious reasons.

  • +
  • First, we started with two “normal size” (20 people) practice +workshops

  • +
  • Then we did a 100 person workshop. It went well, but there is less +tolerance for problems.

  • +
+
+

Basic preparation

+
    +
  • You need more breaks are needed

  • +
  • People have a way of doing too many things and not focusing.

  • +
  • How to attend an online +workshop” +guide to prepare learners

  • +
+
+
+

Basic platform: Zoom

+
    +
  • Zoom (not the most ethical, but worked well and was available)

  • +
  • Zoom mechanics: instructions for +students.

    +
      +
    • Mostly things that are known

    • +
    • We don’t use Zoom interaction features much anymore +(faster/slower/etc), but breakout rooms and HackMD instead

    • +
    +
  • +
  • See also: Online training +manual +(which is getting a bit old compared to what is below).

  • +
+
+
+

Breakout rooms, bring your own team

+
    +
  • Breakout rooms are

    +
      +
    • Static: same people across whole workshop

    • +
    • Contain one helper per room (see below)

    • +
    +
  • +
  • Team registration: accept a “team” field when registering, people on the +same team are put together.

    +
      +
    • Gives motivations for learners to bring their colleagues and +learn together.

    • +
    • More than one person learning together greatly increases update

    • +
    +
  • +
  • You need a powerful enough registration system to assign rooms and +email them to people!

  • +
  • We ask people to name themselves “(N) Firstname Lastname” or “(N,H) +Firstname Lastname” for helpers. Then it is fast to assign them to +their designated breakout rooms.

  • +
  • See also: Breakout room +mechanics

  • +
+
+
+

Helper training

+
    +
  • Each breakout room has a helper

  • +
  • Helper should be a little bit familiar, but not expected to be able +to answer all questions.

  • +
  • Special, custom helper +training +since helpers make or break the workshop

  • +
  • Helper recruitment:

    +
      +
    • Our networks

    • +
    • Team registration: if a team registers with their own helper, then +they are guaranteed to get in together. “bring your own breakout +room”

    • +
    • Former learners, ask them to come back.

    • +
    +
  • +
  • Two helper trainings the week before the workshop.

  • +
+
+
+

Staff roles

+

To reduce stress on any one person, we clearly define the different +roles and try to avoid overlap. We actually have enough people for +all of these, so it works well.

+
    +
  • Workshop coordinator

    +
      +
    • Registration, etc.

    • +
    +
  • +
  • Zoom host

    +
      +
    • Handles registration, breakout rooms, recording, Zoom chat.

    • +
    +
  • +
  • HackMD helper

    +
      +
    • Dedicated to watching HackMD and answering questions quickly.

    • +
    • Host on manuals

    • +
    +
  • +
  • Expert helpers

    +
      +
    • “Spare hands” who rotate between breakout rooms and make sure +helpers are doing well.

    • +
    • Give feedback to instructor about how breakout rooms are going.

    • +
    • Take the place of missing helpers.

    • +
    • Easy way for any people with a bit of spare time to help out.

    • +
    • Expert helpers in workshop

    • +
    +
  • +
  • Instructors

    +
      +
    • Teach, they shouldn’t overlap with the above roles (but serve as +expert helpers other times).

    • +
    • Usually also improve the lesson a bit before teaching

    • +
    • General staff intro in manuals

    • +
    +
  • +
  • Workshop preparation meeting

    + +
  • +
+
+
+

HackMD

+
    +
  • We’ve been using it here

  • +
  • Chat doesn’t work wen large, written +document does.

  • +
  • HackMD can just about scale to ~100 person workshop. Recommend +learners keep it in view mode while not editing.

  • +
  • Voice questions are still allowed, but will be recorded. Staff +raise important questions from HackMD to the instructor immediately.

  • +
  • HackMD also allows communication when in breakout rooms.

  • +
  • You can get multiple answers, and answers can be improved over +time.

  • +
  • HackMD +mechanics +and HackMD +helpers.

  • +
+
+
+

Recording and streaming

+
    +
  • When you have 100 people, main room is quiet anyway: you don’t lose +much by recording.

    +
      +
    • Questions anonymously in HackMD, privacy loss is not so bad

    • +
    +
  • +
  • Breakout rooms are never recorded

  • +
  • Streaming

    +
      +
    • We streamed via Twitch: https://twitch.tv/coderefinery

    • +
    • We typically get 5-40 viewers.

    • +
    • Zoom can directly send the stream to Twitch: no extra software +needed.

    • +
    • Twitch archives videos for 14 days, which allows learners to get +an instant reply (we get hundreds of views in the next days).

    • +
    • So while possibly not useful for new people to learn, the instant +reply is very useful. Instructor can also work on problems in +main stream during breakout rooms, which learners can watch +later.

    • +
    • Streamers also have access to HackMD to ask questions.

    • +
    +
  • +
  • Certain tricks needed to keep learners from appearing in recording +or stream

    +
      +
    • “Spotlight video”, host does not go to gallery view, uses dual +monitor mode. We are still figuring this out.

    • +
    +
  • +
+
+
+

Installation time

+
    +
  • People have to be ready once we start, or else everything fails.

  • +
  • Two installation help times the week before.

  • +
  • Every email emphasizes that you have to be prepared, and “requires” +you to attend workshops (but really it’s only)

  • +
  • Installation instructions include steps to verify

  • +
  • Installation instructions also include video demonstrations of +installation and verification.

  • +
  • We haven’t had that many installation problems, but also we keep the +requirements simple.

  • +
  • Helper introduction is right before software install time, so +helpers can stay and help with install if they want.

  • +
  • Design to be easy to install and get set up.

  • +
+
+
+

Other notes

+
    +
  • Make breakout sessions as long as possible: 10 minutes is really too +short. 20 minutes is a good minimum time.

  • +
  • Be very clear about exercise expectations

  • +
  • Keep HackMD updated as a log.

  • +
  • Don’t combine breaks and breakout times.

  • +
  • The more people you have, the more diverse audience you have and the +more people overwhelmed and under whelmed.

  • +
+
+
+
+

Workshop collaborations

+

Why limit ourselves to CodeRefinery workshop? Why not use our network +and techniquess for more

+
    +
  • Case study: Python for Scientific +Computing

    +
      +
    • Started by Aalto

    • +
    • Announced to CodeRefinery, five more instructors from three +countries joined.

    • +
    • Rapid collaboration, taught course shortly later.

    • +
    • Announced to all institutions. Some places had physical rooms, +some were pure online

    • +
    • Also streamed

    • +
    • It was much more fun and less stressful to work together

    • +
    +
  • +
  • We want to continue this kind of collaboration in other workshops.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file