diff --git a/.gitignore b/.gitignore index 723ef36..361103f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,15 @@ -.idea \ No newline at end of file +*.pyc +*~ +__pycache__ +.DS_Store +.idea +env +envs +errors.txt +log.txt +traceback.txt +*.rpyc +saves +cache +tl +more.md \ No newline at end of file diff --git a/README.md b/README.md index 47f75e8..4b85a82 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,36 @@ -# Welcome to the world of Python! - -[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) - -For beginners, we will learn the basic concepts of -programming using Python. This can be your jump off towards web development, -scripting, data processing and more! - -For immediate/advanced Pythonistas, let's spread our knowledge of Python and learn more! - -If you have questions, please feel free to ask and participate on our [Gitter group](https://gitter.im/WWCodeManila/Python). +# Welcome, Pythonistas! +!> Please go to our official [GitHub Page](https://wwcodemanila.github.io/WWCodeManila-Python/#/) +if you're viewing this from the source code repository. ## About this study group -!> Read this [document](wwcodemanila/study_groups.md) first to know what study groups are. +!> If you're not yet familiar with study groups, read this [document](wwcodemanila/study_groups.md) +first to know what they are. -This study group is held once a month and is led by our volunteer leaders. However, everyone is welcome to join, learn, and share their knowledge in the community. +This study group is held once a month and is led by our volunteer leaders. -Everyone joining this study group and other Women Who Code events must follow our [code of conduct](https://github.com/WomenWhoCode/guidelines-resources/blob/master/code_of_conduct.md). +Everyone is welcome to join, learn, and share their knowledge in the community +as long as they abide by our [code of conduct](https://github.com/WomenWhoCode/guidelines-resources/blob/master/code_of_conduct.md). ### Setup -* We currently subgroup into: - - Python beginners - - Flask beginners - - Advanced Pythonistas - -* Spend the hours randomly into: - - Getting to know first-timers - - Discuss questions/issues raised last meetup or on Gitter - - Lightning Talk (anyone who wants to share/chikka something!) - - Self-paced or mini study session - - Today I Learned (TIL) - - Announcements +During the study groups, we usually spend the time: + +- getting to know first-timers, +- discussing questions/issues raised during the last meetup, +- presenting lightning talks (anyone who wants to share/chika something!), +- doing self-paced and/or mini study sessions +- sharing TILS (Today I Learned), and +- communicating announcements. ## Relevant links -- [Gitter Chat](https://gitter.im/WWCodeManila/Python): Interact with the community. You can share something about Python, or ask help if you're stuck on a problem. -- [Github](https://github.com/wwcodemanila/WWCodeManila-Python): View study group code -- [Meetup](https://bit.ly/wwcodemanilameetups): Get updated with the upcoming study group and other event schedules. -- [Facebook](https://facebook.com/wwcodemanila): Get updated about what's happening with the community. -- [Twitter](https://twitter.com/wwcodemanila): Get updates about current and future events. +- [GitHub](https://github.com/wwcodemanila/WWCodeManila-Python): View our study group resources. +- [Meetup](https://bit.ly/wwcodemanilameetups): Get updates about our upcoming study groups and events. +- [Facebook](https://facebook.com/wwcodemanila): Get updates about what's happening in the community. +- [Twitter](https://twitter.com/wwcodemanila): Get updates about our current and future events. ## Helping out @@ -52,19 +41,20 @@ Attend one of our [events](https://bit.ly/wwcodemanilameetups) and talk to us! : ### Donate -Even a little amount is a big help for us to achieve our mission of inspiring women to excel in tech careers. :heart: +Any amount will greatly help us achieve our mission of inspiring women to excel in tech careers. :heart: -You can donate at our [Open Collective](https://opencollective.com/wwcodemanila). +Donations are accepted via [Open Collective](https://opencollective.com/wwcodemanila). ### Hosting -Do you want to host one of our study groups? Email us at **manila@womenwhocode.com**. +Do you want to help us host one of our study groups? Email us at **manila@womenwhocode.com**. -## Contributors +## Mentors -- Nicole Tibay +- Alysson Alvaran +- Angelica Lapastora - Marylette Roa -- Clau Yagyagan -- Micaela Reyes +- Issa Tingzon - Iris Uy -- Alysson Alvaran +- Clau Yagyagan +- Nicole Tibay diff --git a/_coverpage.html b/_coverpage.html index 9640903..eda94af 100644 --- a/_coverpage.html +++ b/_coverpage.html @@ -1,9 +1,5 @@

logo

-

Python Study Group

@@ -16,20 +12,9 @@

Python Study Group

- - - - -

diff --git a/_media/bg.jpg b/_media/bg.jpg index 7c5a7b5..3cf5c92 100644 Binary files a/_media/bg.jpg and b/_media/bg.jpg differ diff --git a/_media/gitter.png b/_media/gitter.png deleted file mode 100644 index 66813aa..0000000 Binary files a/_media/gitter.png and /dev/null differ diff --git a/_sidebar.md b/_sidebar.md index 95db90f..28c59c7 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,43 +1,65 @@ -- Women Who Code Manila - - [About WWCode Manila](wwcodemanila/about.md) - - [Study Groups](wwcodemanila/study_groups.md) - -- Getting Started - - [Installation](getting_started/installation_guide.md) - - [Run a basic Python program](getting_started/warm_up.md) - - [Sharing your work](getting_started/exercise_upload_step.md) - -- Basic Concepts - - [Variables, Arithmetic Operations, Keyboard Input](basic_concepts/variables.md) - - [Let's go Git!](git/README.md) - - [Strings pa more!](basic_concepts/strings.md) - - [PEP8](basic_concepts/pep8.md) - - [Lists](basic_concepts/lists.md) - - [Conditional Statements](basic_concepts/conditional_statements.md) - - [Loops](basic_concepts/loops.md) - - [Challenge: I survived Hangman!](basic_concepts/exercises/hangman/README.md) - - [Dictionaries](basic_concepts/dictionaries.md) - - [Functions](basic_concepts/functions.md) - - [Classes and Module](http://introtopython.org/classes.html) - - [Error Handling](basic_concepts/error_handling.md) - - [Challenge: It's 2048!](basic_concepts/exercises/2048/README.md) - -- Advanced Concepts - - [List comprehension](https://hackernoon.com/list-comprehension-in-python-8895a785550b) - - [Generators](https://anandology.com/python-practice-book/iterators.html) - - [Decorators](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/) - -- Flask - - [Introduction](flask/discussions/01_introduction.md) - - [Setting up Flask and virtual environments](flask/discussions/02_setup.md) - - [Building my first Flask app](flask/discussions/03_my_first_flask_app.md) - - [Creating URL routes](flask/discussions/04_url_routes.md) - - [Styling templates and passing variables](flask/discussions/05_templates_and_variables.md) - - Integrating databases using SQLite :soon: - - Forming forms :soon: - - Using cookies and sessions :soon: - - Deploying my app :soon: - - Wrapping up :soon: - -- Resources - - [References](resources/references.md) +- Women Who Code Manila + - [About WWCode Manila](wwcodemanila/about.md) + - [Study Groups](wwcodemanila/study_groups.md) + +- Getting Started + - [Installation](getting_started/installation_guide.md) + - [Run a basic Python program](getting_started/warm_up.md) + - [Sharing your work](getting_started/exercise_upload_step.md) + +- Basic Concepts + - [Variables, Arithmetic Operations, Keyboard Input](basic_concepts/variables.md) + - [Let's go Git!](git/README.md) + - [Strings pa more!](basic_concepts/strings.md) + - [PEP8](basic_concepts/pep8.md) + - [List, tuple, set](basic_concepts/lists.md) + - [Conditional Statements](basic_concepts/conditional_statements.md) + - [Loops](basic_concepts/loops.md) + - [Challenge: I survived Hangman!](basic_concepts/exercises/hangman/README.md) + - [Dictionaries](basic_concepts/dictionaries.md) + - [Functions](basic_concepts/functions.md) + - [Classes and Module](http://introtopython.org/classes.html) + - [Error Handling](basic_concepts/error_handling.md) + - [Challenge: It's 2048!](basic_concepts/exercises/2048/README.md) + +- Advanced Concepts + - [List comprehension](https://hackernoon.com/list-comprehension-in-python-8895a785550b) + - [Generators](https://anandology.com/python-practice-book/iterators.html) + - [Decorators](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/) + +- Flask + - [Introduction](flask/discussions/01_introduction.md) + - [Setting up Flask and virtual environments](flask/discussions/02_setup.md) + - [Building my first Flask app](flask/discussions/03_my_first_flask_app.md) + - [Creating URL routes](flask/discussions/04_url_routes.md) + - [Styling templates and passing variables](flask/discussions/05_templates_and_variables.md) + - Integrating databases using SQLite :soon: + - Forming forms :soon: + - Using cookies and sessions :soon: + - Deploying my app :soon: + - Wrapping up :soon: + +- Ren'Py + - [Introduction](ren'py/introduction.md) + - [Installation and setting up](ren'py/installation.md) + - [Creating a new game](ren'py/create-new-game.md) + - [Aling Nena VN](ren'py/aling-nena-vn.md) + - [Tutorial Part 1](ren'py/scene1.md) + - [Tutorial Part 2](ren'py/scene2.md) + - [Tutorial Part 3](ren'py/scene3.md) + - [Tutorial Part 4](ren'py/scene4.md) + - [Tutorial Part 5 - Ending](ren'py/scene567.md) + +- Django + - [Introduction](django/01_introduction.md) + - [Setting up Django and virtual environments](django/02_setup.md) + - [Creating your first Django application](django/03_start_project.md) + - [Creating Users module](django/04_create_users_module.md) + - [Creating Users endpoints](django/05_endpoints.md) + - [Creating Questions module](django/06_create_questions_module.md) + - [Creating the frontend of the application](django/07_create_frontend.md) + - [Adding VueJS to the application](django/08_add_vue.md) + - [Adding VueJS to the application (continuation)](django/09_vue_cont.md) + +- Resources + - [References](resources/references.md) diff --git a/basic_concepts/exercises/exercises03/exercise03_01.py b/basic_concepts/exercises/exercises03/exercise03_01.py deleted file mode 100644 index 6ed0f89..0000000 --- a/basic_concepts/exercises/exercises03/exercise03_01.py +++ /dev/null @@ -1,42 +0,0 @@ -''' Lists Exercise 1: Share and tell us the output ''' - -my_list = ['w', 'o', 'm', 'e', 'n', 'w', 'h', 'o', 'c', 'o', 'd', 'e'] -aTuple = (123, 'C++', 'Java', 'Python') - - -max(my_list) - -## Output: - -min(my_list) - -## Output: - -list(aTuple) - -## Output: - -my_list.count('o') - -## Output: - -my_list.index('o') - -## Output: - -my_list.sort() - -## my_list -## Output: - -my_list.reverse() - -## my_list -## Output: - -copied_list = my_list.copy() - -## copied_list -## Output: - - diff --git a/basic_concepts/exercises/exercises03/exercise03_02.py b/basic_concepts/exercises/exercises03/exercise03_02.py deleted file mode 100644 index 97ccf58..0000000 --- a/basic_concepts/exercises/exercises03/exercise03_02.py +++ /dev/null @@ -1,18 +0,0 @@ -''' Lists Exercise 2: Working list ''' - -# Make a list that includes four careers, such as 'programmer', 'truck driver', etc.... - - -# Use the list.index() function to find the index of one career in your list. - - -# Use the in function to show that this career is in your list. - - -# Use the append() function to add a new career to your list. - - -# Use the insert() function to add a new career at the beginning of the list. - - -# Use a loop to show all the careers in your list. \ No newline at end of file diff --git a/basic_concepts/exercises/exercises03/exercise03_03.py b/basic_concepts/exercises/exercises03/exercise03_03.py deleted file mode 100644 index e9b58b2..0000000 --- a/basic_concepts/exercises/exercises03/exercise03_03.py +++ /dev/null @@ -1,7 +0,0 @@ -''' List Exercise 3 -Write a program that accepts a series of numbers, outputs all odd numbers in a list in ascending order, -and all even numbers in a list in descending order. -Sample Input: 1,2,35,45,7,8,912,23,1 -Sample Output: [1, 1, 7, 23, 35, 45] # odd - [912, 8, 2] # even -''' \ No newline at end of file diff --git a/basic_concepts/exercises/exercises03/exercise03_04.py b/basic_concepts/exercises/exercises03/exercise03_04.py deleted file mode 100644 index e089f55..0000000 --- a/basic_concepts/exercises/exercises03/exercise03_04.py +++ /dev/null @@ -1,35 +0,0 @@ -''' List Exercise 4 - -Suppose you and your friend Sally goes to the supermarket. You have the following items on your shopping list: - tomatoes, carrots, beans, milk, cabbage, corn, papaya, orange -Sally has the following on her list: - milk, tacos, cabbage, fish, beans, tuna, corn, pasta - -You and Sally decide to accomplish grocery shopping together. - -1. Write a program that outputs a new shopping list containing both of your lists, without the repeated entries, in alphabetical order -''' - -# your solution here - - -''' -While shopping, you bumped into your friend Kris. Kris saw your list, and advised you not to get the fifth item as they ran out already. -A little while later, your other friend Nat called and asked you to get peanut butter and ice cream - -2. Output the item that ran out, and your updated groceries list which includes Nat's, in alphabetical order -''' - -# your solution here - - - -''' -You were finally heading to the checkout counters; however, you noticed that the lines were too long. You and Sally decided to split the -groceries alternatively, with you lining up with the first item, Sally the second item, you the third, and so on. - -3. Output your final list, and output Sally's list -''' - - -# your solution here diff --git a/basic_concepts/exercises/lists/list.py b/basic_concepts/exercises/lists/list.py new file mode 100644 index 0000000..258a091 --- /dev/null +++ b/basic_concepts/exercises/lists/list.py @@ -0,0 +1,10 @@ +# Write a program that accepts 3 integers and separate these into odd and even numbers. +# Duplicates are permited in the input but not in the output. + +# Example + +# >>> Enter first number: 3567 +# >>> Enter second number: 789 +# >>> Enter third number: 1234 +# odd: {789, 3567} +# even: {1234} diff --git a/basic_concepts/exercises/lists/list_solution.py b/basic_concepts/exercises/lists/list_solution.py new file mode 100644 index 0000000..a0daa52 --- /dev/null +++ b/basic_concepts/exercises/lists/list_solution.py @@ -0,0 +1,38 @@ +# Write a program that accepts 3 integers and separate these into odd and even numbers. +# Duplicates are permited in the input but not in the output. + +# Example + +# >>> Enter first number: 3567 +# >>> Enter second number: 789 +# >>> Enter third number: 1234 +# odd: {789, 3567} +# even: {1234} + + +odd = [] +even = [] + +num1 = int(input("Enter first number: ")) + +if num1 % 2 == 1: + odd.append(num1) +else: even.append(num1) + +num2 = int(input("Enter second number: ")) + +if num2 % 2 == 1: + odd.append(num2) +else: even.append(num2) + + +num3 = int(input("Enter third number: ")) + +if num3 % 2 == 1: + odd.append(num3) +else: even.append(num3) + + + +print(f"odd: {set(odd)}") +print(f"even: {set(even)}") \ No newline at end of file diff --git a/basic_concepts/lists.md b/basic_concepts/lists.md index cc29abc..0dfa492 100644 --- a/basic_concepts/lists.md +++ b/basic_concepts/lists.md @@ -1,2 +1,446 @@ -## Slide Reference -Please view [here](https://docs.google.com/presentation/d/1901VMP5cIUHjmeAdDATMFgTQ_1l0k0gtV4DdJOfQ0eM/edit?usp=sharing) +So far, we have talked about some of the different data types in Python: + +* integer +* float +* string +* boolean + + In the succeeding sections, we'll cover other commonly used data types in Python: list, tuples, sets, and dictionaries. + +## List + +A list stores a collection of elements in Python. Actually, it may not contain any element at all. A list starts and ends with square brackets `[` and `]` and uses commas `,` to separate each element. These elements could be of the same, or different data types. + +### Creating lists + +To create a list, simply put comma-separated elements inside square brackets, as shown below: + +```python +# a list containing the same data types (strings) +a = ["hey", "there", "you"] + +# list of mixed data types +b = [1, 2, "papaya"] + +# list of lists +c = [[1,2], [3, 4]] + +# list of dictionaries (dictionaries will be covered in the succeeding section) +d = [{"a": "apple"}, {"b": "ball"}] +``` + +You can also create an empty list just by typing two square brackets: + +```python +x = [ ] +``` + +Or using the `list()` function + +```python +e = list() +print(e) +``` + +You can use the same function to convert strings into list + +```python +w = "womenwhocode" +w_list = list(w) +print(w_list) +``` + +!> Try `list()` on other data types. + +Lists can be created from other lists by slicing (see below). + + +### Accessing and slicing lists + +Accessing elements in a list is the same as accessing elements in strings: you use integer indices + +```python +colors = ["red", "blue", "green"] +print(colors[0]) +print(colors[2]) +print(colors[-2]) +``` + +```shell +red +green +blue +``` + +Slicing elements involves specifying a range of indices using `:`. + +```python +rhyme = [1,2,"buckle","my", "shoe", 3, 4] +words = rhyme[2:-2] +print(words) +``` + +Notice that slicing a list produces a list as well. + +```python +print(type(words)) +``` + +``` + +``` + +### Updating lists + +Once created, a list can be changed. That is, we consider them **mutable** objects in Python. Thus, one way to update a list is to re-assign a value to a particular index or indices. + +```python +odd = [2, 4, 6, 8] # not odd at all + +odd[0] = 1 # change the first value +print(odd) + +odd[1:] = [3, 5, 7] # change the rest of the values +print(odd) + +``` + +``` +[1, 4, 6, 8] +[1, 3, 5, 7] +``` + +Elements can also be added to lists + +```python +odd.append(9) # add to a number to end of list +print(odd) + +odd.extend([11, 15]) # append the contents of a sequence ([11, 15]) to list +print(odd) + +odd.insert(-1, 13) # insert object (13) at position (-1) +print(odd) +``` + +``` +[1, 3, 5, 7, 9] +[1, 3, 5, 7, 9, 11, 15] +[1, 3, 5, 7, 9, 11, 13, 15] +``` + +!> Notice that applying these methods changes the list itself. Think of ways in which this could be useful. Think of where this may not be ideal for your code or application. + +Deleting elements in a list can be done in several ways: + +```python +my_list = ["p", "r", "o", "b", "l", "e", "m"] + +del my_list[2] # remove the element in my_list[2] +print(my_list) + +my_list.remove("p") # remove the first occurence of "p" +print(my_list) + +my_list[2:3] = [] # substitute element in [2:3] thereby removing them +print(my_list) # from list. + +my_list.pop() # remove the last element +print(my_list) + +my_list.pop(1) # remove the element in index 1 +print(my_list) + +my_list.clear() # remove all elements +print(my_list) +``` + +``` +['p', 'r', 'b', 'l', 'e', 'm'] +['r', 'b', 'l', 'e', 'm'] +['r', 'b', 'e', 'm'] +['r', 'b', 'e'] +['r', 'e'] +[] +``` + +!> Note that, out of the above methods, only `pop` returns a value. What happens when we use a single index instead of range in the second example above? i.e. `my_list[2] = []` + +An entire list can also be deleted using the `del` statement. Printing the list results in an error, confirming that the list has been deleted. + +```python +del my_list +print(my_list) +``` +``` +Traceback (most recent call last): + File "test.py", line 21, in + print(my_list) +NameError: name 'my_list' is not defined +``` + + +### Basic operations + +Like strings, the operations `*` and `+` can be applied to lists. The results of these are new lists. + +```python +x = ["a", "b", "c"] + [1, 2, 3] +y = ["hello"] * 3 +z = 3 * ["world"] + +print(x) +print(y) +print(z) +``` +``` +['a', 'b', 'c', 1, 2, 3] +['hello', 'hello', 'hello'] +['world', 'world', 'world'] +``` + +!> Remember that `+` is permissible only on two or more *lists* while `*` is permissible between a *list* and an *integer*. + + +Here are other functions and methods that can be applied to a list (e.g. `list`). Try them for your self to see what they can do: + +- `len()` +- `max()` +- `min()` +- `list.count()` +- `list.index()` +- `list.reverse()` +- `list.sort()` + + +## Tuple + +Tuples are similar to lists in that they contain zero or more comma-separated elements of the same or different data types. However, one important thing to remember about tuples is that they are **immutable**; that is, unlike lists (and similar to strings) once a tuple is created, it cannot be changed. + +Tuples are bounded by parentheses `(` and `)`: + +```python +tup1 = ("t", ) # tuple with one element +tup2 = ("hello", "world") # tuple containing the same data type i.e. strings +tup3 = (1, "a", 1.5) # tuple containing different data types +tup_e = () # an empty tuple +tup4 = ([1, 2, 3], "4") # a tuple containing a list +tup5 = (("x", "y", "z"), (1, 2, 3)) # a tuple containing tuples +``` + +!> Notice that there is a trailing comma when we defined the tuple `tup1 = ("t", )` containing a single element. Why do you think is this necessary? What happens if we leave out the comma at the end? + + +Accessing and slicing elements in a tuple also makes use of integer indices and ranges of indices `:`: + +```python +print(tup2[1]) +print(tup3[0:2]) +``` + +``` +'world' +(1, 'a') +``` + +!> Try slicing a tuple and check the data type of the result. + +Similar to list, a tuple can be created from a string using the function `tuple()`: + +```python +t = tuple("code") + +print(t) +``` + +You can convert a list to a tuple using `list()`, and convert a tuple to a list using `list()` + +```python +m = tuple(["make", "me", "a", "tuple"]) +n = list(("make", "me", "a", "list")) + +print(m) +print(n) +``` + +``` +('make', 'me', 'a', 'tuple') +['make', 'me', 'a', 'list'] +``` + + +### Updating tuples + +Consider the following: + +```python +x = (1, 2, 4) + +x[-1] = 3 +``` + +What happens when we tried to substitute a value? + +Since tuples are immutable, updating and deleting a value within a tuple is not possible and will result in an error. We can, however, think of another way to come up with the desired elements. In the example above, we want a tuple with three consecutive numbers `(1, 2, 3)`. While updating an immutable object is not possible, we can define new tuples instead and perform a combination of operations. + +```python +z = x[0:-1] +y = (3, ) + +t_cons = z + y + +print(t_cons) +``` + +``` +(1, 2, 3) +``` + +An entire tuple can be deleted using the `del` statement. Printing the tuple after it has been deleted results in an error (`NameError`), confirming that the deletion has taken place. + +```python +del t_cons + +print(t_cons) +``` + +``` +Traceback (most recent call last): + File "", line 1, in +NameError: name 't_cons' is not defined +``` + +### Basic operations + +As illustrated in a previous example, `+` is permitted on tuples. Likewise, `*` can be used, resulting in new tuples. + +``` +a = ("hi",) + ("hello",) +b = ("bye",) * 3 + +print(a) +print(b) +``` + +``` +('hi', 'hello') +('bye', 'bye', 'bye') +``` + +A similar logic applies to tuples as list when using these operations: `+` can be applied to two or more *tuples*, `*` works with a *tuple* and an *integer*. + +Here are other functions that work with tuples. Try the following and see what they can do: + +- `len()` +- `max()` +- `min()` + +## Set + +A set is an *unordered* collection of data that has *no duplicate elements*. A set in Python is what it sounds like from your math lessons: it can be used to carry out operations like union, intersection, and differences. + +We will not dwell too much on sets during this study group, but in case you might have a use for sets and set operations in the future, you can read more about these [here](https://www.programiz.com/python-programming/set). + +A set consists of zero or more comma-separated elements within curly braces `{` and `}`. The values may or may not be of the same data types. Likewise, the `set()` function can be used to make an empty set, or convert a list or tuple to a set. + +The following are examples of sets + +```python +set1 = {1, 2, 3} +set2 = {("a", "b",), 3.0} +``` + +!> Simply using `{}` does not result in a set (e.g. `e = {}`). What would the type be? + +The following will result in an error + +```python +x = {[1, 2, 3], 4} +y = {{1, 2, 3 }, 4} +``` +This is because both lists and sets can change over time (they are mutable ~ unhashable), unlike tuples and strings which are immutable and therefore permitted in sets. Dictionaries, discussed in the succeeding section, are also mutable and therefore cannot be contained in sets. + +As mentioned, sets are *unordered*, hence accessing an element using integers and slicing using a range of indices do not make sense in a set and will therefore result in an error. + + +```python +set1[0] +``` + +Also the elements in sets are *deduplicated*. Even though you intentionally wrote a set with duplicate elements, these will still be stored as a single entities. + +```python +set3 = {1,1,1,1} +print(set3) +``` + + +### Updating a set + +While indices have no meaning in sets, sets are still mutable. Hence, elements in a set can be updated and/or removed. + +```python +my_set = {1, 3, 6} +print(my_set) + +my_set.add(2) +print(my_set) + +my_set.update([4, 5]) +print(my_set) + +my_set.update([6,7], {8,9}) +print(my_set) +``` + +``` +{1, 3, 6} +{1, 2, 3, 6} +{1, 2, 3, 4, 5, 6} +{1, 2, 3, 4, 5, 6, 7, 8, 9} +``` + +To remove elements or the set itself: + +```python + +another_set = {1, 2, 3, "a", "b", "c"} +print(another_set) + +another_set.discard(3) # discard 3 +print(another_set) + +another_set.remove(2) # remove 2 +print(another_set) + +another_set.discard(3) # discard 3 again +print(another_set) + +another_set.remove(3) # remove 3 + +another_set.clear() # remove all elements in set +print(another_set) + +del another_set # delete the set itself +print(another_set) +``` + +!> From running the code above, what do you think is the difference between `.remove()` and `.discard()`? + + +## Challenge + + +!> Please use the template below + +[filename](exercises/lists/list.py ':include :type=code python') + +[challenge_partial](../challenge_partial.md ':include') + + +## Put your thinking cap on! + +- How is an **array** in Python different from a list? +- We've briefly covered **mutable** (e.g. list, sets) and **immutable** (e.g. strings) objects in Python. What other objects are considered mutable? How about immutable? +- Strings, lists, and tuples have plenty in common in terms of the methods and operations that can be done to them. Why do you think this is so? + diff --git a/django/01_introduction.md b/django/01_introduction.md new file mode 100644 index 0000000..de55653 --- /dev/null +++ b/django/01_introduction.md @@ -0,0 +1,39 @@ +# Web Development with Django + +Welcome to Python - Django Web Framework Study Group. Have a little sip of your :coffee: first before we start building. :computer: + +Before we deep dive into the world of Django, check these things first in your local machine: + +- [x] I have a text editor installed in my computer (e.g. Notepad++, Sublime). +- [x] I have Python installed in my computer. +- [x] I'm familiar with the basics concepts of Python. + +## What will you learn? + +Once you have finished our study group, you will be able to create a Quora/Reddit-like web application. You will also learn the following in the process: +- Django, DRF, and VueJS +- How to use Vue CLI and Vue Router + +## What is Django? + +[Django](https://www.djangoproject.com/) is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. It’s free and open source. + +## Why You Should Learn Django? +- It is written in Python (obviously). +- You don't need to rely on external libraries / packages. +- It has an in-depth [documentation](https://www.djangoproject.com/). +- You can ask for help by joining to their [community](https://stackoverflow.com/questions/tagged/django). + +## Applications powered by Django +- Spotify +- Pinterest +- Instagram +- Mozilla +- Disqus +- National Geograpic +- Knight Foundation + +## References +- [Django Girls Tutorial](https://tutorial.djangogirls.org/en/) +- [The Complete Guide to Django REST Framework and Vue JS](https://www.udemy.com/course/the-complete-guide-to-django-rest-framework-and-vue-js/learn/lecture/14198644?start=0#overview) +- [10 Popular Websites Built With Django](https://djangostars.com/blog/10-popular-sites-made-on-django/) \ No newline at end of file diff --git a/django/02_setup.md b/django/02_setup.md new file mode 100644 index 0000000..c6a7886 --- /dev/null +++ b/django/02_setup.md @@ -0,0 +1,125 @@ +## Goals + +- [ ] Understand the importance of virtual environments +- [ ] Install and create a virtual environment +- [ ] Install and use `virtualenvwrapper` +- [ ] Install Django and Django Rest Framework through pip + +## Virtual Environments + +A **virtual environment** is a self-contained directory tree that contains a Python installation for a particular version of Python, plus a number of additional packages. It is used to isolate a particular project to avoid conflicts with the requirements of another project. **`virtualenv`** is a tool used to create Python virtual environments. + +## Installing 'virtualenv' + +Check if `virtualenv` already exists in your system through your terminal or console: + +```shell +$ virtualenv --version +``` + +If you see a version number, that means you already have it installed and may now proceed to the next step. Otherwise, install `virtualenv` through the Python package manager, a.k.a. `pip`: + +```shell +$ pip install virtualenv +``` + +Visit this [link](https://packaging.python.org/guides/installing-using-pip-and-virtualenv/) for more info on how to make sure you have the latest version of pip installed. + +## Working with 'virtualenv' + +To create a virtual environment, go to your project's directory and run `virtualenv`: + +```shell +cd path/to/directory +virtualenv env +``` + +The second argument refers to the location where you want to create the `virtualenv`. Generally, you can just create this in your project and call it `env`. `virtualenv` will create a virtual Python installation in the `env` folder. + +**Note**: Don't forget to exclude your `virtualenv` directory from your version control system using .gitignore or similar. + +To activate your `virtualenv`: + +```shell +Windows +$ .\env\Scripts\activate + +Linux and macOS +$ source env/bin/activate +``` + +To confirm if you're in the `virtualenv` by checking the location of your Python interpreter, which should point to the `env` directory: + +```shell +Windows +$ where python + +Linux and macOS +$ which python +``` + +As long as your `virtualenv` is activated, pip will install packages into that specific environment and you'll be able to import and use packages in your Python application. + +To leave your `virtualenv`, simply run: + +```shell +$ deactivate +``` + +## Bonus: virtualenvwrapper + +To make working with virtual environments easier (especially for Windows uers), you can use [virtualenvwrapper](http://virtualenvwrapper.readthedocs.io/en/latest/), which is a set of extensions to the `virtualenv` tool. It also places all of your virtual environments in a single location. + +```shell +Mac: +$ pip install virtualenvwrapper +$ export WORKON_HOME=~/Envs +$ source /usr/local/bin/virtualenvwrapper.sh + +Windows: +$ pip install virtualenvwrapper-win +``` + +Once you've installed `virtualenvwrapper`, create a new isolated development environment: + +```shell +mkvirtualenv portfolio +``` + +This produced a folder named `portolio` inside the `Envs` folder with a clean copy of Python inside. + +To activate `virtualenv` with `virtualenvwrapper`: + +```shell +$ workon portfolio +``` + +You may also check the list of existing virtual environments in your `Envs` folder by typing: + +```shell +$ workon +``` + +## Installing Django and Django Rest Framework + +To install Django through `pip`, just run: + +```shell +$ pip install django djangorestframework +``` + +## Saving packages + +To save the list of packages installed in your environment for easier reproduction: + +```shell +$ pip freeze > requirements.txt +``` + +This will save what you've installed so far in a text file named `requirements.txt`. + +To install the packages listed in a `requirements.txt` file: + +```shell +$ pip install -r requirements.txt +``` diff --git a/django/03_start_project.md b/django/03_start_project.md new file mode 100644 index 0000000..4a32ff2 --- /dev/null +++ b/django/03_start_project.md @@ -0,0 +1,61 @@ +## Goals + +- [ ] Starting the project +- [ ] Setting things up +- [ ] Running the server + +## Starting the project + +Once you've installed the `Django` web framework inside your `env` virtual environment, start the project by typing this command: +``` +django-admin startproject forumapp . +``` + +Your directory structure should look like this: +``` +django +C:. +│ manage.py +│ requirements.txt +│ +└───forumapp + asgi.py + settings.py + urls.py + wsgi.py + __init__.py +``` +These files are: + +- The outer `django/` root directory is a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like. +- `manage.py`: A command-line utility that lets you interact with this Django project in various ways. +- The inner `forumapp/` directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. forumapp.urls). +- `forumapp/__init__.py`: An empty file that tells Python that this directory should be considered a Python package. If you’re a Python beginner, read [more about packages](https://docs.python.org/3/tutorial/modules.html#tut-packages) in the official Python docs. +- `forumapp/settings.py`: Settings/configuration for this Django project. Django settings will tell you all about how settings work. +- `forumapp/urls.py`: The URL declarations for this Django project; a “table of contents” of your Django-powered site. +- `forumapp/asgi.py`: An entry-point for ASGI-compatible web servers to serve your project. See [How to deploy with ASGI](https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/) for more details. +- `forumapp/wsgi.py`: An entry-point for WSGI-compatible web servers to serve your project. See [How to deploy with WSGI](https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/) for more details. + +## Setting things up + +Using your favorite text editor, go to `forumapp/settings.py`. The first thing that we need to consider editing is the `TIME_ZONE`. You may get the relevant time zone in the [Wikipedia's list of time zone.](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) + +The code should look like this: +``` +TIME_ZONE = 'Asia/Manila' +``` + +The second thing to check is the language. If English is not your native language, you can add this to change the default buttons and notifications from Django to be in your language. +``` +LANGUAGE_CODE = 'en-us' +``` + +## Running the server +Once checked and ensured that the directory or the project that you are working on has the same structure stated above, run the server by typing this command: +``` +python manage.py migrate +python manage.py runserver +``` + +Check your browser, then go to `localhost:8000` or `http://127.0.0.1:8000/`. + diff --git a/django/04_create_users_module.md b/django/04_create_users_module.md new file mode 100644 index 0000000..743be8b --- /dev/null +++ b/django/04_create_users_module.md @@ -0,0 +1,346 @@ +## Goals +- [ ] Create users module + - [ ] Adding a model + - [ ] Registering users module to admin +- [ ] Application Settings +- [ ] Create a superuser +- [ ] Install other required libraries +- [ ] Adding to urls +- [ ] Settings and Templates + +## Create `users` module +``` +python manage.py startapp users +``` + +``` +django +C:. +│ manage.py +│ requirements.txt +│ +├───forumapp +│ │ asgi.py +│ │ settings.py +│ │ urls.py +│ │ wsgi.py +│ |____init__.py +│ +└───users + │ admin.py + │ apps.py + │ models.py + │ tests.py + │ views.py + │ __init__.py + │ + └───migrations + __init__.py +``` + +In order to use the newly-created module (`users`), and the library `rest_framework`, +add them to the file `settings.py`. `rest_framework.authtoken` should also be added for token authentication. +``` +INSTALLED_APPS = [ + 'rest_framework', + 'rest_framework.authtoken', + 'users' +] +``` +### Adding a model +We are not going to add new fields to the model, but it is also a good idea to think about the future of the project. We are going to use the User model of django. +Go to `users/models.py`, enter this command: +``` +from django.contrib.auth.models import AbstractUser + +class CustomUser(AbstractUser): + pass +``` + +The user model is important for the authentication. We need to explicitly state that we're using a custom model. In `settings.py`, add this at the end: +``` +AUTH_USER_MODEL = "users.CustomUser" +``` + +### Registering users module to admin +Add the custom model user. Go to `users/admin.py`, enter this command: +``` +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from users.models import CustomUser + +class CustomUserAdmin(UserAdmin): + model = CustomUser + list_display = ["username", "email", "is_staff"] + + +admin.site.register(CustomUser, CustomUserAdmin) +``` + +Then make migrations, migrate: + +``` +> python manage.py makemigrations +> python manage.py migrate +``` + +## Create a superuser + +Now, we already have the users module, but we don't have an actual `user`. What are we going to do is to create a `superuser`. + +``` +python manage.py createsuperuser +``` + +Enter your information and press enter. + +``` +Username: admin123 +Email address: admin123@example.com +Password: admin123 +Password (again): admin123 +Superuser created successfully. +``` + +Now, let's run again the server. + +``` +python manage.py runserver +``` + +Access the admin interface by entering this url in your browser: +``` +http://localhost:8000/admin +``` + +## Install other required libraries +We need to enable creation of new accounts and authenticate them, so we will be needing a couple of packages in our project. +``` +pip install django-rest-auth django-allauth django-registration django-crispy-forms +pip freeze > requirements.txt +``` + +- django-rest-auth enables user registration with activation, login/logout, etc. +- django-allauth enables signup of both local and social accounts +- django-registration enables two-phase(with confirmation email)/one-phase(immediately active and logged in)registration +- django-crispy-forms used to create good looking forms + +We also need to activate our installed libraries in `settings.py`: +``` +'django.contrib.sites' +'allauth', +'allauth.account', +'allauth.socialaccount', +'rest_auth', +'rest_auth.registration' + +'crispy_forms' +``` + +Next is setting important variables to the libraries the we added. +``` +# Custom User Model +AUTH_USER_MODEL= 'users.CustomUser' + +# django-crispy-forms +CRISPY_TEMPLATE_PACK = 'bootstrap4' + +# django.contrib.sites +SITE_ID = 1 + +# django.allauth +ACCOUNT_EMAIL_VERIFICATION = 'none' +ACCOUNT_EMAIL_REQUIRED = (True) +``` + +Then make migrations, migrate: + +``` +> python manage.py makemigrations +> python manage.py migrate +``` + +## Adding to urls +Add new urls to our application. In `forumapp/urls.py`: +``` +from django.urls import include, path, re_path + +urlpatterns = [ + path('admin/', admin.site.urls), + + # Login and registration paths provided by django + path('accounts/', include('django.contrib.auth.urls')), + + # Login via browsable API + path('api-auth/', include('rest_framework.urls')), + + # Login via rest + path('api/rest-auth/', include('rest_auth.urls')), + + # Registration via rest + path('api/rest-auth/registration/', include('rest_auth.registration.urls')), + +] +``` + +We are going to use the views provided by the Django registration package, even though those views expect us to use a default user model. Since we are using a custom user, we also need to create a custom form. + +In users folder, create `forms.py`. Also enter this script: +``` +from django_registration.forms import RegistrationForm +from users.models import CustomUser + + +class CustomUserForm(Registration Form): + + class Meta(RegistrationForm.Meta): + model = CustomUser +``` + +Now, import the file to `forumapp/urls.py`. +``` +# Skip email verification +from django_registration.backends.one_step.views import RegistrationView + +from users.forms import CustomUserForm + +# Custom version of the registration provided by django registration +path('accounts/register/', + RegistrationView.as_view( + form_class=CustomUserForm, + success_url = '/', + ), name='django_registration_register'), + +# Other URLs provided by django registration package +path('accounts/', include('django_registration.backends.one_step.urls')), +``` +For more info about RegistrationView, go to this [link.](https://django-registration.readthedocs.io/en/3.1.2/one-step-workflow.html) + + +After that, go to `settings.py`, add the following. This will help us redirect after logging in, logging out. +``` +LOGIN_URL = 'accounts/login/' +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' +``` + +## Settings and Templates +The next step that we are going to do is to create templates that are needed to authenticate users via browser. + +Go to `forumapp/settings.py`, set this command: +``` +# Django-REST-Framework +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework.authentication.TokenAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ), + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.IsAuthenticated', + ), +} +``` + +Then create a templates directory. Still inside the `settings.py` file, add the directory inside the dictionary `TEMPLATES` like this. Also add the templates folder in the root directory. +``` +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR / 'templates'], # this should be added + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] +``` + +Inside the templates folder, add two more folders: `django_registration` `registration`. + +- `django_registration` - to cater the templates required by Django Registration package. +- `registration` - store all the login related templates used by Django. + +Now, we have to make sure that the authetication-related templates share a common layout. Let's create a new file called `templates/auth_layout.html`. +``` + + + + + + + + + Forum App + + + +

+ {% block content %} + {% endblock %} +
+ + + +``` + +We can add a new template called `templates/registration/login.html`. This html file will call the main design `auth_layout`, then add new style such as the login form container. +``` +{% extends 'auth_layout.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Login

+
+
+ {% csrf_token %} + {{ form | crispy }} + +
+
+{% endblock %} +``` + +Now, let's define the style `login-form-container` in `templates/auth_layout.html`. The style tag should be inside the `` tag. +``` + +``` + +Next is to create a template called `templates/django_registration/registration_form.html`. Just copy from `templates/registration/login.html`, then change necessary information. +``` +{% extends 'auth_layout.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Create your Account

+
+
+ {% csrf_token %} + {{ form|crispy }} + +
+
+{% endblock %} +``` + +Don't forget also to add the style in `templates/auth_layout.html`. +``` + +``` + +Now reload, then check your browser! Access this URL: +`localhost:8000/accounts/register` \ No newline at end of file diff --git a/django/05_endpoints.md b/django/05_endpoints.md new file mode 100644 index 0000000..beddd5c --- /dev/null +++ b/django/05_endpoints.md @@ -0,0 +1,117 @@ +## Goals +- [ ] Create a homepage endpoint +- [ ] Create endpoints for users module + +## Create a homepage endpoint +We are now going to create our endpoint. Endpoints provide a useful information about the user that is currently connected to the application. + +We saw in the `settings.py` file that the URLs are set to these. Now, we are going to create a path that points to homepage('/') and link a view to render the template. +``` +LOGIN_REDIRECT_URL = '/' +``` + +Create a folder in the root directory called `core`. Inside the folder create `__init__.py` and `views.py`. Inside the view, add this script. +``` +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic.base import TemplateView + + +class IndexTemplateView(LoginRequiredMixin, TemplateView): + + # overwrite the method + def get_template_names(self): + template_name = 'index.html' + return template_name +``` +We have the the `template_name` to `index.html`, but we don't have it yet, so we are going to create it inside the folder `templates`. +``` + + + + + + + Forum App + + + +

Vue JS

+ +
+ + + +``` + +Create a path for the class `IndexTemplateView`. Import it inside the `forumapp/urls.py`. + +``` +from core.views import IndexTemplateView + +# Put this at the end of the urlpatterns +re_path(r"^.*$", IndexTemplateView.as_view(), name='entry-point'), +``` + +Check again your browser, then go to `localhost:8000` or `http://127.0.0.1:8000/`. You should be seeing Vue JS text. + +## Create endpoints for users module +We will continue creating endpoints for the users module. Create the folder `api` in `users` module. Inside it, create the ff folders: +``` +- serializers.py +- urls.py +- views.py +``` + +Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes, then rendered to `JSON`, or `XML`. + +In `users/api/serializers.py`, add this set of code: +``` +from rest_framework import serializers +from users.models import CustomUser + + +class UserDisplaySerializer(serializers.ModelSerializer): + + class Meta: + model = CustomUser + fields = ["username"] +``` + +The view function, takes a web request and returns a web response. It is important to know that views handles the logic that gets processed each time a different URL is visited. + +In `users/api/views.py`, add this block of code: + +``` +from rest_framework.response import Response +from rest_framework.views import APIView +from users.api.serializers import UserDisplaySerializer + + +class CurrentUserAPIView(APIView): + + def get(self, request): + serializer = UserDisplaySerializer(request.user) + return Response(serializer.data) +``` + +We need to ensure that our created view is registered in `users/api/urls.py`. +``` +from django.urls import path +from users.api.views import CurrentUserAPIView + +urlpatterns = [ + path("user/", CurrentUserAPIView.as_view(), name="current-user") +] +``` + +And in `forumapp/urls.py`, register the api under users. +``` + path("api/", include("users.api.urls")), +``` + +Again reload and check your browser! Access this URL: +`localhost:8000/api/user/` + +As you can see in the browser, the `username` is shown. It is because of what we did earlier in the serializer and view. + + diff --git a/django/06_create_questions_module.md b/django/06_create_questions_module.md new file mode 100644 index 0000000..a20ff35 --- /dev/null +++ b/django/06_create_questions_module.md @@ -0,0 +1,404 @@ +## Goals +- [ ] Create questions module +- [ ] Create questions and answers serializer +- [ ] Create questions views +- [ ] Create answers views +- [ ] Create detail endpoints +- [ ] Create like endpoint + +## Create `questions` module +``` +python manage.py startapp questions +``` + +After starting the application, register the app in `forumapp/settings.py` +``` +INSTALLED_APPS = [ + ... + 'questions' +] +``` + +Define the model that we will be using for the `questions` and `anwsers`. In `questions/models.py`: +``` +from django.db import models +from django.conf import settings + + +class Question(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + content = models.CharField(max_length=240) + slug = models.SlugField(max_length=255, unique=True) + author = models.ForeignKey(settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + related_name="questions") + + def __str__(self): + return self.content + + +class Answer(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + body = models.TextField() + question = models.ForeignKey(Question, + on_delete=models.CASCADE, + related_name="answers") + author = models.ForeignKey(settings.AUTH_USER_MODEL, + on_delete=models.CASCADE) + voters = models.ManyToManyField(settings.AUTH_USER_MODEL, + related_name="votes") + + def __str__(self): + return self.author.username +``` + +Then make migrations, migrate: + +``` +> python manage.py makemigrations +> python manage.py migrate +``` + +Let us also register the models that we created to `questions/admin.py`. +``` +from django.contrib import admin +from questions.models import Answer, Question + +admin.site.register(Answer) +admin.site.register(Question) + +``` + +We have defined a `SlugField` in the model. A slug is a short label for something, containing only letters, numbers or hyphens. A SlugField is a field that is automatically created. In this case, we have to find a way to create it, as it also has to be unique. We are going to use `signal`, that is used with the model. + +Create the file `questions/signals.py`: +``` +from django.db.models.signals import pre_save +from django.dispatch import receiver +from django.utils.text import slugify + +from core.utils import generate_random_string +from questions.models import Question +``` + +Then create a `generate_random_string` function inside `core/utils.py`: +``` +import random +import string + +ALPHANUMERIC_CHARS = string.ascii_lowercase + string.digits +STRING_LENGTH = 6 + +def generate_random_string(chars=ALPHANUMERIC_CHARS, length=STRING_LENGTH): + return "".join(random.choice(chars) for _ in range(length)) +``` + +After that, go back to `questions/signals.py`. Add the function `add_slug_to_question`. This will also call the function that we created in `core/utils.py` +``` +@receiver(pre_save, sender=Question) +def add_slug_to_question(sender, instance, *args, **kwargs): + if instance and not instance.slug: + slug = slugify(instance.content) + random_string = generate_random_string() + instance.slug = slug + "-" + random_string +``` + +Complete the setup by registering this to `questions/apps.py`. +``` +from django.apps import AppConfig + + +class QuestionsConfig(AppConfig): + name = 'questions' + + def ready(self): + import questions.signals +``` + +And in `questions/__init__.py`, register the `QuestionsConfig`. +``` +default_app_config = "questions.apps.QuestionsConfig" +``` + +Check that everything works fine in your terminal by typing +``` +$ python manage.py shell + +>>> from django.contrib.auth import get_user_model +>>> custom_user = get_user_model() +>>> u = custom_user.objects.first() +>>> u + +>>> from questions.models import Question +>>> q = Question.objects.create(author=u, content="First, question! Does it work?") +>>> q + +>>> q.slug +'first-question-does-it-work-ea8vb1' +``` + +## Create questions and answers serializer +In the previous part of this chapter, we created a model for `Questions` and `Answers`. Now we need to create a seralizer for them. + +Create folder `questions/api` then create `serializers.py`. +``` +from rest_framework import serializers +from questions.models import Answer, Question + + +class AnswerSerializer(serializers.ModelSerializer): + author = serializers.StringRelatedField(read_only=True) + created_at = serializers.SerializerMethodField() + likes_count = serializers.SerializerMethodField() + user_has_voted = serializers.SerializerMethodField() + question_slug = serializers.SerializerMethodField() + + class Meta: + model = Answer + exclude = ["question", "voters", "updated_at"] + + def get_created_at(self, instance): + return instance.created_at.strftime("%B %d, %Y") + + def get_likes_count(self, instance): + return instance.voters.count() + + def get_user_has_voted(self, instance): + request = self.context.get("request") + return instance.voters.filter(pk=request.user.pk).exists() + + def get_question_slug(self, instance): + return instance.question.slug + + +class QuestionSerializer(serializers.ModelSerializer): + author = serializers.StringRelatedField(read_only=True) + created_at = serializers.SerializerMethodField() + slug = serializers.SlugField(read_only=True) + answers_count = serializers.SerializerMethodField() + user_has_answered = serializers.SerializerMethodField() + + class Meta: + model = Question + exclude = ["updated_at"] + + def get_created_at(self, instance): + return instance.created_at.strftime("%B %d, %Y") + + def get_answers_count(self, instance): + return instance.answers.count() + + def get_user_has_answered(self, instance): + request = self.context.get("request") + return instance.answers.filter(author=request.user).exists() +``` + +## Create `questions` views +In this part we will create a viewset for module `questions`. It is a class-based view without method handlers such as `get` or `post`, but it provides actions such as `.list()` and `.create()`. +questions/api/views.py + +``` +from rest_framework import serializers, viewsets +from rest_framework.permissions import IsAuthenticated + +from questions.api.serializers import QuestionSerializer +from questions.api.permissions import IsAuthorOrReadOnly +from questions.models import Question + + +class QuestionViewSet(viewsets.ModelViewSet): + queryset = Question.objects.all() + lookup_field = 'slug' + serializer_class = QuestionSerializer + permission_classes = [IsAuthenticated, IsAuthorOrReadOnly] + + def perform_create(self, serializer): + serializer.save(author=self.request.user) + + +``` + +Then we will create a `permissions.py` file in `questions/api` folder to secure the api and restrict other users from accessing the apis. We will create a class `IsAuthorOrReadOnly`. + +``` +from rest_framework import permissions + + +class IsAuthorOrReadOnly(permissions.BasePermission): + + def has_object_permission(self, request, view, obj): + if request.method in permissions.SAFE_METHODS: + return True + return obj.author == request.user +``` + + +In `questions/api/urls.py`, register the view. +``` +from django.urls import include, path +from rest_framework import routers, urlpatterns +from rest_framework.routers import DefaultRouter + +from questions.api import views as qv + +router = DefaultRouter() +router.register(r"questions", qv.QuestionViewSet) + + +urlpatterns = [ + path("", include(router.urls)) +] +``` + +After that, register the `questions` url in the `forumapp/urls.py` file. Register this inside the urlpatterns. +``` + path('api/', include('questions.api.urls')), +``` + +Now, try the newly created api by accessing it in your browser then by typing `localhost:8000/api/questions/`. You may access the api with the question instance. You may also try to accessor update an individual questions by adding the slug value at the end of the search bar. +``` +example: +http://localhost:8000/api/questions/first-question-does-it-work-7ue6r8/ +``` + +## Create `answers` views +In `questions/api/views.py`, we are going to create two separate views, first to let the users answer the question, and second to list all of the answers for the questions. + +``` +from rest_framework import generics, viewsets +from rest_framework.exceptions import ValidationError +from rest_framework.generics import get_object_or_404 + + +from questions.api.serializers import AnswerSerializer, QuestionSerializer +from questions.models import Answer, Question + + +class AnswerCreateAPIView(generics.CreateAPIView): + queryset = Answer.objects.all() + serializer_class = AnswerSerializer + permission_classes = [IsAuthenticated] + + def perform_create(self, serializer): + request_user = self.request.user + kwarg_slug = self.kwargs.get("slug") + question = get_object_or_404(Question, slug=kwarg_slug) + + if question.answers.filter(author=request_user).exists(): + raise ValidationError("You have already answered this question!") + serializer.save(author=self.request.user, question=question) +``` + +Then register the View to `questions/api/urls.py` +``` +path("questions//answer/", + qv.AnswerCreateAPIView.as_view(), name='answer-create') +``` + +Now, go back to your browser then check whether you see an answer field, like in the example below: +``` +http://localhost:8000/api/questions/do-you-like-guitars-norzk0/answer/ + +``` + +Once you accessed the link in your browser, you may notice that you cannot access a list of all of the answers in each question. The next thing that we need to do is to create a view that will list them all. + +In `questions/api/views.py`, create another class called `AnswerListAPIView`. + +``` +class AnswerListAPIView(generics.ListAPIView): + serializer_class = AnswerSerializer + permission_classes = [IsAuthenticated] + + def get_queryset(self): + kwarg_slug = self.kwargs.get('slug') + return Answer.objects.filter(question__slug=kwarg_slug).order_by('-created_at') +``` + +Same as what we did earlier, register the view `AnswerListAPIView` to `questions/api/urls.py`. + +``` +path("questions//answers/", + qv.AnswerListAPIView.as_view(), name='answer-list') +``` + +Perfect! Now, go back to your browser, then access this link `http://localhost:8000/api/questions//answers/`. You may now check the list of the answers in each question. :tada: + + +## Create detail endpoint +To finish our backend setup, we need two more endpoints; one for Retrieving, Updating and Deleting answers, and one for the "like" feature. + +In `questions/api/views.py`, add a class called `AnswerRUDApiView`. + +``` +class AnswerRUDApiView(generics.RetrieveUpdateDestroyAPIView): + queryset = Answer.objects.all() + serializer_class = AnswerSerializer + permission_classes = [IsAuthenticated, IsAuthorOrReadOnly] +``` +Then register again in `questions/api/urls.py`. +``` +path("answers//", + qv.AnswerRUDApiView.as_view(), name='answer-detail') +``` +Try accessing the url `http://localhost:8000/api/questions//answers/`, you can see a list of answers with id. After that, get the id, then use that id in url `http://localhost:8000/api/answers//`. You may see the details of the answer. Try also updating and deleting the answer. + +## Create like endpoint +Let us now create the last endpoint - the like endpoint. +In `questions/api/views.py`, add a class called `AnswerLikeAPIView`. +``` +from rest_framework import generics, status, viewsets + +from rest_framework.response import Response +from rest_framework.views import APIView + + +class AnswerLikeAPIView(APIView): + serializer_class = AnswerSerializer + permission_classes = [IsAuthenticated] + + def delete(self, request, pk): + answer = get_object_or_404(Answer, pk=pk) + user = request.user + + answer.voters.remove(user) + answer.save() + + serializer_context = {'request': request} + serializer = self.serializer_class(answer, context=serializer_context) + + return Response(serializer.data, status=status.HTTP_200_OK) + + def post(self, request, pk): + answer = get_object_or_404(Answer, pk=pk) + user = request.user + + answer.voters.add(user) + answer.save() + + serializer_context = {'request': request} + serializer = self.serializer_class(answer, context=serializer_context) + + return Response(serializer.data, status=status.HTTP_200_OK) +``` + +Register the view in `questions/api/urls.py`. + +``` +path("answers//like/", + qv.AnswerLikeAPIView.as_view(), name='answer-like') +``` + +Access the created endpoint by typing in `http://localhost:8000/api/answers//like/`. + +The last thing that we need to do is to set the pagination in `settings.py` file. +``` +REST_FRAMEWORK = { + ... + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 2 +} +``` + diff --git a/django/07_create_frontend.md b/django/07_create_frontend.md new file mode 100644 index 0000000..3b1d7f0 --- /dev/null +++ b/django/07_create_frontend.md @@ -0,0 +1,103 @@ +## Goals +- [ ] Create a Registration Link on the Login Page +- [ ] Create a Login Link on the Registration Page +- [ ] Adding Margins to Layout +- [ ] Adding a Border + +## Create a Registration Link on the Login Page +Yay! We are done setting-up the backend of our application! Now, we will be focusing on the front-end side of the app. We want to make it more `user-friendly` that is why we are going to modify or add a few things. + +Open `templates/registration/login.html`. Add this line of code after `

Login

`: + +``` +

Share Your Knowledge!

+``` + +Also, add the registration link inside the class `login-form-container` after the `form` tag: + +``` +

Or Create an Account

+``` + +The code should look like this: +``` +{% extends 'auth_layout.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Login

+

Share Your Knowledge!

+ +{% endblock %} +``` + +Go to url `http://localhost:8000/accounts/login/` and see the changes. + +## Create a Login Link on the Registration Page +In this part, we are going to do the same steps. In `templates/django_registration/registration_form.html`, add this code inside the class `registration-form-container`, under the `form` tag. + +``` +

Or Login

+``` +The code should look like this: +``` +{% extends 'auth_layout.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Create Your Account

+
+
+ {% csrf_token %} + {{ form | crispy }} + +
+

Or Login

+
+{% endblock %} +``` + +Then check the changes by accessing this url: `http://localhost:8000/accounts/register/`. + +## Adding Margins to Layout +In this part, we are going to add some margins to our `registration` page and `login` page. +In `templates/auth_layout.html`, add a css class called `outer-area`. The style would look as follows: +``` + .outer-area { + margin-top: 100px; + } +``` +Then add a new div tag outside the div class `auth-box text-center`. In the newly added div tag, call the `outer-area` class. It should look like this: + +``` + + +
+
+ {% block content %} + {% endblock %} +
+
+ + +``` + +## Adding a Border +To add a border on registration and login page, add a css class named `auth-box`. Then add these other details: +``` +.auth-box { + border: 3px solid lightgray; + border-radius: 10px; + padding-top: 25px; + padding-bottom: 25px; + width: 600px; + margin: auto; +} +``` \ No newline at end of file diff --git a/django/08_add_vue.md b/django/08_add_vue.md new file mode 100644 index 0000000..ca9efa6 --- /dev/null +++ b/django/08_add_vue.md @@ -0,0 +1,195 @@ +## Goals +- [ ] Install NPM +- [ ] Install VueCLI +- [ ] Add Vue to application + +## Install NPM +Go to `https://nodejs.org/en/download/`, download the latest or the LTS version of Node. Install node with the recommended settings. Check if Node and NPM is installed by checking in your terminal: + +``` +> npm --version +6.14.14 +> node --version +v14.17.4 +``` + +## Install VueCLI +Once the NodeJS has been installed in your computer, you may now install the VueCLI. In your terminal, type this command: +``` +sudo npm i -g @vue/cli +``` +Then test if its working by typing +``` +vue create hello-vue +Vue CLI v4.5.13 +? Please pick a preset: Manually select features +? Check the features needed for your project: Choose Vue version, Babel, Router, Linter +? Choose a version of Vue.js that you want to start the project with 2.x +? Use history mode for router? (Requires proper server setup for index fallback in production) Yes +? Pick a linter / formatter config: Prettier +? Pick additional lint features: Lint on save +? Where do you prefer placing config for Babel, ESLint, etc.? In package.json +? Save this as a preset for future projects? (y/N) N +``` + +Wait for a few minutes, then once completed, will show a prompt like this: + +``` +📄 Generating README.md... + +🎉 Successfully created project hello-vue2. +👉 Get started with the following commands: + + $ cd hello-vue + $ npm run serve +``` + +Go to `hello-vue` and type `npm run serve`. It will remind you to access to `http://localhost:/`. Go to that url and check if Vue is showing. This indicates that Vue is properly installed to your computer. + + +## Add Vue to application +We are going to create a simple Vue project in our Django project. Ensure that the project name is `frontend`, like so: +``` +vue create frontend +``` + +Set the config like the ones below: +``` +vue create hello-vue +Vue CLI v4.5.13 +? Please pick a preset: Manually select features +? Check the features needed for your project: Choose Vue version, Babel, Router, Linter +? Choose a version of Vue.js that you want to start the project with 2.x +? Use history mode for router? (Requires proper server setup for index fallback in production) Yes +? Pick a linter / formatter config: Prettier +? Pick additional lint features: Lint on save +? Where do you prefer placing config for Babel, ESLint, etc.? In package.json +? Save this as a preset for future projects? (y/N) N +``` + +Then, we're going to install a package `webpack-bundle-tracker` to keep track of the code in our frontend application. +Go to `frontend` folder then install the webpack tracker: +``` +cd frontend + +npm install --save-dev webpack-bundle-tracker@0.4.3 +``` + +Next, create a file inside the folder `frontend`. Name it `vue.config.js`. +``` +const BundleTracker = require("webpack-bundle-tracker"); + +module.exports = { + // on Windows you might want to set publicPath: "http://127.0.0.1:8080/" + publicPath: "http://127.0.0.1:8081/", + outputDir: './dist/', + + chainWebpack: config => { + + config + .plugin('BundleTracker') + .use(BundleTracker, [{filename: './webpack-stats.json'}]) + + config.output + .filename('bundle.js') + + config.optimization + .splitChunks(false) + + config.resolve.alias + .set('__STATIC__', 'static') + + config.devServer + // the first 3 lines of the following code have been added to the configuration + .public('http://127.0.0.1:8080') + .host('127.0.0.1') + .port(8080) + .hotOnly(true) + .watchOptions({poll: 1000}) + .https(false) + .disableHostCheck(true) + .headers({"Access-Control-Allow-Origin": ["\*"]}) + + }, + + // uncomment before executing 'npm run build' + // css: { + // extract: { + // filename: 'bundle.css', + // chunkFilename: 'bundle.css', + // }, + // } + +}; + +``` + +Next, we are going to install a webpack loader in Django environment. This will help us read the changes given by the bundle tracker. +``` +pip install django-webpack-loader==0.7.0 +``` + +Update the requirements.txt file. +``` +pip freeze > requirements.txt +``` + +Then add the webpack_loader library to `settings.py`. +``` +INSTALLED_APPS = [ + 'webpack_loader', +] + +// on the bottom of settings.py file +WEBPACK_LOADER = { + 'DEFAULT': { + 'BUNDLE_DIR_NAME': 'dist/', + 'STATS_FILE': BASE_DIR / 'frontend' / 'webpack-stats.json' + } +} +``` + +Add this code inside the file `templates/index.html`, on the first line of the code: +``` +{% load render_bundle from webpack_loader %} +``` +Also, add this inside the body of the code, after the div id app: +``` +{% render_bundle 'app' %} +``` + +The index file should look this this: +``` +{% load render_bundle from webpack_loader %} + + + + + + + Forum App + + + +

Vue JS

+ +
+ + {% render_bundle 'app' %} + + + +``` + +Run server of both django and vue separately. +``` +python manage.py runserver + +npm run serve +``` + + +(Optional) You may also explore the vue project by typing this command. +``` +vue ui +``` \ No newline at end of file diff --git a/django/09_vue_cont.md b/django/09_vue_cont.md new file mode 100644 index 0000000..8e023db --- /dev/null +++ b/django/09_vue_cont.md @@ -0,0 +1,507 @@ +## Goals +- [ ] Additional setup +- [ ] Add navbar component +- [ ] Initialize csrf token +- [ ] Add home component and questions list +- [ ] Add single question component + +## Additional Setup +Add this script to be shown whenever there is an error with JavaScript in `templates/index.html`, above the div id app. +``` + +``` + +Comment out the base key-value in `src/router/index.js`, `const router`. This will remove the extended baseurl that we saw in our browser. +``` +const router = new VueRouter({ + mode: "history", + // base: process.env.BASE_URL, + routes, +}); +``` + +## Add navbar component +Now, we are going to create a navbar component to our application. + +New file `templates/base.html`. Code should be like this. +``` + + + + + + + Forum Application + + + {% block style %} + {% endblock %} + + + + {% block content %} + {% endblock %} + + + +``` + +Change the `auth-layout` page to this: +``` +{% extends "base.html" %} +{% block style %} + +{% endblock %} + + +{% block content %} +
+
+ {% block auth %} + {% endblock %} +
+
+{% endblock %} +``` + +As you can see here in the code, it has several blocks called liquid tags. It basically helps to override the specific parts of the template. + +Now, we should change some block names in files `templates/django_registration/registration_form.html` and `templates/registration/login.html`. +``` +{% block auth %} + ... +{% endblock %} +``` + +We should add add an import of the `auth-layout` to the same files mentioned. This should be added on the first line of the code. +``` +{% extends 'auth_layout.html' %} +``` + +Now we are going to add a file `frontend/src/components/Navbar.vue` to add the navigation bar. +``` + + + + + +``` + +Then, import this navbar component in `frontend/src/App.vue`. Under the template tag, add a new tag called script. +``` + +``` + +Remove the following as it is no longer needed +``` + +``` + +Then, replace it with ``. The code should look like this: +``` + + + + + +``` + +Check the changes in your broswer! + +Let's add a container in our html code in `frontend/src/views/Home.vue`. +``` +
+ Vue logo + +
+``` + +## Initialize csrf token +In `frontend` folder, create a folder named `common`. Add two files named `csrf_token.js` and `api.service.js` + +Add this script in `csrf_token.js`. +``` +function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== '') { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; +} +const CSRF_TOKEN = getCookie('csrftoken'); + +export { CSRF_TOKEN }; +``` + +On the other hand, add this script inside `api.service.js`. +``` +import { CSRF_TOKEN } from "./csrf_token.js" + +async function getJSON(response) { + if (response.status === 204) return ''; + return response.json() +} + +function apiService(endpoint, method, data) { + const config = { + method: method || "GET", + body: data !== undefined ? JSON.stringify(data) : null, + headers: { + 'content-type': 'application/json', + 'X-CSRFTOKEN': CSRF_TOKEN + } + }; + return fetch(endpoint, config) + .then(getJSON) + .catch(error => console.log(error)) +} + +export { apiService }; +``` + +Then remove the VueJS logo by deleting or commenting this line of code in file `frontend/src/views/Home.vue` +``` + Vue logo +``` + +## Add home component and questions list +Let's do a little bit of cleanup. Delete this code in `frontend/src/views/Home.vue` +``` + + +``` + +In `frontend/src/views/Home.vue`, import apiService +``` + + + +``` + +Import the Questions.vue file to `frontend/src/router/index.js`. +``` +import Question from "../views/Question.vue"; +... + + { + path: "/question/:slug", + name: "question", + component: Question, + props: true + }, +``` + +Then add another router-link in `frontend/src/views/Home.vue`. Add also a style for the question link class. +``` +

+ {{ question.content }} + +

+``` +``` + +``` + +After the changes, the file `frontend/src/views/Home.vue` should look like this: +``` + + + + + +``` + + diff --git a/flask/discussions/09_deployment.md b/flask/discussions/09_deployment.md index f4c62c3..4f3990c 100644 --- a/flask/discussions/09_deployment.md +++ b/flask/discussions/09_deployment.md @@ -1,3 +1,57 @@ ## Goals -- [ ] +- [ ] Deploy your first Flask application to Heroku via GitHub + +## Heroku + +Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud. + +While they have a free plan that is ideal for experimenting with cloud applications in a limited sandbox, they also have good pricing options based on dynos consumed. Dynos are smart, lightweight containers built for modern languages and developer productivity. Basically, you only pay for what you use, prorated to the second. + +## Creating a Heroku application + +After signing up and logging in, you will be redirected to the dashboard. + +It displays your account type, where the default is Personal. You can also create teams to collaborate with other people, although you need to add a valid credit card to do so. Below that, it lists all the applications that you have so far, its name (alyssonalvaran), application type (Python), stack type (heroku-16), and region (United States). + +To create a new app, click the New button across your account type located on the upper right portion of your dashboard and select Create new app. + +You will be asked to provide an app name and region. For demonstration purposes, I created an app named pineapples-on-pizza. + +Once you select Create app, the next screen that will appear is the deploy tab of your newly created application. At this point, you can already access your app by selecting the Open app button on the upper right portion of your dashboard or going to .herokuapp.com, which is my case is https://pineapples-on-pizza.herokuapp.com/. + +Now that you’re done creating a Heroku app, the next thing that you have to do is to prepare your Flask app. + +## Green unicorn + +Green unicorn, or simply Gunicorn, is a Python Web Server Gateway Interface (WSGI) HTTP server for UNIX, ported from Ruby’s Unicorn project. Basically, this lightweight pre-fork worker model will enable us to deploy our Flask app to Heroku. + +You can install this easily through pip. + +``` +$ pip3 install gunicorn +``` + +After installing, create a file named Procfile (yes, without an extension) and add this line here inside: + +``` +web: gunicorn app:app +``` + +## requirements.txt + +That’s it! The final preparation that you have to do is to make sure that all of your packages are frozen to the text file requirements.txt. You can do this by simply entering this in the command line: + +``` +$ pip3 freeze > requirements.txt +``` + +## Connecting your Heroku app to a GitHub repository + +Assuming that you have already pushed your latest changes to your GitHub repository, go back to the deploy tab of your Heroku application. In the Deployment method section, select GitHub. This opens the Connect to GitHub where you can search for a repository to connect to. Just search the name of your repository, which in my case is pineapples-on-pizza, and select the connect button. + +Congratulations! Your Flask app is now deployed at pineapples-on-pizza.herokuapp.com! + +## Bonus: Automatic deploys + +You can automatically deploy your Heroku app everytime you push something to your GitHub repository by simply choosing a branch to deploy (default is Master) and selecting the Enable Automatic Deploys button in the Automatic deploys section of your Heroku app’s deploy tab. \ No newline at end of file diff --git a/flask/exercises/WebForm/app/app.py b/flask/exercises/WebForm/app/app.py deleted file mode 100644 index b4aecba..0000000 --- a/flask/exercises/WebForm/app/app.py +++ /dev/null @@ -1,35 +0,0 @@ -from flask import Flask, render_template, flash, request -from wtforms import Form, TextField, TextAreaField, validators, StringField, SubmitField - -# App config. -DEBUG = True -app = Flask(__name__) -app.config.from_object(__name__) -app.config['SECRET_KEY'] = '7d441f27d441f27567d441f2b6176a' - -class ReusableForm(Form): - name = TextField('Name:', validators=[validators.required()]) - email = TextField('Email:', validators=[validators.required(), validators.Length(min=6, max=35)]) - password = TextField('Password:', validators=[validators.required(), validators.Length(min=3, max=35)]) - -@app.route("/", methods=['GET', 'POST']) -def hello(): - form = ReusableForm(request.form) - - print(form.errors) - if request.method == 'POST': - name=request.form['name'] - password=request.form['password'] - email=request.form['email'] - print(name, " ", email, " ", password) - - if form.validate(): - # Save the comment here. - flash('Thank you, ' + name) - else: - flash('Error: All the form fields are required. ') - - return render_template('hello.html', form=form) - -if __name__ == "__main__": - app.run() \ No newline at end of file diff --git a/flask/exercises/WebForm/app/templates/hello.html b/flask/exercises/WebForm/app/templates/hello.html deleted file mode 100644 index 3c2f359..0000000 --- a/flask/exercises/WebForm/app/templates/hello.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - Reusable Form Demo - - - - - - - - -
-

Flask Web Form

-
- {{ form.csrf }} -
- - -
- - -
- - -
- -
-
- {% with messages = get_flashed_messages(with_categories=true) %} - {% if messages %} - {% for message in messages %} - {% if "Error" not in message[1]: %} -
- Success! {{ message[1] }} -
- {% endif %} - - {% if "Error" in message[1]: %} -
- {{ message[1] }} -
- {% endif %} - {% endfor %} - {% endif %} - {% endwith %} -
- - \ No newline at end of file diff --git a/flask/exercises/WebForm/requirements.txt b/flask/exercises/WebForm/requirements.txt deleted file mode 100644 index 6b28289..0000000 --- a/flask/exercises/WebForm/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -click==6.7 -Flask==0.12.2 -Flask-WTF==0.14.2 -itsdangerous==0.24 -Jinja2==2.9.6 -MarkupSafe==1.0 -Werkzeug==0.12.2 -WTForms==2.1 diff --git a/flask/exercises/portfolio-hello-world/.gitignore b/flask/exercises/portfolio-hello-world/.gitignore deleted file mode 100644 index ed8ebf5..0000000 --- a/flask/exercises/portfolio-hello-world/.gitignore +++ /dev/null @@ -1 +0,0 @@ -__pycache__ \ No newline at end of file diff --git a/flask/exercises/portfolio-hello-world/app.py b/flask/exercises/portfolio-hello-world/app.py deleted file mode 100644 index 1f4519e..0000000 --- a/flask/exercises/portfolio-hello-world/app.py +++ /dev/null @@ -1,6 +0,0 @@ -from flask import Flask -app = Flask(__name__) - -@app.route('/') -def hello_world(): - return 'Hello, World!' \ No newline at end of file diff --git a/flask/exercises/portfolio-hello-world/requirements.txt b/flask/exercises/portfolio-hello-world/requirements.txt deleted file mode 100644 index 34ffbb7..0000000 --- a/flask/exercises/portfolio-hello-world/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -click==6.7 -Flask==1.0.2 -itsdangerous==0.24 -Jinja2==2.10 -MarkupSafe==1.0 -Werkzeug==0.14.1 diff --git a/flask/exercises/portfolio-templates-and-variables/.gitignore b/flask/exercises/portfolio-templates-and-variables/.gitignore deleted file mode 100644 index ed8ebf5..0000000 --- a/flask/exercises/portfolio-templates-and-variables/.gitignore +++ /dev/null @@ -1 +0,0 @@ -__pycache__ \ No newline at end of file diff --git a/flask/exercises/portfolio-templates-and-variables/app.py b/flask/exercises/portfolio-templates-and-variables/app.py deleted file mode 100644 index cf28749..0000000 --- a/flask/exercises/portfolio-templates-and-variables/app.py +++ /dev/null @@ -1,34 +0,0 @@ -from flask import Flask, render_template # Import render_template. -from random import randint #Import randint. -app = Flask(__name__) - -@app.route("/") -@app.route("/home/") -def home(): - return "Home" - -@app.route("/about/") -def about(): - # Syntax: render_template(filename) - return render_template("about.html") - -@app.route("/skills/", defaults={'username': None}) -@app.route("/skills//") -def skills(username): - # Syntax: render_template(filename, variable/s) - return render_template("skills.html", username=username) - -@app.route("/projects/") -def projects(): - projects = ["Facebook", "Twitter", "Instagram", "Uber", "Grab"] - # Use randint() to generate a random integer. - # Syntax: randint(lowest number, highest number) - randNo = randint(0, len(projects) - 1) - project = projects[randNo] - - # Use **locals() to pass multiple variables. - return render_template("projects.html", **locals()) - -@app.route("/contact/") -def contact(): - return "Contact" \ No newline at end of file diff --git a/flask/exercises/portfolio-templates-and-variables/requirements.txt b/flask/exercises/portfolio-templates-and-variables/requirements.txt deleted file mode 100644 index 30dde8b..0000000 --- a/flask/exercises/portfolio-templates-and-variables/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -click==6.7 -Flask==0.12.2 -itsdangerous==0.24 -Jinja2==2.10 -MarkupSafe==1.0 -Werkzeug==0.14.1 diff --git a/flask/exercises/portfolio-templates-and-variables/static/css/bootstrap.min.css b/flask/exercises/portfolio-templates-and-variables/static/css/bootstrap.min.css deleted file mode 100644 index ed3905e..0000000 --- a/flask/exercises/portfolio-templates-and-variables/static/css/bootstrap.min.css +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.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}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/flask/exercises/portfolio-templates-and-variables/static/js/bootstrap.min.js b/flask/exercises/portfolio-templates-and-variables/static/js/bootstrap.min.js deleted file mode 100644 index 9bcd2fc..0000000 --- a/flask/exercises/portfolio-templates-and-variables/static/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under the MIT license - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/flask/exercises/portfolio-templates-and-variables/static/js/jquery-3.2.1.min.js b/flask/exercises/portfolio-templates-and-variables/static/js/jquery-3.2.1.min.js deleted file mode 100644 index 644d35e..0000000 --- a/flask/exercises/portfolio-templates-and-variables/static/js/jquery-3.2.1.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), -a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), -null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,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"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r(" - - - \ No newline at end of file diff --git a/flask/exercises/portfolio-templates-and-variables/templates/projects.html b/flask/exercises/portfolio-templates-and-variables/templates/projects.html deleted file mode 100644 index 6176bb1..0000000 --- a/flask/exercises/portfolio-templates-and-variables/templates/projects.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "layout.html" %} - -{% block body %} - -

Welcome to the Projects page.

- -

These are what I've done so far:

-
    - - -{% for p in projects %} -
  • {{ p }}
  • -{% endfor %} -
- -

... and {{ project }} is the one that I enjoyed coding the most.

- -{% endblock %} \ No newline at end of file diff --git a/flask/exercises/portfolio-templates-and-variables/templates/skills.html b/flask/exercises/portfolio-templates-and-variables/templates/skills.html deleted file mode 100644 index f494f5d..0000000 --- a/flask/exercises/portfolio-templates-and-variables/templates/skills.html +++ /dev/null @@ -1,22 +0,0 @@ - -{% extends "layout.html" %} - - -{% block body %} - -

Welcome to the Skills page.

- -

- - -{% if username == None %} - Hi, stranger. What's your name? -{% else %} - - - - Hi, {{username|title}}! -{% endif %} -

- -{% endblock %} \ No newline at end of file diff --git a/flask/exercises/portfolio-url-routes/.gitignore b/flask/exercises/portfolio-url-routes/.gitignore deleted file mode 100644 index ed8ebf5..0000000 --- a/flask/exercises/portfolio-url-routes/.gitignore +++ /dev/null @@ -1 +0,0 @@ -__pycache__ \ No newline at end of file diff --git a/flask/exercises/portfolio-url-routes/app.py b/flask/exercises/portfolio-url-routes/app.py deleted file mode 100644 index 507a703..0000000 --- a/flask/exercises/portfolio-url-routes/app.py +++ /dev/null @@ -1,40 +0,0 @@ -from flask import Flask -app = Flask(__name__) - -# Different URLs can be redirected to the same page. -@app.route("/") -@app.route("/home/") -def home(): - return "Home" - -# This URL will return a 404 error if you try to access it with a trailing slash ("/about/"). -@app.route("/about") # Always add a trailing slash at the end to avoid this error. -def about(): - return "About" - -# URLs can accept inputs through its variable parts. -@app.route("/about//") -def about_location(location): - return "I am from %s." % location - -@app.route("/skills/") -def skills(): - return "Skills" - -# It can also accept inputs with specified data types. -@app.route("/skills//") -def skills_toeic(toeic_score): - return "My TOEIC score is %d / 90." % toeic_score - -# You can set default values in case there's no input from the user. -@app.route("/projects/", defaults={'amount': 0}) -@app.route("/projects/") -def projects(amount): - return "I have %d project/s to date." % amount - -@app.route("/contact/") -def contact(): - return "Contact" - -if __name__ == "__main__": - app.run() \ No newline at end of file diff --git a/flask/exercises/portfolio-url-routes/requirements.txt b/flask/exercises/portfolio-url-routes/requirements.txt deleted file mode 100644 index 30dde8b..0000000 --- a/flask/exercises/portfolio-url-routes/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -click==6.7 -Flask==0.12.2 -itsdangerous==0.24 -Jinja2==2.10 -MarkupSafe==1.0 -Werkzeug==0.14.1 diff --git a/getting_started/installation_guide.md b/getting_started/installation_guide.md index a57a711..0245eb4 100644 --- a/getting_started/installation_guide.md +++ b/getting_started/installation_guide.md @@ -1,10 +1,21 @@ -## Check existing installation +We need to install the **Python interpreter** first! -We need Python first! +!> For our study group, we will be using `Python 3`, preferably >= `Python 3.6`. -!> For our study group, we will be using `Python 3`, preferably >= `Python 3.6` :) +You also need to have a **text editor** to write your code in. This can be (but not limited to) one of the following: + +* [Atom](https://atom.io) +* [Gedit](https://wiki.gnome.org/Apps/Gedit) +* [Notepad++](https://notepad-plus-plus.org) +* [Sublime Text](https://www.sublimetext.com) +* [Visual Studio Code](https://code.visualstudio.com) + + + +## Check existing Python installation + +To check if Python is already installed in your system, open your terminal or command prompt. -To check if Python is already installed, open your terminal or command prompt. - For Windows users, search for `cmd` - For Linux and Mac users, search for `terminal` @@ -30,12 +41,60 @@ Python 3.6.0 ## Tutorial -For a detailed installation process, please [use this tutorial](https://tutorial.djangogirls.org/en/python_installation/). +For a detailed installation process, you can [use this tutorial](https://tutorial.djangogirls.org/en/python_installation). + +### Windows and OS X -!> For **Windows** user, please don't forget to add Python in your PATH as per below. +1. Download the installer for the latest version from the [Python Software Foundation](https://www.python.org/downloads/release). +2. Run the installer by double-clicking it, and following the succeeding instructions. + +!> For **Windows** users, please don't forget to add Python in your PATH as per below. ![Add Python to PATH](https://eavictor.files.wordpress.com/2016/05/add_python_3-5_to_pathinstall_now.png?w=594) + +!> For **OS X** users, ensure your Mac settings allow installing packages that are not from the App Store. Go to `"System Preferences" > "Security & Privacy," > "General"`. Set "Allow apps downloaded from:" to "Mac App Store and identified developers." + + +### Linux + +Check the Linux distrubution using the `terminal` + +``` +grep ^NAME= /etc/os-release +``` + +Type one of the following commands in the `termimal` depending on your respective Linux distribution. + +* **Debian** or **Ubuntu** + + ``` + sudo apt install python3 + ``` + +* **Fedora** + + ``` + sudo dnf install python3 + ``` + +* **openSUSE** + + ``` + sudo zypper intall python3 + ``` + +You can also try [compiling from source](https://realpython.com/installing-python/#compiling-python-from-source) if you want the latest version or an alternative installation of Python. + +### Chromebook + +For Chromebook users, you'll need to connect to a cloud IDE provider. You can follow [these instructions](https://tutorial.djangogirls.org/en/chromebook_setup). + + + +Finally, [check if you have successfully installed Python](#check-existing-python-installation). + + Done! You can now start coding in Python! ## Put your thinking cap on! diff --git a/index.html b/index.html index 070eb19..d3a6591 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,6 @@ - Women Who Code Manila Python Study Group @@ -21,13 +15,7 @@
diff --git a/ren'py/aling-nena-vn.md b/ren'py/aling-nena-vn.md new file mode 100644 index 0000000..cd7facf --- /dev/null +++ b/ren'py/aling-nena-vn.md @@ -0,0 +1,53 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Aling Nena's visual novel + +We'll be going through a simple interactive game featuring Aling Nena and her *apo* (grandchild). You may have met Aling Nena during one of our basic Python study groups. + +## Plotline + +This game follows the adventure of the player (you!) as Aling Nena's grandchild who have visited her in the province one summer vacation. You'll be interacting with many **characters**: + +- Aling Nena, your grandmother +- Lita and Boy, your friends +- Bert and Tasya, Aling Nena's *suki* (loyal customers) in her *sari-sari* store (a small grocery store) + +The story takes places in various **scenes**: + +- Inside Aling Nena's house +- Outside in the streets +- In Aling Nena's store +- The beach + +Along the way, you'll have to decide what your character will do next by selecting answers in a **menu** screen. Depending on your answers along the branching storyline, you'll either encounter a *good ending* or a *bad ending*. + +## Materials + +The materials for this Ren'Py game tutorial are [here](http://bit.ly/wwcodemanila-renpy). These include: + +- [ ] code for the game +- [ ] assets (images) for the game + +Feel free to play this game and/or look at the codes `script.rpy` and `batobato.rpy` to familiarize your self with the gameplay as well as how the code is structured. + +!> If you haven't done so already, create a new Ren'Py game from the launcher called `Aling Nena VN` or whatever title you want to put in. Make sure you set the screen size to 1980 px by 720 px. + +## Scripts + +As mentioned earlier, Ren'Py creates default scripts with example codes and values when a new game is created: + +- `script.rpy` - contains the main dialogue and scenes in our game. This is the file we'll be working with the most in order to create our interactive novel. +- `options.rpy` - here, we can specify some details about the game e.g. the title that will be shown in the main screen and the game version +- `gui.rpy` - this is where we can change how the game will look like including accent colors, fonts, and menu borders. +- `screens.rpy` - here we can set other properties of the game e.g. the positions of the menus and labels in each screen. + +In general, Ren'Py reads all `.rpy` scripts as one so we can actually split multiple parts of the game's narration into different `.rpy` files or just write all in a single file. + +# Exercise + +Open the script `script.rpy`. Clear everything from this file as we will be replacing the default story with our own story. + +Are you ready to learn how to make your own visual novel with Python? Let's begin! + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/assets/bert.png b/ren'py/assets/bert.png new file mode 100644 index 0000000..2f2dffe Binary files /dev/null and b/ren'py/assets/bert.png differ diff --git a/ren'py/assets/bg beach.png b/ren'py/assets/bg beach.png new file mode 100644 index 0000000..78f10ac Binary files /dev/null and b/ren'py/assets/bg beach.png differ diff --git a/ren'py/assets/bg inside house.png b/ren'py/assets/bg inside house.png new file mode 100644 index 0000000..264a39d Binary files /dev/null and b/ren'py/assets/bg inside house.png differ diff --git a/ren'py/assets/bg store.png b/ren'py/assets/bg store.png new file mode 100644 index 0000000..fef37b4 Binary files /dev/null and b/ren'py/assets/bg store.png differ diff --git a/ren'py/assets/bg street.png b/ren'py/assets/bg street.png new file mode 100644 index 0000000..f509172 Binary files /dev/null and b/ren'py/assets/bg street.png differ diff --git a/ren'py/assets/boy.png b/ren'py/assets/boy.png new file mode 100644 index 0000000..1e8dd57 Binary files /dev/null and b/ren'py/assets/boy.png differ diff --git a/ren'py/assets/lita.png b/ren'py/assets/lita.png new file mode 100644 index 0000000..3205cca Binary files /dev/null and b/ren'py/assets/lita.png differ diff --git a/ren'py/assets/nena sad.png b/ren'py/assets/nena sad.png new file mode 100644 index 0000000..7f860cf Binary files /dev/null and b/ren'py/assets/nena sad.png differ diff --git a/ren'py/assets/nena.png b/ren'py/assets/nena.png new file mode 100644 index 0000000..258f43b Binary files /dev/null and b/ren'py/assets/nena.png differ diff --git a/ren'py/assets/store prices.png b/ren'py/assets/store prices.png new file mode 100644 index 0000000..dfe4ae1 Binary files /dev/null and b/ren'py/assets/store prices.png differ diff --git a/ren'py/assets/store rewards.png b/ren'py/assets/store rewards.png new file mode 100644 index 0000000..9218d0c Binary files /dev/null and b/ren'py/assets/store rewards.png differ diff --git a/ren'py/assets/tasya.png b/ren'py/assets/tasya.png new file mode 100644 index 0000000..64707f5 Binary files /dev/null and b/ren'py/assets/tasya.png differ diff --git a/ren'py/create-new-game.md b/ren'py/create-new-game.md new file mode 100644 index 0000000..1765f22 --- /dev/null +++ b/ren'py/create-new-game.md @@ -0,0 +1,52 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +The Ren'Py software development kit already provides features such as saving, loading, and adjusting the preferences in a game. When you create a new game, you'll already have access to a game menu interface! All you really need to focus on is on creating the game itself. + +# Creating a new game + +1. In the Ren'Py engine, click `+ Create New Project` . + + + +2. The default language settings is in English. If you're going to use another language, go to to `Preferences` and choose the appropriate language. Otherwise, click `Continue` at the next prompt. + + + +3. Next, you'll need to input the *Project Name*, then click `Continue`. + + + +4. In the next window, you'll have to specify the *resolution of your game*. Whatever resolution you choose, make sure to fit your assets (backgrounds, character images, and other game images) in this size. Then, click `Continue`. + + + +5. Choose the *accent and background colors*. You can change these later on in the scripts. Then, click `Continue`. + + + +6. It will take a few seconds to setup the game environments. + + + +7. Once done, you'll be able to see the Project Name you specified in the main menu of the Ren'Py engine. Ren'Py has preloaded some of the scripts with the default codes and values. Under `Edit File`, click `All script files` to see all of these scripts in your code editor, or click `Launch Project` to see the default game interface. + + + + + +The default game interface will look like this: + + + + + + + +# Exercise + +In order to go ahead with the next parts of this study guide, first create a new Ren'Py game from the launcher. Set the title to `Aling Nena VN` or whatever title you want to put in. Make sure you set the screen size to 1980 px by 720 px. + +Next, we'll know more about the plot of Aling Nena's visual novel. + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/game/batobato.rpy b/ren'py/game/batobato.rpy new file mode 100644 index 0000000..2594657 --- /dev/null +++ b/ren'py/game/batobato.rpy @@ -0,0 +1,73 @@ +label game: + + $ gamef = True + + scene bg street with fade + + show lita at left with moveinright + show boy at right with moveinleft + + l "Let's play bato-bato pik!" + + show boy at center with moveinright + b "You'll play against me. Best of three!" + + python: + from random import randint + uscore = 0 + bscore = 0 + while uscore | bscore < 2: + + renpy.say(b, "Bato-bato pik!") + + choices = {"r": "Rock", "p": "Paper", "s": "Scissors"} + uhand = renpy.display_menu([("Rock", "r"), ("Paper", "p"), ("Scissors", "s")]) + bhand = choices.keys()[randint(0,2)] + + uhand_c = choices[uhand] + bhand_c = choices[bhand] + + renpy.say(b, "[bhand_c]") + + hands = (uhand, bhand) + + wins = [ + ('p', 'r'), + ('r', 's'), + ('s', 'p'), + ] + tie = False + if hands[0] == hands[1]: + tie = True + result = "It's a tie!" + elif hands in wins: + result = "wins" + uscore += 1 + else: + result = "loses" + bscore += 1 + + if not tie: + renpy.say(l, "[name] picked [uhand_c], Boy picked [bhand_c] \n [name] [result]! {w} \n Boy: [bscore], [name]: [uscore]") + else: + renpy.say(l, "[name] picked [uhand_c], Boy picked [bhand_c] \n [result]! {w} \n Boy: [bscore], [name]: [uscore]") + + if uscore > bscore: + renpy.say(l, "[name] is the WINNER!") + winner = True + else: + renpy.say(l, "Boy wins. [name] LOSES!") + winner = False + + if winner: + show boy at right with moveinleft + l "Well done, [name]." + b "You defeated me!" + else: + show boy at right with moveinleft + b "Oh well, there's always a next time, [name]." + + l "Let's play another game!" + "You spend the rest of the day playing." + + jump ending diff --git a/ren'py/game/gui.rpy b/ren'py/game/gui.rpy new file mode 100644 index 0000000..bc0f969 --- /dev/null +++ b/ren'py/game/gui.rpy @@ -0,0 +1,474 @@ +################################################################################ +## Initialization +################################################################################ + +## The init offset statement causes the initialization statements in this file +## to run before init statements in any other file. +init offset = -2 + +## Calling gui.init resets the styles to sensible default values, and sets the +## width and height of the game. +init python: + gui.init(1280, 720) + + + +################################################################################ +## GUI Configuration Variables +################################################################################ + + +## Colors ###################################################################### +## +## The colors of text in the interface. + +## An accent color used throughout the interface to label and highlight text. +define gui.accent_color = '#0099cc' + +## The color used for a text button when it is neither selected nor hovered. +define gui.idle_color = '#888888' + +## The small color is used for small text, which needs to be brighter/darker to +## achieve the same effect. +define gui.idle_small_color = '#aaaaaa' + +## The color that is used for buttons and bars that are hovered. +define gui.hover_color = '#66c1e0' + +## The color used for a text button when it is selected but not focused. A +## button is selected if it is the current screen or preference value. +define gui.selected_color = '#ffffff' + +## The color used for a text button when it cannot be selected. +define gui.insensitive_color = '#8888887f' + +## Colors used for the portions of bars that are not filled in. These are not +## used directly, but are used when re-generating bar image files. +define gui.muted_color = '#003d51' +define gui.hover_muted_color = '#005b7a' + +## The colors used for dialogue and menu choice text. +define gui.text_color = '#ffffff' +define gui.interface_text_color = '#ffffff' + + +## Fonts and Font Sizes ######################################################## + +## The font used for in-game text. +define gui.text_font = "DejaVuSans.ttf" + +## The font used for character names. +define gui.name_text_font = "DejaVuSans.ttf" + +## The font used for out-of-game text. +define gui.interface_text_font = "DejaVuSans.ttf" + +## The size of normal dialogue text. +define gui.text_size = 22 + +## The size of character names. +define gui.name_text_size = 30 + +## The size of text in the game's user interface. +define gui.interface_text_size = 22 + +## The size of labels in the game's user interface. +define gui.label_text_size = 24 + +## The size of text on the notify screen. +define gui.notify_text_size = 16 + +## The size of the game's title. +define gui.title_text_size = 50 + + +## Main and Game Menus ######################################################### + +## The images used for the main and game menus. +define gui.main_menu_background = "gui/main_menu.png" +define gui.game_menu_background = "gui/game_menu.png" + + +## Dialogue #################################################################### +## +## These variables control how dialogue is displayed on the screen one line at a +## time. + +## The height of the textbox containing dialogue. +define gui.textbox_height = 185 + +## The placement of the textbox vertically on the screen. 0.0 is the top, 0.5 is +## center, and 1.0 is the bottom. +define gui.textbox_yalign = 1.0 + + +## The placement of the speaking character's name, relative to the textbox. +## These can be a whole number of pixels from the left or top, or 0.5 to center. +define gui.name_xpos = 240 +define gui.name_ypos = 0 + +## The horizontal alignment of the character's name. This can be 0.0 for left- +## aligned, 0.5 for centered, and 1.0 for right-aligned. +define gui.name_xalign = 0.0 + +## The width, height, and borders of the box containing the character's name, or +## None to automatically size it. +define gui.namebox_width = None +define gui.namebox_height = None + +## The borders of the box containing the character's name, in left, top, right, +## bottom order. +define gui.namebox_borders = Borders(5, 5, 5, 5) + +## If True, the background of the namebox will be tiled, if False, the +## background of the namebox will be scaled. +define gui.namebox_tile = False + + +## The placement of dialogue relative to the textbox. These can be a whole +## number of pixels relative to the left or top side of the textbox, or 0.5 to +## center. +define gui.dialogue_xpos = 268 +define gui.dialogue_ypos = 50 + +## The maximum width of dialogue text, in pixels. +define gui.dialogue_width = 744 + +## The horizontal alignment of the dialogue text. This can be 0.0 for left- +## aligned, 0.5 for centered, and 1.0 for right-aligned. +define gui.dialogue_text_xalign = 0.0 + + +## Buttons ##################################################################### +## +## These variables, along with the image files in gui/button, control aspects of +## how buttons are displayed. + +## The width and height of a button, in pixels. If None, Ren'Py computes a size. +define gui.button_width = None +define gui.button_height = None + +## The borders on each side of the button, in left, top, right, bottom order. +define gui.button_borders = Borders(4, 4, 4, 4) + +## If True, the background image will be tiled. If False, the background image +## will be linearly scaled. +define gui.button_tile = False + +## The font used by the button. +define gui.button_text_font = gui.interface_text_font + +## The size of the text used by the button. +define gui.button_text_size = gui.interface_text_size + +## The color of button text in various states. +define gui.button_text_idle_color = gui.idle_color +define gui.button_text_hover_color = gui.hover_color +define gui.button_text_selected_color = gui.selected_color +define gui.button_text_insensitive_color = gui.insensitive_color + +## The horizontal alignment of the button text. (0.0 is left, 0.5 is center, 1.0 +## is right). +define gui.button_text_xalign = 0.0 + + +## These variables override settings for different kinds of buttons. Please see +## the gui documentation for the kinds of buttons available, and what each is +## used for. +## +## These customizations are used by the default interface: + +define gui.radio_button_borders = Borders(18, 4, 4, 4) + +define gui.check_button_borders = Borders(18, 4, 4, 4) + +define gui.confirm_button_text_xalign = 0.5 + +define gui.page_button_borders = Borders(10, 4, 10, 4) + +define gui.quick_button_borders = Borders(10, 4, 10, 0) +define gui.quick_button_text_size = 14 +define gui.quick_button_text_idle_color = gui.idle_small_color +define gui.quick_button_text_selected_color = gui.accent_color + +## You can also add your own customizations, by adding properly-named variables. +## For example, you can uncomment the following line to set the width of a +## navigation button. + +# define gui.navigation_button_width = 250 + + +## Choice Buttons ############################################################## +## +## Choice buttons are used in the in-game menus. + +define gui.choice_button_width = 790 +define gui.choice_button_height = None +define gui.choice_button_tile = False +define gui.choice_button_borders = Borders(100, 5, 100, 5) +define gui.choice_button_text_font = gui.text_font +define gui.choice_button_text_size = gui.text_size +define gui.choice_button_text_xalign = 0.5 +define gui.choice_button_text_idle_color = "#cccccc" +define gui.choice_button_text_hover_color = "#ffffff" +define gui.choice_button_text_insensitive_color = "#444444" + + +## File Slot Buttons ########################################################### +## +## A file slot button is a special kind of button. It contains a thumbnail +## image, and text describing the contents of the save slot. A save slot uses +## image files in gui/button, like the other kinds of buttons. + +## The save slot button. +define gui.slot_button_width = 276 +define gui.slot_button_height = 206 +define gui.slot_button_borders = Borders(10, 10, 10, 10) +define gui.slot_button_text_size = 14 +define gui.slot_button_text_xalign = 0.5 +define gui.slot_button_text_idle_color = gui.idle_small_color +define gui.slot_button_text_selected_idle_color = gui.selected_color +define gui.slot_button_text_selected_hover_color = gui.hover_color + +## The width and height of thumbnails used by the save slots. +define config.thumbnail_width = 256 +define config.thumbnail_height = 144 + +## The number of columns and rows in the grid of save slots. +define gui.file_slot_cols = 3 +define gui.file_slot_rows = 2 + + +## Positioning and Spacing ##################################################### +## +## These variables control the positioning and spacing of various user interface +## elements. + +## The position of the left side of the navigation buttons, relative to the left +## side of the screen. +define gui.navigation_xpos = 40 + +## The vertical position of the skip indicator. +define gui.skip_ypos = 10 + +## The vertical position of the notify screen. +define gui.notify_ypos = 45 + +## The spacing between menu choices. +define gui.choice_spacing = 22 + +## Buttons in the navigation section of the main and game menus. +define gui.navigation_spacing = 4 + +## Controls the amount of spacing between preferences. +define gui.pref_spacing = 10 + +## Controls the amount of spacing between preference buttons. +define gui.pref_button_spacing = 0 + +## The spacing between file page buttons. +define gui.page_spacing = 0 + +## The spacing between file slots. +define gui.slot_spacing = 10 + +## The position of the main menu text. +define gui.main_menu_text_xalign = 1.0 + + +## Frames ###################################################################### +## +## These variables control the look of frames that can contain user interface +## components when an overlay or window is not present. + +## Generic frames. +define gui.frame_borders = Borders(4, 4, 4, 4) + +## The frame that is used as part of the confirm screen. +define gui.confirm_frame_borders = Borders(40, 40, 40, 40) + +## The frame that is used as part of the skip screen. +define gui.skip_frame_borders = Borders(16, 5, 50, 5) + +## The frame that is used as part of the notify screen. +define gui.notify_frame_borders = Borders(16, 5, 40, 5) + +## Should frame backgrounds be tiled? +define gui.frame_tile = False + + +## Bars, Scrollbars, and Sliders ############################################### +## +## These control the look and size of bars, scrollbars, and sliders. +## +## The default GUI only uses sliders and vertical scrollbars. All of the other +## bars are only used in creator-written screens. + +## The height of horizontal bars, scrollbars, and sliders. The width of vertical +## bars, scrollbars, and sliders. +define gui.bar_size = 25 +define gui.scrollbar_size = 12 +define gui.slider_size = 25 + +## True if bar images should be tiled. False if they should be linearly scaled. +define gui.bar_tile = False +define gui.scrollbar_tile = False +define gui.slider_tile = False + +## Horizontal borders. +define gui.bar_borders = Borders(4, 4, 4, 4) +define gui.scrollbar_borders = Borders(4, 4, 4, 4) +define gui.slider_borders = Borders(4, 4, 4, 4) + +## Vertical borders. +define gui.vbar_borders = Borders(4, 4, 4, 4) +define gui.vscrollbar_borders = Borders(4, 4, 4, 4) +define gui.vslider_borders = Borders(4, 4, 4, 4) + +## What to do with unscrollable scrollbars in the gui. "hide" hides them, while +## None shows them. +define gui.unscrollable = "hide" + + +## History ##################################################################### +## +## The history screen displays dialogue that the player has already dismissed. + +## The number of blocks of dialogue history Ren'Py will keep. +define config.history_length = 250 + +## The height of a history screen entry, or None to make the height variable at +## the cost of performance. +define gui.history_height = 140 + +## The position, width, and alignment of the label giving the name of the +## speaking character. +define gui.history_name_xpos = 155 +define gui.history_name_ypos = 0 +define gui.history_name_width = 155 +define gui.history_name_xalign = 1.0 + +## The position, width, and alignment of the dialogue text. +define gui.history_text_xpos = 170 +define gui.history_text_ypos = 2 +define gui.history_text_width = 740 +define gui.history_text_xalign = 0.0 + + +## NVL-Mode #################################################################### +## +## The NVL-mode screen displays the dialogue spoken by NVL-mode characters. + +## The borders of the background of the NVL-mode background window. +define gui.nvl_borders = Borders(0, 10, 0, 20) + +## The maximum number of NVL-mode entries Ren'Py will display. When more entries +## than this are to be show, the oldest entry will be removed. +define gui.nvl_list_length = 6 + +## The height of an NVL-mode entry. Set this to None to have the entries +## dynamically adjust height. +define gui.nvl_height = 115 + +## The spacing between NVL-mode entries when gui.nvl_height is None, and between +## NVL-mode entries and an NVL-mode menu. +define gui.nvl_spacing = 10 + +## The position, width, and alignment of the label giving the name of the +## speaking character. +define gui.nvl_name_xpos = 430 +define gui.nvl_name_ypos = 0 +define gui.nvl_name_width = 150 +define gui.nvl_name_xalign = 1.0 + +## The position, width, and alignment of the dialogue text. +define gui.nvl_text_xpos = 450 +define gui.nvl_text_ypos = 8 +define gui.nvl_text_width = 590 +define gui.nvl_text_xalign = 0.0 + +## The position, width, and alignment of nvl_thought text (the text said by the +## nvl_narrator character.) +define gui.nvl_thought_xpos = 240 +define gui.nvl_thought_ypos = 0 +define gui.nvl_thought_width = 780 +define gui.nvl_thought_xalign = 0.0 + +## The position of nvl menu_buttons. +define gui.nvl_button_xpos = 450 +define gui.nvl_button_xalign = 0.0 + +## Localization ################################################################ + +## This controls where a line break is permitted. The default is suitable +## for most languages. A list of available values can be found at https:// +## www.renpy.org/doc/html/style_properties.html#style-property-language + +define gui.language = "unicode" + + +################################################################################ +## Mobile devices +################################################################################ + +init python: + + ## This increases the size of the quick buttons to make them easier to touch + ## on tablets and phones. + if renpy.variant("touch"): + + gui.quick_button_borders = Borders(40, 14, 40, 0) + + ## This changes the size and spacing of various GUI elements to ensure they + ## are easily visible on phones. + if renpy.variant("small"): + + ## Font sizes. + gui.text_size = 30 + gui.name_text_size = 36 + gui.notify_text_size = 25 + gui.interface_text_size = 30 + gui.button_text_size = 30 + gui.label_text_size = 34 + + ## Adjust the location of the textbox. + gui.textbox_height = 240 + gui.name_xpos = 80 + gui.text_xpos = 90 + gui.text_width = 1100 + + ## Change the size and spacing of various things. + gui.slider_size = 36 + + gui.choice_button_width = 1240 + + gui.navigation_spacing = 20 + gui.pref_button_spacing = 10 + + gui.history_height = 190 + gui.history_text_width = 690 + + gui.quick_button_text_size = 20 + + ## File button layout. + gui.file_slot_cols = 2 + gui.file_slot_rows = 2 + + ## NVL-mode. + gui.nvl_height = 170 + + gui.nvl_name_width = 305 + gui.nvl_name_xpos = 325 + + gui.nvl_text_width = 915 + gui.nvl_text_xpos = 345 + gui.nvl_text_ypos = 5 + + gui.nvl_thought_width = 1240 + gui.nvl_thought_xpos = 20 + + gui.nvl_button_width = 1240 + gui.nvl_button_xpos = 20 + + + diff --git a/ren'py/game/gui/bar/bottom.png b/ren'py/game/gui/bar/bottom.png new file mode 100644 index 0000000..3398dd5 Binary files /dev/null and b/ren'py/game/gui/bar/bottom.png differ diff --git a/ren'py/game/gui/bar/left.png b/ren'py/game/gui/bar/left.png new file mode 100644 index 0000000..af91a99 Binary files /dev/null and b/ren'py/game/gui/bar/left.png differ diff --git a/ren'py/game/gui/bar/right.png b/ren'py/game/gui/bar/right.png new file mode 100644 index 0000000..8d0de62 Binary files /dev/null and b/ren'py/game/gui/bar/right.png differ diff --git a/ren'py/game/gui/bar/top.png b/ren'py/game/gui/bar/top.png new file mode 100644 index 0000000..fea53c6 Binary files /dev/null and b/ren'py/game/gui/bar/top.png differ diff --git a/ren'py/game/gui/button/check_foreground.png b/ren'py/game/gui/button/check_foreground.png new file mode 100644 index 0000000..9ba7a3b Binary files /dev/null and b/ren'py/game/gui/button/check_foreground.png differ diff --git a/ren'py/game/gui/button/check_selected_foreground.png b/ren'py/game/gui/button/check_selected_foreground.png new file mode 100644 index 0000000..acb5805 Binary files /dev/null and b/ren'py/game/gui/button/check_selected_foreground.png differ diff --git a/ren'py/game/gui/button/choice_hover_background.png b/ren'py/game/gui/button/choice_hover_background.png new file mode 100644 index 0000000..583985d Binary files /dev/null and b/ren'py/game/gui/button/choice_hover_background.png differ diff --git a/ren'py/game/gui/button/choice_idle_background.png b/ren'py/game/gui/button/choice_idle_background.png new file mode 100644 index 0000000..632758a Binary files /dev/null and b/ren'py/game/gui/button/choice_idle_background.png differ diff --git a/ren'py/game/gui/button/hover_background.png b/ren'py/game/gui/button/hover_background.png new file mode 100644 index 0000000..390198c Binary files /dev/null and b/ren'py/game/gui/button/hover_background.png differ diff --git a/ren'py/game/gui/button/idle_background.png b/ren'py/game/gui/button/idle_background.png new file mode 100644 index 0000000..390198c Binary files /dev/null and b/ren'py/game/gui/button/idle_background.png differ diff --git a/ren'py/game/gui/button/quick_hover_background.png b/ren'py/game/gui/button/quick_hover_background.png new file mode 100644 index 0000000..e98b76b Binary files /dev/null and b/ren'py/game/gui/button/quick_hover_background.png differ diff --git a/ren'py/game/gui/button/quick_idle_background.png b/ren'py/game/gui/button/quick_idle_background.png new file mode 100644 index 0000000..e98b76b Binary files /dev/null and b/ren'py/game/gui/button/quick_idle_background.png differ diff --git a/ren'py/game/gui/button/radio_foreground.png b/ren'py/game/gui/button/radio_foreground.png new file mode 100644 index 0000000..9ba7a3b Binary files /dev/null and b/ren'py/game/gui/button/radio_foreground.png differ diff --git a/ren'py/game/gui/button/radio_selected_foreground.png b/ren'py/game/gui/button/radio_selected_foreground.png new file mode 100644 index 0000000..acb5805 Binary files /dev/null and b/ren'py/game/gui/button/radio_selected_foreground.png differ diff --git a/ren'py/game/gui/button/slot_hover_background.png b/ren'py/game/gui/button/slot_hover_background.png new file mode 100644 index 0000000..f337d98 Binary files /dev/null and b/ren'py/game/gui/button/slot_hover_background.png differ diff --git a/ren'py/game/gui/button/slot_idle_background.png b/ren'py/game/gui/button/slot_idle_background.png new file mode 100644 index 0000000..61557df Binary files /dev/null and b/ren'py/game/gui/button/slot_idle_background.png differ diff --git a/ren'py/game/gui/frame.png b/ren'py/game/gui/frame.png new file mode 100644 index 0000000..966d1e3 Binary files /dev/null and b/ren'py/game/gui/frame.png differ diff --git a/ren'py/game/gui/game_menu.png b/ren'py/game/gui/game_menu.png new file mode 100644 index 0000000..e832491 Binary files /dev/null and b/ren'py/game/gui/game_menu.png differ diff --git a/ren'py/game/gui/main_menu.png b/ren'py/game/gui/main_menu.png new file mode 100644 index 0000000..e832491 Binary files /dev/null and b/ren'py/game/gui/main_menu.png differ diff --git a/ren'py/game/gui/namebox.png b/ren'py/game/gui/namebox.png new file mode 100644 index 0000000..98a69ec Binary files /dev/null and b/ren'py/game/gui/namebox.png differ diff --git a/ren'py/game/gui/notify.png b/ren'py/game/gui/notify.png new file mode 100644 index 0000000..afdd0e3 Binary files /dev/null and b/ren'py/game/gui/notify.png differ diff --git a/ren'py/game/gui/nvl.png b/ren'py/game/gui/nvl.png new file mode 100644 index 0000000..9bbe5d4 Binary files /dev/null and b/ren'py/game/gui/nvl.png differ diff --git a/ren'py/game/gui/overlay/confirm.png b/ren'py/game/gui/overlay/confirm.png new file mode 100644 index 0000000..5ab43e8 Binary files /dev/null and b/ren'py/game/gui/overlay/confirm.png differ diff --git a/ren'py/game/gui/overlay/game_menu.png b/ren'py/game/gui/overlay/game_menu.png new file mode 100644 index 0000000..86a972c Binary files /dev/null and b/ren'py/game/gui/overlay/game_menu.png differ diff --git a/ren'py/game/gui/overlay/main_menu.png b/ren'py/game/gui/overlay/main_menu.png new file mode 100644 index 0000000..2a52321 Binary files /dev/null and b/ren'py/game/gui/overlay/main_menu.png differ diff --git a/ren'py/game/gui/phone/bar/bottom.png b/ren'py/game/gui/phone/bar/bottom.png new file mode 100644 index 0000000..3398dd5 Binary files /dev/null and b/ren'py/game/gui/phone/bar/bottom.png differ diff --git a/ren'py/game/gui/phone/bar/left.png b/ren'py/game/gui/phone/bar/left.png new file mode 100644 index 0000000..af91a99 Binary files /dev/null and b/ren'py/game/gui/phone/bar/left.png differ diff --git a/ren'py/game/gui/phone/bar/right.png b/ren'py/game/gui/phone/bar/right.png new file mode 100644 index 0000000..8d0de62 Binary files /dev/null and b/ren'py/game/gui/phone/bar/right.png differ diff --git a/ren'py/game/gui/phone/bar/top.png b/ren'py/game/gui/phone/bar/top.png new file mode 100644 index 0000000..fea53c6 Binary files /dev/null and b/ren'py/game/gui/phone/bar/top.png differ diff --git a/ren'py/game/gui/phone/button/check_foreground.png b/ren'py/game/gui/phone/button/check_foreground.png new file mode 100644 index 0000000..6ae65b6 Binary files /dev/null and b/ren'py/game/gui/phone/button/check_foreground.png differ diff --git a/ren'py/game/gui/phone/button/check_selected_foreground.png b/ren'py/game/gui/phone/button/check_selected_foreground.png new file mode 100644 index 0000000..e31a712 Binary files /dev/null and b/ren'py/game/gui/phone/button/check_selected_foreground.png differ diff --git a/ren'py/game/gui/phone/button/choice_hover_background.png b/ren'py/game/gui/phone/button/choice_hover_background.png new file mode 100644 index 0000000..583985d Binary files /dev/null and b/ren'py/game/gui/phone/button/choice_hover_background.png differ diff --git a/ren'py/game/gui/phone/button/choice_idle_background.png b/ren'py/game/gui/phone/button/choice_idle_background.png new file mode 100644 index 0000000..632758a Binary files /dev/null and b/ren'py/game/gui/phone/button/choice_idle_background.png differ diff --git a/ren'py/game/gui/phone/button/hover_background.png b/ren'py/game/gui/phone/button/hover_background.png new file mode 100644 index 0000000..900c145 Binary files /dev/null and b/ren'py/game/gui/phone/button/hover_background.png differ diff --git a/ren'py/game/gui/phone/button/idle_background.png b/ren'py/game/gui/phone/button/idle_background.png new file mode 100644 index 0000000..900c145 Binary files /dev/null and b/ren'py/game/gui/phone/button/idle_background.png differ diff --git a/ren'py/game/gui/phone/button/radio_foreground.png b/ren'py/game/gui/phone/button/radio_foreground.png new file mode 100644 index 0000000..6ae65b6 Binary files /dev/null and b/ren'py/game/gui/phone/button/radio_foreground.png differ diff --git a/ren'py/game/gui/phone/button/radio_selected_foreground.png b/ren'py/game/gui/phone/button/radio_selected_foreground.png new file mode 100644 index 0000000..e31a712 Binary files /dev/null and b/ren'py/game/gui/phone/button/radio_selected_foreground.png differ diff --git a/ren'py/game/gui/phone/button/slot_hover_background.png b/ren'py/game/gui/phone/button/slot_hover_background.png new file mode 100644 index 0000000..f337d98 Binary files /dev/null and b/ren'py/game/gui/phone/button/slot_hover_background.png differ diff --git a/ren'py/game/gui/phone/button/slot_idle_background.png b/ren'py/game/gui/phone/button/slot_idle_background.png new file mode 100644 index 0000000..61557df Binary files /dev/null and b/ren'py/game/gui/phone/button/slot_idle_background.png differ diff --git a/ren'py/game/gui/phone/nvl.png b/ren'py/game/gui/phone/nvl.png new file mode 100644 index 0000000..f6d4289 Binary files /dev/null and b/ren'py/game/gui/phone/nvl.png differ diff --git a/ren'py/game/gui/phone/overlay/game_menu.png b/ren'py/game/gui/phone/overlay/game_menu.png new file mode 100644 index 0000000..8a57016 Binary files /dev/null and b/ren'py/game/gui/phone/overlay/game_menu.png differ diff --git a/ren'py/game/gui/phone/overlay/main_menu.png b/ren'py/game/gui/phone/overlay/main_menu.png new file mode 100644 index 0000000..b36d987 Binary files /dev/null and b/ren'py/game/gui/phone/overlay/main_menu.png differ diff --git a/ren'py/game/gui/phone/scrollbar/horizontal_hover_bar.png b/ren'py/game/gui/phone/scrollbar/horizontal_hover_bar.png new file mode 100644 index 0000000..b7f0aeb Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/horizontal_hover_bar.png differ diff --git a/ren'py/game/gui/phone/scrollbar/horizontal_hover_thumb.png b/ren'py/game/gui/phone/scrollbar/horizontal_hover_thumb.png new file mode 100644 index 0000000..0d5b932 Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/horizontal_hover_thumb.png differ diff --git a/ren'py/game/gui/phone/scrollbar/horizontal_idle_bar.png b/ren'py/game/gui/phone/scrollbar/horizontal_idle_bar.png new file mode 100644 index 0000000..9bf07b6 Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/horizontal_idle_bar.png differ diff --git a/ren'py/game/gui/phone/scrollbar/horizontal_idle_thumb.png b/ren'py/game/gui/phone/scrollbar/horizontal_idle_thumb.png new file mode 100644 index 0000000..cc59261 Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/horizontal_idle_thumb.png differ diff --git a/ren'py/game/gui/phone/scrollbar/vertical_hover_bar.png b/ren'py/game/gui/phone/scrollbar/vertical_hover_bar.png new file mode 100644 index 0000000..07c701a Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/vertical_hover_bar.png differ diff --git a/ren'py/game/gui/phone/scrollbar/vertical_hover_thumb.png b/ren'py/game/gui/phone/scrollbar/vertical_hover_thumb.png new file mode 100644 index 0000000..9ea8113 Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/vertical_hover_thumb.png differ diff --git a/ren'py/game/gui/phone/scrollbar/vertical_idle_bar.png b/ren'py/game/gui/phone/scrollbar/vertical_idle_bar.png new file mode 100644 index 0000000..1f1cb2c Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/vertical_idle_bar.png differ diff --git a/ren'py/game/gui/phone/scrollbar/vertical_idle_thumb.png b/ren'py/game/gui/phone/scrollbar/vertical_idle_thumb.png new file mode 100644 index 0000000..9714eb2 Binary files /dev/null and b/ren'py/game/gui/phone/scrollbar/vertical_idle_thumb.png differ diff --git a/ren'py/game/gui/phone/slider/horizontal_hover_bar.png b/ren'py/game/gui/phone/slider/horizontal_hover_bar.png new file mode 100644 index 0000000..b782a0b Binary files /dev/null and b/ren'py/game/gui/phone/slider/horizontal_hover_bar.png differ diff --git a/ren'py/game/gui/phone/slider/horizontal_hover_thumb.png b/ren'py/game/gui/phone/slider/horizontal_hover_thumb.png new file mode 100644 index 0000000..0c9734f Binary files /dev/null and b/ren'py/game/gui/phone/slider/horizontal_hover_thumb.png differ diff --git a/ren'py/game/gui/phone/slider/horizontal_idle_bar.png b/ren'py/game/gui/phone/slider/horizontal_idle_bar.png new file mode 100644 index 0000000..52d5e7b Binary files /dev/null and b/ren'py/game/gui/phone/slider/horizontal_idle_bar.png differ diff --git a/ren'py/game/gui/phone/slider/horizontal_idle_thumb.png b/ren'py/game/gui/phone/slider/horizontal_idle_thumb.png new file mode 100644 index 0000000..1f2ca5d Binary files /dev/null and b/ren'py/game/gui/phone/slider/horizontal_idle_thumb.png differ diff --git a/ren'py/game/gui/phone/slider/vertical_hover_bar.png b/ren'py/game/gui/phone/slider/vertical_hover_bar.png new file mode 100644 index 0000000..daf4a91 Binary files /dev/null and b/ren'py/game/gui/phone/slider/vertical_hover_bar.png differ diff --git a/ren'py/game/gui/phone/slider/vertical_hover_thumb.png b/ren'py/game/gui/phone/slider/vertical_hover_thumb.png new file mode 100644 index 0000000..a51a60c Binary files /dev/null and b/ren'py/game/gui/phone/slider/vertical_hover_thumb.png differ diff --git a/ren'py/game/gui/phone/slider/vertical_idle_bar.png b/ren'py/game/gui/phone/slider/vertical_idle_bar.png new file mode 100644 index 0000000..9e0f890 Binary files /dev/null and b/ren'py/game/gui/phone/slider/vertical_idle_bar.png differ diff --git a/ren'py/game/gui/phone/slider/vertical_idle_thumb.png b/ren'py/game/gui/phone/slider/vertical_idle_thumb.png new file mode 100644 index 0000000..a49b5d0 Binary files /dev/null and b/ren'py/game/gui/phone/slider/vertical_idle_thumb.png differ diff --git a/ren'py/game/gui/phone/textbox.png b/ren'py/game/gui/phone/textbox.png new file mode 100644 index 0000000..ed7b0a6 Binary files /dev/null and b/ren'py/game/gui/phone/textbox.png differ diff --git a/ren'py/game/gui/scrollbar/horizontal_hover_bar.png b/ren'py/game/gui/scrollbar/horizontal_hover_bar.png new file mode 100644 index 0000000..b7f0aeb Binary files /dev/null and b/ren'py/game/gui/scrollbar/horizontal_hover_bar.png differ diff --git a/ren'py/game/gui/scrollbar/horizontal_hover_thumb.png b/ren'py/game/gui/scrollbar/horizontal_hover_thumb.png new file mode 100644 index 0000000..0d5b932 Binary files /dev/null and b/ren'py/game/gui/scrollbar/horizontal_hover_thumb.png differ diff --git a/ren'py/game/gui/scrollbar/horizontal_idle_bar.png b/ren'py/game/gui/scrollbar/horizontal_idle_bar.png new file mode 100644 index 0000000..9bf07b6 Binary files /dev/null and b/ren'py/game/gui/scrollbar/horizontal_idle_bar.png differ diff --git a/ren'py/game/gui/scrollbar/horizontal_idle_thumb.png b/ren'py/game/gui/scrollbar/horizontal_idle_thumb.png new file mode 100644 index 0000000..cc59261 Binary files /dev/null and b/ren'py/game/gui/scrollbar/horizontal_idle_thumb.png differ diff --git a/ren'py/game/gui/scrollbar/vertical_hover_bar.png b/ren'py/game/gui/scrollbar/vertical_hover_bar.png new file mode 100644 index 0000000..07c701a Binary files /dev/null and b/ren'py/game/gui/scrollbar/vertical_hover_bar.png differ diff --git a/ren'py/game/gui/scrollbar/vertical_hover_thumb.png b/ren'py/game/gui/scrollbar/vertical_hover_thumb.png new file mode 100644 index 0000000..9ea8113 Binary files /dev/null and b/ren'py/game/gui/scrollbar/vertical_hover_thumb.png differ diff --git a/ren'py/game/gui/scrollbar/vertical_idle_bar.png b/ren'py/game/gui/scrollbar/vertical_idle_bar.png new file mode 100644 index 0000000..1f1cb2c Binary files /dev/null and b/ren'py/game/gui/scrollbar/vertical_idle_bar.png differ diff --git a/ren'py/game/gui/scrollbar/vertical_idle_thumb.png b/ren'py/game/gui/scrollbar/vertical_idle_thumb.png new file mode 100644 index 0000000..9714eb2 Binary files /dev/null and b/ren'py/game/gui/scrollbar/vertical_idle_thumb.png differ diff --git a/ren'py/game/gui/skip.png b/ren'py/game/gui/skip.png new file mode 100644 index 0000000..734b21e Binary files /dev/null and b/ren'py/game/gui/skip.png differ diff --git a/ren'py/game/gui/slider/horizontal_hover_bar.png b/ren'py/game/gui/slider/horizontal_hover_bar.png new file mode 100644 index 0000000..b6d9c4f Binary files /dev/null and b/ren'py/game/gui/slider/horizontal_hover_bar.png differ diff --git a/ren'py/game/gui/slider/horizontal_hover_thumb.png b/ren'py/game/gui/slider/horizontal_hover_thumb.png new file mode 100644 index 0000000..515667a Binary files /dev/null and b/ren'py/game/gui/slider/horizontal_hover_thumb.png differ diff --git a/ren'py/game/gui/slider/horizontal_idle_bar.png b/ren'py/game/gui/slider/horizontal_idle_bar.png new file mode 100644 index 0000000..8d0de62 Binary files /dev/null and b/ren'py/game/gui/slider/horizontal_idle_bar.png differ diff --git a/ren'py/game/gui/slider/horizontal_idle_thumb.png b/ren'py/game/gui/slider/horizontal_idle_thumb.png new file mode 100644 index 0000000..06dc563 Binary files /dev/null and b/ren'py/game/gui/slider/horizontal_idle_thumb.png differ diff --git a/ren'py/game/gui/slider/vertical_hover_bar.png b/ren'py/game/gui/slider/vertical_hover_bar.png new file mode 100644 index 0000000..8d0c007 Binary files /dev/null and b/ren'py/game/gui/slider/vertical_hover_bar.png differ diff --git a/ren'py/game/gui/slider/vertical_hover_thumb.png b/ren'py/game/gui/slider/vertical_hover_thumb.png new file mode 100644 index 0000000..4cea34b Binary files /dev/null and b/ren'py/game/gui/slider/vertical_hover_thumb.png differ diff --git a/ren'py/game/gui/slider/vertical_idle_bar.png b/ren'py/game/gui/slider/vertical_idle_bar.png new file mode 100644 index 0000000..fea53c6 Binary files /dev/null and b/ren'py/game/gui/slider/vertical_idle_bar.png differ diff --git a/ren'py/game/gui/slider/vertical_idle_thumb.png b/ren'py/game/gui/slider/vertical_idle_thumb.png new file mode 100644 index 0000000..1046998 Binary files /dev/null and b/ren'py/game/gui/slider/vertical_idle_thumb.png differ diff --git a/ren'py/game/gui/textbox.png b/ren'py/game/gui/textbox.png new file mode 100644 index 0000000..618bcb8 Binary files /dev/null and b/ren'py/game/gui/textbox.png differ diff --git a/ren'py/game/gui/window_icon.png b/ren'py/game/gui/window_icon.png new file mode 100644 index 0000000..62c79cb Binary files /dev/null and b/ren'py/game/gui/window_icon.png differ diff --git a/ren'py/game/options.rpy b/ren'py/game/options.rpy new file mode 100644 index 0000000..8a8e151 --- /dev/null +++ b/ren'py/game/options.rpy @@ -0,0 +1,213 @@ +## This file contains options that can be changed to customize your game. +## +## Lines beginning with two '#' marks are comments, and you shouldn't uncomment +## them. Lines beginning with a single '#' mark are commented-out code, and you +## may want to uncomment them when appropriate. + + +## Basics ###################################################################### + +## A human-readable name of the game. This is used to set the default window +## title, and shows up in the interface and error reports. +## +## The _() surrounding the string marks it as eligible for translation. + +define config.name = _("My VN") + + +## Determines if the title given above is shown on the main menu screen. Set +## this to False to hide the title. + +define gui.show_name = True + + +## The version of the game. + +define config.version = "1.0" + + +## Text that is placed on the game's about screen. Place the text between the +## triple-quotes, and leave a blank line between paragraphs. + +define gui.about = _p(""" +""") + + +## A short name for the game used for executables and directories in the built +## distribution. This must be ASCII-only, and must not contain spaces, colons, +## or semicolons. + +define build.name = "MyVN" + + +## Sounds and music ############################################################ + +## These three variables control which mixers are shown to the player by +## default. Setting one of these to False will hide the appropriate mixer. + +define config.has_sound = True +define config.has_music = True +define config.has_voice = True + + +## To allow the user to play a test sound on the sound or voice channel, +## uncomment a line below and use it to set a sample sound to play. + +# define config.sample_sound = "sample-sound.ogg" +# define config.sample_voice = "sample-voice.ogg" + + +## Uncomment the following line to set an audio file that will be played while +## the player is at the main menu. This file will continue playing into the +## game, until it is stopped or another file is played. + +# define config.main_menu_music = "main-menu-theme.ogg" + + +## Transitions ################################################################# +## +## These variables set transitions that are used when certain events occur. +## Each variable should be set to a transition, or None to indicate that no +## transition should be used. + +## Entering or exiting the game menu. + +define config.enter_transition = dissolve +define config.exit_transition = dissolve + + +## Between screens of the game menu. + +define config.intra_transition = dissolve + + +## A transition that is used after a game has been loaded. + +define config.after_load_transition = None + + +## Used when entering the main menu after the game has ended. + +define config.end_game_transition = None + + +## A variable to set the transition used when the game starts does not exist. +## Instead, use a with statement after showing the initial scene. + + +## Window management ########################################################### +## +## This controls when the dialogue window is displayed. If "show", it is always +## displayed. If "hide", it is only displayed when dialogue is present. If +## "auto", the window is hidden before scene statements and shown again once +## dialogue is displayed. +## +## After the game has started, this can be changed with the "window show", +## "window hide", and "window auto" statements. + +define config.window = "auto" + + +## Transitions used to show and hide the dialogue window + +define config.window_show_transition = Dissolve(.2) +define config.window_hide_transition = Dissolve(.2) + + +## Preference defaults ######################################################### + +## Controls the default text speed. The default, 0, is infinite, while any other +## number is the number of characters per second to type out. + +default preferences.text_cps = 0 + + +## The default auto-forward delay. Larger numbers lead to longer waits, with 0 +## to 30 being the valid range. + +default preferences.afm_time = 15 + + +## Save directory ############################################################## +## +## Controls the platform-specific place Ren'Py will place the save files for +## this game. The save files will be placed in: +## +## Windows: %APPDATA\RenPy\ +## +## Macintosh: $HOME/Library/RenPy/ +## +## Linux: $HOME/.renpy/ +## +## This generally should not be changed, and if it is, should always be a +## literal string, not an expression. + +define config.save_directory = "MyVN-1569378769" + + +## Icon ######################################################################## +## +## The icon displayed on the taskbar or dock. + +define config.window_icon = "gui/window_icon.png" + + +## Build configuration ######################################################### +## +## This section controls how Ren'Py turns your project into distribution files. + +init python: + + ## The following functions take file patterns. File patterns are case- + ## insensitive, and matched against the path relative to the base directory, + ## with and without a leading /. If multiple patterns match, the first is + ## used. + ## + ## In a pattern: + ## + ## / is the directory separator. + ## + ## * matches all characters, except the directory separator. + ## + ## ** matches all characters, including the directory separator. + ## + ## For example, "*.txt" matches txt files in the base directory, "game/ + ## **.ogg" matches ogg files in the game directory or any of its + ## subdirectories, and "**.psd" matches psd files anywhere in the project. + + ## Classify files as None to exclude them from the built distributions. + + build.classify('**~', None) + build.classify('**.bak', None) + build.classify('**/.**', None) + build.classify('**/#**', None) + build.classify('**/thumbs.db', None) + + ## To archive files, classify them as 'archive'. + + # build.classify('game/**.png', 'archive') + # build.classify('game/**.jpg', 'archive') + + ## Files matching documentation patterns are duplicated in a mac app build, + ## so they appear in both the app and the zip file. + + build.documentation('*.html') + build.documentation('*.txt') + +## Set this to a string containing your Apple Developer ID Application to enable +## codesigning on the Mac. Be sure to change it to your own Apple-issued ID. + +# define build.mac_identity = "Developer ID Application: Guy Shy (XHTE5H7Z42)" + + +## A Google Play license key is required to download expansion files and perform +## in-app purchases. It can be found on the "Services & APIs" page of the Google +## Play developer console. + +# define build.google_play_key = "..." + + +## The username and project name associated with an itch.io project, separated +## by a slash. + +# define build.itch_project = "renpytom/test-project" diff --git a/ren'py/game/screens.rpy b/ren'py/game/screens.rpy new file mode 100644 index 0000000..3b5d137 --- /dev/null +++ b/ren'py/game/screens.rpy @@ -0,0 +1,1515 @@ +################################################################################ +## Initialization +################################################################################ + +init offset = -1 + + +################################################################################ +## Styles +################################################################################ + +style default: + properties gui.text_properties() + language gui.language + +style input: + properties gui.text_properties("input", accent=True) + adjust_spacing False + +style hyperlink_text: + properties gui.text_properties("hyperlink", accent=True) + hover_underline True + +style gui_text: + properties gui.text_properties("interface") + + +style button: + properties gui.button_properties("button") + +style button_text is gui_text: + properties gui.text_properties("button") + yalign 0.5 + + +style label_text is gui_text: + properties gui.text_properties("label", accent=True) + +style prompt_text is gui_text: + properties gui.text_properties("prompt") + + +style bar: + ysize gui.bar_size + left_bar Frame("gui/bar/left.png", gui.bar_borders, tile=gui.bar_tile) + right_bar Frame("gui/bar/right.png", gui.bar_borders, tile=gui.bar_tile) + +style vbar: + xsize gui.bar_size + top_bar Frame("gui/bar/top.png", gui.vbar_borders, tile=gui.bar_tile) + bottom_bar Frame("gui/bar/bottom.png", gui.vbar_borders, tile=gui.bar_tile) + +style scrollbar: + ysize gui.scrollbar_size + base_bar Frame("gui/scrollbar/horizontal_[prefix_]bar.png", gui.scrollbar_borders, tile=gui.scrollbar_tile) + thumb Frame("gui/scrollbar/horizontal_[prefix_]thumb.png", gui.scrollbar_borders, tile=gui.scrollbar_tile) + +style vscrollbar: + xsize gui.scrollbar_size + base_bar Frame("gui/scrollbar/vertical_[prefix_]bar.png", gui.vscrollbar_borders, tile=gui.scrollbar_tile) + thumb Frame("gui/scrollbar/vertical_[prefix_]thumb.png", gui.vscrollbar_borders, tile=gui.scrollbar_tile) + +style slider: + ysize gui.slider_size + base_bar Frame("gui/slider/horizontal_[prefix_]bar.png", gui.slider_borders, tile=gui.slider_tile) + thumb "gui/slider/horizontal_[prefix_]thumb.png" + +style vslider: + xsize gui.slider_size + base_bar Frame("gui/slider/vertical_[prefix_]bar.png", gui.vslider_borders, tile=gui.slider_tile) + thumb "gui/slider/vertical_[prefix_]thumb.png" + + +style frame: + padding gui.frame_borders.padding + background Frame("gui/frame.png", gui.frame_borders, tile=gui.frame_tile) + + + +################################################################################ +## In-game screens +################################################################################ + + +## Say screen ################################################################## +## +## The say screen is used to display dialogue to the player. It takes two +## parameters, who and what, which are the name of the speaking character and +## the text to be displayed, respectively. (The who parameter can be None if no +## name is given.) +## +## This screen must create a text displayable with id "what", as Ren'Py uses +## this to manage text display. It can also create displayables with id "who" +## and id "window" to apply style properties. +## +## https://www.renpy.org/doc/html/screen_special.html#say + +screen say(who, what): + style_prefix "say" + + window: + id "window" + + if who is not None: + + window: + id "namebox" + style "namebox" + text who id "who" + + text what id "what" + + + ## If there's a side image, display it above the text. Do not display on the + ## phone variant - there's no room. + if not renpy.variant("small"): + add SideImage() xalign 0.0 yalign 1.0 + + +## Make the namebox available for styling through the Character object. +init python: + config.character_id_prefixes.append('namebox') + +style window is default +style say_label is default +style say_dialogue is default +style say_thought is say_dialogue + +style namebox is default +style namebox_label is say_label + + +style window: + xalign 0.5 + xfill True + yalign gui.textbox_yalign + ysize gui.textbox_height + + background Image("gui/textbox.png", xalign=0.5, yalign=1.0) + +style namebox: + xpos gui.name_xpos + xanchor gui.name_xalign + xsize gui.namebox_width + ypos gui.name_ypos + ysize gui.namebox_height + + background Frame("gui/namebox.png", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign) + padding gui.namebox_borders.padding + +style say_label: + properties gui.text_properties("name", accent=True) + xalign gui.name_xalign + yalign 0.5 + +style say_dialogue: + properties gui.text_properties("dialogue") + + xpos gui.dialogue_xpos + xsize gui.dialogue_width + ypos gui.dialogue_ypos + + +## Input screen ################################################################ +## +## This screen is used to display renpy.input. The prompt parameter is used to +## pass a text prompt in. +## +## This screen must create an input displayable with id "input" to accept the +## various input parameters. +## +## https://www.renpy.org/doc/html/screen_special.html#input + +screen input(prompt): + style_prefix "input" + + window: + + vbox: + xalign gui.dialogue_text_xalign + xpos gui.dialogue_xpos + xsize gui.dialogue_width + ypos gui.dialogue_ypos + + text prompt style "input_prompt" + input id "input" + +style input_prompt is default + +style input_prompt: + xalign gui.dialogue_text_xalign + properties gui.text_properties("input_prompt") + +style input: + xalign gui.dialogue_text_xalign + xmaximum gui.dialogue_width + + +## Choice screen ############################################################### +## +## This screen is used to display the in-game choices presented by the menu +## statement. The one parameter, items, is a list of objects, each with caption +## and action fields. +## +## https://www.renpy.org/doc/html/screen_special.html#choice + +screen choice(items): + style_prefix "choice" + + vbox: + for i in items: + textbutton i.caption action i.action + + +## When this is true, menu captions will be spoken by the narrator. When false, +## menu captions will be displayed as empty buttons. +define config.narrator_menu = True + + +style choice_vbox is vbox +style choice_button is button +style choice_button_text is button_text + +style choice_vbox: + xalign 0.5 + ypos 270 + yanchor 0.5 + + spacing gui.choice_spacing + +style choice_button is default: + properties gui.button_properties("choice_button") + +style choice_button_text is default: + properties gui.button_text_properties("choice_button") + + +## Quick Menu screen ########################################################### +## +## The quick menu is displayed in-game to provide easy access to the out-of-game +## menus. + +screen quick_menu(): + + ## Ensure this appears on top of other screens. + zorder 100 + + if quick_menu: + + hbox: + style_prefix "quick" + + xalign 0.5 + yalign 1.0 + + textbutton _("Back") action Rollback() + textbutton _("History") action ShowMenu('history') + textbutton _("Skip") action Skip() alternate Skip(fast=True, confirm=True) + textbutton _("Auto") action Preference("auto-forward", "toggle") + textbutton _("Save") action ShowMenu('save') + textbutton _("Q.Save") action QuickSave() + textbutton _("Q.Load") action QuickLoad() + textbutton _("Prefs") action ShowMenu('preferences') + + +## This code ensures that the quick_menu screen is displayed in-game, whenever +## the player has not explicitly hidden the interface. +init python: + config.overlay_screens.append("quick_menu") + +default quick_menu = True + +style quick_button is default +style quick_button_text is button_text + +style quick_button: + properties gui.button_properties("quick_button") + +style quick_button_text: + properties gui.button_text_properties("quick_button") + + +################################################################################ +## Main and Game Menu Screens +################################################################################ + +## Navigation screen ########################################################### +## +## This screen is included in the main and game menus, and provides navigation +## to other menus, and to start the game. + +screen navigation(): + + vbox: + style_prefix "navigation" + + xpos gui.navigation_xpos + yalign 0.5 + + spacing gui.navigation_spacing + + if main_menu: + + textbutton _("Start") action Start() + + else: + + textbutton _("History") action ShowMenu("history") + + textbutton _("Save") action ShowMenu("save") + + textbutton _("Load") action ShowMenu("load") + + textbutton _("Preferences") action ShowMenu("preferences") + + if _in_replay: + + textbutton _("End Replay") action EndReplay(confirm=True) + + elif not main_menu: + + textbutton _("Main Menu") action MainMenu() + + textbutton _("About") action ShowMenu("about") + + if renpy.variant("pc"): + + ## Help isn't necessary or relevant to mobile devices. + textbutton _("Help") action ShowMenu("help") + + ## The quit button is banned on iOS and unnecessary on Android. + textbutton _("Quit") action Quit(confirm=not main_menu) + + +style navigation_button is gui_button +style navigation_button_text is gui_button_text + +style navigation_button: + size_group "navigation" + properties gui.button_properties("navigation_button") + +style navigation_button_text: + properties gui.button_text_properties("navigation_button") + + +## Main Menu screen ############################################################ +## +## Used to display the main menu when Ren'Py starts. +## +## https://www.renpy.org/doc/html/screen_special.html#main-menu + +screen main_menu(): + + ## This ensures that any other menu screen is replaced. + tag menu + + style_prefix "main_menu" + + add gui.main_menu_background + + ## This empty frame darkens the main menu. + frame: + pass + + ## The use statement includes another screen inside this one. The actual + ## contents of the main menu are in the navigation screen. + use navigation + + if gui.show_name: + + vbox: + text "[config.name!t]": + style "main_menu_title" + + text "[config.version]": + style "main_menu_version" + + +style main_menu_frame is empty +style main_menu_vbox is vbox +style main_menu_text is gui_text +style main_menu_title is main_menu_text +style main_menu_version is main_menu_text + +style main_menu_frame: + xsize 280 + yfill True + + background "gui/overlay/main_menu.png" + +style main_menu_vbox: + xalign 1.0 + xoffset -20 + xmaximum 800 + yalign 1.0 + yoffset -20 + +style main_menu_text: + properties gui.text_properties("main_menu", accent=True) + +style main_menu_title: + properties gui.text_properties("title") + +style main_menu_version: + properties gui.text_properties("version") + + +## Game Menu screen ############################################################ +## +## This lays out the basic common structure of a game menu screen. It's called +## with the screen title, and displays the background, title, and navigation. +## +## The scroll parameter can be None, or one of "viewport" or "vpgrid". When +## this screen is intended to be used with one or more children, which are +## transcluded (placed) inside it. + +screen game_menu(title, scroll=None, yinitial=0.0): + + style_prefix "game_menu" + + if main_menu: + add gui.main_menu_background + else: + add gui.game_menu_background + + frame: + style "game_menu_outer_frame" + + hbox: + + ## Reserve space for the navigation section. + frame: + style "game_menu_navigation_frame" + + frame: + style "game_menu_content_frame" + + if scroll == "viewport": + + viewport: + yinitial yinitial + scrollbars "vertical" + mousewheel True + draggable True + pagekeys True + + side_yfill True + + vbox: + transclude + + elif scroll == "vpgrid": + + vpgrid: + cols 1 + yinitial yinitial + + scrollbars "vertical" + mousewheel True + draggable True + pagekeys True + + side_yfill True + + transclude + + else: + + transclude + + use navigation + + textbutton _("Return"): + style "return_button" + + action Return() + + label title + + if main_menu: + key "game_menu" action ShowMenu("main_menu") + + +style game_menu_outer_frame is empty +style game_menu_navigation_frame is empty +style game_menu_content_frame is empty +style game_menu_viewport is gui_viewport +style game_menu_side is gui_side +style game_menu_scrollbar is gui_vscrollbar + +style game_menu_label is gui_label +style game_menu_label_text is gui_label_text + +style return_button is navigation_button +style return_button_text is navigation_button_text + +style game_menu_outer_frame: + bottom_padding 30 + top_padding 120 + + background "gui/overlay/game_menu.png" + +style game_menu_navigation_frame: + xsize 280 + yfill True + +style game_menu_content_frame: + left_margin 40 + right_margin 20 + top_margin 10 + +style game_menu_viewport: + xsize 920 + +style game_menu_vscrollbar: + unscrollable gui.unscrollable + +style game_menu_side: + spacing 10 + +style game_menu_label: + xpos 50 + ysize 120 + +style game_menu_label_text: + size gui.title_text_size + color gui.accent_color + yalign 0.5 + +style return_button: + xpos gui.navigation_xpos + yalign 1.0 + yoffset -30 + + +## About screen ################################################################ +## +## This screen gives credit and copyright information about the game and Ren'Py. +## +## There's nothing special about this screen, and hence it also serves as an +## example of how to make a custom screen. + +screen about(): + + tag menu + + ## This use statement includes the game_menu screen inside this one. The + ## vbox child is then included inside the viewport inside the game_menu + ## screen. + use game_menu(_("About"), scroll="viewport"): + + style_prefix "about" + + vbox: + + label "[config.name!t]" + text _("Version [config.version!t]\n") + + ## gui.about is usually set in options.rpy. + if gui.about: + text "[gui.about!t]\n" + + text _("Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]") + + +## This is redefined in options.rpy to add text to the about screen. +define gui.about = "" + + +style about_label is gui_label +style about_label_text is gui_label_text +style about_text is gui_text + +style about_label_text: + size gui.label_text_size + + +## Load and Save screens ####################################################### +## +## These screens are responsible for letting the player save the game and load +## it again. Since they share nearly everything in common, both are implemented +## in terms of a third screen, file_slots. +## +## https://www.renpy.org/doc/html/screen_special.html#save https:// +## www.renpy.org/doc/html/screen_special.html#load + +screen save(): + + tag menu + + use file_slots(_("Save")) + + +screen load(): + + tag menu + + use file_slots(_("Load")) + + +screen file_slots(title): + + default page_name_value = FilePageNameInputValue(pattern=_("Page {}"), auto=_("Automatic saves"), quick=_("Quick saves")) + + use game_menu(title): + + fixed: + + ## This ensures the input will get the enter event before any of the + ## buttons do. + order_reverse True + + ## The page name, which can be edited by clicking on a button. + button: + style "page_label" + + key_events True + xalign 0.5 + action page_name_value.Toggle() + + input: + style "page_label_text" + value page_name_value + + ## The grid of file slots. + grid gui.file_slot_cols gui.file_slot_rows: + style_prefix "slot" + + xalign 0.5 + yalign 0.5 + + spacing gui.slot_spacing + + for i in range(gui.file_slot_cols * gui.file_slot_rows): + + $ slot = i + 1 + + button: + action FileAction(slot) + + has vbox + + add FileScreenshot(slot) xalign 0.5 + + text FileTime(slot, format=_("{#file_time}%A, %B %d %Y, %H:%M"), empty=_("empty slot")): + style "slot_time_text" + + text FileSaveName(slot): + style "slot_name_text" + + key "save_delete" action FileDelete(slot) + + ## Buttons to access other pages. + hbox: + style_prefix "page" + + xalign 0.5 + yalign 1.0 + + spacing gui.page_spacing + + textbutton _("<") action FilePagePrevious() + + if config.has_autosave: + textbutton _("{#auto_page}A") action FilePage("auto") + + if config.has_quicksave: + textbutton _("{#quick_page}Q") action FilePage("quick") + + ## range(1, 10) gives the numbers from 1 to 9. + for page in range(1, 10): + textbutton "[page]" action FilePage(page) + + textbutton _(">") action FilePageNext() + + +style page_label is gui_label +style page_label_text is gui_label_text +style page_button is gui_button +style page_button_text is gui_button_text + +style slot_button is gui_button +style slot_button_text is gui_button_text +style slot_time_text is slot_button_text +style slot_name_text is slot_button_text + +style page_label: + xpadding 50 + ypadding 3 + +style page_label_text: + text_align 0.5 + layout "subtitle" + hover_color gui.hover_color + +style page_button: + properties gui.button_properties("page_button") + +style page_button_text: + properties gui.button_text_properties("page_button") + +style slot_button: + properties gui.button_properties("slot_button") + +style slot_button_text: + properties gui.button_text_properties("slot_button") + + +## Preferences screen ########################################################## +## +## The preferences screen allows the player to configure the game to better suit +## themselves. +## +## https://www.renpy.org/doc/html/screen_special.html#preferences + +screen preferences(): + + tag menu + + use game_menu(_("Preferences"), scroll="viewport"): + + vbox: + + hbox: + box_wrap True + + if renpy.variant("pc"): + + vbox: + style_prefix "radio" + label _("Display") + textbutton _("Window") action Preference("display", "window") + textbutton _("Fullscreen") action Preference("display", "fullscreen") + + vbox: + style_prefix "radio" + label _("Rollback Side") + textbutton _("Disable") action Preference("rollback side", "disable") + textbutton _("Left") action Preference("rollback side", "left") + textbutton _("Right") action Preference("rollback side", "right") + + vbox: + style_prefix "check" + label _("Skip") + textbutton _("Unseen Text") action Preference("skip", "toggle") + textbutton _("After Choices") action Preference("after choices", "toggle") + textbutton _("Transitions") action InvertSelected(Preference("transitions", "toggle")) + + ## Additional vboxes of type "radio_pref" or "check_pref" can be + ## added here, to add additional creator-defined preferences. + + null height (4 * gui.pref_spacing) + + hbox: + style_prefix "slider" + box_wrap True + + vbox: + + label _("Text Speed") + + bar value Preference("text speed") + + label _("Auto-Forward Time") + + bar value Preference("auto-forward time") + + vbox: + + if config.has_music: + label _("Music Volume") + + hbox: + bar value Preference("music volume") + + if config.has_sound: + + label _("Sound Volume") + + hbox: + bar value Preference("sound volume") + + if config.sample_sound: + textbutton _("Test") action Play("sound", config.sample_sound) + + + if config.has_voice: + label _("Voice Volume") + + hbox: + bar value Preference("voice volume") + + if config.sample_voice: + textbutton _("Test") action Play("voice", config.sample_voice) + + if config.has_music or config.has_sound or config.has_voice: + null height gui.pref_spacing + + textbutton _("Mute All"): + action Preference("all mute", "toggle") + style "mute_all_button" + + +style pref_label is gui_label +style pref_label_text is gui_label_text +style pref_vbox is vbox + +style radio_label is pref_label +style radio_label_text is pref_label_text +style radio_button is gui_button +style radio_button_text is gui_button_text +style radio_vbox is pref_vbox + +style check_label is pref_label +style check_label_text is pref_label_text +style check_button is gui_button +style check_button_text is gui_button_text +style check_vbox is pref_vbox + +style slider_label is pref_label +style slider_label_text is pref_label_text +style slider_slider is gui_slider +style slider_button is gui_button +style slider_button_text is gui_button_text +style slider_pref_vbox is pref_vbox + +style mute_all_button is check_button +style mute_all_button_text is check_button_text + +style pref_label: + top_margin gui.pref_spacing + bottom_margin 2 + +style pref_label_text: + yalign 1.0 + +style pref_vbox: + xsize 225 + +style radio_vbox: + spacing gui.pref_button_spacing + +style radio_button: + properties gui.button_properties("radio_button") + foreground "gui/button/radio_[prefix_]foreground.png" + +style radio_button_text: + properties gui.button_text_properties("radio_button") + +style check_vbox: + spacing gui.pref_button_spacing + +style check_button: + properties gui.button_properties("check_button") + foreground "gui/button/check_[prefix_]foreground.png" + +style check_button_text: + properties gui.button_text_properties("check_button") + +style slider_slider: + xsize 350 + +style slider_button: + properties gui.button_properties("slider_button") + yalign 0.5 + left_margin 10 + +style slider_button_text: + properties gui.button_text_properties("slider_button") + +style slider_vbox: + xsize 450 + + +## History screen ############################################################## +## +## This is a screen that displays the dialogue history to the player. While +## there isn't anything special about this screen, it does have to access the +## dialogue history stored in _history_list. +## +## https://www.renpy.org/doc/html/history.html + +screen history(): + + tag menu + + ## Avoid predicting this screen, as it can be very large. + predict False + + use game_menu(_("History"), scroll=("vpgrid" if gui.history_height else "viewport"), yinitial=1.0): + + style_prefix "history" + + for h in _history_list: + + window: + + ## This lays things out properly if history_height is None. + has fixed: + yfit True + + if h.who: + + label h.who: + style "history_name" + substitute False + + ## Take the color of the who text from the Character, if + ## set. + if "color" in h.who_args: + text_color h.who_args["color"] + + $ what = renpy.filter_text_tags(h.what, allow=gui.history_allow_tags) + text what: + substitute False + + if not _history_list: + label _("The dialogue history is empty.") + + +## This determines what tags are allowed to be displayed on the history screen. + +define gui.history_allow_tags = set() + + +style history_window is empty + +style history_name is gui_label +style history_name_text is gui_label_text +style history_text is gui_text + +style history_text is gui_text + +style history_label is gui_label +style history_label_text is gui_label_text + +style history_window: + xfill True + ysize gui.history_height + +style history_name: + xpos gui.history_name_xpos + xanchor gui.history_name_xalign + ypos gui.history_name_ypos + xsize gui.history_name_width + +style history_name_text: + min_width gui.history_name_width + text_align gui.history_name_xalign + +style history_text: + xpos gui.history_text_xpos + ypos gui.history_text_ypos + xanchor gui.history_text_xalign + xsize gui.history_text_width + min_width gui.history_text_width + text_align gui.history_text_xalign + layout ("subtitle" if gui.history_text_xalign else "tex") + +style history_label: + xfill True + +style history_label_text: + xalign 0.5 + + +## Help screen ################################################################# +## +## A screen that gives information about key and mouse bindings. It uses other +## screens (keyboard_help, mouse_help, and gamepad_help) to display the actual +## help. + +screen help(): + + tag menu + + default device = "keyboard" + + use game_menu(_("Help"), scroll="viewport"): + + style_prefix "help" + + vbox: + spacing 15 + + hbox: + + textbutton _("Keyboard") action SetScreenVariable("device", "keyboard") + textbutton _("Mouse") action SetScreenVariable("device", "mouse") + + if GamepadExists(): + textbutton _("Gamepad") action SetScreenVariable("device", "gamepad") + + if device == "keyboard": + use keyboard_help + elif device == "mouse": + use mouse_help + elif device == "gamepad": + use gamepad_help + + +screen keyboard_help(): + + hbox: + label _("Enter") + text _("Advances dialogue and activates the interface.") + + hbox: + label _("Space") + text _("Advances dialogue without selecting choices.") + + hbox: + label _("Arrow Keys") + text _("Navigate the interface.") + + hbox: + label _("Escape") + text _("Accesses the game menu.") + + hbox: + label _("Ctrl") + text _("Skips dialogue while held down.") + + hbox: + label _("Tab") + text _("Toggles dialogue skipping.") + + hbox: + label _("Page Up") + text _("Rolls back to earlier dialogue.") + + hbox: + label _("Page Down") + text _("Rolls forward to later dialogue.") + + hbox: + label "H" + text _("Hides the user interface.") + + hbox: + label "S" + text _("Takes a screenshot.") + + hbox: + label "V" + text _("Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}.") + + +screen mouse_help(): + + hbox: + label _("Left Click") + text _("Advances dialogue and activates the interface.") + + hbox: + label _("Middle Click") + text _("Hides the user interface.") + + hbox: + label _("Right Click") + text _("Accesses the game menu.") + + hbox: + label _("Mouse Wheel Up\nClick Rollback Side") + text _("Rolls back to earlier dialogue.") + + hbox: + label _("Mouse Wheel Down") + text _("Rolls forward to later dialogue.") + + +screen gamepad_help(): + + hbox: + label _("Right Trigger\nA/Bottom Button") + text _("Advances dialogue and activates the interface.") + + hbox: + label _("Left Trigger\nLeft Shoulder") + text _("Rolls back to earlier dialogue.") + + hbox: + label _("Right Shoulder") + text _("Rolls forward to later dialogue.") + + + hbox: + label _("D-Pad, Sticks") + text _("Navigate the interface.") + + hbox: + label _("Start, Guide") + text _("Accesses the game menu.") + + hbox: + label _("Y/Top Button") + text _("Hides the user interface.") + + textbutton _("Calibrate") action GamepadCalibrate() + + +style help_button is gui_button +style help_button_text is gui_button_text +style help_label is gui_label +style help_label_text is gui_label_text +style help_text is gui_text + +style help_button: + properties gui.button_properties("help_button") + xmargin 8 + +style help_button_text: + properties gui.button_text_properties("help_button") + +style help_label: + xsize 250 + right_padding 20 + +style help_label_text: + size gui.text_size + xalign 1.0 + text_align 1.0 + + + +################################################################################ +## Additional screens +################################################################################ + + +## Confirm screen ############################################################## +## +## The confirm screen is called when Ren'Py wants to ask the player a yes or no +## question. +## +## https://www.renpy.org/doc/html/screen_special.html#confirm + +screen confirm(message, yes_action, no_action): + + ## Ensure other screens do not get input while this screen is displayed. + modal True + + zorder 200 + + style_prefix "confirm" + + add "gui/overlay/confirm.png" + + frame: + + vbox: + xalign .5 + yalign .5 + spacing 30 + + label _(message): + style "confirm_prompt" + xalign 0.5 + + hbox: + xalign 0.5 + spacing 100 + + textbutton _("Yes") action yes_action + textbutton _("No") action no_action + + ## Right-click and escape answer "no". + key "game_menu" action no_action + + +style confirm_frame is gui_frame +style confirm_prompt is gui_prompt +style confirm_prompt_text is gui_prompt_text +style confirm_button is gui_medium_button +style confirm_button_text is gui_medium_button_text + +style confirm_frame: + background Frame([ "gui/confirm_frame.png", "gui/frame.png"], gui.confirm_frame_borders, tile=gui.frame_tile) + padding gui.confirm_frame_borders.padding + xalign .5 + yalign .5 + +style confirm_prompt_text: + text_align 0.5 + layout "subtitle" + +style confirm_button: + properties gui.button_properties("confirm_button") + +style confirm_button_text: + properties gui.button_text_properties("confirm_button") + + +## Skip indicator screen ####################################################### +## +## The skip_indicator screen is displayed to indicate that skipping is in +## progress. +## +## https://www.renpy.org/doc/html/screen_special.html#skip-indicator + +screen skip_indicator(): + + zorder 100 + style_prefix "skip" + + frame: + + hbox: + spacing 6 + + text _("Skipping") + + text "▸" at delayed_blink(0.0, 1.0) style "skip_triangle" + text "▸" at delayed_blink(0.2, 1.0) style "skip_triangle" + text "▸" at delayed_blink(0.4, 1.0) style "skip_triangle" + + +## This transform is used to blink the arrows one after another. +transform delayed_blink(delay, cycle): + alpha .5 + + pause delay + + block: + linear .2 alpha 1.0 + pause .2 + linear .2 alpha 0.5 + pause (cycle - .4) + repeat + + +style skip_frame is empty +style skip_text is gui_text +style skip_triangle is skip_text + +style skip_frame: + ypos gui.skip_ypos + background Frame("gui/skip.png", gui.skip_frame_borders, tile=gui.frame_tile) + padding gui.skip_frame_borders.padding + +style skip_text: + size gui.notify_text_size + +style skip_triangle: + ## We have to use a font that has the BLACK RIGHT-POINTING SMALL TRIANGLE + ## glyph in it. + font "DejaVuSans.ttf" + + +## Notify screen ############################################################### +## +## The notify screen is used to show the player a message. (For example, when +## the game is quicksaved or a screenshot has been taken.) +## +## https://www.renpy.org/doc/html/screen_special.html#notify-screen + +screen notify(message): + + zorder 100 + style_prefix "notify" + + frame at notify_appear: + text "[message!tq]" + + timer 3.25 action Hide('notify') + + +transform notify_appear: + on show: + alpha 0 + linear .25 alpha 1.0 + on hide: + linear .5 alpha 0.0 + + +style notify_frame is empty +style notify_text is gui_text + +style notify_frame: + ypos gui.notify_ypos + + background Frame("gui/notify.png", gui.notify_frame_borders, tile=gui.frame_tile) + padding gui.notify_frame_borders.padding + +style notify_text: + properties gui.text_properties("notify") + + +## NVL screen ################################################################## +## +## This screen is used for NVL-mode dialogue and menus. +## +## https://www.renpy.org/doc/html/screen_special.html#nvl + + +screen nvl(dialogue, items=None): + + window: + style "nvl_window" + + has vbox: + spacing gui.nvl_spacing + + ## Displays dialogue in either a vpgrid or the vbox. + if gui.nvl_height: + + vpgrid: + cols 1 + yinitial 1.0 + + use nvl_dialogue(dialogue) + + else: + + use nvl_dialogue(dialogue) + + ## Displays the menu, if given. The menu may be displayed incorrectly if + ## config.narrator_menu is set to True, as it is above. + for i in items: + + textbutton i.caption: + action i.action + style "nvl_button" + + add SideImage() xalign 0.0 yalign 1.0 + + +screen nvl_dialogue(dialogue): + + for d in dialogue: + + window: + id d.window_id + + fixed: + yfit gui.nvl_height is None + + if d.who is not None: + + text d.who: + id d.who_id + + text d.what: + id d.what_id + + +## This controls the maximum number of NVL-mode entries that can be displayed at +## once. +define config.nvl_list_length = gui.nvl_list_length + +style nvl_window is default +style nvl_entry is default + +style nvl_label is say_label +style nvl_dialogue is say_dialogue + +style nvl_button is button +style nvl_button_text is button_text + +style nvl_window: + xfill True + yfill True + + background "gui/nvl.png" + padding gui.nvl_borders.padding + +style nvl_entry: + xfill True + ysize gui.nvl_height + +style nvl_label: + xpos gui.nvl_name_xpos + xanchor gui.nvl_name_xalign + ypos gui.nvl_name_ypos + yanchor 0.0 + xsize gui.nvl_name_width + min_width gui.nvl_name_width + text_align gui.nvl_name_xalign + +style nvl_dialogue: + xpos gui.nvl_text_xpos + xanchor gui.nvl_text_xalign + ypos gui.nvl_text_ypos + xsize gui.nvl_text_width + min_width gui.nvl_text_width + text_align gui.nvl_text_xalign + layout ("subtitle" if gui.nvl_text_xalign else "tex") + +style nvl_thought: + xpos gui.nvl_thought_xpos + xanchor gui.nvl_thought_xalign + ypos gui.nvl_thought_ypos + xsize gui.nvl_thought_width + min_width gui.nvl_thought_width + text_align gui.nvl_thought_xalign + layout ("subtitle" if gui.nvl_text_xalign else "tex") + +style nvl_button: + properties gui.button_properties("nvl_button") + xpos gui.nvl_button_xpos + xanchor gui.nvl_button_xalign + +style nvl_button_text: + properties gui.button_text_properties("nvl_button") + + + +################################################################################ +## Mobile Variants +################################################################################ + +style pref_vbox: + variant "medium" + xsize 450 + +## Since a mouse may not be present, we replace the quick menu with a version +## that uses fewer and bigger buttons that are easier to touch. +screen quick_menu(): + variant "touch" + + zorder 100 + + if quick_menu: + + hbox: + style_prefix "quick" + + xalign 0.5 + yalign 1.0 + + textbutton _("Back") action Rollback() + textbutton _("Skip") action Skip() alternate Skip(fast=True, confirm=True) + textbutton _("Auto") action Preference("auto-forward", "toggle") + textbutton _("Menu") action ShowMenu() + + +style window: + variant "small" + background "gui/phone/textbox.png" + +style radio_button: + variant "small" + foreground "gui/phone/button/radio_[prefix_]foreground.png" + +style check_button: + variant "small" + foreground "gui/phone/button/check_[prefix_]foreground.png" + +style nvl_window: + variant "small" + background "gui/phone/nvl.png" + +style main_menu_frame: + variant "small" + background "gui/phone/overlay/main_menu.png" + +style game_menu_outer_frame: + variant "small" + background "gui/phone/overlay/game_menu.png" + +style game_menu_navigation_frame: + variant "small" + xsize 340 + +style game_menu_content_frame: + variant "small" + top_margin 0 + +style pref_vbox: + variant "small" + xsize 400 + +style bar: + variant "small" + ysize gui.bar_size + left_bar Frame("gui/phone/bar/left.png", gui.bar_borders, tile=gui.bar_tile) + right_bar Frame("gui/phone/bar/right.png", gui.bar_borders, tile=gui.bar_tile) + +style vbar: + variant "small" + xsize gui.bar_size + top_bar Frame("gui/phone/bar/top.png", gui.vbar_borders, tile=gui.bar_tile) + bottom_bar Frame("gui/phone/bar/bottom.png", gui.vbar_borders, tile=gui.bar_tile) + +style scrollbar: + variant "small" + ysize gui.scrollbar_size + base_bar Frame("gui/phone/scrollbar/horizontal_[prefix_]bar.png", gui.scrollbar_borders, tile=gui.scrollbar_tile) + thumb Frame("gui/phone/scrollbar/horizontal_[prefix_]thumb.png", gui.scrollbar_borders, tile=gui.scrollbar_tile) + +style vscrollbar: + variant "small" + xsize gui.scrollbar_size + base_bar Frame("gui/phone/scrollbar/vertical_[prefix_]bar.png", gui.vscrollbar_borders, tile=gui.scrollbar_tile) + thumb Frame("gui/phone/scrollbar/vertical_[prefix_]thumb.png", gui.vscrollbar_borders, tile=gui.scrollbar_tile) + +style slider: + variant "small" + ysize gui.slider_size + base_bar Frame("gui/phone/slider/horizontal_[prefix_]bar.png", gui.slider_borders, tile=gui.slider_tile) + thumb "gui/phone/slider/horizontal_[prefix_]thumb.png" + +style vslider: + variant "small" + xsize gui.slider_size + base_bar Frame("gui/phone/slider/vertical_[prefix_]bar.png", gui.vslider_borders, tile=gui.slider_tile) + thumb "gui/phone/slider/vertical_[prefix_]thumb.png" + +style slider_pref_vbox: + variant "small" + xsize None + +style slider_pref_slider: + variant "small" + xsize 600 diff --git a/ren'py/game/script.rpy b/ren'py/game/script.rpy new file mode 100644 index 0000000..ef0c7a1 --- /dev/null +++ b/ren'py/game/script.rpy @@ -0,0 +1,235 @@ +define n = Character("Aling Nena") +define u = Character("[name]") +define b = Character("Boy") +define l = Character("Lita") +define r = Character("Bert") +define t = Character("Tasya") + +define gamef = False +define storef = False +define correct_change = False +define correct_item = False +define baonf = False +define beachf = False +define rewardf = False + +label start: + scene bg inside house + + "It's the start of summer vacation." + "You decided to go to the province to spend some time with your lola --" + show nena + "Aling Nena" + n "Apo, what's your name again?" + + "{i}Ay naku, my lola always forgets my name.{/i}" + + python: + name = renpy.input("What is your name?").title() + + u "I'm [name], Lola Nena." + n "Ah, yes. [name]. I remember now." + u "..." + n "Can you help with my errands today, apo?" + + menu: + "Yes, Lola. You can always count on me.": + n "Thanks Apo. I'm sure I can count on you." + "Hmm. I rather sleep.": + n "Really? Your Mom and Dad will hear about this!" + u "Alright, Lola. I'll help you." + +label street: + + scene bg street with fade + + show nena + + n "Right, let's get started. We need to go to my Sari-sari store. Please help me for the day, Apo." + + hide nena + + show lita at left with moveinright + l "Hi, Aling Nena and [name]!" + + show boy at right with moveinleft + b "Hello po!" + b "Long time no see, [name]! Tara, let's play!" + + show nena + n "Naku apo, you said you'll help me." + + menu: + "Lola, mamaya na. I'll play with my friends first.": + n "Ay naku, apo. Bahala ka." + jump game + "Sorry Lita and Boy, I promised my Lola I'll help her today.": + jump store + +label store: + $ storef = True + scene bg store with fade + + show nena + n "Thanks, [name], for helping me in the store today." + u "It's okay Lola Nena." + + hide nena + show bert with moveinright + + r "Good day, Aling Nena." + n "Good day, Bert. What is your business today?" + show store prices at Position(xpos = 0.10, ypos=0.10, xanchor = 0.0, yanchor = 0.0) with dissolve + r "I need 2 kilos of rice, 2 cans of sardines, and 1 liter of oil, please." + u "I'll help you today, Bert." + + with fade + + u "Here you go." + "You give the items to Bert." + r "Hohoho. Thanks, [name]. Here's Php 100." + u "Wait a minute, Bert..." + "{i}He bought 2 kilos of rice, 2 cans of sardines, and 1 liter of oil ... {w} And he gave me Php 100. That means ... {/i}" + + menu: + "I should give him a change of {b}Php 20{/b}": + u "Your change is Php 20." + "You give the change to Bert." + $ correct_change = True + "I should give him a change of {b}Php 10{/b}": + u "Your change is Php 10." + "You give the change to Bert." + "{b}No change{/b}": + u "Oops. Nothing." + + if correct_change: + "Bert smiles and walks away." + hide store prices + hide bert with moveoutleft + else: + "You pocket the rest of the change." + "Bert frowns and walks away." + hide store prices + hide bert with moveoutleft + + with fade + show tasya with moveinleft + + t "Good day Aling Nena and [name]." + u "What brings you here, Tasya?" + t "I'm here to collect my reward from Aling Nena's Sari-sari store." + u "Congratulations, Tasya! What reward number did you avail?" + show store rewards at Position(xpos = 0.90, ypos=0.10, xanchor = 1.0, yanchor = 0.0) with dissolve + t "It's number 5." + + "You give her ... " + + menu: + "Coke Sakto": + "... Coke Sakto." + "Boy Bawang": + "... Boy Bawang." + "Php 15 load": + "... Php 15 load." + $ correct_item = True + + if correct_item: + "Tasya smiles and walks away." + hide store rewards + hide tasya with moveoutright + else: + "You keep the reward for your self." + "Tasya frowns and walks away." + hide store rewards + hide tasya with moveoutright + + if correct_change and correct_item: + jump reward + else: + jump ending + +label reward: + + $ rewardf = True + + with fade + show nena + + n "You did well, [name]! Because you helped me a lot today, I will give you a reward." + n "Which will it be?" + + menu: + "I can give you a baon to spend with your friends.": + $ baonf = True + u "Thanks for the allowance, Lola. I'll go play with Lita and Boy now." + n "Go ahead, Apo. You deserve it." + jump game + "We'll go to the beach.": + $ beachf = True + u "Let's go the beach, Lola!" + jump beach + +label beach: + $ baonf = True + scene bg beach with fade + + u "Wow, Lola! The beach is so pretty." + n "Yes, it is. Glad you like it here." + + jump ending + +label ending: + + scene bg inside house with fade + + if rewardf: + if baonf: + "You were able to spend the rest of the day with your friends Lita and Boy." + "You bought snacks for the three of you from the allowance Aling Nena gave you." + elif beachf: + pass + + "And just like that, your summer vacation in the province passed in bliss and happiness." + + with fade + + show nena + + u "Thank you Lola Nena for letting me stay with you for the summer." + n "You're always welcome here, [name]." + u "I'll comeback again next vacation!" + n "Sure, apo!" + + scene bg inside house with fade + + "THE END" + + else: + "You went home after a long day." + show nena sad + "Your Lola Nena is waiting for you. She doesn't look happy." + n "Apo, I have called your Mom and Dad. They will fetch you here tomorrow." + u "But.. but Lola..." + + if gamef: + $ desc = "a lazy" + n "You only played all day with your friends even though you promised to help me." + elif storef: + if correct_change == False: + $ desc = "a dishonest" + n "Bert told me that you did not give him the correct change." + n "Instead, you pocketed the excess amount!" + if correct_item == False: + $ desc = "an untrustworthy" + n "Tasya said that you didn't give her the correct reward." + n "Instead, you kept it to your self!" + + n "I have no use for [desc] grandchild." + + scene bg inside house with fade + + "And just like that, your summer vacation in the province is OVER." + + "THE END" + + return \ No newline at end of file diff --git a/ren'py/images/create_new_01.png b/ren'py/images/create_new_01.png new file mode 100644 index 0000000..5370d73 Binary files /dev/null and b/ren'py/images/create_new_01.png differ diff --git a/ren'py/images/create_new_02.png b/ren'py/images/create_new_02.png new file mode 100644 index 0000000..5684c85 Binary files /dev/null and b/ren'py/images/create_new_02.png differ diff --git a/ren'py/images/create_new_03.png b/ren'py/images/create_new_03.png new file mode 100644 index 0000000..103270f Binary files /dev/null and b/ren'py/images/create_new_03.png differ diff --git a/ren'py/images/create_new_04.png b/ren'py/images/create_new_04.png new file mode 100644 index 0000000..4a5c74a Binary files /dev/null and b/ren'py/images/create_new_04.png differ diff --git a/ren'py/images/create_new_05.png b/ren'py/images/create_new_05.png new file mode 100644 index 0000000..e4ebc68 Binary files /dev/null and b/ren'py/images/create_new_05.png differ diff --git a/ren'py/images/create_new_06.png b/ren'py/images/create_new_06.png new file mode 100644 index 0000000..7309e87 Binary files /dev/null and b/ren'py/images/create_new_06.png differ diff --git a/ren'py/images/create_new_07.png b/ren'py/images/create_new_07.png new file mode 100644 index 0000000..59f99e7 Binary files /dev/null and b/ren'py/images/create_new_07.png differ diff --git a/ren'py/images/game_interface_01.png b/ren'py/images/game_interface_01.png new file mode 100644 index 0000000..ea8ae5e Binary files /dev/null and b/ren'py/images/game_interface_01.png differ diff --git a/ren'py/images/game_interface_02.png b/ren'py/images/game_interface_02.png new file mode 100644 index 0000000..0ea4a44 Binary files /dev/null and b/ren'py/images/game_interface_02.png differ diff --git a/ren'py/images/renpy_editor.png b/ren'py/images/renpy_editor.png new file mode 100644 index 0000000..2ec1eaf Binary files /dev/null and b/ren'py/images/renpy_editor.png differ diff --git a/ren'py/images/renpy_engine.png b/ren'py/images/renpy_engine.png new file mode 100644 index 0000000..3c39ebb Binary files /dev/null and b/ren'py/images/renpy_engine.png differ diff --git a/ren'py/images/renpy_exe.png b/ren'py/images/renpy_exe.png new file mode 100644 index 0000000..e7d34f2 Binary files /dev/null and b/ren'py/images/renpy_exe.png differ diff --git a/ren'py/installation.md b/ren'py/installation.md new file mode 100644 index 0000000..3ff8e6b --- /dev/null +++ b/ren'py/installation.md @@ -0,0 +1,49 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Installation + +You'll need: + +- [ ] the Ren'Py software development kit +- [ ] A code editor + +The Ren'Py binaries already include Python so you don't need to download the Python interpreter beforehand. + +## Download + +You'll need to download the latest Ren'Py software development kit for your specific operating system. Currently, it is available for Windows XP and up, Mac OS X 10.6 and up, and Linux x86/x86_64. + +[Download it here](https://www.renpy.org/latest.html) + +You'll also need a text editor, preferably with code highlighting. If you have one installed already, you can set it up in *Preferences* (described below). If not, you can download through the Ren'Py engine (described below). + +## Extract + +Once downloaded, double click on the installer to start the process (Windows). For Mac or Linux systems, you may either double click from the file viewer or use the commandline to extract the compressed file. To start the engine, double-click on `renpy.exe` for Windows, `renpy.app` for Mac or execute the`renpy` shell script for Linux inside the folder `renpy-`. + +You'll then be able to access the main screen of the Ren'Py engine. + + + +From here you can (1) Create new projects `+ Create New Project`; (2) Access the directories and scripts inside each project; (3) Launch a project or game; (3) Modify the settings of the engine `Preferences`; (4) Package a game for distribution, and many others. + +You can also access both the "Tutorial" and a sample Ren'Py game called "The Question". Check these out to learn more about Ren'Py by selecting the project name under `Projects` then clicking `Launch Project`. + +## Setup editor + +To link a code editor with Ren'Py files (`*.rpy`), go to `Preferences`. Under `Text Editor`, you can then choose to download one of the editors e.g. *Atom, Editra*, or *jEdit*. Or specify an editor that you have already installed in your system in *System Editor* + + + +Once you have finished linking an editor to Ren'Py files, click `Return` to go back to the main screen. + + + +## Exercise + +Try if you can launch the editor of your choice from the Ren'Py engine by selecting the project "The Question" and then clicking `script.rpy` under `Edit file`. (We'll learn what these scripts are later). You should be able to read the code in your code editor. + +That's it! You have now installed and setup the tools that we'll need in order to make a game (visual novel) using Python. + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/introduction.md b/ren'py/introduction.md new file mode 100644 index 0000000..3017ec1 --- /dev/null +++ b/ren'py/introduction.md @@ -0,0 +1,29 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Game development using Ren'Py + +## A Python x Game Development study groups collaboration + +We will be making a simple interactive game or *visual novel* using a Python engine called Ren'Py. This is a collaboration between the WWCode Manila Python :snake:, and Game Development :video_game: ​Study Groups! + +**Game development** with Python is under one of our advanced topics. While a working knowledge of Python is needed in order to carry out some of the exercises in this study guide, Ren'Py also has its own syntax. We'll be learning and applying these throughout this study session. + + + +# What is Ren'Py + +Ren'Py is a game engine used to make visual novels - interactive stories with words, sounds, and often with choose-your-own-ending storyline. It has its own simple scripting language, and since it's based on Python, you can also leverage your coding skills in order to make more complex games. + + + + + +# Resources + +If you want to learn more about Ren'Py or developing visual novels, you can check these websites. Games which used Ren'Py are also available in these sites. + +- [The Official Ren'Py website](https://www.renpy.org/) +- [Lemma Soft Forums for creators of visual novels and story-based games ](https://lemmasoft.renai.us/forums/) + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/more.md b/ren'py/more.md new file mode 100644 index 0000000..61af417 --- /dev/null +++ b/ren'py/more.md @@ -0,0 +1,10 @@ +**More Ren'Py topics:** + +- Inserting music and sounds :soon: +- Customizing the GUI :soon: +- Customizing main sceen :soon: +- Splash screen :soon: +- End screen (credits) :soon: +- Translations :soon: +- Building an executable :soon: + diff --git a/ren'py/readme.md b/ren'py/readme.md new file mode 100644 index 0000000..428253a --- /dev/null +++ b/ren'py/readme.md @@ -0,0 +1,20 @@ +Repo to be merged into [WWCode Manila Python Study Group](https://wwcodemanila.github.io/WWCodeManila-Python/#/) page. + +This is a collaboration between the WWCode Manila Python :snake:, and Game Development :video_game: Study Groups. + +The following should go inside `_sidebar.md` in our docsify. + +- Ren'Py + + - [Introduction](introduction.md) + - [Installation and setting up](installation.md) + - [Creating a new game](create-new-game.md) + - [Aling Nena VN](aling-nena-vn.md) + - [Tutorial Part 1](scene1.md) + - [Tutorial Part 2](scene2.md) + - [Tutorial Part 3](scene3.md) + - [Tutorial Part 4](scene4.md) + - [Tutorial Part 5 - Ending](scene567.md) + +[Sample game](game/), draft only. + diff --git a/ren'py/scene1.md b/ren'py/scene1.md new file mode 100644 index 0000000..153ac12 --- /dev/null +++ b/ren'py/scene1.md @@ -0,0 +1,262 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Scene 1 + +The first scene opens with your character interacting with Aling Nena for the first time. It is set inside Aling Nena's house. Aling Nena asks you questions which you must supply the answer to. + +In implementing this scene, we'll learn about important Ren'Py *statements*: + +- [ ] Label statements +- [ ] Say statements +- [ ] Defining Characters +- [ ] User inputs +- [ ] Menu statements + +We'll also learn a little about how to + +- [ ] use text-tags, and +- [ ] include images + +Here is the code for our first scene. Copy the following code into `script.rpy` and try to run it using the Ren'Py launcher. + +!> Tip: You can use `Back` in the game screen to view the dialogue before or `Skip` to go ahead until some decision point is reached. Try these in order to view the different outcomes of your decision. + +```python +define n = Character("Aling Nena") +define u = Character("[name]") + +label start: + scene bg inside house + + "It's the start of summer vacation." + "You decided to go to the province to spend some time with your lola --" + show nena + "Aling Nena" + n "Apo, what's your name again?" + + "{i}Ay naku, my lola always forgets my name.{/i}" + + python: + name = renpy.input("What is your name?").title() + + u "I'm [name], Lola Nena." + n "Ah, yes. [name]. I remember now." + u "..." + n "Can you help with my errands today, apo?" + + menu: + "Yes, Lola. You can always count on me.": + n "Thanks Apo. I'm sure I can count on you." + "Hmm. I rather sleep.": + n "Really? Your Mom and Dad will hear about this!" + u "Alright, Lola. I'll help you." +``` + +We'll break down this code in the following sections. Feel free to replace or edit your `script.rpy` in order to follow along. + +## Label statement + +First, let's consider this simplistic subset of our first scene, containing only the first part of the dialogue: + +```python +label start: + "It's the start of summer vacation." + "You decided to go to the province to spend some time with your lola --" + "Aling Nena" + "Aling Nena" "Apo, what's your name again?" + "Anna" "I'm Anna, Lola Nena." +``` + +The `label ` statement in the first line defines a specific chunk in our program. The particular statement `label start` is a *special* statement in Ren'Py denoting the start of the game. Everything else follows this statement. + +!> Thus, always start your first story block with `label start`. + +## Say statements + +After `label start` are *say statements*. Notice that these are indented with respect to the label statement, denoting that they are part of the `label start` *block*. In Python as well as Ren'Py, uniform indentations are important; codes following ":" in the same block must be indented with the *same number of spaces or tabs*. + +There are two kinds of say statements: + +One kind denotes a *narration*. Narrations consist of a single line in quotations. You can break narrations into different lines and this will show in the game in succeeding screens. + +``` +"It's the start of summer vacation." +"You decided to go to the province to spend some time with your lola --" +"Aling Nena" +``` + +The second type denotes a character speaking: + +``` +"Aling Nena" "Apo, what's your name again?" +"Anna" "I'm Anna, Lola Nena." +``` + +In this case, a space separates the character name and what he or she is saying. Both the name and dialogue is in quotations. + +While this is all good and handy when coding the rest of the dialogue, it's cumbersome to always type the same names over and over again. + +## Defining characters + +Fortunately, you can define characters using the `Character()` class in Ren'Py. This is usually defined before the start block using the format: `define = Character("name of character")` + +Let's define a variable `n` in lieu of our first character, Aling Nena. + +```python +define n = Character("Aling Nena") +label start: + "It's the start of summer vacation." + "You decided to go to the province to spend some time with your lola --" + "Aling Nena" + n "Apo, what's your name again?" + "Anna" "I'm Anna, Lola Nena." +``` + +We can then use `n` in the succeeding dialogues instead of verbosely writing `"Aling Nena"` as in the 6th line: + +```python +n "Apo, what's your name again?" +``` + +You can add more customization on how your character and its dialogue will be displayed by specifying values for keywords inside `Character()`. For example, you can further specify a color when Aling Nena's name is displayed using `color=""`, e.g. + +```python +define n = Character("Aling Nena", color="#FF8426") +``` + +This displays the character name in orange instead of the default blue. You can learn more about how the character displays can be customized [here](https://www.renpy.org/doc/html/dialogue.html#Character). + +## Exercise + +Define a variable for the character "Anna" and use this for the rest of the dialogue. + +## User inputs and text-tags + +Let's challenge our self even more by requiring a user input from the player. In this case, instead of defining another character named "Anna", let's ask the player to supply a name for the character he or she is playing: + +```python +define n = Character("Aling Nena") +define u = Character("[name]") +label start: + "It's the start of summer vacation." + "You decided to go to the province to spend some time with your lola --" + "Aling Nena" + n "Apo, what's your name again?" + "{i}Ay naku, my lola always forgets my name.{/i}" + python: + name = renpy.input("What is your name?").title() + u "I'm [name], Lola Nena." + n "Ah, yes. [name]. I remember now." + u "..." + n "Can you help with my errands today, apo?" +``` + +In a usual Python script, user-inputs are passed inside the `input()` function. In Ren'Py, we do this using `renpy.input()` inside a *`python` block*. We'll see another example of this integration in the succeeding sections. + +We can then save the user input in a variable called `name` which we can treat as a string in Python. In our example, using the `.title()` method makes sure that the first letters of the character name is always capitalized. + +```python +python: + name = renpy.input("What's your name?").title() +``` + +Outside the `python` block, we can use this variable in a dialogue using square brackets `[]`, i.e. `[name]`. Likewise, we can use `[name]` to define a character at the start. + +```python +define u = Character("[name]") +# ... +u "I'm [name], Lola Nena." +``` + +Code preceded by `#` is also a comment in Ren'Py just like in any Python code. + +### Text-tags + +You might have also noticed a line bounded by `{i}{/i}`. This is how we can add more flair in this story by using a convention when writing character thoughts: italization. These are generally called *text-tags* which are enclosed by `{}`. + +```python +"{i}Ay naku, my lola always forgets my name.{/i}" +``` + +Text-tags offer further customizations on how certain texts are displayed inside the dialogue. Other examples of text-tags include: + +- `{b}bold{/b}` +- `{s}strikethrough{/s}` +- `{alpha=0.5}translucent{/alpha}` +- `{color=#0080c0}color change{/color}` + +We won't be discussing all Ren'Py text-tags any more than necessary in this game but you can learn more about it [here](https://www.renpy.org/doc/html/text.html?highlight=text%20tags#general-text-tags). + +Next, let's learn about one of the special features of an interactive novel: the in-game choices, which direct the flow of the story. + +## Menu statement + +Choices that a player makes are defined inside the `menu` block: + +```python + menu: + "Yes, Lola. You can always count on me.": + n "Thanks Apo. I'm sure I can count on you." + "Hmm. I rather sleep.": + n "Really? Your Mom and Dad will hear about this!" + u "Alright, Lola. I'll help you." +``` + +The `menu` statement should still be inside a `label` statement that's why it is indented. + +The choices are found in the the first level enclosed by quotations: (1) `"Yes, Lola. You can always count on me."` and (2) `"Hmm. I rather sleep."` + + The *consequences* are found in the next level. In this example, the consequences are simply different dialogues between the player and Aling Nena. + +Notice that uniform indentations denote statements that group together. + +Last but not the least, let's include some visuals! It won't be a visual novel if it doesn't have some graphics. + +## Images + +There are two types of images in our first scene: One is for the background, and the others are the characters. + +```python +define n = Character("Aling Nena") +define u = Character("[name]") + +label start: + scene bg inside house + + "It's the start of summer vacation." + "You decided to go to the province to spend some time with your lola --" + show nena + "Aling Nena" + n "Apo, what's your name again?" +``` + +The `scene` statement adds a background image which persists until another `scene` statement is called, while the `show` statement puts another image on top of the background image. + +If these images are not present, Ren'Py shows some default graphics. Try to run the game from the Ren'Py launcher at this poin to see what this looks like. + +Now, copy the images `bg inside house.png` and `nena.png` from the `assets` folder into `game/images`. Run the game again. + +`bg inside house` and `nena` refers to the file names inside our game folder; that is, `bg inside house.png` and `nena.png`. You can also define a custom image name and path using the `image` statement: + +```python +image my_image = "/path/to/my/image.png" +# ... +show my_image +``` + +To hide a particular image on top of the background, you can use the `hide` statement: + +```python +hide my_image +``` + +!> Calling the `scene` statement wipes everything from the screen and replaces it with the background image, so it won't be necessary to hide images like character images before changing the scene. + +Ren'Py creates a directory called `images` when a new project is created. This is where we will put our images so we can easily find them. In practice, it doesn't matter where your images are as long as they are inside the `game` folder and are named accordingly or you have correctly put the image path using the `image` statement. + +That's it! Look at the complete code again and see how easy it is to read the code and figure out the storyline. + +We'll learn more about positioning and transitions between images in the next section. + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/scene2.md b/ren'py/scene2.md new file mode 100644 index 0000000..755715e --- /dev/null +++ b/ren'py/scene2.md @@ -0,0 +1,218 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Scene 2 + +Our next scene happens on your way to Aling Nena's store. You bump into your friends Lita and Boy and you're now faced with another decision - will you break your promise to Aling Nena or remain true to your words? + +In implementing this scene, we'll learn about: + +- [ ] Positioning images +- [ ] Transitions +- [ ] Flags and if-else statements +- [ ] Jump statements + +You'll first need to add two characters before the `label start` block along with the previous two characters. + +```python +define b = Character("Boy") +define l = Character("Lita") +``` + +In addition, we'll define two other variables called `gamef` and `storef` and set their values to `False`. Write them just below where you defined the characters before the `label start` block. + +```python +define gamef = False +define storef = False +``` + +Next, copy the assets `bg street.png` , `lita.png`, and `boy.png` from the `assets` folder into `game/images`. + +Here is the full code for the next scene. Copy the following code into `script.rpy` after the `label start` block. It's a new `label` statement so it *should not be* indented inside the previous block. + +```python +label street: + + scene bg street with fade + + show nena + + n "Right, let's get started. We need to go to my Sari-sari store. Please help me for the day, Apo." + + hide nena + + show lita at left with moveinright + l "Hi, Aling Nena and [name]!" + + show boy at right with moveinleft + b "Hello po!" + b "Long time no see, [name]! Tara, let's play!" + + show nena + n "Naku apo, you said you'll help me." + + menu: + "Lola, mamaya na. I'll play with my friends first.": + n "Ay naku, apo. Bahala ka." + jump game + "Sorry Lita and Boy, I promised my Lola I'll help her today.": + jump store + +label store: + $ storef = True + pass +``` + +Create a new script called `batobato.rpy`. Write the following code: + +```python +label game: + $ gamef = True + pass +``` + +Try to run the game using the Ren'Py launcher. + +!> Tip: You can use `Back` in the game screen to view the dialogue before or `Skip` to go ahead until some decision point is reached. Try these in order to view the different outcomes of your decision. + +## Positioning images + +Continuing with our discussion about inserting images to our visual novel, positioning images in Ren'Py is as straight forward as using the `at` preposition, e.g: + +```python +show lita at left +``` + +Ren'Py has a pre-defined set of positions: `left`, `right`, `center` (default), and `truecenter` (centered horizontally and vertically). You can also define your own custom position using the `Position()` class. We'll revisit how to use this class later in Scene 4. + +## Transitions + +Instead of simply popping in a scene or character image, transitions can be used to aide your storytelling. Like positions, this can simply be introduced using `with`: + +```python +scene bg street with fade +``` + +Transitions can be combined with positions: + +```python +show lita at left +with moveinright +``` + +which is the same as + +```python +show lita at left with moveinright +``` + +Like positions, Ren'Py has predefined transitions such as `fade`, `dissolve`, and `pixellate`. Likewise, you can define your own transitions using the different *transition classes*. You can learn more about the different pre-defined transitions and transition classes [here](https://www.renpy.org/doc/html/transitions.html). + +## Jump statement + +The `jump` statement indicates that a particular `label` statement should be run next: + +```python +#... + menu: + "Play": + # ... + jump game + "Store": + # ... + jump store +label game: + "Player chooses play" +label store: + pass +``` + +You can think of the label name as pointers and the jump names as directives to run codes in these pointers next. + +If you haven't decided what to put inside the next `label` block yet, you can prepare a `label` statement beforehand and just use`pass`, just like a regular Python `pass` statement: + +```python +label store: + pass +``` + + Otherwise, the game will terminate in an error when it couldn't find the the next labelled block. + +Let's fill out `label game` and `label store` in Scenes 3 and 4. + +## Flags and If-else statements + +In our game, it is important to remember the choices of the player since some of these choices can determine what happens later on. + +Ren'Py supports the use of *flags*. Just like characters, these can be set using the `define` statement before the `label` block. + +```python +define flag = False +label game: + $ flag = True +label home: + "Home" +``` + +Later on in the game, these flags can be used in an `if-else` statement. + +```python +label evaluate: + if flag: + "You played a game." + else: + "You went home." +``` + +Notice that you don't have to define an `if-else` statement inside a `python` block and that instead of writing the variable as `$ flag` in the `if` statement, you just use the name of the variable without `$`. If you need this variable outside the `if-else` or even `elif` statements, you'll need to precede it as `$ flag`. + +In our code above for Scene 2, the variables `gamef` and `storef` are first set to `False` and then switched to `True` when the game ran the respective `label` blocks ... which, in turn, depended on the choice of the player under the `menu` block: + +```python +define gamef = False +define storef = False + +# ... + +label street: + +# ... + + menu: + "Lola, mamaya na. I'll play with my friends first.": + n "Ay naku, apo. Bahala ka." + jump game + "Sorry Lita and Boy, I promised my Lola I'll help her today.": + jump store + +label store: + $ storef = True + pass +``` + +and in `batobato.rpy` + +```python +label game: + $ gamef = True + pass +``` + +This is how the game remembers that a particular choice has been made. It doesn't really matter if you change the value of the flag inside the `menu` block or inside the `label` block, so long as this aides the readability of your code i.e. if you write all other flags in your code in the same manner. + +We'll use this values later on in the `label ending` block, in Scene 7 (the last scene): + +```python +label ending: + #... + if gamef: + #... + elif storef: + # .. +``` + + + +In the next part, we'll learn how to use other Python equivalent statements in Ren'Py by making a mini-game *bato-bato pik* (rock, paper, scissors). + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/scene3.md b/ren'py/scene3.md new file mode 100644 index 0000000..fb032a9 --- /dev/null +++ b/ren'py/scene3.md @@ -0,0 +1,146 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Scene 3 + +In this scene, you played *bato-bato pik* (rock, paper, scissors) with your friends Lita and Boy who you met previously in Scene 2. + +Here, we'll learn more about + +- [ ] Python equivalent statements in Ren'Py + +## Exercise + +Try making our own implementation of Rock, Paper, Scissors in Python first . A player wins if he or she scores 2 points first (best of three) against the computer. Only wins or loses count towards any point, ties do not change the scores. + +Replace the code in `batobato.rpy` from the previous section with the following code. Go over the `python` block carefully. We won't be discussing this particular implementation in detail, instead we'll focus on the Ren'Py code. + +```python +label game: + + $ gamef = True + + scene bg street with fade + + show lita at left with moveinright + show boy at right with moveinleft + + l "Let's play bato-bato pik!" + + show boy at center with moveinright + b "You'll play against me. Best of three!" + + python: + from random import randint + uscore = 0 + bscore = 0 + while uscore | bscore < 2: + + renpy.say(b, "Bato-bato pik!") + + choices = {"r": "Rock", "p": "Paper", "s": "Scissors"} + uhand = renpy.display_menu([("Rock", "r"), ("Paper", "p"), ("Scissors", "s")]) + bhand = choices.keys()[randint(0,2)] + + uhand_c = choices[uhand] + bhand_c = choices[bhand] + + renpy.say(b, "[bhand_c]") + + hands = (uhand, bhand) + + wins = [ + ('p', 'r'), + ('r', 's'), + ('s', 'p'), + ] + tie = False + if hands[0] == hands[1]: + tie = True + result = "It's a tie!" + elif hands in wins: + result = "wins" + uscore += 1 + else: + result = "loses" + bscore += 1 + + if not tie: + renpy.say(l, "[name] picked [uhand_c], Boy picked [bhand_c] \n [name] [result]! {w} \n Boy: [bscore], [name]: [uscore]") + else: + renpy.say(l, "[name] picked [uhand_c], Boy picked [bhand_c] \n [result]! {w} \n Boy: [bscore], [name]: [uscore]") + + if uscore > bscore: + renpy.say(l, "[name] is the WINNER!") + winner = True + else: + renpy.say(l, "Boy wins. [name] LOSES!") + winner = False + + if winner: + show boy at right with moveinleft + l "Well done, [name]." + b "You defeated me!" + else: + show boy at right with moveinleft + b "Oh well, there's always a next time, [name]." + + l "Let's play another game!" + "You spend the rest of the day playing." + + jump ending + +``` + +In `script.py`, add the following `label` statement: + +```python +label ending: + pass +``` + +Try to run the game using the Ren'Py launcher. + +!> Tip: You can use `Back` in the game screen to view the dialogue before or `Skip` to go ahead until some decision point is reached. Try these in order to view the different outcomes of your decision. + +## Python equivalent statements + +The `renpy.` offers a convinient interface to integrate Python into your Ren'Py code. We've already used one of these when we discussed user-defined inputs in Scene 1: `renpy.input()` + +You'll need to implement these equivalent statements under a `python` block. + +In this code we used: + +- `renpy.say()` +- `renpy.display_menu()` + +Notice that, when displaying a variable in a `renpy.say()` statement, we can just enclose it with `[]` as in: + +```python +renpy.say(l, "[name] picked [uhand_c], Boy picked [bhand_c] \n [name] [result]! {w} \n Boy: [bscore], [name]: [uscore]") +``` + +Other equivalent statements and there usages can be found [here](https://www.renpy.org/doc/html/statement_equivalents.html). Here are some that we have already encountered in the previous sections. + +- `renpy.jump()` - `jump` statement +- `renpy.scene()` - `scene` statement +- `renpy.show()` - `show` statement +- `renpy.with_statement()` - transitions, i.e. `with` + +## Misc + +You can actually write the code in`batobato.rpy` inside `script.rpy`. Ren'Py consolidates all `label` statements into one when it is run, so it doesn't really matter whether you partition your code into different files. In cases of large games; however, it might be more efficient or readible to divide the game into different files. This section just demonstrates that making multiple files is possible. + +## Exercise + +If you made your own Rock, Paper, Scissors game in Python, implement your code in this Ren'Py game instead. + +You may also want to make your own mini-game (examples are: Hangman, Guess the Number, or even *Pinoy Henyo*) instead of or in addition to the one we used here. You can try coding it in Python first then integate it into this Ren'Py game using equivalent statements. + +What does the text-tag `{w}{/w}` do? + +What does `\n` do ? + +[challenge_partial](../challenge_partial.md ':include') + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/scene4.md b/ren'py/scene4.md new file mode 100644 index 0000000..f823d89 --- /dev/null +++ b/ren'py/scene4.md @@ -0,0 +1,139 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +# Scene 4 + +This scene takes place inside Aling Nena's store. You're then tasked to assist two customers: Bert and Tasya. The manner with which you answer their concerns will determine the succeeding scenes. + +At this point, we've already covered much of what can be learned in implementing a basic visual novel using Ren'Py. We'll only need to discuss + +- [ ] Custom-defined positions + +You'll first need to add our last two characters before the `label start` block along with the other characters: + +```python +define r = Character("Bert") +define t = Character("Tasya") +``` + +And these flags below where you defined the characters and before the `label start` block. + +```python +define correct_change = False +define correct_item = False +``` + +Next, copy the assets `bg store.png` , `bert.png`, `tasya.png`, `store prices.png` and `store rewards.png` from the `assets` folder into `game/images`. + +Here is the code that we'll be using. Replace the codes below the`label store` block in your `script.rpy` code and add a new block `label reward` after it: + +```python +label store: + $ storef = True + scene bg store with fade + + show nena + n "Thanks, [name], for helping me in the store today." + u "It's okay Lola Nena." + + hide nena + show bert with moveinright + + r "Good day, Aling Nena." + n "Good day, Bert. What is your business today?" + show store prices at Position(xpos = 0.10, ypos=0.10, xanchor = 0.0, yanchor = 0.0) with dissolve + r "I need 2 kilos of rice, 2 cans of sardines, and 1 liter of oil, please." + u "I'll help you today, Bert." + + with fade + + u "Here you go." + "You give the items to Bert." + r "Hohoho. Thanks, [name]. Here's Php 100." + u "Wait a minute, Bert..." + "{i}He bought 2 kilos of rice, 2 cans of sardines, and 1 liter of oil ... {w} And he gave me Php 100. That means ... {/i}" + + menu: + "I should give him a change of {b}Php 20{/b}": + u "Your change is Php 20." + "You give the change to Bert." + $ correct_change = True + "I should give him a change of {b}Php 10{/b}": + u "Your change is Php 10." + "You give the change to Bert." + "{b}No change{/b}": + u "Oops. Nothing." + + if correct_change: + "Bert smiles and walks away." + hide store prices + hide bert with moveoutleft + else: + "You pocket the rest of the change." + "Bert frowns and walks away." + hide store prices + hide bert with moveoutleft + + with fade + show tasya with moveinleft + + t "Good day Aling Nena and [name]." + u "What brings you here, Tasya?" + t "I'm here to collect my reward from Aling Nena's Sari-sari store." + u "Congratulations, Tasya! What reward number did you avail?" + show store rewards at Position(xpos = 0.90, ypos=0.10, xanchor = 1.0, yanchor = 0.0) with dissolve + t "It's number 5." + + "You give her ... " + + menu: + "Coke Sakto": + "... Coke Sakto." + "Boy Bawang": + "... Boy Bawang." + "Php 15 load": + "... Php 15 load." + $ correct_item = True + + if correct_item: + "Tasya smiles and walks away." + hide store rewards + hide tasya with moveoutright + else: + "You keep the reward for your self." + "Tasya frowns and walks away." + hide store rewards + hide tasya with moveoutright + + if correct_change and correct_item: + jump reward + else: + jump ending + +label reward: + pass +``` + +## Custom-defined image positions + +As mentioned earlier, you can specify where in the screen an image will show instead of using the pre-defined Ren'Py positions. This can be done using the class `Position()`. + +For example: + +``` +show store prices at Position(xpos = 0.10, ypos=0.10, xanchor = 0.0, yanchor = 0.0) with dissolve +``` + +In this case you'll need to set the following arguments: + +`xpos` or `ypos`: Point on the screen defined by x (horizontal) and y (vertical) positions + +`xanchor` or `yanchor`: An x and y position of a point on the image. If specified, this point will be positioned on the screen at the location indicated by`xpos` and `ypos`. + +Along the x-axis, `0.0` is on the extreme left, while `1.0` is on the extreme right. Along the y-axis, `0.0` is on the top-most, while a value of `1.0` is the bottom-most of the screen or image. + +# Exercise + +Practice with repositioning the images `store prices.png` and `store rewards.png` somewhere else in the screen by changing the keywords in the `Position()` class. + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/ren'py/scene567.md b/ren'py/scene567.md new file mode 100644 index 0000000..cd253cc --- /dev/null +++ b/ren'py/scene567.md @@ -0,0 +1,166 @@ +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + +At this point, we've covered all there is to discuss in our simple visual novel. + +We'll just need to complete our game with three more `label` blocks: reward, beach, ending. + +Add these flags below where you defined the characters and before the `label start` block. + +```python +define baonf = False +define beachf = False +define rewardf = False +``` + +Copy the assets `bg beach.png` and `nena sad.png` from the `assets` folder into `game/images`. + +# Scene 5 + +This scene is only run when both `$ correct_change` and `$ correct_item` are `True`. + +Replace the `pass` statement in the `label reward` block in `script.rpy`: + +```python +label reward: + + $ rewardf = True + + with fade + show nena + + n "You did well, [name]! Because you helped me a lot today, I will give you a reward." + n "Which will it be?" + + menu: + "I can give you a baon to spend with your friends.": + $ baonf = True + u "Thanks for the allowance, Lola. I'll go play with Lita and Boy now." + n "Go ahead, Apo. You deserve it." + jump game + "We'll go to the beach.": + $ beachf = True + u "Let's go the beach, Lola!" + jump beach +``` + +Notice that in this scene, if the player decides to have a *baon* (allowance) as a reward, the game will run "back to" Scene 3 wherein we made a mini-game. `jump` statements can be powerful tools to facilitate any loops in the narration or storyline. + +# Scene 6 + +Add the following in `script.rpy`: + +```python +label beach: + $ baonf = True + scene bg beach with fade + + u "Wow, Lola! The beach is so pretty." + n "Yes, it is. Glad you like it here." + + jump ending +``` + +# Scene 7 / Ending + +Last, add the following in `script.rpy`, replace the statement under the `label ending` block: + +```python +label ending: + + scene bg inside house with fade + + if rewardf: + if baonf: + "You were able to spend the rest of the day with your friends Lita and Boy." + "You bought snacks for the three of you from the allowance Aling Nena gave you." + elif beachf: + pass + + "And just like that, your summer vacation in the province passed in bliss and happiness." + + with fade + + show nena + + u "Thank you Lola Nena for letting me stay with you for the summer." + n "You're always welcome here, [name]." + u "I'll comeback again next vacation!" + n "Sure, apo!" + + scene bg inside house with fade + + "THE END" + + else: + "You went home after a long day." + show nena sad + "Your Lola Nena is waiting for you. She doesn't look happy." + n "Apo, I have called your Mom and Dad. They will fetch you here tomorrow." + u "But.. but Lola..." + + if gamef: + $ desc = "a lazy" + n "You only played all day with your friends even though you promised to help me." + elif storef: + if correct_change == False: + $ desc = "a dishonest" + n "Bert told me that you did not give him the correct change." + n "Instead, you pocketed the excess amount!" + if correct_item == False: + $ desc = "an untrustworthy" + n "Tasya said that you didn't give her the correct reward." + n "Instead, you kept it to your self!" + + n "I have no use for [desc] grandchild." + + scene bg inside house with fade + + "And just like that, your summer vacation in the province is OVER." + + "THE END" + + return +``` + +Try to run the game using the Ren'Py launcher. + +!> Tip: You can use `Back` in the game screen to view the dialogue before or `Skip` to go ahead until some decision point is reached. Try these in order to view the different outcomes of your decision. + +Note that in this scene, we have defined a variable by preceeding the variable name with `$ ` and equating it to a value, e.g. + +```python +$ desc = "a lazy" +``` + +This is the same as when we previously defined a *flag* variable, although in this case we did not write a `define` statement for the `desc` variable first. You can do the same thing with our flag variables only that, sometimes, it is more readable to write or define the flags first thing in the code. (For instance, it's more efficient to find them after many lines of coding). + +## Return statement + +The `return` statement, like `label start` is another special statement in Ren'Py which means the end of the game. When this statement is run, no matter where in the game it is, the game immediately terminates. + +For example, if we have inserted `return` in the `label beach` block before the `jump ending` statement: + +```python +label beach: + $ baonf = True + scene bg beach with fade + + u "Wow, Lola! The beach is so pretty." + n "Yes, it is. Glad you like it here." + + return + jump ending +``` + +What do you think will happen? Try this by modifying this block as above. The game will immediately terminate without the character ever experiencing the ending! + +That's it! Congratulations on creating a simple virtual novel. + +# Project + +Make a visual novel of your own. Write or choose a story, gather your own assets, build awesome characters, make up interesting dialogues! Share your work! We'll love to play it! :heart: + +[challenge_partial](../challenge_partial.md ':include') + +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/WWCodeManila/Python) + diff --git a/sidebar.md b/sidebar.md new file mode 100644 index 0000000..340c791 --- /dev/null +++ b/sidebar.md @@ -0,0 +1,62 @@ +- Women Who Code Manila + - [About WWCode Manila](wwcodemanila/about.md) + - [Study Groups](wwcodemanila/study_groups.md) + +- Getting Started + - [Installation](getting_started/installation_guide.md) + - [Run a basic Python program](getting_started/warm_up.md) + - [Sharing your work](getting_started/exercise_upload_step.md) + +- Basic Concepts + - [Variables, Arithmetic Operations, Keyboard Input](basic_concepts/variables.md) + - [Let's go Git!](git/README.md) + - [Strings pa more!](basic_concepts/strings.md) + - [PEP8](basic_concepts/pep8.md) + - [List, tuple, set](basic_concepts/lists.md) + - [Conditional Statements](basic_concepts/conditional_statements.md) + - [Loops](basic_concepts/loops.md) + - [Challenge: I survived Hangman!](basic_concepts/exercises/hangman/README.md) + - [Dictionaries](basic_concepts/dictionaries.md) + - [Functions](basic_concepts/functions.md) + - [Classes and Module](http://introtopython.org/classes.html) + - [Error Handling](basic_concepts/error_handling.md) + - [Challenge: It's 2048!](basic_concepts/exercises/2048/README.md) + +- Advanced Concepts + - [List comprehension](https://hackernoon.com/list-comprehension-in-python-8895a785550b) + - [Generators](https://anandology.com/python-practice-book/iterators.html) + - [Decorators](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/) + +- Flask + - [Introduction](flask/discussions/01_introduction.md) + - [Setting up Flask and virtual environments](flask/discussions/02_setup.md) + - [Building my first Flask app](flask/discussions/03_my_first_flask_app.md) + - [Creating URL routes](flask/discussions/04_url_routes.md) + - [Styling templates and passing variables](flask/discussions/05_templates_and_variables.md) + - Integrating databases using SQLite :soon: + - Forming forms :soon: + - Using cookies and sessions :soon: + - Deploying my app :soon: + - Wrapping up :soon: + +- Ren'Py + - [Introduction](ren'py/introduction.md) + - [Installation and setting up](ren'py/installation.md) + - [Creating a new game](ren'py/create-new-game.md) + - [Aling Nena VN](ren'py/aling-nena-vn.md) + - [Tutorial Part 1](ren'py/scene1.md) + - [Tutorial Part 2](ren'py/scene2.md) + - [Tutorial Part 3](ren'py/scene3.md) + - [Tutorial Part 4](ren'py/scene4.md) + - [Tutorial Part 5 - Ending](ren'py/scene567.md) + +- Django + - [Introduction](django/01_introduction.md) + - [Setting up Django and virtual environments](django/02_setup.md) + - [Creating your first Django application](django/03_start_project.md) + - [Creating Users module](django/04_create_users_module.md) + - [Creating endpoints](django/05_endpoints.md) + - [Creating Questions module](django/06_create_questions_module.md) + +- Resources + - [References](resources/references.md)