From a3cc9332b24882a01b5f633a511c070508f5572f Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Sat, 24 Dec 2022 20:30:30 +0530 Subject: [PATCH 01/34] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b64d5c34 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 IRIS-NITK + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From f021a6868fc95f9afdffdf1681a41affabf61a3a Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:47:25 +0530 Subject: [PATCH 02/34] Add instructions for dev devcontainer --- setup/dev_container.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup/dev_container.md b/setup/dev_container.md index ca4c1cbf..34eeb59e 100644 --- a/setup/dev_container.md +++ b/setup/dev_container.md @@ -29,8 +29,12 @@ cd IRIS-RoR-Bootcamp-2022 code . ``` ## 3. Open the folder in dev container -* Click on quick actions Status bar item, and from the dropdown select **Reopen in Container**. This uses the dev container [config file](https://github.com/IRIS-NITK/IRIS-RoR-Bootcamp-2022/blob/install-ror/.devcontainer/devcontainer.json) inside `.devcontainer` folder to create a new dev container. -r +* Open the repo in VS code and press Ctrl + Shift + p to bring up the Command Palette, +and search for command **Dev Containers: Reopen in Container** and execute it. This uses the dev +container [config file](https://github.com/IRIS-NITK/IRIS-RoR-Bootcamp-2022/blob/install-ror/.devcontainer/devcontainer.json) +inside `.devcontainer` folder to create a new dev container. + +dev_cont * The VS Code window will reload and start building the dev container. A progress notification provides status updates. * After the build completes, VS Code will automatically connect to the container. @@ -44,4 +48,4 @@ The container has `rvm`, `node` and `yarn` preinstalled so you can get started o -------------------------------------------------- -Once done head over [here](./README.md#rvm), to learn about RVM and gemsets. \ No newline at end of file +Once done head over [here](./README.md#rvm), to learn about RVM and gemsets. From 3c772632a76d40c220a68e71d237ba566980ebfa Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Mon, 26 Dec 2022 14:19:00 +0530 Subject: [PATCH 03/34] add week-2 to readme --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d2bf1b7..9e4c637e 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,10 @@ ## [Week 1 - HTML and CSS](/week_1) In the first week, we will introduce you to basic concepts related to Web Development and Git. +## [Week 2 - Ruby and Installations](/week_2) +In this week, we'll take a look at Ruby and instructions to get your device ready for creating Ruby on Rails projects. + +Head to [setup](/setup) for installation instructions. + ## Contact -In case of doubts related to the Bootcamp, feel free to reach out to the mentors on the [**#doubts**](https://discord.com/channels/1052463702558908416/1052467811143913552) channel on [Discord](https://discord.gg/Gb3R7CFe). +In case of doubts related to the Bootcamp, feel free to reach out to the mentors on the [**#doubts**](https://discord.com/channels/1052463702558908416/1052467811143913552) channel on [Discord](https://discord.gg/HQKpB6XH). From 6c71da680b3f4a8243039cd8778bd254895fee02 Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Mon, 26 Dec 2022 14:23:47 +0530 Subject: [PATCH 04/34] change github link to youtube link for week-2 TODO: Merge Week-2 Ruby and Assignment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e4c637e..6112c971 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## [Week 1 - HTML and CSS](/week_1) In the first week, we will introduce you to basic concepts related to Web Development and Git. -## [Week 2 - Ruby and Installations](/week_2) +## [Week 2 - Ruby and Installations](https://www.youtube.com/watch?v=GQoQoJmmAuM&list=PLd4eAZyzurEj3WRhTpPAW3hfmM6a6CspK&index=5) In this week, we'll take a look at Ruby and instructions to get your device ready for creating Ruby on Rails projects. Head to [setup](/setup) for installation instructions. From e17608a35dfb5b45219046fc19073238a4b1db68 Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Mon, 26 Dec 2022 19:12:05 +0530 Subject: [PATCH 05/34] [Week 2] Theory and assignment (#60) * Update Discord invite link * Add resource links from previous year Co-authored-by: KeerthiBhushanM <97404965+KeerthiBhushanM@users.noreply.github.com> --- .github/workflows/week2.yml | 32 ++++ .gitignore | 54 ++++++ week_2/README.md | 102 +++++++++++ week_2/intro_to_ruby.md | 344 ++++++++++++++++++++++++++++++++++++ week_2/pet.rb | 115 ++++++++++++ week_2/pet_test.rb | 117 ++++++++++++ week_2/prime_numbers.rb | 18 ++ week_2/prime_test.rb | 32 ++++ week_2/screenshots/irb.png | Bin 0 -> 67049 bytes 9 files changed, 814 insertions(+) create mode 100644 .github/workflows/week2.yml create mode 100644 .gitignore create mode 100644 week_2/README.md create mode 100644 week_2/intro_to_ruby.md create mode 100644 week_2/pet.rb create mode 100644 week_2/pet_test.rb create mode 100644 week_2/prime_numbers.rb create mode 100644 week_2/prime_test.rb create mode 100644 week_2/screenshots/irb.png diff --git a/.github/workflows/week2.yml b/.github/workflows/week2.yml new file mode 100644 index 00000000..c69aeba6 --- /dev/null +++ b/.github/workflows/week2.yml @@ -0,0 +1,32 @@ +name: 'Week 2 Assignment' + +on: + pull_request: + types: [synchronize, opened, reopened, edited] + branches: + - 'week2_*' + + workflow_dispatch: + +jobs: + week2: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.5 + working-directory: week_2 + bundler-cache: true + + - name: Test Prime + working-directory: week_2 + run: ruby prime_test.rb + + - name: Test Pet store + working-directory: week_2 + run: ruby pet_test.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7b6d8d72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +*.rbc +capybara-*.html +.rspec +/db/*.sqlite3 +/db/*.sqlite3-journal +/db/*.sqlite3-[0-9]* +/public/system +/coverage/ +/spec/tmp +*.orig +rerun.txt +pickle-email-*.html + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# dotenv +# TODO Comment out this rule if environment variables can be committed +.env + +## Environment normalization: +/.bundle +/vendor/bundle + +# these should all be checked in to normalize the environment: +# Gemfile.lock, .ruby-version, .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +.rvmrc + +# if using bower-rails ignore default bower_components path bower.json files +/vendor/assets/bower_components +*.bowerrc +bower.json + +# Ignore pow environment settings +.powenv + + +# Ignore node_modules +node_modules/ + + +# Ignore yarn files +/yarn-error.log +yarn-debug.log* +.yarn-integrity + + +**/imp.rb +**/p_imp.rb \ No newline at end of file diff --git a/week_2/README.md b/week_2/README.md new file mode 100644 index 00000000..8c328915 --- /dev/null +++ b/week_2/README.md @@ -0,0 +1,102 @@ +# Week 2 - Ruby +- [Intro to Ruby](./intro_to_ruby.md) + +To make you familar with ruby syntax, we have created some exercises to help you +learn and practice Ruby syntax - covering conditional statements (`if`, `else`, `elsif`), +different ways of iteration (`each`, `map`) and some object oriented code. + +If you not familiar with programming concepts like `variable`, `function` and `class`, +you can refer to the following resources +- [TryRuby](https://try.ruby-lang.org/) +- [Learn Ruby the Hard Way](https://learnrubythehardway.org/book/). + +## Pre-requisites +- [Ruby is installed](https://github.com/IRIS-NITK/IRIS-RoR-Bootcamp-2022/tree/week2_assignment/setup). + +> Follow this guide to [setup your workspace](https://github.com/IRIS-NITK/IRIS-RoR-Bootcamp-2022/tree/week2_assignment/setup) + +- Make sure you are in the correct directory(week_2) while running commands +```bash +cd week_2 +ls #imp.rb p_imp.rb pet.rb pet_test.rb .... +rvm gemset create week_2 +rvm use 3.0.5@week_2 +ruby +``` + +## Submission +- Use the week2_ branch for your work +```bash +git checkout -b week2_ +``` +- Your Pull Request will be graded by the automated tests. +- Once you have completed the assignment, submit a Pull +Request with your work to the branch `week2_assignment` **(not `main`)**. + +## Prime number + +This is a simple assignment to familiarize ourself with ruby. +In this assignment we will learn about loops in ruby and a bit of +error handling. + +A [prime number](https://en.wikipedia.org/wiki/Prime_number) is a +whole number greater than 1 that cannot be exactly divided by +any whole number other than itself and 1 +(e.g. 2, 3, 5, 7, 11). + +The function below takes a [keyword argument](https://en.wikipedia.org/wiki/Named_parameter) `n` and +returns an array of prime numbers less than or equal to `n`. + +For example, `prime_numbers(n: 20)` should return the following: +`[2, 3, 5, 7, 11, 13, 17, 19]` + +If the user gives a invalid input like -4. +We will raise an `ArgumentError` exception to let the caller know that +their function arguments were incorrect. + +**Note** - Do not use use the inbuilt `prime` library +> Implement the function `prime_numbers` in the file [`prime_numbers.rb`](prime_numbers.rb) +> and test your code with `ruby prime_test.rb`. + +- [Ruby - if...else, case, unless - TutorialPoint](https://www.tutorialspoint.com/ruby/ruby_if_else.htm) +- [Ruby Keyword Arguments](https://thoughtbot.com/upcase/videos/ruby-keyword-arguments) +- [How to Use Ruby Conversion Methods](https://www.rubyguides.com/2018/09/ruby-conversion-methods/) +- [A Beginner's Guide to Exceptions in Ruby](https://www.honeybadger.io/blog/a-beginner-s-guide-to-exceptions-in-ruby/) + +## Pet Store + +You are working at a pet store and want to build a system +to let the pet owners know the maintenance cost of their pets. + +The pet is represented using the `Pet` class. A `Pet` stores +the following information: +- Name of the pet (`name`) +- Type of animal(Mammals, Fish ...)(`animal_type_id`) +- Food consumed by the pet per day in Kg(`food_consumed_per_day`) + +> Implement the class `Pet` above in the file [`pet.rb`](pet.rb) and test +> your code with `ruby pet_test.rb`. + +- [attr_accessor, attr_writer and attr_reader](https://www.rubyguides.com/2018/11/attr_accessor/) +- [map](https://apidock.com/ruby/Enumerable/map) +- [Ruby - Classes and Objects](https://www.tutorialspoint.com/ruby/ruby_classes.htm) +- [Class and Instance Methods in Ruby](http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/) +- [group_by (Enumerable)](https://apidock.com/ruby/Enumerable/group_by) +- [reduce (Enumerable)](https://apidock.com/ruby/Enumerable/reduce) + + +## Interactive Console + +You can use the interactive ruby (`irb`) to help understand and debug +your code. `irb` is similar to python's interactive console and lets you +run any ruby code. + +For example, to debug `prime_numbers.rb` do the following: +- Open a ruby console using `irb`. +- Include the ruby program using `require_relative 'prime_numbers'`. +- Execute the function (or any valid ruby statement using the + interpreter). + +![image](https://user-images.githubusercontent.com/66632353/209439834-f103fe31-4d5f-41d0-83e6-f2559163f7fb.png) + +- [How to use IRB to Explore Ruby](https://www.digitalocean.com/community/tutorials/how-to-use-irb-to-explore-ruby) diff --git a/week_2/intro_to_ruby.md b/week_2/intro_to_ruby.md new file mode 100644 index 00000000..f860a6d0 --- /dev/null +++ b/week_2/intro_to_ruby.md @@ -0,0 +1,344 @@ +#

____INTRO TO RUBY____

+## Literals +A literal is any notation that lets you represent a fixed value in source code. For instance, all of the following are literals in Ruby: +``` +'Hello, world!' // string literal +375 // integer literal +3.141528 // float literal +true // boolean literal +{ 'a' => 1, 'b' => 2 } // hash literal +[ 1, 2, 3 ] // array literal +:sym // symbol literal +nil // nil literal +``` +
+ +## Printing and Reading Inputs +We can use print or puts statements to print on the console. The difference between the two is that puts automatically appends a new line while print does not. + +``` +puts "Hello" # puts inserts a new line +print "there" # print does not insert a new line +puts "!" +``` +We can use gets to read inputs from the console +``` +abc = gets +puts abc +``` +
+ +## Comments in Ruby +Sometimes comments are necessary in our program to increase the readability of the code that we write. The interpreter treats every word u type in the code as code itself. Hence we need to follow certain syntax to add comments. +

+To add a single line comments we can just use # and the entire line following hash is ignored by the compiler + +``` +# This is a single line comment +``` +To add multi line comments. We can use =begin =end and insert all our comments between the two + +``` +=begin + Multi Line Comments +=end +``` +
+ +## Operators in Ruby +Operators are anything that performs an operation on operands. +### Basic Arithmetic +The Ruby programming language supports various arithmetic operators for all floating-point and integer numbers. These operators are + (addition), - (subtraction), * (multiplication), **(Exponent), / (division), and % (modulo) +``` +puts 2 * 3 + 1/2 # Basic Arithmetic: +, -, /, * +puts 2**3 # Exponent +puts 2.pow(3) # Same as above +puts 10 % 3 # Modulus Op. : returns remainder of 10/3 +puts 10 / 3.0 # int's and doubles +``` +### Relational Operators +Relational operators these check the relation between the two operands and return a true or false which is mostly used in conditional branching statements. +1. Less than(<) used to check if an operand is less than the other +2. Greater than(>) used to check if an operand is greater than the other +3. Less than or equal to(<=) used to check if an operand is less than or equal to the other +4. Greater than or equal to(>=) used to check if an operand is greater than or equal to the other +5. Comparison(==) is used to check if the two strings are equal +
+ +## Some important functions +1. [.pow() function](https://apidock.com/ruby/v2_5_5/Integer/pow) . This is similar to ** function . Its used to raise a number to a power of n +2. [.abs() function](https://apidock.com/ruby/v2_5_5/Rational/abs). this function returns the absolute value of the number +3. [Math.sqrt()](https://apidock.com/ruby/v2_5_5/Math/sqrt/class) . This function is present in the Math class. This function returns the square root of a number +4. [Math.log()](https://apidock.com/ruby/Math/log/class) . This function returns the log of a number to the base of e +5. [.to_i](https://apidock.com/ruby/String/to_i) This is used to convert any literal into integer literal +6. [.to_f](https://apidock.com/ruby/v2_5_5/String/to_f) This is used to convert any literal into float literal +7. [.to_s](https://apidock.com/ruby/Method/to_s) This is used to convert any literal into string literal + +``` +puts 2.pow(3) # 8 +puts 2**3 # 8 +puts Math.sqrt(144) # 12.0 +puts Math.log(10) # divide by 2.303 for base 10 +puts -5.abs() # 5 +puts 3.14.to_s + 4.to_s # 3.144 +puts 3.to_f # 3.0 +puts "3.0".to_s # 3.0 +puts 100 + "50".to_i # 150 +puts 100 + "50.99".to_f # 150.99 +``` +
+ +## Arrays +Arrays are ordered continuous collection of data. Each element of an array is associated with a unique linear integer number called as index which can be used to access the array elements +Here are some most used array functions +1. This is the standard syntax to access an array element: Arrayname[index] +2. We can remove the last element of an array using the .pop() function +3. Delete the element at a particular index using the delete_at() function +4. Append an element to the array using the push() function +5. Insert an element at a particular index using the insert() function. +(Both push and insert is used to add element to array. The difference is we get to choose where to add the element in insert function) +6. We can sort the array using .sort() function +7. We can use the .include? Function to check if an element exist in the array + +``` +arr = [4, 8, 16, 23, 42.0, "IRIS"] +#idx 0 1 2 3 4 5 +#idx -6 -5 -4 -3 -2 -1 + +arr[0] = 90 +puts arr[0] # 90 +puts arr[-1] # IRIS + +# start at index 2 and give me 3 elements +puts arr[2,3] # 16, 23, 42.0 + +# give me elements from 2 to 5th index (inclusive) +puts arr[2..5] # 16, 23, 42.0, IRIS + + +## Array Methods + +puts arr.length + +# remove an element at the end +arr.pop() + +# remove element at index 2 +arr.delete_at(2) + +# add an element at the end +arr.push(44) + +# insert 1 at index 0 +# insert(index, element) +arr.insert(0,1) + +# sort an array +puts arr.sort + +# check if array includes 4 +puts arr.include? 4 + +``` +
+ +## Strings +1. .chomp - used to remove the blank line that is automatically generated by gets method +2. .strip - used to remove white spaces. +3. .length() - used to get the length of the string +4. .include? - used to check if an element/substring exists in string +5. .chop() - used to remove last character of the string +6. String Interpolation ("#{var}" and "+var+") - used to replace the placeholders with their corresponding values + +``` +greeting = "Hello" +#indexes: 01234 + +puts greeting.length # 5 +puts greeting[0] # H +puts greeting.include? "llo" # true +puts greeting.include? "z" # false +puts greeting[1,3] #e ll +puts greeting.chop() +# puts greeting.strip() + +# String interpolation +name = "John" +puts "Your name is #{name}" +puts "Your name is " + name + + +# User Input + +puts "Enter your name: " +name = gets # automatically creates a new line +puts "Hello #{name}, how are you" + +puts "Enter first num: " +num1 = gets.chomp +=begin +method that removes the blank line that is automatically created by “gets” after the input +=end +puts "enter second num: " +num2 = gets.chomp +puts num1 + num2 +``` +
+ +## Hashes +A Hash is a collection of key-value pairs like this: "employee" = > "salary". It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index. We can access a value of an hash element by using the key associated with the element which is similar to how we access elements through index in arrays. +1. We can create a new hash using .new function +2. We can print all the values of an hash using .values function +3. We can print all the keys of an hash using .keys function +4. We can delete a particular element of an hash by passing the key to the delete() function +5. We can check if a key exists in an hash using .include?() +6. We can merge two different arrays using .merge() function +``` +# New Hash +h1 = {} +h2 = Hash.new + +# New syntax +h1 = {city: "Bangalore", country: "India"} + +# => is called the hash rocket - old syntax +h2 = {:name => "Keerthi", :branch => "ECE", :age => 2} + +# mix and match +hash = {name: "Keerthi", :branch => "ECE", age: 19} + +puts h1 +puts h1.values +puts h1.keys +puts h1.include?(:city) +puts hash.merge(h1) + +# Delete the key value pair referenced by name +# hash.delete(:name) + +# hash[:name] = "Parth" +puts hash[:name] +puts hash[:branch] +``` +
+ +## Naming Conventions +We need to follow certain standards while we name different Arrays/Variables/Hashes/Strings. +- Names are case-sensitive and may begin with letters, _ +- After, may include letters, numbers, _ +- Convention says Start with a lowercase word, then additional words are lowercase separated by an underscore ex. my_first_variable +- The name cannot be a ruby keyword ( BEGIN, END, alias, and, begin, break, case, class, def, module, next, nil, not, or, redo, rescue, retry, return, +elsif, end, false, ensure, for, if, true, undef, unless, do, else, super, then, until, when, while, defined?, self) +
+ +## If Else Statements +The if/else statement executes a block of code if a specified condition is true. If the condition is false, another block of code can be executed +``` +is_student = true +is_smart = true + +if is_student and is_smart + puts "You are a smart student" +elsif is_student and !is_smart + puts "You are not a smart student" +else + puts "You are not a student" +end # Output= You are a smart student +``` +We also have this unless statements which executes a block of code when the condition is false instead! +``` +is_student = false + +unless is_student + puts "You are not a student" +end # Output= You are not a student +``` +
+ +## Loop Statements +A program loop is a series of statements that executes for a specified number of repetitions or until specified conditions are met. +### for...in loop +for loops are used to loop over a collection of elements with a iterating variable. +``` +my_nums = [4, 8, 15, 16, 23, 42] + +for num in my_nums + puts num +end + +for index in 0..5 + puts index +end +``` +### .each do loop +This loop creates an iterator object and loops it throughout the collection specified +``` +my_nums = [4, 8, 15, 16, 23, 42] + +my_nums.each do |num| + puts num +end + +5.times do |idx| # 5.times returns 5 integer starting from 0 + puts idx +end +``` +### While loop +Executes code while conditional is true. A while loop is used when the condition until when the loop should run is unkown. A while loop's conditional is separated from code by the reserved word do. +``` +index = 1 +while index <= 5 + puts index + index += 1 +end +``` +
+ + +## Map Method +The map method takes an enumerable object, (i.e. the object you call it on), and a block.
+Then, for each of the elements in the enumerable, it executes the block, passing it the current element as an argument.
The result of evaluating the block is then used to construct the resulting array.
+Applying map on an array returns a new array where each element is the result of evaluating the block with the element as an argument. +``` +[1, 2, 3].map { |n| n * 2 } # => [2, 4, 6] + +[1, 2, 3].map { |n| n.even? } +# could be written as +[1, 2, 3].map(&:even?) + +my_array = [ + [1, 2, 3, 4], + [5, 6, 7, 8], +] +my_array.map { |row| row.map { |col| col + 1 } } +# => [[2, 3, 4, 5], [6, 7, 8, 9]] +``` +
+ +## Select in ruby +Select() is a Array class method which returns a new array containing all elements of array for which the given block returns a true value.
+You can use the select method in Ruby to filter an array of objects. +For example, you can find all the even numbers in a list using +``` +[1,2,3,4,5,6].select { |n| n.even? } +``` +you can also use select with hashes +``` +stock = { + apples: 10, + oranges: 5, + bananas: 1 +} +stock.select { |k, v| v > 1 } +# {:apples=>10, :oranges=>5} +``` +Where k represents the key & v represent the values
+ +## References +- [https://launchschool.com](https://launchschool.com/books/ruby/read/introduction#briefhistory) +- [https://www.codecademy.com](https://www.codecademy.com/learn/learn-ruby/modules/learn-ruby-introduction-to-ruby-u) +- [https://github.com/FabriDamazio](https://github.com/FabriDamazio/Ruby-Quick-Reference-Guide) +- [https://www.mikedane.com](https://www.mikedane.com/programming-languages/ruby/in-one-video/) +- [https://gist.github.com/mittal-parth](https://gist.github.com/mittal-parth/9feaf30f7919f2b2fef5a16d793ed520) + + diff --git a/week_2/pet.rb b/week_2/pet.rb new file mode 100644 index 00000000..954a713b --- /dev/null +++ b/week_2/pet.rb @@ -0,0 +1,115 @@ +class Pet + ANIMAL_TYPE = { + 1 => 'Arthropod', + 2 => 'Fish', + 3 => 'Amphibia', + 4 => 'Reptiles', + 5 => 'Birds', + 6 => 'Mammals' + } + + # Each animal type requires a diffrent type of food + # The food cost per 1 kg is is stored in the `FOOD_COST_PER_KG` Hash + # where the `key` is the animal id and `value` is the cost + # + # Eg- The food of reptiles(animal_type id = 4) costs 300/kg. + # (FOOD_COST_PER_KG[4] = 300) + FOOD_COST_PER_KG = { + 1 => 100, + 2 => 600, + 3 => 1000, + 4 => 300, + 5 => 450, + 6 => 800 + } + + # Each animal requires its own habitat. + # + # The `HABITATS` hash stores the habitat required by each animal + # The `key` is the habitat and the `value` is the array of + # animal_type ids that live in that habitat. + # + # "habitat" => [animal_type_id] + HABITATS = { + "Aquatic" => [2, 1, 3], + "Terrariums" => [4], + "Cages" => [5, 6] + } + + attr_accessor :name, :animal_type_id, :food_consumed_per_day + + def initialize(name: , animal_type_id: , food_consumed_per_day:) + @name = name + @animal_type_id = animal_type_id + @food_consumed_per_day = food_consumed_per_day + end + + # Return the habitat of the pet + def habitat + raise NotImplementedError # TODO + end + + # Returns the cost of food required to feed the animal + # per day + def food_cost_per_day + return FOOD_COST_PER_KG[animal_type_id] * food_consumed_per_day + end + + # This function takes the number of `days` as the input + # and returns the food required(in kgs) to feed the + # pet for that many number of days + # + # Eg - if the pet requires 0.5 kg of food per day + # (i.e, food_consumed_per_day = 0.5), then + # pet.food_required(5) will return 2.5 as the answer + # + # cat = Pet.new(name: 'cat', animal_type_id: 6, food_consumed_per_day: 0.4) + # cat.food_required(28) = 11.2 (0.4 * 28) + def food_required(days) + raise NotImplementedError # TODO + end + + # This function takes the number of `days` as the input + # and returns the cost incurred to feed the pet for + # that many number of days + # + # cat = Pet.new(name: 'cat', animal_type_id: 6, food_consumed_per_day: 0.4) + # cat.food_cost(28) = 8960 + def food_cost(days) + raise NotImplementedError # TODO + end + + # This function takes an array of pets and the `days` + # as input and returns the cost to feed them all + # for the specified number of `days` + # + # Eg - + # cat = Pet.new(name: 'cat', animal_type_id: 6, food_consumed_per_day: 0.4) + # dog = Pet.new(name: 'dog', animal_type_id: 6, food_consumed_per_day: 0.7) + # fish = Pet.new(name: 'clownfish', animal_type_id: 2, food_consumed_per_day: 0.1) + # snake = Pet.new(name: 'python', animal_type_id: 4, food_consumed_per_day: 0.3) + # Pet.cost_to_feed([cat, dog, fish, snake], 6) will return 6180.0 + def self.cost_to_feed(pets, days) + raise NotImplementedError # TODO + end + + # This function takes an array of pets as input + # and returns a hash with pets name grouped by their animal type + # + # Eg - + # cat = Pet.new(name: 'cat', animal_type_id: 6, food_consumed_per_day: 0.4) + # dog = Pet.new(name: 'dog', animal_type_id: 6, food_consumed_per_day: 0.7) + # fish = Pet.new(name: 'clownfish', animal_type_id: 2, food_consumed_per_day: 0.1) + # snake = Pet.new(name: 'python', animal_type_id: 4, food_consumed_per_day: 0.3) + # Pet.group_by_animal_type([cat, dog, fish, snake]) will return the follwing hash + # { + # 6 => ['cat', 'dog'], + # 2 => ['clownfish'], + # 4 => ['python'] + # } + # + # Note - Order is not important + def self.group_by_animal_type(pets) + raise NotImplementedError # TODO + end +end diff --git a/week_2/pet_test.rb b/week_2/pet_test.rb new file mode 100644 index 00000000..49b01a1c --- /dev/null +++ b/week_2/pet_test.rb @@ -0,0 +1,117 @@ +require_relative 'pet' +require 'minitest/autorun' + +class PetTest < Minitest::Test + PETS = [ + { + pet: Pet.new(name: 'cat', + animal_type_id: 6, + food_consumed_per_day: 0.4 + ), + days: 10, + food_required: 4.0, + food_cost: 3200.0, + habitat: 'Cages' + }, + { + pet: Pet.new(name: 'dog', + animal_type_id: 6, + food_consumed_per_day: 2 + ), + days: 5, + food_required: 10, + food_cost: 8000, + habitat: 'Cages' + }, + { + pet: Pet.new(name: 'clownfish', + animal_type_id: 2, + food_consumed_per_day: 0.01 + ), + days: 100, + food_required: 1, + food_cost: 600, + habitat: 'Aquatic' + }, + { + pet: Pet.new(name: 'python', + animal_type_id: 4, + food_consumed_per_day: 0.1 + ), + days: 0, + food_required: 0, + food_cost: 0, + habitat: 'Terrariums' + } + ] + + def test_animal_habitat + PETS.each do |pet| + assert_equal pet[:habitat], pet[:pet].habitat + end + end + + def test_food_required_for_n_days + PETS.each do |pet| + assert_equal pet[:food_required], pet[:pet].food_required(pet[:days]) + end + end + + def test_food_cost_for_n_days + PETS.each do |pet| + assert_equal pet[:food_cost], pet[:pet].food_cost(pet[:days]) + end + end + + def test_cost_to_feed_pets + expected_cost = [] + + # generate 100 random pets + rand_pets = (1..100).map do + pet = Pet.new(name: "Pet-#{(0...8).map { (65 + rand(25)).chr }.join}", + animal_type_id: rand(1..6), + food_consumed_per_day: 2 + ) + + expected_cost << pet.food_cost_per_day + + pet + end + + [4, 5, 7, 50, 0, 18, 400].each do |days| + assert_equal Pet.cost_to_feed(rand_pets, days), + expected_cost.reduce(0) { |sum, c| sum + c * days }, + "Cost to feed animals do not match" + end + end + + def test_group_by_animal_type + expected = {} + + # generate 100 random pets + rand_pets = (1..100).map do + pet = Pet.new(name: "Pet-#{(0...8).map { (65 + rand(25)).chr }.join}", + animal_type_id: rand(1..6), + food_consumed_per_day: 2 + ) + + if expected[pet.animal_type_id] + expected[pet.animal_type_id] << pet.name + else + expected[pet.animal_type_id] = [pet.name] + end + + pet + end + + answer = Pet.group_by_animal_type(rand_pets) + + assert_equal Set.new(expected.keys), Set.new(answer.keys), + "No extra animal type ids should be present" + + expected.each do |k, pet_names| + assert_equal Set.new(pet_names), Set.new(answer[k]), + "Group of animal_type_id = #{k}, doesn't match" + end + end +end diff --git a/week_2/prime_numbers.rb b/week_2/prime_numbers.rb new file mode 100644 index 00000000..777a8cf5 --- /dev/null +++ b/week_2/prime_numbers.rb @@ -0,0 +1,18 @@ +# A prime number is a whole number greater than 1 +# that cannot be exactly divided by any whole number +# other than itself and 1 +# (e.g. 2, 3, 5, 7, 11). + +# The function below takes a keyword arguments `n` and +# returns an array of prime numbers less than or equal to +# `n`. + +# For example, prime_numbers(n: 20) should return the following: +# [2, 3, 5, 7, 11, 13, 17, 19] + +# If the user gives a invalid input like -4 +# We will raise an `ArgumentError` exception to let the caller know that +# their function arguments were incorrect. +def prime_numbers(n:) + raise NotImplementedError # TODO +end diff --git a/week_2/prime_test.rb b/week_2/prime_test.rb new file mode 100644 index 00000000..29b00ad3 --- /dev/null +++ b/week_2/prime_test.rb @@ -0,0 +1,32 @@ +require_relative 'prime_numbers' +require 'minitest/autorun' + +class PrimeTest < Minitest::Test + PRIMES = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, + 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, + 167, 173, 179, 181, 191, 193, 197, 199 + ] + + def test_prime_numbers + expected = [] + + PRIMES.each do |prime| + expected << prime + + assert_equal expected, prime_numbers(n: prime), + "Wrong asnwer for n: #{prime}" + end + end + + def test_raises_argument_error + assert_raises(ArgumentError) do + prime_numbers(n: -55) + end + + assert_raises(ArgumentError) do + prime_numbers(n: -3) + end + end +end diff --git a/week_2/screenshots/irb.png b/week_2/screenshots/irb.png new file mode 100644 index 0000000000000000000000000000000000000000..7e0186aa734a11140e1bda62be13dd0458ef593e GIT binary patch literal 67049 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 Date: Mon, 26 Dec 2022 19:51:46 +0530 Subject: [PATCH 06/34] Add week 2 and installation guide --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6112c971..198473e6 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,22 @@ ## [Essential Git](/essential_git.md) +## [Installation Guide](/setup) +We have provided three ways of setting up a development environment, +[Local Setup](/setup/local_setup.md), [GitHub codespaces](/setup/github_codespaces.md) +and [Dev Container](/setup/dev_container.md). We recommend you to choose [GitHub codespaces](/setup/github_codespaces.md) +if you face any issues while installing ruby [locally](/setup/local_setup.md). + +> We recommend sticking to the versions mentioned in the Installation Guide and +> run commands exactly as instructed, as all assignments in this Bootcamp are +> tested with these versions. + ## [Week 1 - HTML and CSS](/week_1) In the first week, we will introduce you to basic concepts related to Web Development and Git. -## [Week 2 - Ruby and Installations](https://www.youtube.com/watch?v=GQoQoJmmAuM&list=PLd4eAZyzurEj3WRhTpPAW3hfmM6a6CspK&index=5) +## [Week 2 - Ruby](/week_2) In this week, we'll take a look at Ruby and instructions to get your device ready for creating Ruby on Rails projects. -Head to [setup](/setup) for installation instructions. ## Contact In case of doubts related to the Bootcamp, feel free to reach out to the mentors on the [**#doubts**](https://discord.com/channels/1052463702558908416/1052467811143913552) channel on [Discord](https://discord.gg/HQKpB6XH). From 71c385ac54c909926dccd276876d1b44363f2f55 Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Mon, 26 Dec 2022 20:21:15 +0530 Subject: [PATCH 07/34] Update README.md --- week_2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/week_2/README.md b/week_2/README.md index 8c328915..45a35dbc 100644 --- a/week_2/README.md +++ b/week_2/README.md @@ -18,7 +18,7 @@ you can refer to the following resources - Make sure you are in the correct directory(week_2) while running commands ```bash cd week_2 -ls #imp.rb p_imp.rb pet.rb pet_test.rb .... +ls #pet.rb pet_test.rb .... rvm gemset create week_2 rvm use 3.0.5@week_2 ruby From 4eec818696473905e66401c4a39ab8caf4af85c4 Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Wed, 28 Dec 2022 12:17:34 +0530 Subject: [PATCH 08/34] Update prime_test.rb --- week_2/prime_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/week_2/prime_test.rb b/week_2/prime_test.rb index 29b00ad3..5fc3183e 100644 --- a/week_2/prime_test.rb +++ b/week_2/prime_test.rb @@ -1,5 +1,6 @@ require_relative 'prime_numbers' require 'minitest/autorun' +require 'set' class PrimeTest < Minitest::Test PRIMES = [ From 677067b5f99ddbc77f843889bc006974c04a7da2 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Wed, 28 Dec 2022 12:22:06 +0530 Subject: [PATCH 09/34] Week 2 test require set --- week_2/prime_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/week_2/prime_test.rb b/week_2/prime_test.rb index 29b00ad3..5fc3183e 100644 --- a/week_2/prime_test.rb +++ b/week_2/prime_test.rb @@ -1,5 +1,6 @@ require_relative 'prime_numbers' require 'minitest/autorun' +require 'set' class PrimeTest < Minitest::Test PRIMES = [ From c6cfaa0a07e63780e3895b05acce4747a4fa1543 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Wed, 28 Dec 2022 12:27:11 +0530 Subject: [PATCH 10/34] Week 2 test require set --- week_2/pet_test.rb | 1 + week_2/prime_test.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/week_2/pet_test.rb b/week_2/pet_test.rb index 49b01a1c..3af94c2a 100644 --- a/week_2/pet_test.rb +++ b/week_2/pet_test.rb @@ -1,5 +1,6 @@ require_relative 'pet' require 'minitest/autorun' +require 'set' class PetTest < Minitest::Test PETS = [ diff --git a/week_2/prime_test.rb b/week_2/prime_test.rb index 5fc3183e..29b00ad3 100644 --- a/week_2/prime_test.rb +++ b/week_2/prime_test.rb @@ -1,6 +1,5 @@ require_relative 'prime_numbers' require 'minitest/autorun' -require 'set' class PrimeTest < Minitest::Test PRIMES = [ From b98ad46595bf6bc45c2604bb7eb08c3793a23de1 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Tue, 10 Jan 2023 06:14:26 +0530 Subject: [PATCH 11/34] Add hello_wolrd from previous year --- week_3/README.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 week_3/README.md diff --git a/week_3/README.md b/week_3/README.md new file mode 100644 index 00000000..467602b1 --- /dev/null +++ b/week_3/README.md @@ -0,0 +1,70 @@ +# Week 3 - Getting Started with Rails + +In this week we will get started with Rails. + +We will create a simple rails app with two pages, a Home Page and an About Me page. + +## Steps +- [Set Up Local Workplace](../setup/) + +- Create a new [gemset](../setup/README.md#RVM) and install rails +```bash +cd week_3 +rvm gemset create week_3 +rvm use 3.0.5@week_3 +gem install rails --version 7.0.4 +``` + +- Create a new Rails project `hello_world` in the directory `week_1` +```bash +rails new hello_world --css=bootstrap --skip-git +cd hello_world +rvm use 3.0.5@week_3 +``` + +> The command `rails new` initialises a Rails project. We have passed +> the flag `--skip-git` to avoid initializing Git again as we are +> already within a Git repository. + +- Run the rails server using below command and go to http://localhost:3000/. +```bash +rails server +``` + +You should see the rails logo. + +### Add a controller + +- Generate a new controller `PageController` with actions `root` and + `about_me`: + +```bash +rails generate controller Page root about_me +``` + +> A _controller_ is responsible for making sense of request and producing +> the appropriate output. It acts as a middleman between the Data +> (Model) and Presentation (View). Controllers are stored in +> `app/controllers` directory. + + +> The generator creates the files and fills it with some default code. +> the above command creates a controller +> `PagesController`, creates new view files `root.html.erb` and +> `about_me.html.erb` and modifies the routes file + +- Edit the routes file (`config/routes.rb`) as follow to add new routes: + +```ruby +Rails.application.routes.draw do + get '/', to: 'page#root' + get 'about_me', to: 'page#about_me' +end + +The routes file specifies the URLs that are recognized by the application. + +- Edit the view files `app/views/page/root.html.erb` and `app/views/page/about_me.html.erb`. + +- You should be able to see see your changes at `http://localhost:3000` and + `http://localhost:3000/about_me`. + From ef6ea0ea6373353d5c13145c8f1cabcd992ccbf2 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Tue, 10 Jan 2023 06:58:29 +0530 Subject: [PATCH 12/34] Add hello_wolrd from previous year --- week_3/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/week_3/README.md b/week_3/README.md index 467602b1..2b817a8e 100644 --- a/week_3/README.md +++ b/week_3/README.md @@ -60,6 +60,7 @@ Rails.application.routes.draw do get '/', to: 'page#root' get 'about_me', to: 'page#about_me' end +``` The routes file specifies the URLs that are recognized by the application. From ae786d7a2c7ef5e0470be4707c2d478786221623 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Tue, 10 Jan 2023 16:30:57 +0530 Subject: [PATCH 13/34] Football scaffold --- week_3/football/.ruby-version | 1 + week_3/football/Gemfile | 75 + week_3/football/Gemfile.lock | 234 + week_3/football/Procfile.dev | 3 + week_3/football/README.md | 24 + week_3/football/Rakefile | 6 + week_3/football/app/assets/builds/.keep | 0 .../app/assets/builds/application.css | 18774 ++++++++++++++++ .../football/app/assets/builds/application.js | 3 + .../app/assets/builds/application.js.map | 7 + week_3/football/app/assets/config/manifest.js | 2 + week_3/football/app/assets/images/.keep | 0 .../stylesheets/application.bootstrap.scss | 2 + .../app/channels/application_cable/channel.rb | 4 + .../channels/application_cable/connection.rb | 4 + .../app/controllers/application_controller.rb | 2 + .../football/app/controllers/concerns/.keep | 0 .../football_players_controller.rb | 70 + .../app/helpers/application_helper.rb | 2 + .../app/helpers/football_players_helper.rb | 2 + week_3/football/app/javascript/application.js | 4 + .../app/javascript/controllers/application.js | 9 + .../controllers/hello_controller.js | 7 + .../app/javascript/controllers/index.js | 8 + week_3/football/app/jobs/application_job.rb | 7 + .../app/mailers/application_mailer.rb | 4 + .../football/app/models/application_record.rb | 3 + week_3/football/app/models/concerns/.keep | 0 week_3/football/app/models/football_player.rb | 2 + .../_football_player.html.erb | 87 + .../_football_player.json.jbuilder | 2 + .../app/views/football_players/_form.html.erb | 102 + .../app/views/football_players/edit.html.erb | 10 + .../app/views/football_players/index.html.erb | 14 + .../football_players/index.json.jbuilder | 1 + .../app/views/football_players/new.html.erb | 9 + .../app/views/football_players/show.html.erb | 10 + .../views/football_players/show.json.jbuilder | 1 + .../app/views/layouts/application.html.erb | 16 + .../app/views/layouts/mailer.html.erb | 13 + .../app/views/layouts/mailer.text.erb | 1 + week_3/football/bin/bundle | 114 + week_3/football/bin/dev | 8 + week_3/football/bin/rails | 4 + week_3/football/bin/rake | 4 + week_3/football/bin/setup | 33 + week_3/football/config.ru | 6 + week_3/football/config/application.rb | 22 + week_3/football/config/boot.rb | 4 + week_3/football/config/cable.yml | 10 + week_3/football/config/credentials.yml.enc | 1 + week_3/football/config/database.yml | 25 + week_3/football/config/environment.rb | 5 + .../config/environments/development.rb | 70 + .../config/environments/production.rb | 93 + week_3/football/config/environments/test.rb | 60 + week_3/football/config/initializers/assets.rb | 13 + .../initializers/content_security_policy.rb | 25 + .../initializers/filter_parameter_logging.rb | 8 + .../config/initializers/inflections.rb | 16 + .../config/initializers/permissions_policy.rb | 11 + week_3/football/config/locales/en.yml | 33 + week_3/football/config/master.key | 1 + week_3/football/config/puma.rb | 43 + week_3/football/config/routes.rb | 7 + week_3/football/config/storage.yml | 34 + .../20230110105345_create_football_players.rb | 25 + week_3/football/db/schema.rb | 36 + week_3/football/db/seeds.rb | 7 + week_3/football/lib/assets/.keep | 0 week_3/football/lib/tasks/.keep | 0 week_3/football/package.json | 17 + week_3/football/public/404.html | 67 + week_3/football/public/422.html | 67 + week_3/football/public/500.html | 66 + .../public/apple-touch-icon-precomposed.png | 0 week_3/football/public/apple-touch-icon.png | 0 week_3/football/public/favicon.ico | 0 week_3/football/public/robots.txt | 1 + week_3/football/storage/.keep | 0 .../test/application_system_test_case.rb | 5 + .../application_cable/connection_test.rb | 11 + week_3/football/test/controllers/.keep | 0 .../football_players_controller_test.rb | 48 + week_3/football/test/fixtures/files/.keep | 0 .../test/fixtures/football_players.yml | 1746 ++ week_3/football/test/helpers/.keep | 0 week_3/football/test/integration/.keep | 0 week_3/football/test/mailers/.keep | 0 week_3/football/test/models/.keep | 0 .../test/models/football_player_test.rb | 7 + week_3/football/test/system/.keep | 0 .../test/system/football_players_test.rb | 73 + week_3/football/test/test_helper.rb | 13 + week_3/football/vendor/.keep | 0 week_3/football/yarn.lock | 300 + 96 files changed, 22664 insertions(+) create mode 100644 week_3/football/.ruby-version create mode 100644 week_3/football/Gemfile create mode 100644 week_3/football/Gemfile.lock create mode 100644 week_3/football/Procfile.dev create mode 100644 week_3/football/README.md create mode 100644 week_3/football/Rakefile create mode 100644 week_3/football/app/assets/builds/.keep create mode 100644 week_3/football/app/assets/builds/application.css create mode 100644 week_3/football/app/assets/builds/application.js create mode 100644 week_3/football/app/assets/builds/application.js.map create mode 100644 week_3/football/app/assets/config/manifest.js create mode 100644 week_3/football/app/assets/images/.keep create mode 100644 week_3/football/app/assets/stylesheets/application.bootstrap.scss create mode 100644 week_3/football/app/channels/application_cable/channel.rb create mode 100644 week_3/football/app/channels/application_cable/connection.rb create mode 100644 week_3/football/app/controllers/application_controller.rb create mode 100644 week_3/football/app/controllers/concerns/.keep create mode 100644 week_3/football/app/controllers/football_players_controller.rb create mode 100644 week_3/football/app/helpers/application_helper.rb create mode 100644 week_3/football/app/helpers/football_players_helper.rb create mode 100644 week_3/football/app/javascript/application.js create mode 100644 week_3/football/app/javascript/controllers/application.js create mode 100644 week_3/football/app/javascript/controllers/hello_controller.js create mode 100644 week_3/football/app/javascript/controllers/index.js create mode 100644 week_3/football/app/jobs/application_job.rb create mode 100644 week_3/football/app/mailers/application_mailer.rb create mode 100644 week_3/football/app/models/application_record.rb create mode 100644 week_3/football/app/models/concerns/.keep create mode 100644 week_3/football/app/models/football_player.rb create mode 100644 week_3/football/app/views/football_players/_football_player.html.erb create mode 100644 week_3/football/app/views/football_players/_football_player.json.jbuilder create mode 100644 week_3/football/app/views/football_players/_form.html.erb create mode 100644 week_3/football/app/views/football_players/edit.html.erb create mode 100644 week_3/football/app/views/football_players/index.html.erb create mode 100644 week_3/football/app/views/football_players/index.json.jbuilder create mode 100644 week_3/football/app/views/football_players/new.html.erb create mode 100644 week_3/football/app/views/football_players/show.html.erb create mode 100644 week_3/football/app/views/football_players/show.json.jbuilder create mode 100644 week_3/football/app/views/layouts/application.html.erb create mode 100644 week_3/football/app/views/layouts/mailer.html.erb create mode 100644 week_3/football/app/views/layouts/mailer.text.erb create mode 100755 week_3/football/bin/bundle create mode 100755 week_3/football/bin/dev create mode 100755 week_3/football/bin/rails create mode 100755 week_3/football/bin/rake create mode 100755 week_3/football/bin/setup create mode 100644 week_3/football/config.ru create mode 100644 week_3/football/config/application.rb create mode 100644 week_3/football/config/boot.rb create mode 100644 week_3/football/config/cable.yml create mode 100644 week_3/football/config/credentials.yml.enc create mode 100644 week_3/football/config/database.yml create mode 100644 week_3/football/config/environment.rb create mode 100644 week_3/football/config/environments/development.rb create mode 100644 week_3/football/config/environments/production.rb create mode 100644 week_3/football/config/environments/test.rb create mode 100644 week_3/football/config/initializers/assets.rb create mode 100644 week_3/football/config/initializers/content_security_policy.rb create mode 100644 week_3/football/config/initializers/filter_parameter_logging.rb create mode 100644 week_3/football/config/initializers/inflections.rb create mode 100644 week_3/football/config/initializers/permissions_policy.rb create mode 100644 week_3/football/config/locales/en.yml create mode 100644 week_3/football/config/master.key create mode 100644 week_3/football/config/puma.rb create mode 100644 week_3/football/config/routes.rb create mode 100644 week_3/football/config/storage.yml create mode 100644 week_3/football/db/migrate/20230110105345_create_football_players.rb create mode 100644 week_3/football/db/schema.rb create mode 100644 week_3/football/db/seeds.rb create mode 100644 week_3/football/lib/assets/.keep create mode 100644 week_3/football/lib/tasks/.keep create mode 100644 week_3/football/package.json create mode 100644 week_3/football/public/404.html create mode 100644 week_3/football/public/422.html create mode 100644 week_3/football/public/500.html create mode 100644 week_3/football/public/apple-touch-icon-precomposed.png create mode 100644 week_3/football/public/apple-touch-icon.png create mode 100644 week_3/football/public/favicon.ico create mode 100644 week_3/football/public/robots.txt create mode 100644 week_3/football/storage/.keep create mode 100644 week_3/football/test/application_system_test_case.rb create mode 100644 week_3/football/test/channels/application_cable/connection_test.rb create mode 100644 week_3/football/test/controllers/.keep create mode 100644 week_3/football/test/controllers/football_players_controller_test.rb create mode 100644 week_3/football/test/fixtures/files/.keep create mode 100644 week_3/football/test/fixtures/football_players.yml create mode 100644 week_3/football/test/helpers/.keep create mode 100644 week_3/football/test/integration/.keep create mode 100644 week_3/football/test/mailers/.keep create mode 100644 week_3/football/test/models/.keep create mode 100644 week_3/football/test/models/football_player_test.rb create mode 100644 week_3/football/test/system/.keep create mode 100644 week_3/football/test/system/football_players_test.rb create mode 100644 week_3/football/test/test_helper.rb create mode 100644 week_3/football/vendor/.keep create mode 100644 week_3/football/yarn.lock diff --git a/week_3/football/.ruby-version b/week_3/football/.ruby-version new file mode 100644 index 00000000..316881c9 --- /dev/null +++ b/week_3/football/.ruby-version @@ -0,0 +1 @@ +ruby-3.0.5 diff --git a/week_3/football/Gemfile b/week_3/football/Gemfile new file mode 100644 index 00000000..4cd0ccbf --- /dev/null +++ b/week_3/football/Gemfile @@ -0,0 +1,75 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "3.0.5" + +# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" +gem "rails", "~> 7.0.4" + +# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] +gem "sprockets-rails" + +# Use sqlite3 as the database for Active Record +gem "sqlite3", "~> 1.4" + +# Use the Puma web server [https://github.com/puma/puma] +gem "puma", "~> 5.0" + +# Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails] +gem "jsbundling-rails" + +# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] +gem "turbo-rails" + +# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] +gem "stimulus-rails" + +# Bundle and process CSS [https://github.com/rails/cssbundling-rails] +gem "cssbundling-rails" + +# Build JSON APIs with ease [https://github.com/rails/jbuilder] +gem "jbuilder" + +# Use Redis adapter to run Action Cable in production +# gem "redis", "~> 4.0" + +# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] +# gem "kredis" + +# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] +# gem "bcrypt", "~> 3.1.7" + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] + +# Reduces boot times through caching; required in config/boot.rb +gem "bootsnap", require: false + +# Use Sass to process CSS +# gem "sassc-rails" + +# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] +# gem "image_processing", "~> 1.2" + +group :development, :test do + # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # Use console on exceptions pages [https://github.com/rails/web-console] + gem "web-console" + + # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] + # gem "rack-mini-profiler" + + # Speed up commands on slow machines / big apps [https://github.com/rails/spring] + # gem "spring" +end + +group :test do + # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] + gem "capybara" + gem "selenium-webdriver" + gem "webdrivers" +end diff --git a/week_3/football/Gemfile.lock b/week_3/football/Gemfile.lock new file mode 100644 index 00000000..8fe6e76c --- /dev/null +++ b/week_3/football/Gemfile.lock @@ -0,0 +1,234 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.4) + actionpack (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activesupport (= 7.0.4) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.4) + actionview (= 7.0.4) + activesupport (= 7.0.4) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.4) + actionpack (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.4) + activesupport (= 7.0.4) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.3.6) + activemodel (7.0.4) + activesupport (= 7.0.4) + activerecord (7.0.4) + activemodel (= 7.0.4) + activesupport (= 7.0.4) + activestorage (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activesupport (= 7.0.4) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + bindex (0.8.1) + bootsnap (1.15.0) + msgpack (~> 1.2) + builder (3.2.4) + capybara (3.38.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + concurrent-ruby (1.1.10) + crass (1.0.6) + cssbundling-rails (1.1.2) + railties (>= 6.0.0) + date (3.3.3) + debug (1.7.1) + irb (>= 1.5.0) + reline (>= 0.3.1) + erubi (1.12.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + io-console (0.6.0) + irb (1.6.2) + reline (>= 0.3.0) + jbuilder (2.11.5) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + jsbundling-rails (1.1.1) + railties (>= 6.0.0) + loofah (2.19.1) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.8.0) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) + matrix (0.4.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.17.0) + msgpack (1.6.0) + net-imap (0.3.4) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.1) + timeout + net-smtp (0.3.3) + net-protocol + nio4r (2.5.8) + nokogiri (1.13.10-x86_64-linux) + racc (~> 1.4) + public_suffix (5.0.1) + puma (5.6.5) + nio4r (~> 2.0) + racc (1.6.2) + rack (2.2.5) + rack-test (2.0.2) + rack (>= 1.3) + rails (7.0.4) + actioncable (= 7.0.4) + actionmailbox (= 7.0.4) + actionmailer (= 7.0.4) + actionpack (= 7.0.4) + actiontext (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activemodel (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + bundler (>= 1.15.0) + railties (= 7.0.4) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.4) + loofah (~> 2.19, >= 2.19.1) + railties (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + regexp_parser (2.6.1) + reline (0.3.2) + io-console (~> 0.5) + rexml (3.2.5) + rubyzip (2.3.2) + selenium-webdriver (4.7.1) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + sprockets (4.2.0) + concurrent-ruby (~> 1.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + sqlite3 (1.5.4-x86_64-linux) + stimulus-rails (1.2.1) + railties (>= 6.0.0) + thor (1.2.1) + timeout (0.3.1) + turbo-rails (1.3.2) + actionpack (>= 6.0.0) + activejob (>= 6.0.0) + railties (>= 6.0.0) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + webdrivers (5.2.0) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0) + websocket (1.2.9) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.6.6) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + capybara + cssbundling-rails + debug + jbuilder + jsbundling-rails + puma (~> 5.0) + rails (~> 7.0.4) + selenium-webdriver + sprockets-rails + sqlite3 (~> 1.4) + stimulus-rails + turbo-rails + tzinfo-data + web-console + webdrivers + +RUBY VERSION + ruby 3.0.5p211 + +BUNDLED WITH + 2.2.33 diff --git a/week_3/football/Procfile.dev b/week_3/football/Procfile.dev new file mode 100644 index 00000000..db85284f --- /dev/null +++ b/week_3/football/Procfile.dev @@ -0,0 +1,3 @@ +web: unset PORT && bin/rails server +js: yarn build --watch +css: yarn build:css --watch diff --git a/week_3/football/README.md b/week_3/football/README.md new file mode 100644 index 00000000..7db80e4c --- /dev/null +++ b/week_3/football/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/week_3/football/Rakefile b/week_3/football/Rakefile new file mode 100644 index 00000000..9a5ea738 --- /dev/null +++ b/week_3/football/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative "config/application" + +Rails.application.load_tasks diff --git a/week_3/football/app/assets/builds/.keep b/week_3/football/app/assets/builds/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/app/assets/builds/application.css b/week_3/football/app/assets/builds/application.css new file mode 100644 index 00000000..f48b5b62 --- /dev/null +++ b/week_3/football/app/assets/builds/application.css @@ -0,0 +1,18774 @@ +@charset "UTF-8"; +/*! + * Bootstrap v5.2.3 (https://getbootstrap.com/) + * Copyright 2011-2022 The Bootstrap Authors + * Copyright 2011-2022 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +:root { + --bs-blue: #0d6efd; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #d63384; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #198754; + --bs-teal: #20c997; + --bs-cyan: #0dcaf0; + --bs-black: #000; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #0d6efd; + --bs-secondary: #6c757d; + --bs-success: #198754; + --bs-info: #0dcaf0; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 13, 110, 253; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 25, 135, 84; + --bs-info-rgb: 13, 202, 240; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-body-color-rgb: 33, 37, 41; + --bs-body-bg-rgb: 255, 255, 255; + --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-bg: #fff; + --bs-border-width: 1px; + --bs-border-style: solid; + --bs-border-color: #dee2e6; + --bs-border-color-translucent: rgba(0, 0, 0, 0.175); + --bs-border-radius: 0.375rem; + --bs-border-radius-sm: 0.25rem; + --bs-border-radius-lg: 0.5rem; + --bs-border-radius-xl: 1rem; + --bs-border-radius-2xl: 2rem; + --bs-border-radius-pill: 50rem; + --bs-link-color: #0d6efd; + --bs-link-hover-color: #0a58ca; + --bs-code-color: #d63384; + --bs-highlight-bg: #fff3cd; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + border: 0; + border-top: 1px solid; + opacity: 0.25; +} + +h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; +} + +h1, .h1 { + font-size: calc(1.375rem + 1.5vw); +} +@media (min-width: 1200px) { + h1, .h1 { + font-size: 2.5rem; + } +} + +h2, .h2 { + font-size: calc(1.325rem + 0.9vw); +} +@media (min-width: 1200px) { + h2, .h2 { + font-size: 2rem; + } +} + +h3, .h3 { + font-size: calc(1.3rem + 0.6vw); +} +@media (min-width: 1200px) { + h3, .h3 { + font-size: 1.75rem; + } +} + +h4, .h4 { + font-size: calc(1.275rem + 0.3vw); +} +@media (min-width: 1200px) { + h4, .h4 { + font-size: 1.5rem; + } +} + +h5, .h5 { + font-size: 1.25rem; +} + +h6, .h6 { + font-size: 1rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title] { + text-decoration: underline dotted; + cursor: help; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: 0.5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small, .small { + font-size: 0.875em; +} + +mark, .mark { + padding: 0.1875em; + background-color: var(--bs-highlight-bg); +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +a { + color: var(--bs-link-color); + text-decoration: underline; +} +a:hover { + color: var(--bs-link-hover-color); +} + +a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 0.875em; +} +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 0.875em; + color: var(--bs-code-color); + word-wrap: break-word; +} +a > code { + color: inherit; +} + +kbd { + padding: 0.1875rem 0.375rem; + font-size: 0.875em; + color: var(--bs-body-bg); + background-color: var(--bs-body-color); + border-radius: 0.25rem; +} +kbd kbd { + padding: 0; + font-size: 1em; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: #6c757d; + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +button { + border-radius: 0; +} + +button:focus:not(:focus-visible) { + outline: 0; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +select { + text-transform: none; +} + +[role=button] { + cursor: pointer; +} + +select { + word-wrap: normal; +} +select:disabled { + opacity: 1; +} + +[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { + display: none !important; +} + +button, +[type=button], +[type=reset], +[type=submit] { + -webkit-appearance: button; +} +button:not(:disabled), +[type=button]:not(:disabled), +[type=reset]:not(:disabled), +[type=submit]:not(:disabled) { + cursor: pointer; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: calc(1.275rem + 0.3vw); + line-height: inherit; +} +@media (min-width: 1200px) { + legend { + font-size: 1.5rem; + } +} +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type=search] { + outline-offset: -2px; + -webkit-appearance: textfield; +} + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::file-selector-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: calc(1.625rem + 4.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-1 { + font-size: 5rem; + } +} + +.display-2 { + font-size: calc(1.575rem + 3.9vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-2 { + font-size: 4.5rem; + } +} + +.display-3 { + font-size: calc(1.525rem + 3.3vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-3 { + font-size: 4rem; + } +} + +.display-4 { + font-size: calc(1.475rem + 2.7vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-4 { + font-size: 3.5rem; + } +} + +.display-5 { + font-size: calc(1.425rem + 2.1vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-5 { + font-size: 3rem; + } +} + +.display-6 { + font-size: calc(1.375rem + 1.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-6 { + font-size: 2.5rem; + } +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 0.875em; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} +.blockquote > :last-child { + margin-bottom: 0; +} + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: 0.875em; + color: #6c757d; +} +.blockquote-footer::before { + content: "— "; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #fff; + border: 1px solid var(--bs-border-color); + border-radius: 0.375rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 0.875em; + color: #6c757d; +} + +.container, +.container-fluid, +.container-xxl, +.container-xl, +.container-lg, +.container-md, +.container-sm { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container-sm, .container { + max-width: 540px; + } +} +@media (min-width: 768px) { + .container-md, .container-sm, .container { + max-width: 720px; + } +} +@media (min-width: 992px) { + .container-lg, .container-md, .container-sm, .container { + max-width: 960px; + } +} +@media (min-width: 1200px) { + .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1140px; + } +} +@media (min-width: 1400px) { + .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1320px; + } +} +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); +} +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333333%; +} + +.offset-2 { + margin-left: 16.66666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333333%; +} + +.offset-5 { + margin-left: 41.66666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333333%; +} + +.offset-8 { + margin-left: 66.66666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333333%; +} + +.offset-11 { + margin-left: 91.66666667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333333%; + } + .offset-sm-2 { + margin-left: 16.66666667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333333%; + } + .offset-sm-5 { + margin-left: 41.66666667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333333%; + } + .offset-sm-8 { + margin-left: 66.66666667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333333%; + } + .offset-sm-11 { + margin-left: 91.66666667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 3rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333333%; + } + .offset-md-2 { + margin-left: 16.66666667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333333%; + } + .offset-md-5 { + margin-left: 41.66666667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333333%; + } + .offset-md-8 { + margin-left: 66.66666667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333333%; + } + .offset-md-11 { + margin-left: 91.66666667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 3rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333333%; + } + .offset-lg-2 { + margin-left: 16.66666667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333333%; + } + .offset-lg-5 { + margin-left: 41.66666667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333333%; + } + .offset-lg-8 { + margin-left: 66.66666667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333333%; + } + .offset-lg-11 { + margin-left: 91.66666667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 3rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333333%; + } + .offset-xl-2 { + margin-left: 16.66666667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333333%; + } + .offset-xl-5 { + margin-left: 41.66666667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333333%; + } + .offset-xl-8 { + margin-left: 66.66666667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333333%; + } + .offset-xl-11 { + margin-left: 91.66666667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 3rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1400px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-left: 0; + } + .offset-xxl-1 { + margin-left: 8.33333333%; + } + .offset-xxl-2 { + margin-left: 16.66666667%; + } + .offset-xxl-3 { + margin-left: 25%; + } + .offset-xxl-4 { + margin-left: 33.33333333%; + } + .offset-xxl-5 { + margin-left: 41.66666667%; + } + .offset-xxl-6 { + margin-left: 50%; + } + .offset-xxl-7 { + margin-left: 58.33333333%; + } + .offset-xxl-8 { + margin-left: 66.66666667%; + } + .offset-xxl-9 { + margin-left: 75%; + } + .offset-xxl-10 { + margin-left: 83.33333333%; + } + .offset-xxl-11 { + margin-left: 91.66666667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 3rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 3rem; + } +} +.table { + --bs-table-color: var(--bs-body-color); + --bs-table-bg: transparent; + --bs-table-border-color: var(--bs-border-color); + --bs-table-accent-bg: transparent; + --bs-table-striped-color: var(--bs-body-color); + --bs-table-striped-bg: rgba(0, 0, 0, 0.05); + --bs-table-active-color: var(--bs-body-color); + --bs-table-active-bg: rgba(0, 0, 0, 0.1); + --bs-table-hover-color: var(--bs-body-color); + --bs-table-hover-bg: rgba(0, 0, 0, 0.075); + width: 100%; + margin-bottom: 1rem; + color: var(--bs-table-color); + vertical-align: top; + border-color: var(--bs-table-border-color); +} +.table > :not(caption) > * > * { + padding: 0.5rem 0.5rem; + background-color: var(--bs-table-bg); + border-bottom-width: 1px; + box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg); +} +.table > tbody { + vertical-align: inherit; +} +.table > thead { + vertical-align: bottom; +} + +.table-group-divider { + border-top: 2px solid currentcolor; +} + +.caption-top { + caption-side: top; +} + +.table-sm > :not(caption) > * > * { + padding: 0.25rem 0.25rem; +} + +.table-bordered > :not(caption) > * { + border-width: 1px 0; +} +.table-bordered > :not(caption) > * > * { + border-width: 0 1px; +} + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0; +} +.table-borderless > :not(:first-child) { + border-top-width: 0; +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color); +} + +.table-striped-columns > :not(caption) > tr > :nth-child(even) { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color); +} + +.table-active { + --bs-table-accent-bg: var(--bs-table-active-bg); + color: var(--bs-table-active-color); +} + +.table-hover > tbody > tr:hover > * { + --bs-table-accent-bg: var(--bs-table-hover-bg); + color: var(--bs-table-hover-color); +} + +.table-primary { + --bs-table-color: #000; + --bs-table-bg: #cfe2ff; + --bs-table-border-color: #bacbe6; + --bs-table-striped-bg: #c5d7f2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bacbe6; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfd1ec; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-secondary { + --bs-table-color: #000; + --bs-table-bg: #e2e3e5; + --bs-table-border-color: #cbccce; + --bs-table-striped-bg: #d7d8da; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbccce; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d1d2d4; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-success { + --bs-table-color: #000; + --bs-table-bg: #d1e7dd; + --bs-table-border-color: #bcd0c7; + --bs-table-striped-bg: #c7dbd2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bcd0c7; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c1d6cc; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-info { + --bs-table-color: #000; + --bs-table-bg: #cff4fc; + --bs-table-border-color: #badce3; + --bs-table-striped-bg: #c5e8ef; + --bs-table-striped-color: #000; + --bs-table-active-bg: #badce3; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfe2e9; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-warning { + --bs-table-color: #000; + --bs-table-bg: #fff3cd; + --bs-table-border-color: #e6dbb9; + --bs-table-striped-bg: #f2e7c3; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e6dbb9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #ece1be; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-danger { + --bs-table-color: #000; + --bs-table-bg: #f8d7da; + --bs-table-border-color: #dfc2c4; + --bs-table-striped-bg: #eccccf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfc2c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5c7ca; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-light { + --bs-table-color: #000; + --bs-table-bg: #f8f9fa; + --bs-table-border-color: #dfe0e1; + --bs-table-striped-bg: #ecedee; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfe0e1; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5e6e7; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-dark { + --bs-table-color: #fff; + --bs-table-bg: #212529; + --bs-table-border-color: #373b3e; + --bs-table-striped-bg: #2c3034; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373b3e; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323539; + --bs-table-hover-color: #fff; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 767.98px) { + .table-responsive-md { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 991.98px) { + .table-responsive-lg { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 1199.98px) { + .table-responsive-xl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 1399.98px) { + .table-responsive-xxl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +.form-label { + margin-bottom: 0.5rem; +} + +.col-form-label { + padding-top: calc(0.375rem + 1px); + padding-bottom: calc(0.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.5rem + 1px); + padding-bottom: calc(0.5rem + 1px); + font-size: 1.25rem; +} + +.col-form-label-sm { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + font-size: 0.875rem; +} + +.form-text { + margin-top: 0.25rem; + font-size: 0.875em; + color: #6c757d; +} + +.form-control { + display: block; + width: 100%; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + appearance: none; + border-radius: 0.375rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} +.form-control[type=file] { + overflow: hidden; +} +.form-control[type=file]:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control:focus { + color: #212529; + background-color: #fff; + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-control::-webkit-date-and-time-value { + height: 1.5em; +} +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} +.form-control:disabled { + background-color: #e9ecef; + opacity: 1; +} +.form-control::file-selector-button { + padding: 0.375rem 0.75rem; + margin: -0.375rem -0.75rem; + margin-inline-end: 0.75rem; + color: #212529; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control::file-selector-button { + transition: none; + } +} +.form-control:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: #dde0e3; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.375rem 0; + margin-bottom: 0; + line-height: 1.5; + color: #212529; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} +.form-control-plaintext:focus { + outline: 0; +} +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + min-height: calc(1.5em + 0.5rem + 2px); + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + border-radius: 0.25rem; +} +.form-control-sm::file-selector-button { + padding: 0.25rem 0.5rem; + margin: -0.25rem -0.5rem; + margin-inline-end: 0.5rem; +} + +.form-control-lg { + min-height: calc(1.5em + 1rem + 2px); + padding: 0.5rem 1rem; + font-size: 1.25rem; + border-radius: 0.5rem; +} +.form-control-lg::file-selector-button { + padding: 0.5rem 1rem; + margin: -0.5rem -1rem; + margin-inline-end: 1rem; +} + +textarea.form-control { + min-height: calc(1.5em + 0.75rem + 2px); +} +textarea.form-control-sm { + min-height: calc(1.5em + 0.5rem + 2px); +} +textarea.form-control-lg { + min-height: calc(1.5em + 1rem + 2px); +} + +.form-control-color { + width: 3rem; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem; +} +.form-control-color:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control-color::-moz-color-swatch { + border: 0 !important; + border-radius: 0.375rem; +} +.form-control-color::-webkit-color-swatch { + border-radius: 0.375rem; +} +.form-control-color.form-control-sm { + height: calc(1.5em + 0.5rem + 2px); +} +.form-control-color.form-control-lg { + height: calc(1.5em + 1rem + 2px); +} + +.form-select { + display: block; + width: 100%; + padding: 0.375rem 2.25rem 0.375rem 0.75rem; + -moz-padding-start: calc(0.75rem - 3px); + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + background-color: #fff; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 0.75rem center; + background-size: 16px 12px; + border: 1px solid #ced4da; + border-radius: 0.375rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} +@media (prefers-reduced-motion: reduce) { + .form-select { + transition: none; + } +} +.form-select:focus { + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-select[multiple], .form-select[size]:not([size="1"]) { + padding-right: 0.75rem; + background-image: none; +} +.form-select:disabled { + background-color: #e9ecef; +} +.form-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #212529; +} + +.form-select-sm { + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; + border-radius: 0.25rem; +} + +.form-select-lg { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; + border-radius: 0.5rem; +} + +.form-check { + display: block; + min-height: 1.5rem; + padding-left: 1.5em; + margin-bottom: 0.125rem; +} +.form-check .form-check-input { + float: left; + margin-left: -1.5em; +} + +.form-check-reverse { + padding-right: 1.5em; + padding-left: 0; + text-align: right; +} +.form-check-reverse .form-check-input { + float: right; + margin-right: -1.5em; + margin-left: 0; +} + +.form-check-input { + width: 1em; + height: 1em; + margin-top: 0.25em; + vertical-align: top; + background-color: #fff; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: 1px solid rgba(0, 0, 0, 0.25); + appearance: none; + print-color-adjust: exact; +} +.form-check-input[type=checkbox] { + border-radius: 0.25em; +} +.form-check-input[type=radio] { + border-radius: 50%; +} +.form-check-input:active { + filter: brightness(90%); +} +.form-check-input:focus { + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-check-input:checked { + background-color: #0d6efd; + border-color: #0d6efd; +} +.form-check-input:checked[type=checkbox] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); +} +.form-check-input:checked[type=radio] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); +} +.form-check-input[type=checkbox]:indeterminate { + background-color: #0d6efd; + border-color: #0d6efd; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); +} +.form-check-input:disabled { + pointer-events: none; + filter: none; + opacity: 0.5; +} +.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { + cursor: default; + opacity: 0.5; +} + +.form-switch { + padding-left: 2.5em; +} +.form-switch .form-check-input { + width: 2em; + margin-left: -2.5em; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); + background-position: left center; + border-radius: 2em; + transition: background-position 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-switch .form-check-input { + transition: none; + } +} +.form-switch .form-check-input:focus { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e"); +} +.form-switch .form-check-input:checked { + background-position: right center; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} +.form-switch.form-check-reverse { + padding-right: 2.5em; + padding-left: 0; +} +.form-switch.form-check-reverse .form-check-input { + margin-right: -2.5em; + margin-left: 0; +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.btn-check[disabled] + .btn, .btn-check:disabled + .btn { + pointer-events: none; + filter: none; + opacity: 0.65; +} + +.form-range { + width: 100%; + height: 1.5rem; + padding: 0; + background-color: transparent; + appearance: none; +} +.form-range:focus { + outline: 0; +} +.form-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-range::-moz-focus-outer { + border: 0; +} +.form-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #0d6efd; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} +@media (prefers-reduced-motion: reduce) { + .form-range::-webkit-slider-thumb { + transition: none; + } +} +.form-range::-webkit-slider-thumb:active { + background-color: #b6d4fe; +} +.form-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #0d6efd; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} +@media (prefers-reduced-motion: reduce) { + .form-range::-moz-range-thumb { + transition: none; + } +} +.form-range::-moz-range-thumb:active { + background-color: #b6d4fe; +} +.form-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} +.form-range:disabled { + pointer-events: none; +} +.form-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} +.form-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.form-floating { + position: relative; +} +.form-floating > .form-control, +.form-floating > .form-control-plaintext, +.form-floating > .form-select { + height: calc(3.5rem + 2px); + line-height: 1.25; +} +.form-floating > label { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 1rem 0.75rem; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + border: 1px solid transparent; + transform-origin: 0 0; + transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-floating > label { + transition: none; + } +} +.form-floating > .form-control, +.form-floating > .form-control-plaintext { + padding: 1rem 0.75rem; +} +.form-floating > .form-control::placeholder, +.form-floating > .form-control-plaintext::placeholder { + color: transparent; +} +.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown), +.form-floating > .form-control-plaintext:focus, +.form-floating > .form-control-plaintext:not(:placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:-webkit-autofill, +.form-floating > .form-control-plaintext:-webkit-autofill { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-select { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:focus ~ label, +.form-floating > .form-control:not(:placeholder-shown) ~ label, +.form-floating > .form-control-plaintext ~ label, +.form-floating > .form-select ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control:-webkit-autofill ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control-plaintext ~ label { + border-width: 1px 0; +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} +.input-group > .form-control, +.input-group > .form-select, +.input-group > .form-floating { + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0; +} +.input-group > .form-control:focus, +.input-group > .form-select:focus, +.input-group > .form-floating:focus-within { + z-index: 5; +} +.input-group .btn { + position: relative; + z-index: 2; +} +.input-group .btn:focus { + z-index: 5; +} + +.input-group-text { + display: flex; + align-items: center; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.375rem; +} + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + border-radius: 0.5rem; +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + border-radius: 0.25rem; +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: 3rem; +} + +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3), +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4), +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group > .form-floating:not(:first-child) > .form-control, +.input-group > .form-floating:not(:first-child) > .form-select { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: #198754; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: rgba(25, 135, 84, 0.9); + border-radius: 0.375rem; +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: #198754; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: #198754; + box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); +} + +.was-validated textarea.form-control:valid, textarea.form-control.is-valid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .form-select:valid, .form-select.is-valid { + border-color: #198754; +} +.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"] { + padding-right: 4.125rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-position: right 0.75rem center, center right 2.25rem; + background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-select:valid:focus, .form-select.is-valid:focus { + border-color: #198754; + box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); +} + +.was-validated .form-control-color:valid, .form-control-color.is-valid { + width: calc(3rem + calc(1.5em + 0.75rem)); +} + +.was-validated .form-check-input:valid, .form-check-input.is-valid { + border-color: #198754; +} +.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { + background-color: #198754; +} +.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { + box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); +} +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #198754; +} + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid, +.was-validated .input-group > .form-select:not(:focus):valid, +.input-group > .form-select:not(:focus).is-valid, +.was-validated .input-group > .form-floating:not(:focus-within):valid, +.input-group > .form-floating:not(:focus-within).is-valid { + z-index: 3; +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.375rem; +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: #dc3545; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); +} + +.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .form-select:invalid, .form-select.is-invalid { + border-color: #dc3545; +} +.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"] { + padding-right: 4.125rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-position: right 0.75rem center, center right 2.25rem; + background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-control-color:invalid, .form-control-color.is-invalid { + width: calc(3rem + calc(1.5em + 0.75rem)); +} + +.was-validated .form-check-input:invalid, .form-check-input.is-invalid { + border-color: #dc3545; +} +.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { + background-color: #dc3545; +} +.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { + box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); +} +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid, +.was-validated .input-group > .form-select:not(:focus):invalid, +.input-group > .form-select:not(:focus).is-invalid, +.was-validated .input-group > .form-floating:not(:focus-within):invalid, +.input-group > .form-floating:not(:focus-within).is-invalid { + z-index: 4; +} + +.btn { + --bs-btn-padding-x: 0.75rem; + --bs-btn-padding-y: 0.375rem; + --bs-btn-font-family: ; + --bs-btn-font-size: 1rem; + --bs-btn-font-weight: 400; + --bs-btn-line-height: 1.5; + --bs-btn-color: #212529; + --bs-btn-bg: transparent; + --bs-btn-border-width: 1px; + --bs-btn-border-color: transparent; + --bs-btn-border-radius: 0.375rem; + --bs-btn-hover-border-color: transparent; + --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); + --bs-btn-disabled-opacity: 0.65; + --bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5); + display: inline-block; + padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x); + font-family: var(--bs-btn-font-family); + font-size: var(--bs-btn-font-size); + font-weight: var(--bs-btn-font-weight); + line-height: var(--bs-btn-line-height); + color: var(--bs-btn-color); + text-align: center; + text-decoration: none; + vertical-align: middle; + cursor: pointer; + user-select: none; + border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); + border-radius: var(--bs-btn-border-radius); + background-color: var(--bs-btn-bg); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} +.btn:hover { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); +} +.btn-check + .btn:hover { + color: var(--bs-btn-color); + background-color: var(--bs-btn-bg); + border-color: var(--bs-btn-border-color); +} +.btn:focus-visible { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:focus-visible + .btn { + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, .btn.active, .btn.show { + color: var(--bs-btn-active-color); + background-color: var(--bs-btn-active-bg); + border-color: var(--bs-btn-active-border-color); +} +.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible { + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn:disabled, .btn.disabled, fieldset:disabled .btn { + color: var(--bs-btn-disabled-color); + pointer-events: none; + background-color: var(--bs-btn-disabled-bg); + border-color: var(--bs-btn-disabled-border-color); + opacity: var(--bs-btn-disabled-opacity); +} + +.btn-primary { + --bs-btn-color: #fff; + --bs-btn-bg: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0b5ed7; + --bs-btn-hover-border-color: #0a58ca; + --bs-btn-focus-shadow-rgb: 49, 132, 253; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0a58ca; + --bs-btn-active-border-color: #0a53be; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #0d6efd; + --bs-btn-disabled-border-color: #0d6efd; +} + +.btn-secondary { + --bs-btn-color: #fff; + --bs-btn-bg: #6c757d; + --bs-btn-border-color: #6c757d; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #5c636a; + --bs-btn-hover-border-color: #565e64; + --bs-btn-focus-shadow-rgb: 130, 138, 145; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #565e64; + --bs-btn-active-border-color: #51585e; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #6c757d; + --bs-btn-disabled-border-color: #6c757d; +} + +.btn-success { + --bs-btn-color: #fff; + --bs-btn-bg: #198754; + --bs-btn-border-color: #198754; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #157347; + --bs-btn-hover-border-color: #146c43; + --bs-btn-focus-shadow-rgb: 60, 153, 110; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #146c43; + --bs-btn-active-border-color: #13653f; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #198754; + --bs-btn-disabled-border-color: #198754; +} + +.btn-info { + --bs-btn-color: #000; + --bs-btn-bg: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #31d2f2; + --bs-btn-hover-border-color: #25cff2; + --bs-btn-focus-shadow-rgb: 11, 172, 204; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #3dd5f3; + --bs-btn-active-border-color: #25cff2; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #0dcaf0; + --bs-btn-disabled-border-color: #0dcaf0; +} + +.btn-warning { + --bs-btn-color: #000; + --bs-btn-bg: #ffc107; + --bs-btn-border-color: #ffc107; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #ffca2c; + --bs-btn-hover-border-color: #ffc720; + --bs-btn-focus-shadow-rgb: 217, 164, 6; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #ffcd39; + --bs-btn-active-border-color: #ffc720; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #ffc107; + --bs-btn-disabled-border-color: #ffc107; +} + +.btn-danger { + --bs-btn-color: #fff; + --bs-btn-bg: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #bb2d3b; + --bs-btn-hover-border-color: #b02a37; + --bs-btn-focus-shadow-rgb: 225, 83, 97; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #b02a37; + --bs-btn-active-border-color: #a52834; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #dc3545; + --bs-btn-disabled-border-color: #dc3545; +} + +.btn-light { + --bs-btn-color: #000; + --bs-btn-bg: #f8f9fa; + --bs-btn-border-color: #f8f9fa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #d3d4d5; + --bs-btn-hover-border-color: #c6c7c8; + --bs-btn-focus-shadow-rgb: 211, 212, 213; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #c6c7c8; + --bs-btn-active-border-color: #babbbc; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f8f9fa; + --bs-btn-disabled-border-color: #f8f9fa; +} + +.btn-dark { + --bs-btn-color: #fff; + --bs-btn-bg: #212529; + --bs-btn-border-color: #212529; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #424649; + --bs-btn-hover-border-color: #373b3e; + --bs-btn-focus-shadow-rgb: 66, 70, 73; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #4d5154; + --bs-btn-active-border-color: #373b3e; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #212529; + --bs-btn-disabled-border-color: #212529; +} + +.btn-outline-primary { + --bs-btn-color: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0d6efd; + --bs-btn-hover-border-color: #0d6efd; + --bs-btn-focus-shadow-rgb: 13, 110, 253; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0d6efd; + --bs-btn-active-border-color: #0d6efd; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0d6efd; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0d6efd; + --bs-gradient: none; +} + +.btn-outline-secondary { + --bs-btn-color: #6c757d; + --bs-btn-border-color: #6c757d; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #6c757d; + --bs-btn-hover-border-color: #6c757d; + --bs-btn-focus-shadow-rgb: 108, 117, 125; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #6c757d; + --bs-btn-active-border-color: #6c757d; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #6c757d; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #6c757d; + --bs-gradient: none; +} + +.btn-outline-success { + --bs-btn-color: #198754; + --bs-btn-border-color: #198754; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #198754; + --bs-btn-hover-border-color: #198754; + --bs-btn-focus-shadow-rgb: 25, 135, 84; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #198754; + --bs-btn-active-border-color: #198754; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #198754; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #198754; + --bs-gradient: none; +} + +.btn-outline-info { + --bs-btn-color: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #0dcaf0; + --bs-btn-hover-border-color: #0dcaf0; + --bs-btn-focus-shadow-rgb: 13, 202, 240; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #0dcaf0; + --bs-btn-active-border-color: #0dcaf0; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0dcaf0; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0dcaf0; + --bs-gradient: none; +} + +.btn-outline-warning { + --bs-btn-color: #ffc107; + --bs-btn-border-color: #ffc107; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #ffc107; + --bs-btn-hover-border-color: #ffc107; + --bs-btn-focus-shadow-rgb: 255, 193, 7; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #ffc107; + --bs-btn-active-border-color: #ffc107; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #ffc107; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #ffc107; + --bs-gradient: none; +} + +.btn-outline-danger { + --bs-btn-color: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #dc3545; + --bs-btn-hover-border-color: #dc3545; + --bs-btn-focus-shadow-rgb: 220, 53, 69; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #dc3545; + --bs-btn-active-border-color: #dc3545; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #dc3545; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dc3545; + --bs-gradient: none; +} + +.btn-outline-light { + --bs-btn-color: #f8f9fa; + --bs-btn-border-color: #f8f9fa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f8f9fa; + --bs-btn-hover-border-color: #f8f9fa; + --bs-btn-focus-shadow-rgb: 248, 249, 250; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f8f9fa; + --bs-btn-active-border-color: #f8f9fa; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f8f9fa; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f8f9fa; + --bs-gradient: none; +} + +.btn-outline-dark { + --bs-btn-color: #212529; + --bs-btn-border-color: #212529; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #212529; + --bs-btn-hover-border-color: #212529; + --bs-btn-focus-shadow-rgb: 33, 37, 41; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #212529; + --bs-btn-active-border-color: #212529; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #212529; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #212529; + --bs-gradient: none; +} + +.btn-link { + --bs-btn-font-weight: 400; + --bs-btn-color: var(--bs-link-color); + --bs-btn-bg: transparent; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: var(--bs-link-hover-color); + --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: var(--bs-link-hover-color); + --bs-btn-active-border-color: transparent; + --bs-btn-disabled-color: #6c757d; + --bs-btn-disabled-border-color: transparent; + --bs-btn-box-shadow: none; + --bs-btn-focus-shadow-rgb: 49, 132, 253; + text-decoration: underline; +} +.btn-link:focus-visible { + color: var(--bs-btn-color); +} +.btn-link:hover { + color: var(--bs-btn-hover-color); +} + +.btn-lg, .btn-group-lg > .btn { + --bs-btn-padding-y: 0.5rem; + --bs-btn-padding-x: 1rem; + --bs-btn-font-size: 1.25rem; + --bs-btn-border-radius: 0.5rem; +} + +.btn-sm, .btn-group-sm > .btn { + --bs-btn-padding-y: 0.25rem; + --bs-btn-padding-x: 0.5rem; + --bs-btn-font-size: 0.875rem; + --bs-btn-border-radius: 0.25rem; +} + +.fade { + transition: opacity 0.15s linear; +} +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing.collapse-horizontal { + transition: none; + } +} + +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + --bs-dropdown-zindex: 1000; + --bs-dropdown-min-width: 10rem; + --bs-dropdown-padding-x: 0; + --bs-dropdown-padding-y: 0.5rem; + --bs-dropdown-spacer: 0.125rem; + --bs-dropdown-font-size: 1rem; + --bs-dropdown-color: #212529; + --bs-dropdown-bg: #fff; + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-border-radius: 0.375rem; + --bs-dropdown-border-width: 1px; + --bs-dropdown-inner-border-radius: calc(0.375rem - 1px); + --bs-dropdown-divider-bg: var(--bs-border-color-translucent); + --bs-dropdown-divider-margin-y: 0.5rem; + --bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-dropdown-link-color: #212529; + --bs-dropdown-link-hover-color: #1e2125; + --bs-dropdown-link-hover-bg: #e9ecef; + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #0d6efd; + --bs-dropdown-link-disabled-color: #adb5bd; + --bs-dropdown-item-padding-x: 1rem; + --bs-dropdown-item-padding-y: 0.25rem; + --bs-dropdown-header-color: #6c757d; + --bs-dropdown-header-padding-x: 1rem; + --bs-dropdown-header-padding-y: 0.5rem; + position: absolute; + z-index: var(--bs-dropdown-zindex); + display: none; + min-width: var(--bs-dropdown-min-width); + padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x); + margin: 0; + font-size: var(--bs-dropdown-font-size); + color: var(--bs-dropdown-color); + text-align: left; + list-style: none; + background-color: var(--bs-dropdown-bg); + background-clip: padding-box; + border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color); + border-radius: var(--bs-dropdown-border-radius); +} +.dropdown-menu[data-bs-popper] { + top: 100%; + left: 0; + margin-top: var(--bs-dropdown-spacer); +} + +.dropdown-menu-start { + --bs-position: start; +} +.dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0; +} + +.dropdown-menu-end { + --bs-position: end; +} +.dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-start { + --bs-position: start; + } + .dropdown-menu-sm-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-sm-end { + --bs-position: end; + } + .dropdown-menu-sm-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 768px) { + .dropdown-menu-md-start { + --bs-position: start; + } + .dropdown-menu-md-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-md-end { + --bs-position: end; + } + .dropdown-menu-md-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 992px) { + .dropdown-menu-lg-start { + --bs-position: start; + } + .dropdown-menu-lg-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-lg-end { + --bs-position: end; + } + .dropdown-menu-lg-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 1200px) { + .dropdown-menu-xl-start { + --bs-position: start; + } + .dropdown-menu-xl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xl-end { + --bs-position: end; + } + .dropdown-menu-xl-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 1400px) { + .dropdown-menu-xxl-start { + --bs-position: start; + } + .dropdown-menu-xxl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xxl-end { + --bs-position: end; + } + .dropdown-menu-xxl-end[data-bs-popper] { + right: 0; + left: auto; + } +} +.dropup .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: var(--bs-dropdown-spacer); +} +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--bs-dropdown-spacer); +} +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} +.dropend .dropdown-toggle:empty::after { + margin-left: 0; +} +.dropend .dropdown-toggle::after { + vertical-align: 0; +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: var(--bs-dropdown-spacer); +} +.dropstart .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} +.dropstart .dropdown-toggle::after { + display: none; +} +.dropstart .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} +.dropstart .dropdown-toggle:empty::after { + margin-left: 0; +} +.dropstart .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-divider { + height: 0; + margin: var(--bs-dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--bs-dropdown-divider-bg); + opacity: 1; +} + +.dropdown-item { + display: block; + width: 100%; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + clear: both; + font-weight: 400; + color: var(--bs-dropdown-link-color); + text-align: inherit; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border: 0; +} +.dropdown-item:hover, .dropdown-item:focus { + color: var(--bs-dropdown-link-hover-color); + background-color: var(--bs-dropdown-link-hover-bg); +} +.dropdown-item.active, .dropdown-item:active { + color: var(--bs-dropdown-link-active-color); + text-decoration: none; + background-color: var(--bs-dropdown-link-active-bg); +} +.dropdown-item.disabled, .dropdown-item:disabled { + color: var(--bs-dropdown-link-disabled-color); + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x); + margin-bottom: 0; + font-size: 0.875rem; + color: var(--bs-dropdown-header-color); + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + color: var(--bs-dropdown-link-color); +} + +.dropdown-menu-dark { + --bs-dropdown-color: #dee2e6; + --bs-dropdown-bg: #343a40; + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-box-shadow: ; + --bs-dropdown-link-color: #dee2e6; + --bs-dropdown-link-hover-color: #fff; + --bs-dropdown-divider-bg: var(--bs-border-color-translucent); + --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15); + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #0d6efd; + --bs-dropdown-link-disabled-color: #adb5bd; + --bs-dropdown-header-color: #adb5bd; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + flex: 1 1 auto; +} +.btn-group > .btn-check:checked + .btn, +.btn-group > .btn-check:focus + .btn, +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn-check:checked + .btn, +.btn-group-vertical > .btn-check:focus + .btn, +.btn-group-vertical > .btn:hover, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.btn-toolbar .input-group { + width: auto; +} + +.btn-group { + border-radius: 0.375rem; +} +.btn-group > :not(.btn-check:first-child) + .btn, +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn.dropdown-toggle-split:first-child, +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:nth-child(n+3), +.btn-group > :not(.btn-check) + .btn, +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} +.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after { + margin-left: 0; +} +.dropstart .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn ~ .btn, +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav { + --bs-nav-link-padding-x: 1rem; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-link-color); + --bs-nav-link-hover-color: var(--bs-link-hover-color); + --bs-nav-link-disabled-color: #6c757d; + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x); + font-size: var(--bs-nav-link-font-size); + font-weight: var(--bs-nav-link-font-weight); + color: var(--bs-nav-link-color); + text-decoration: none; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .nav-link { + transition: none; + } +} +.nav-link:hover, .nav-link:focus { + color: var(--bs-nav-link-hover-color); +} +.nav-link.disabled { + color: var(--bs-nav-link-disabled-color); + pointer-events: none; + cursor: default; +} + +.nav-tabs { + --bs-nav-tabs-border-width: 1px; + --bs-nav-tabs-border-color: #dee2e6; + --bs-nav-tabs-border-radius: 0.375rem; + --bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6; + --bs-nav-tabs-link-active-color: #495057; + --bs-nav-tabs-link-active-bg: #fff; + --bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #fff; + border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color); +} +.nav-tabs .nav-link { + margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width)); + background: none; + border: var(--bs-nav-tabs-border-width) solid transparent; + border-top-left-radius: var(--bs-nav-tabs-border-radius); + border-top-right-radius: var(--bs-nav-tabs-border-radius); +} +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + isolation: isolate; + border-color: var(--bs-nav-tabs-link-hover-border-color); +} +.nav-tabs .nav-link.disabled, .nav-tabs .nav-link:disabled { + color: var(--bs-nav-link-disabled-color); + background-color: transparent; + border-color: transparent; +} +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: var(--bs-nav-tabs-link-active-color); + background-color: var(--bs-nav-tabs-link-active-bg); + border-color: var(--bs-nav-tabs-link-active-border-color); +} +.nav-tabs .dropdown-menu { + margin-top: calc(-1 * var(--bs-nav-tabs-border-width)); + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills { + --bs-nav-pills-border-radius: 0.375rem; + --bs-nav-pills-link-active-color: #fff; + --bs-nav-pills-link-active-bg: #0d6efd; +} +.nav-pills .nav-link { + background: none; + border: 0; + border-radius: var(--bs-nav-pills-border-radius); +} +.nav-pills .nav-link:disabled { + color: var(--bs-nav-link-disabled-color); + background-color: transparent; + border-color: transparent; +} +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: var(--bs-nav-pills-link-active-color); + background-color: var(--bs-nav-pills-link-active-bg); +} + +.nav-fill > .nav-link, +.nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; +} + +.nav-justified > .nav-link, +.nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} + +.nav-fill .nav-item .nav-link, +.nav-justified .nav-item .nav-link { + width: 100%; +} + +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} + +.navbar { + --bs-navbar-padding-x: 0; + --bs-navbar-padding-y: 0.5rem; + --bs-navbar-color: rgba(0, 0, 0, 0.55); + --bs-navbar-hover-color: rgba(0, 0, 0, 0.7); + --bs-navbar-disabled-color: rgba(0, 0, 0, 0.3); + --bs-navbar-active-color: rgba(0, 0, 0, 0.9); + --bs-navbar-brand-padding-y: 0.3125rem; + --bs-navbar-brand-margin-end: 1rem; + --bs-navbar-brand-font-size: 1.25rem; + --bs-navbar-brand-color: rgba(0, 0, 0, 0.9); + --bs-navbar-brand-hover-color: rgba(0, 0, 0, 0.9); + --bs-navbar-nav-link-padding-x: 0.5rem; + --bs-navbar-toggler-padding-y: 0.25rem; + --bs-navbar-toggler-padding-x: 0.75rem; + --bs-navbar-toggler-font-size: 1.25rem; + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); + --bs-navbar-toggler-border-color: rgba(0, 0, 0, 0.1); + --bs-navbar-toggler-border-radius: 0.375rem; + --bs-navbar-toggler-focus-width: 0.25rem; + --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out; + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x); +} +.navbar > .container, +.navbar > .container-fluid, +.navbar > .container-sm, +.navbar > .container-md, +.navbar > .container-lg, +.navbar > .container-xl, +.navbar > .container-xxl { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; +} +.navbar-brand { + padding-top: var(--bs-navbar-brand-padding-y); + padding-bottom: var(--bs-navbar-brand-padding-y); + margin-right: var(--bs-navbar-brand-margin-end); + font-size: var(--bs-navbar-brand-font-size); + color: var(--bs-navbar-brand-color); + text-decoration: none; + white-space: nowrap; +} +.navbar-brand:hover, .navbar-brand:focus { + color: var(--bs-navbar-brand-hover-color); +} + +.navbar-nav { + --bs-nav-link-padding-x: 0; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-navbar-color); + --bs-nav-link-hover-color: var(--bs-navbar-hover-color); + --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color); + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.navbar-nav .show > .nav-link, +.navbar-nav .nav-link.active { + color: var(--bs-navbar-active-color); +} +.navbar-nav .dropdown-menu { + position: static; +} + +.navbar-text { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-navbar-color); +} +.navbar-text a, +.navbar-text a:hover, +.navbar-text a:focus { + color: var(--bs-navbar-active-color); +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; +} + +.navbar-toggler { + padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x); + font-size: var(--bs-navbar-toggler-font-size); + line-height: 1; + color: var(--bs-navbar-color); + background-color: transparent; + border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color); + border-radius: var(--bs-navbar-toggler-border-radius); + transition: var(--bs-navbar-toggler-transition); +} +@media (prefers-reduced-motion: reduce) { + .navbar-toggler { + transition: none; + } +} +.navbar-toggler:hover { + text-decoration: none; +} +.navbar-toggler:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width); +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-image: var(--bs-navbar-toggler-icon-bg); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height, 75vh); + overflow-y: auto; +} + +@media (min-width: 576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } + .navbar-expand-sm .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-sm .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-md .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } + .navbar-expand-md .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-md .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } + .navbar-expand-lg .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-lg .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } + .navbar-expand-xl .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 1400px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xxl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xxl .navbar-toggler { + display: none; + } + .navbar-expand-xxl .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +.navbar-expand { + flex-wrap: nowrap; + justify-content: flex-start; +} +.navbar-expand .navbar-nav { + flex-direction: row; +} +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} +.navbar-expand .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); +} +.navbar-expand .navbar-nav-scroll { + overflow: visible; +} +.navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto; +} +.navbar-expand .navbar-toggler { + display: none; +} +.navbar-expand .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; +} +.navbar-expand .offcanvas .offcanvas-header { + display: none; +} +.navbar-expand .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} + +.navbar-dark { + --bs-navbar-color: rgba(255, 255, 255, 0.55); + --bs-navbar-hover-color: rgba(255, 255, 255, 0.75); + --bs-navbar-disabled-color: rgba(255, 255, 255, 0.25); + --bs-navbar-active-color: #fff; + --bs-navbar-brand-color: #fff; + --bs-navbar-brand-hover-color: #fff; + --bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1); + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.card { + --bs-card-spacer-y: 1rem; + --bs-card-spacer-x: 1rem; + --bs-card-title-spacer-y: 0.5rem; + --bs-card-border-width: 1px; + --bs-card-border-color: var(--bs-border-color-translucent); + --bs-card-border-radius: 0.375rem; + --bs-card-box-shadow: ; + --bs-card-inner-border-radius: calc(0.375rem - 1px); + --bs-card-cap-padding-y: 0.5rem; + --bs-card-cap-padding-x: 1rem; + --bs-card-cap-bg: rgba(0, 0, 0, 0.03); + --bs-card-cap-color: ; + --bs-card-height: ; + --bs-card-color: ; + --bs-card-bg: #fff; + --bs-card-img-overlay-padding: 1rem; + --bs-card-group-margin: 0.75rem; + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + height: var(--bs-card-height); + word-wrap: break-word; + background-color: var(--bs-card-bg); + background-clip: border-box; + border: var(--bs-card-border-width) solid var(--bs-card-border-color); + border-radius: var(--bs-card-border-radius); +} +.card > hr { + margin-right: 0; + margin-left: 0; +} +.card > .list-group { + border-top: inherit; + border-bottom: inherit; +} +.card > .list-group:first-child { + border-top-width: 0; + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} +.card > .list-group:last-child { + border-bottom-width: 0; + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} +.card > .card-header + .list-group, +.card > .list-group + .card-footer { + border-top: 0; +} + +.card-body { + flex: 1 1 auto; + padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x); + color: var(--bs-card-color); +} + +.card-title { + margin-bottom: var(--bs-card-title-spacer-y); +} + +.card-subtitle { + margin-top: calc(-0.5 * var(--bs-card-title-spacer-y)); + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link + .card-link { + margin-left: var(--bs-card-spacer-x); +} + +.card-header { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + margin-bottom: 0; + color: var(--bs-card-cap-color); + background-color: var(--bs-card-cap-bg); + border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color); +} +.card-header:first-child { + border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0; +} + +.card-footer { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + color: var(--bs-card-cap-color); + background-color: var(--bs-card-cap-bg); + border-top: var(--bs-card-border-width) solid var(--bs-card-border-color); +} +.card-footer:last-child { + border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius); +} + +.card-header-tabs { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-bottom: calc(-1 * var(--bs-card-cap-padding-y)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); + border-bottom: 0; +} +.card-header-tabs .nav-link.active { + background-color: var(--bs-card-bg); + border-bottom-color: var(--bs-card-bg); +} + +.card-header-pills { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--bs-card-img-overlay-padding); + border-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} + +.card-group > .card { + margin-bottom: var(--bs-card-group-margin); +} +@media (min-width: 576px) { + .card-group { + display: flex; + flex-flow: row wrap; + } + .card-group > .card { + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.accordion { + --bs-accordion-color: #212529; + --bs-accordion-bg: #fff; + --bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; + --bs-accordion-border-color: var(--bs-border-color); + --bs-accordion-border-width: 1px; + --bs-accordion-border-radius: 0.375rem; + --bs-accordion-inner-border-radius: calc(0.375rem - 1px); + --bs-accordion-btn-padding-x: 1.25rem; + --bs-accordion-btn-padding-y: 1rem; + --bs-accordion-btn-color: #212529; + --bs-accordion-btn-bg: var(--bs-accordion-bg); + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-icon-width: 1.25rem; + --bs-accordion-btn-icon-transform: rotate(-180deg); + --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-focus-border-color: #86b7fe; + --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + --bs-accordion-body-padding-x: 1.25rem; + --bs-accordion-body-padding-y: 1rem; + --bs-accordion-active-color: #0c63e4; + --bs-accordion-active-bg: #e7f1ff; +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x); + font-size: 1rem; + color: var(--bs-accordion-btn-color); + text-align: left; + background-color: var(--bs-accordion-btn-bg); + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: var(--bs-accordion-transition); +} +@media (prefers-reduced-motion: reduce) { + .accordion-button { + transition: none; + } +} +.accordion-button:not(.collapsed) { + color: var(--bs-accordion-active-color); + background-color: var(--bs-accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color); +} +.accordion-button:not(.collapsed)::after { + background-image: var(--bs-accordion-btn-active-icon); + transform: var(--bs-accordion-btn-icon-transform); +} +.accordion-button::after { + flex-shrink: 0; + width: var(--bs-accordion-btn-icon-width); + height: var(--bs-accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--bs-accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--bs-accordion-btn-icon-width); + transition: var(--bs-accordion-btn-icon-transition); +} +@media (prefers-reduced-motion: reduce) { + .accordion-button::after { + transition: none; + } +} +.accordion-button:hover { + z-index: 2; +} +.accordion-button:focus { + z-index: 3; + border-color: var(--bs-accordion-btn-focus-border-color); + outline: 0; + box-shadow: var(--bs-accordion-btn-focus-box-shadow); +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--bs-accordion-color); + background-color: var(--bs-accordion-bg); + border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color); +} +.accordion-item:first-of-type { + border-top-left-radius: var(--bs-accordion-border-radius); + border-top-right-radius: var(--bs-accordion-border-radius); +} +.accordion-item:first-of-type .accordion-button { + border-top-left-radius: var(--bs-accordion-inner-border-radius); + border-top-right-radius: var(--bs-accordion-inner-border-radius); +} +.accordion-item:not(:first-of-type) { + border-top: 0; +} +.accordion-item:last-of-type { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} +.accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: var(--bs-accordion-inner-border-radius); + border-bottom-left-radius: var(--bs-accordion-inner-border-radius); +} +.accordion-item:last-of-type .accordion-collapse { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} + +.accordion-body { + padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x); +} + +.accordion-flush .accordion-collapse { + border-width: 0; +} +.accordion-flush .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} +.accordion-flush .accordion-item:first-child { + border-top: 0; +} +.accordion-flush .accordion-item:last-child { + border-bottom: 0; +} +.accordion-flush .accordion-item .accordion-button, .accordion-flush .accordion-item .accordion-button.collapsed { + border-radius: 0; +} + +.breadcrumb { + --bs-breadcrumb-padding-x: 0; + --bs-breadcrumb-padding-y: 0; + --bs-breadcrumb-margin-bottom: 1rem; + --bs-breadcrumb-bg: ; + --bs-breadcrumb-border-radius: ; + --bs-breadcrumb-divider-color: #6c757d; + --bs-breadcrumb-item-padding-x: 0.5rem; + --bs-breadcrumb-item-active-color: #6c757d; + display: flex; + flex-wrap: wrap; + padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x); + margin-bottom: var(--bs-breadcrumb-margin-bottom); + font-size: var(--bs-breadcrumb-font-size); + list-style: none; + background-color: var(--bs-breadcrumb-bg); + border-radius: var(--bs-breadcrumb-border-radius); +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: var(--bs-breadcrumb-item-padding-x); +} +.breadcrumb-item + .breadcrumb-item::before { + float: left; + padding-right: var(--bs-breadcrumb-item-padding-x); + color: var(--bs-breadcrumb-divider-color); + content: var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */; +} +.breadcrumb-item.active { + color: var(--bs-breadcrumb-item-active-color); +} + +.pagination { + --bs-pagination-padding-x: 0.75rem; + --bs-pagination-padding-y: 0.375rem; + --bs-pagination-font-size: 1rem; + --bs-pagination-color: var(--bs-link-color); + --bs-pagination-bg: #fff; + --bs-pagination-border-width: 1px; + --bs-pagination-border-color: #dee2e6; + --bs-pagination-border-radius: 0.375rem; + --bs-pagination-hover-color: var(--bs-link-hover-color); + --bs-pagination-hover-bg: #e9ecef; + --bs-pagination-hover-border-color: #dee2e6; + --bs-pagination-focus-color: var(--bs-link-hover-color); + --bs-pagination-focus-bg: #e9ecef; + --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + --bs-pagination-active-color: #fff; + --bs-pagination-active-bg: #0d6efd; + --bs-pagination-active-border-color: #0d6efd; + --bs-pagination-disabled-color: #6c757d; + --bs-pagination-disabled-bg: #fff; + --bs-pagination-disabled-border-color: #dee2e6; + display: flex; + padding-left: 0; + list-style: none; +} + +.page-link { + position: relative; + display: block; + padding: var(--bs-pagination-padding-y) var(--bs-pagination-padding-x); + font-size: var(--bs-pagination-font-size); + color: var(--bs-pagination-color); + text-decoration: none; + background-color: var(--bs-pagination-bg); + border: var(--bs-pagination-border-width) solid var(--bs-pagination-border-color); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .page-link { + transition: none; + } +} +.page-link:hover { + z-index: 2; + color: var(--bs-pagination-hover-color); + background-color: var(--bs-pagination-hover-bg); + border-color: var(--bs-pagination-hover-border-color); +} +.page-link:focus { + z-index: 3; + color: var(--bs-pagination-focus-color); + background-color: var(--bs-pagination-focus-bg); + outline: 0; + box-shadow: var(--bs-pagination-focus-box-shadow); +} +.page-link.active, .active > .page-link { + z-index: 3; + color: var(--bs-pagination-active-color); + background-color: var(--bs-pagination-active-bg); + border-color: var(--bs-pagination-active-border-color); +} +.page-link.disabled, .disabled > .page-link { + color: var(--bs-pagination-disabled-color); + pointer-events: none; + background-color: var(--bs-pagination-disabled-bg); + border-color: var(--bs-pagination-disabled-border-color); +} + +.page-item:not(:first-child) .page-link { + margin-left: -1px; +} +.page-item:first-child .page-link { + border-top-left-radius: var(--bs-pagination-border-radius); + border-bottom-left-radius: var(--bs-pagination-border-radius); +} +.page-item:last-child .page-link { + border-top-right-radius: var(--bs-pagination-border-radius); + border-bottom-right-radius: var(--bs-pagination-border-radius); +} + +.pagination-lg { + --bs-pagination-padding-x: 1.5rem; + --bs-pagination-padding-y: 0.75rem; + --bs-pagination-font-size: 1.25rem; + --bs-pagination-border-radius: 0.5rem; +} + +.pagination-sm { + --bs-pagination-padding-x: 0.5rem; + --bs-pagination-padding-y: 0.25rem; + --bs-pagination-font-size: 0.875rem; + --bs-pagination-border-radius: 0.25rem; +} + +.badge { + --bs-badge-padding-x: 0.65em; + --bs-badge-padding-y: 0.35em; + --bs-badge-font-size: 0.75em; + --bs-badge-font-weight: 700; + --bs-badge-color: #fff; + --bs-badge-border-radius: 0.375rem; + display: inline-block; + padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x); + font-size: var(--bs-badge-font-size); + font-weight: var(--bs-badge-font-weight); + line-height: 1; + color: var(--bs-badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: var(--bs-badge-border-radius); +} +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.alert { + --bs-alert-bg: transparent; + --bs-alert-padding-x: 1rem; + --bs-alert-padding-y: 1rem; + --bs-alert-margin-bottom: 1rem; + --bs-alert-color: inherit; + --bs-alert-border-color: transparent; + --bs-alert-border: 1px solid var(--bs-alert-border-color); + --bs-alert-border-radius: 0.375rem; + position: relative; + padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x); + margin-bottom: var(--bs-alert-margin-bottom); + color: var(--bs-alert-color); + background-color: var(--bs-alert-bg); + border: var(--bs-alert-border); + border-radius: var(--bs-alert-border-radius); +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; +} + +.alert-dismissible { + padding-right: 3rem; +} +.alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.25rem 1rem; +} + +.alert-primary { + --bs-alert-color: #084298; + --bs-alert-bg: #cfe2ff; + --bs-alert-border-color: #b6d4fe; +} +.alert-primary .alert-link { + color: #06357a; +} + +.alert-secondary { + --bs-alert-color: #41464b; + --bs-alert-bg: #e2e3e5; + --bs-alert-border-color: #d3d6d8; +} +.alert-secondary .alert-link { + color: #34383c; +} + +.alert-success { + --bs-alert-color: #0f5132; + --bs-alert-bg: #d1e7dd; + --bs-alert-border-color: #badbcc; +} +.alert-success .alert-link { + color: #0c4128; +} + +.alert-info { + --bs-alert-color: #055160; + --bs-alert-bg: #cff4fc; + --bs-alert-border-color: #b6effb; +} +.alert-info .alert-link { + color: #04414d; +} + +.alert-warning { + --bs-alert-color: #664d03; + --bs-alert-bg: #fff3cd; + --bs-alert-border-color: #ffecb5; +} +.alert-warning .alert-link { + color: #523e02; +} + +.alert-danger { + --bs-alert-color: #842029; + --bs-alert-bg: #f8d7da; + --bs-alert-border-color: #f5c2c7; +} +.alert-danger .alert-link { + color: #6a1a21; +} + +.alert-light { + --bs-alert-color: #636464; + --bs-alert-bg: #fefefe; + --bs-alert-border-color: #fdfdfe; +} +.alert-light .alert-link { + color: #4f5050; +} + +.alert-dark { + --bs-alert-color: #141619; + --bs-alert-bg: #d3d3d4; + --bs-alert-border-color: #bcbebf; +} +.alert-dark .alert-link { + color: #101214; +} + +@keyframes progress-bar-stripes { + 0% { + background-position-x: 1rem; + } +} +.progress { + --bs-progress-height: 1rem; + --bs-progress-font-size: 0.75rem; + --bs-progress-bg: #e9ecef; + --bs-progress-border-radius: 0.375rem; + --bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075); + --bs-progress-bar-color: #fff; + --bs-progress-bar-bg: #0d6efd; + --bs-progress-bar-transition: width 0.6s ease; + display: flex; + height: var(--bs-progress-height); + overflow: hidden; + font-size: var(--bs-progress-font-size); + background-color: var(--bs-progress-bg); + border-radius: var(--bs-progress-border-radius); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--bs-progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--bs-progress-bar-bg); + transition: var(--bs-progress-bar-transition); +} +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: var(--bs-progress-height) var(--bs-progress-height); +} + +.progress-bar-animated { + animation: 1s linear infinite progress-bar-stripes; +} +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + animation: none; + } +} + +.list-group { + --bs-list-group-color: #212529; + --bs-list-group-bg: #fff; + --bs-list-group-border-color: rgba(0, 0, 0, 0.125); + --bs-list-group-border-width: 1px; + --bs-list-group-border-radius: 0.375rem; + --bs-list-group-item-padding-x: 1rem; + --bs-list-group-item-padding-y: 0.5rem; + --bs-list-group-action-color: #495057; + --bs-list-group-action-hover-color: #495057; + --bs-list-group-action-hover-bg: #f8f9fa; + --bs-list-group-action-active-color: #212529; + --bs-list-group-action-active-bg: #e9ecef; + --bs-list-group-disabled-color: #6c757d; + --bs-list-group-disabled-bg: #fff; + --bs-list-group-active-color: #fff; + --bs-list-group-active-bg: #0d6efd; + --bs-list-group-active-border-color: #0d6efd; + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: var(--bs-list-group-border-radius); +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; +} +.list-group-numbered > .list-group-item::before { + content: counters(section, ".") ". "; + counter-increment: section; +} + +.list-group-item-action { + width: 100%; + color: var(--bs-list-group-action-color); + text-align: inherit; +} +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: var(--bs-list-group-action-hover-color); + text-decoration: none; + background-color: var(--bs-list-group-action-hover-bg); +} +.list-group-item-action:active { + color: var(--bs-list-group-action-active-color); + background-color: var(--bs-list-group-action-active-bg); +} + +.list-group-item { + position: relative; + display: block; + padding: var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x); + color: var(--bs-list-group-color); + text-decoration: none; + background-color: var(--bs-list-group-bg); + border: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color); +} +.list-group-item:first-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} +.list-group-item:last-child { + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit; +} +.list-group-item.disabled, .list-group-item:disabled { + color: var(--bs-list-group-disabled-color); + pointer-events: none; + background-color: var(--bs-list-group-disabled-bg); +} +.list-group-item.active { + z-index: 2; + color: var(--bs-list-group-active-color); + background-color: var(--bs-list-group-active-bg); + border-color: var(--bs-list-group-active-border-color); +} +.list-group-item + .list-group-item { + border-top-width: 0; +} +.list-group-item + .list-group-item.active { + margin-top: calc(-1 * var(--bs-list-group-border-width)); + border-top-width: var(--bs-list-group-border-width); +} + +.list-group-horizontal { + flex-direction: row; +} +.list-group-horizontal > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; +} +.list-group-horizontal > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; +} +.list-group-horizontal > .list-group-item.active { + margin-top: 0; +} +.list-group-horizontal > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; +} +.list-group-horizontal > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + flex-direction: row; + } + .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-sm > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 768px) { + .list-group-horizontal-md { + flex-direction: row; + } + .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-md > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 992px) { + .list-group-horizontal-lg { + flex-direction: row; + } + .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-lg > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 1200px) { + .list-group-horizontal-xl { + flex-direction: row; + } + .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-xl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 1400px) { + .list-group-horizontal-xxl { + flex-direction: row; + } + .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +.list-group-flush { + border-radius: 0; +} +.list-group-flush > .list-group-item { + border-width: 0 0 var(--bs-list-group-border-width); +} +.list-group-flush > .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + color: #084298; + background-color: #cfe2ff; +} +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #084298; + background-color: #bacbe6; +} +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #084298; + border-color: #084298; +} + +.list-group-item-secondary { + color: #41464b; + background-color: #e2e3e5; +} +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #41464b; + background-color: #cbccce; +} +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #41464b; + border-color: #41464b; +} + +.list-group-item-success { + color: #0f5132; + background-color: #d1e7dd; +} +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #0f5132; + background-color: #bcd0c7; +} +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #0f5132; + border-color: #0f5132; +} + +.list-group-item-info { + color: #055160; + background-color: #cff4fc; +} +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #055160; + background-color: #badce3; +} +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #055160; + border-color: #055160; +} + +.list-group-item-warning { + color: #664d03; + background-color: #fff3cd; +} +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #664d03; + background-color: #e6dbb9; +} +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #664d03; + border-color: #664d03; +} + +.list-group-item-danger { + color: #842029; + background-color: #f8d7da; +} +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #842029; + background-color: #dfc2c4; +} +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #842029; + border-color: #842029; +} + +.list-group-item-light { + color: #636464; + background-color: #fefefe; +} +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #636464; + background-color: #e5e5e5; +} +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #636464; + border-color: #636464; +} + +.list-group-item-dark { + color: #141619; + background-color: #d3d3d4; +} +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #141619; + background-color: #bebebf; +} +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #141619; + border-color: #141619; +} + +.btn-close { + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + color: #000; + background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat; + border: 0; + border-radius: 0.375rem; + opacity: 0.5; +} +.btn-close:hover { + color: #000; + text-decoration: none; + opacity: 0.75; +} +.btn-close:focus { + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + opacity: 1; +} +.btn-close:disabled, .btn-close.disabled { + pointer-events: none; + user-select: none; + opacity: 0.25; +} + +.btn-close-white { + filter: invert(1) grayscale(100%) brightness(200%); +} + +.toast { + --bs-toast-zindex: 1090; + --bs-toast-padding-x: 0.75rem; + --bs-toast-padding-y: 0.5rem; + --bs-toast-spacing: 1.5rem; + --bs-toast-max-width: 350px; + --bs-toast-font-size: 0.875rem; + --bs-toast-color: ; + --bs-toast-bg: rgba(255, 255, 255, 0.85); + --bs-toast-border-width: 1px; + --bs-toast-border-color: var(--bs-border-color-translucent); + --bs-toast-border-radius: 0.375rem; + --bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-toast-header-color: #6c757d; + --bs-toast-header-bg: rgba(255, 255, 255, 0.85); + --bs-toast-header-border-color: rgba(0, 0, 0, 0.05); + width: var(--bs-toast-max-width); + max-width: 100%; + font-size: var(--bs-toast-font-size); + color: var(--bs-toast-color); + pointer-events: auto; + background-color: var(--bs-toast-bg); + background-clip: padding-box; + border: var(--bs-toast-border-width) solid var(--bs-toast-border-color); + box-shadow: var(--bs-toast-box-shadow); + border-radius: var(--bs-toast-border-radius); +} +.toast.showing { + opacity: 0; +} +.toast:not(.show) { + display: none; +} + +.toast-container { + --bs-toast-zindex: 1090; + position: absolute; + z-index: var(--bs-toast-zindex); + width: max-content; + max-width: 100%; + pointer-events: none; +} +.toast-container > :not(:last-child) { + margin-bottom: var(--bs-toast-spacing); +} + +.toast-header { + display: flex; + align-items: center; + padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); + color: var(--bs-toast-header-color); + background-color: var(--bs-toast-header-bg); + background-clip: padding-box; + border-bottom: var(--bs-toast-border-width) solid var(--bs-toast-header-border-color); + border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width)); + border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width)); +} +.toast-header .btn-close { + margin-right: calc(-0.5 * var(--bs-toast-padding-x)); + margin-left: var(--bs-toast-padding-x); +} + +.toast-body { + padding: var(--bs-toast-padding-x); + word-wrap: break-word; +} + +.modal { + --bs-modal-zindex: 1055; + --bs-modal-width: 500px; + --bs-modal-padding: 1rem; + --bs-modal-margin: 0.5rem; + --bs-modal-color: ; + --bs-modal-bg: #fff; + --bs-modal-border-color: var(--bs-border-color-translucent); + --bs-modal-border-width: 1px; + --bs-modal-border-radius: 0.5rem; + --bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + --bs-modal-inner-border-radius: calc(0.5rem - 1px); + --bs-modal-header-padding-x: 1rem; + --bs-modal-header-padding-y: 1rem; + --bs-modal-header-padding: 1rem 1rem; + --bs-modal-header-border-color: var(--bs-border-color); + --bs-modal-header-border-width: 1px; + --bs-modal-title-line-height: 1.5; + --bs-modal-footer-gap: 0.5rem; + --bs-modal-footer-bg: ; + --bs-modal-footer-border-color: var(--bs-border-color); + --bs-modal-footer-border-width: 1px; + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-modal-zindex); + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: var(--bs-modal-margin); + pointer-events: none; +} +.modal.fade .modal-dialog { + transition: transform 0.3s ease-out; + transform: translate(0, -50px); +} +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} +.modal.show .modal-dialog { + transform: none; +} +.modal.modal-static .modal-dialog { + transform: scale(1.02); +} + +.modal-dialog-scrollable { + height: calc(100% - var(--bs-modal-margin) * 2); +} +.modal-dialog-scrollable .modal-content { + max-height: 100%; + overflow: hidden; +} +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - var(--bs-modal-margin) * 2); +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + color: var(--bs-modal-color); + pointer-events: auto; + background-color: var(--bs-modal-bg); + background-clip: padding-box; + border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); + border-radius: var(--bs-modal-border-radius); + outline: 0; +} + +.modal-backdrop { + --bs-backdrop-zindex: 1050; + --bs-backdrop-bg: #000; + --bs-backdrop-opacity: 0.5; + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-backdrop-zindex); + width: 100vw; + height: 100vh; + background-color: var(--bs-backdrop-bg); +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop.show { + opacity: var(--bs-backdrop-opacity); +} + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + padding: var(--bs-modal-header-padding); + border-bottom: var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color); + border-top-left-radius: var(--bs-modal-inner-border-radius); + border-top-right-radius: var(--bs-modal-inner-border-radius); +} +.modal-header .btn-close { + padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5); + margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto; +} + +.modal-title { + margin-bottom: 0; + line-height: var(--bs-modal-title-line-height); +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: var(--bs-modal-padding); +} + +.modal-footer { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5); + background-color: var(--bs-modal-footer-bg); + border-top: var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color); + border-bottom-right-radius: var(--bs-modal-inner-border-radius); + border-bottom-left-radius: var(--bs-modal-inner-border-radius); +} +.modal-footer > * { + margin: calc(var(--bs-modal-footer-gap) * 0.5); +} + +@media (min-width: 576px) { + .modal { + --bs-modal-margin: 1.75rem; + --bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + } + .modal-dialog { + max-width: var(--bs-modal-width); + margin-right: auto; + margin-left: auto; + } + .modal-sm { + --bs-modal-width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + --bs-modal-width: 800px; + } +} +@media (min-width: 1200px) { + .modal-xl { + --bs-modal-width: 1140px; + } +} +.modal-fullscreen { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; +} +.modal-fullscreen .modal-content { + height: 100%; + border: 0; + border-radius: 0; +} +.modal-fullscreen .modal-header, +.modal-fullscreen .modal-footer { + border-radius: 0; +} +.modal-fullscreen .modal-body { + overflow-y: auto; +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-header, + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-md-down .modal-header, + .modal-fullscreen-md-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-md-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-header, + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-header, + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 1399.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-header, + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto; + } +} +.tooltip { + --bs-tooltip-zindex: 1080; + --bs-tooltip-max-width: 200px; + --bs-tooltip-padding-x: 0.5rem; + --bs-tooltip-padding-y: 0.25rem; + --bs-tooltip-margin: ; + --bs-tooltip-font-size: 0.875rem; + --bs-tooltip-color: #fff; + --bs-tooltip-bg: #000; + --bs-tooltip-border-radius: 0.375rem; + --bs-tooltip-opacity: 0.9; + --bs-tooltip-arrow-width: 0.8rem; + --bs-tooltip-arrow-height: 0.4rem; + z-index: var(--bs-tooltip-zindex); + display: block; + padding: var(--bs-tooltip-arrow-height); + margin: var(--bs-tooltip-margin); + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-tooltip-font-size); + word-wrap: break-word; + opacity: 0; +} +.tooltip.show { + opacity: var(--bs-tooltip-opacity); +} +.tooltip .tooltip-arrow { + display: block; + width: var(--bs-tooltip-arrow-width); + height: var(--bs-tooltip-arrow-height); +} +.tooltip .tooltip-arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow { + bottom: 0; +} +.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before { + top: -1px; + border-width: var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-top-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow { + left: 0; + width: var(--bs-tooltip-arrow-height); + height: var(--bs-tooltip-arrow-width); +} +.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before { + right: -1px; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-right-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow { + top: 0; +} +.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before { + bottom: -1px; + border-width: 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-bottom-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow { + right: 0; + width: var(--bs-tooltip-arrow-height); + height: var(--bs-tooltip-arrow-width); +} +.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before { + left: -1px; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-left-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.tooltip-inner { + max-width: var(--bs-tooltip-max-width); + padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x); + color: var(--bs-tooltip-color); + text-align: center; + background-color: var(--bs-tooltip-bg); + border-radius: var(--bs-tooltip-border-radius); +} + +.popover { + --bs-popover-zindex: 1070; + --bs-popover-max-width: 276px; + --bs-popover-font-size: 0.875rem; + --bs-popover-bg: #fff; + --bs-popover-border-width: 1px; + --bs-popover-border-color: var(--bs-border-color-translucent); + --bs-popover-border-radius: 0.5rem; + --bs-popover-inner-border-radius: calc(0.5rem - 1px); + --bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-popover-header-padding-x: 1rem; + --bs-popover-header-padding-y: 0.5rem; + --bs-popover-header-font-size: 1rem; + --bs-popover-header-color: ; + --bs-popover-header-bg: #f0f0f0; + --bs-popover-body-padding-x: 1rem; + --bs-popover-body-padding-y: 1rem; + --bs-popover-body-color: #212529; + --bs-popover-arrow-width: 1rem; + --bs-popover-arrow-height: 0.5rem; + --bs-popover-arrow-border: var(--bs-popover-border-color); + z-index: var(--bs-popover-zindex); + display: block; + max-width: var(--bs-popover-max-width); + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-popover-font-size); + word-wrap: break-word; + background-color: var(--bs-popover-bg); + background-clip: padding-box; + border: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-radius: var(--bs-popover-border-radius); +} +.popover .popover-arrow { + display: block; + width: var(--bs-popover-arrow-width); + height: var(--bs-popover-arrow-height); +} +.popover .popover-arrow::before, .popover .popover-arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; + border-width: 0; +} + +.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow { + bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); +} +.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; +} +.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before { + bottom: 0; + border-top-color: var(--bs-popover-arrow-border); +} +.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + bottom: var(--bs-popover-border-width); + border-top-color: var(--bs-popover-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow { + left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); + width: var(--bs-popover-arrow-height); + height: var(--bs-popover-arrow-width); +} +.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; +} +.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before { + left: 0; + border-right-color: var(--bs-popover-arrow-border); +} +.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + left: var(--bs-popover-border-width); + border-right-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow { + top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); +} +.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); +} +.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before { + top: 0; + border-bottom-color: var(--bs-popover-arrow-border); +} +.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + top: var(--bs-popover-border-width); + border-bottom-color: var(--bs-popover-bg); +} +.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: var(--bs-popover-arrow-width); + margin-left: calc(-0.5 * var(--bs-popover-arrow-width)); + content: ""; + border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow { + right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); + width: var(--bs-popover-arrow-height); + height: var(--bs-popover-arrow-width); +} +.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); +} +.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before { + right: 0; + border-left-color: var(--bs-popover-arrow-border); +} +.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + right: var(--bs-popover-border-width); + border-left-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.popover-header { + padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x); + margin-bottom: 0; + font-size: var(--bs-popover-header-font-size); + color: var(--bs-popover-header-color); + background-color: var(--bs-popover-header-bg); + border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-top-left-radius: var(--bs-popover-inner-border-radius); + border-top-right-radius: var(--bs-popover-inner-border-radius); +} +.popover-header:empty { + display: none; +} + +.popover-body { + padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x); + color: var(--bs-popover-body-color); +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + backface-visibility: hidden; + transition: transform 0.6s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start), +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end), +.active.carousel-item-start { + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none; +} +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-start, +.carousel-fade .carousel-item-prev.carousel-item-end { + z-index: 1; + opacity: 1; +} +.carousel-fade .active.carousel-item-start, +.carousel-fade .active.carousel-item-end { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} +@media (prefers-reduced-motion: reduce) { + .carousel-fade .active.carousel-item-start, + .carousel-fade .active.carousel-item-end { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 15%; + padding: 0; + color: #fff; + text-align: center; + background: none; + border: 0; + opacity: 0.5; + transition: opacity 0.15s ease; +} +@media (prefers-reduced-motion: reduce) { + .carousel-control-prev, + .carousel-control-next { + transition: none; + } +} +.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 2rem; + height: 2rem; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100%; +} + +/* rtl:options: { + "autoRename": true, + "stringMap":[ { + "name" : "prev-next", + "search" : "prev", + "replace" : "next" + } ] +} */ +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + margin-right: 15%; + margin-bottom: 1rem; + margin-left: 15%; + list-style: none; +} +.carousel-indicators [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: 30px; + height: 3px; + padding: 0; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: 0.5; + transition: opacity 0.6s ease; +} +@media (prefers-reduced-motion: reduce) { + .carousel-indicators [data-bs-target] { + transition: none; + } +} +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 1.25rem; + left: 15%; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + color: #fff; + text-align: center; +} + +.carousel-dark .carousel-control-prev-icon, +.carousel-dark .carousel-control-next-icon { + filter: invert(1) grayscale(100); +} +.carousel-dark .carousel-indicators [data-bs-target] { + background-color: #000; +} +.carousel-dark .carousel-caption { + color: #000; +} + +.spinner-grow, +.spinner-border { + display: inline-block; + width: var(--bs-spinner-width); + height: var(--bs-spinner-height); + vertical-align: var(--bs-spinner-vertical-align); + border-radius: 50%; + animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name); +} + +@keyframes spinner-border { + to { + transform: rotate(360deg) /* rtl:ignore */; + } +} +.spinner-border { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-border-width: 0.25em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-border; + border: var(--bs-spinner-border-width) solid currentcolor; + border-right-color: transparent; +} + +.spinner-border-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; + --bs-spinner-border-width: 0.2em; +} + +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} +.spinner-grow { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-grow; + background-color: currentcolor; + opacity: 0; +} + +.spinner-grow-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; +} + +@media (prefers-reduced-motion: reduce) { + .spinner-border, + .spinner-grow { + --bs-spinner-animation-speed: 1.5s; + } +} +.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm { + --bs-offcanvas-zindex: 1045; + --bs-offcanvas-width: 400px; + --bs-offcanvas-height: 30vh; + --bs-offcanvas-padding-x: 1rem; + --bs-offcanvas-padding-y: 1rem; + --bs-offcanvas-color: ; + --bs-offcanvas-bg: #fff; + --bs-offcanvas-border-width: 1px; + --bs-offcanvas-border-color: var(--bs-border-color-translucent); + --bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); +} + +@media (max-width: 575.98px) { + .offcanvas-sm { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-sm { + transition: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { + visibility: visible; + } +} +@media (min-width: 576px) { + .offcanvas-sm { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-sm .offcanvas-header { + display: none; + } + .offcanvas-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 767.98px) { + .offcanvas-md { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-md { + transition: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { + visibility: visible; + } +} +@media (min-width: 768px) { + .offcanvas-md { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-md .offcanvas-header { + display: none; + } + .offcanvas-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 991.98px) { + .offcanvas-lg { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-lg { + transition: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { + visibility: visible; + } +} +@media (min-width: 992px) { + .offcanvas-lg { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-lg .offcanvas-header { + display: none; + } + .offcanvas-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1199.98px) { + .offcanvas-xl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-xl { + transition: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { + visibility: visible; + } +} +@media (min-width: 1200px) { + .offcanvas-xl { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-xl .offcanvas-header { + display: none; + } + .offcanvas-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1399.98px) { + .offcanvas-xxl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-xxl { + transition: none; + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { + visibility: visible; + } +} +@media (min-width: 1400px) { + .offcanvas-xxl { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-xxl .offcanvas-header { + display: none; + } + .offcanvas-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +.offcanvas { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .offcanvas { + transition: none; + } +} +.offcanvas.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); +} +.offcanvas.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); +} +.offcanvas.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); +} +.offcanvas.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); +} +.offcanvas.showing, .offcanvas.show:not(.hiding) { + transform: none; +} +.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { + visibility: visible; +} + +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} +.offcanvas-backdrop.fade { + opacity: 0; +} +.offcanvas-backdrop.show { + opacity: 0.5; +} + +.offcanvas-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); +} +.offcanvas-header .btn-close { + padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5); + margin-top: calc(-0.5 * var(--bs-offcanvas-padding-y)); + margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x)); + margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y)); +} + +.offcanvas-title { + margin-bottom: 0; + line-height: 1.5; +} + +.offcanvas-body { + flex-grow: 1; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); + overflow-y: auto; +} + +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentcolor; + opacity: 0.5; +} +.placeholder.btn::before { + display: inline-block; + content: ""; +} + +.placeholder-xs { + min-height: 0.6em; +} + +.placeholder-sm { + min-height: 0.8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +.placeholder-glow .placeholder { + animation: placeholder-glow 2s ease-in-out infinite; +} + +@keyframes placeholder-glow { + 50% { + opacity: 0.2; + } +} +.placeholder-wave { + mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + mask-size: 200% 100%; + animation: placeholder-wave 2s linear infinite; +} + +@keyframes placeholder-wave { + 100% { + mask-position: -200% 0%; + } +} +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.text-bg-primary { + color: #fff !important; + background-color: RGBA(13, 110, 253, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-secondary { + color: #fff !important; + background-color: RGBA(108, 117, 125, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-success { + color: #fff !important; + background-color: RGBA(25, 135, 84, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-info { + color: #000 !important; + background-color: RGBA(13, 202, 240, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-warning { + color: #000 !important; + background-color: RGBA(255, 193, 7, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-danger { + color: #fff !important; + background-color: RGBA(220, 53, 69, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-light { + color: #000 !important; + background-color: RGBA(248, 249, 250, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-dark { + color: #fff !important; + background-color: RGBA(33, 37, 41, var(--bs-bg-opacity, 1)) !important; +} + +.link-primary { + color: #0d6efd !important; +} +.link-primary:hover, .link-primary:focus { + color: #0a58ca !important; +} + +.link-secondary { + color: #6c757d !important; +} +.link-secondary:hover, .link-secondary:focus { + color: #565e64 !important; +} + +.link-success { + color: #198754 !important; +} +.link-success:hover, .link-success:focus { + color: #146c43 !important; +} + +.link-info { + color: #0dcaf0 !important; +} +.link-info:hover, .link-info:focus { + color: #3dd5f3 !important; +} + +.link-warning { + color: #ffc107 !important; +} +.link-warning:hover, .link-warning:focus { + color: #ffcd39 !important; +} + +.link-danger { + color: #dc3545 !important; +} +.link-danger:hover, .link-danger:focus { + color: #b02a37 !important; +} + +.link-light { + color: #f8f9fa !important; +} +.link-light:hover, .link-light:focus { + color: #f9fafb !important; +} + +.link-dark { + color: #212529 !important; +} +.link-dark:hover, .link-dark:focus { + color: #1a1e21 !important; +} + +.ratio { + position: relative; + width: 100%; +} +.ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: ""; +} +.ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ratio-1x1 { + --bs-aspect-ratio: 100%; +} + +.ratio-4x3 { + --bs-aspect-ratio: 75%; +} + +.ratio-16x9 { + --bs-aspect-ratio: 56.25%; +} + +.ratio-21x9 { + --bs-aspect-ratio: 42.8571428571%; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +.sticky-top { + position: sticky; + top: 0; + z-index: 1020; +} + +.sticky-bottom { + position: sticky; + bottom: 0; + z-index: 1020; +} + +@media (min-width: 576px) { + .sticky-sm-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-sm-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 768px) { + .sticky-md-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-md-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 992px) { + .sticky-lg-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-lg-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 1200px) { + .sticky-xl-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-xl-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 1400px) { + .sticky-xxl-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-xxl-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: ""; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentcolor; + opacity: 0.25; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.float-start { + float: left !important; +} + +.float-end { + float: right !important; +} + +.float-none { + float: none !important; +} + +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.overflow-visible { + overflow: visible !important; +} + +.overflow-scroll { + overflow: scroll !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.shadow { + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; +} + +.shadow-sm { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: sticky !important; +} + +.top-0 { + top: 0 !important; +} + +.top-50 { + top: 50% !important; +} + +.top-100 { + top: 100% !important; +} + +.bottom-0 { + bottom: 0 !important; +} + +.bottom-50 { + bottom: 50% !important; +} + +.bottom-100 { + bottom: 100% !important; +} + +.start-0 { + left: 0 !important; +} + +.start-50 { + left: 50% !important; +} + +.start-100 { + left: 100% !important; +} + +.end-0 { + right: 0 !important; +} + +.end-50 { + right: 50% !important; +} + +.end-100 { + right: 100% !important; +} + +.translate-middle { + transform: translate(-50%, -50%) !important; +} + +.translate-middle-x { + transform: translateX(-50%) !important; +} + +.translate-middle-y { + transform: translateY(-50%) !important; +} + +.border { + border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top { + border-top: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-end { + border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-end-0 { + border-right: 0 !important; +} + +.border-bottom { + border-bottom: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-start { + border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-start-0 { + border-left: 0 !important; +} + +.border-primary { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important; +} + +.border-secondary { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important; +} + +.border-success { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important; +} + +.border-info { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important; +} + +.border-warning { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important; +} + +.border-danger { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important; +} + +.border-light { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important; +} + +.border-dark { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important; +} + +.border-white { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important; +} + +.border-1 { + --bs-border-width: 1px; +} + +.border-2 { + --bs-border-width: 2px; +} + +.border-3 { + --bs-border-width: 3px; +} + +.border-4 { + --bs-border-width: 4px; +} + +.border-5 { + --bs-border-width: 5px; +} + +.border-opacity-10 { + --bs-border-opacity: 0.1; +} + +.border-opacity-25 { + --bs-border-opacity: 0.25; +} + +.border-opacity-50 { + --bs-border-opacity: 0.5; +} + +.border-opacity-75 { + --bs-border-opacity: 0.75; +} + +.border-opacity-100 { + --bs-border-opacity: 1; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.vw-100 { + width: 100vw !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.vh-100 { + height: 100vh !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 3rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 3rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 3rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 3rem !important; +} + +.gap-0 { + gap: 0 !important; +} + +.gap-1 { + gap: 0.25rem !important; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + +.gap-4 { + gap: 1.5rem !important; +} + +.gap-5 { + gap: 3rem !important; +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important; +} + +.fs-1 { + font-size: calc(1.375rem + 1.5vw) !important; +} + +.fs-2 { + font-size: calc(1.325rem + 0.9vw) !important; +} + +.fs-3 { + font-size: calc(1.3rem + 0.6vw) !important; +} + +.fs-4 { + font-size: calc(1.275rem + 0.3vw) !important; +} + +.fs-5 { + font-size: 1.25rem !important; +} + +.fs-6 { + font-size: 1rem !important; +} + +.fst-italic { + font-style: italic !important; +} + +.fst-normal { + font-style: normal !important; +} + +.fw-light { + font-weight: 300 !important; +} + +.fw-lighter { + font-weight: lighter !important; +} + +.fw-normal { + font-weight: 400 !important; +} + +.fw-bold { + font-weight: 700 !important; +} + +.fw-semibold { + font-weight: 600 !important; +} + +.fw-bolder { + font-weight: bolder !important; +} + +.lh-1 { + line-height: 1 !important; +} + +.lh-sm { + line-height: 1.25 !important; +} + +.lh-base { + line-height: 1.5 !important; +} + +.lh-lg { + line-height: 2 !important; +} + +.text-start { + text-align: left !important; +} + +.text-end { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-decoration-underline { + text-decoration: underline !important; +} + +.text-decoration-line-through { + text-decoration: line-through !important; +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +/* rtl:begin:remove */ +.text-break { + word-wrap: break-word !important; + word-break: break-word !important; +} + +/* rtl:end:remove */ +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; +} + +.text-muted { + --bs-text-opacity: 1; + color: #6c757d !important; +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-reset { + --bs-text-opacity: 1; + color: inherit !important; +} + +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important; +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + +.bg-gradient { + background-image: var(--bs-gradient) !important; +} + +.user-select-all { + user-select: all !important; +} + +.user-select-auto { + user-select: auto !important; +} + +.user-select-none { + user-select: none !important; +} + +.pe-none { + pointer-events: none !important; +} + +.pe-auto { + pointer-events: auto !important; +} + +.rounded { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.rounded-1 { + border-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-2 { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-3 { + border-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-4 { + border-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-5 { + border-radius: var(--bs-border-radius-2xl) !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-top { + border-top-left-radius: var(--bs-border-radius) !important; + border-top-right-radius: var(--bs-border-radius) !important; +} + +.rounded-end { + border-top-right-radius: var(--bs-border-radius) !important; + border-bottom-right-radius: var(--bs-border-radius) !important; +} + +.rounded-bottom { + border-bottom-right-radius: var(--bs-border-radius) !important; + border-bottom-left-radius: var(--bs-border-radius) !important; +} + +.rounded-start { + border-bottom-left-radius: var(--bs-border-radius) !important; + border-top-left-radius: var(--bs-border-radius) !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media (min-width: 576px) { + .float-sm-start { + float: left !important; + } + .float-sm-end { + float: right !important; + } + .float-sm-none { + float: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-sm-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-sm-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-sm-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 3rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-right: 0 !important; + } + .me-sm-1 { + margin-right: 0.25rem !important; + } + .me-sm-2 { + margin-right: 0.5rem !important; + } + .me-sm-3 { + margin-right: 1rem !important; + } + .me-sm-4 { + margin-right: 1.5rem !important; + } + .me-sm-5 { + margin-right: 3rem !important; + } + .me-sm-auto { + margin-right: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 3rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-left: 0 !important; + } + .ms-sm-1 { + margin-left: 0.25rem !important; + } + .ms-sm-2 { + margin-left: 0.5rem !important; + } + .ms-sm-3 { + margin-left: 1rem !important; + } + .ms-sm-4 { + margin-left: 1.5rem !important; + } + .ms-sm-5 { + margin-left: 3rem !important; + } + .ms-sm-auto { + margin-left: auto !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-sm-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-sm-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-sm-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 3rem !important; + } + .pe-sm-0 { + padding-right: 0 !important; + } + .pe-sm-1 { + padding-right: 0.25rem !important; + } + .pe-sm-2 { + padding-right: 0.5rem !important; + } + .pe-sm-3 { + padding-right: 1rem !important; + } + .pe-sm-4 { + padding-right: 1.5rem !important; + } + .pe-sm-5 { + padding-right: 3rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 3rem !important; + } + .ps-sm-0 { + padding-left: 0 !important; + } + .ps-sm-1 { + padding-left: 0.25rem !important; + } + .ps-sm-2 { + padding-left: 0.5rem !important; + } + .ps-sm-3 { + padding-left: 1rem !important; + } + .ps-sm-4 { + padding-left: 1.5rem !important; + } + .ps-sm-5 { + padding-left: 3rem !important; + } + .gap-sm-0 { + gap: 0 !important; + } + .gap-sm-1 { + gap: 0.25rem !important; + } + .gap-sm-2 { + gap: 0.5rem !important; + } + .gap-sm-3 { + gap: 1rem !important; + } + .gap-sm-4 { + gap: 1.5rem !important; + } + .gap-sm-5 { + gap: 3rem !important; + } + .text-sm-start { + text-align: left !important; + } + .text-sm-end { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} +@media (min-width: 768px) { + .float-md-start { + float: left !important; + } + .float-md-end { + float: right !important; + } + .float-md-none { + float: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-md-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-md-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-md-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 3rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-right: 0 !important; + } + .me-md-1 { + margin-right: 0.25rem !important; + } + .me-md-2 { + margin-right: 0.5rem !important; + } + .me-md-3 { + margin-right: 1rem !important; + } + .me-md-4 { + margin-right: 1.5rem !important; + } + .me-md-5 { + margin-right: 3rem !important; + } + .me-md-auto { + margin-right: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 3rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-left: 0 !important; + } + .ms-md-1 { + margin-left: 0.25rem !important; + } + .ms-md-2 { + margin-left: 0.5rem !important; + } + .ms-md-3 { + margin-left: 1rem !important; + } + .ms-md-4 { + margin-left: 1.5rem !important; + } + .ms-md-5 { + margin-left: 3rem !important; + } + .ms-md-auto { + margin-left: auto !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-md-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-md-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-md-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 3rem !important; + } + .pe-md-0 { + padding-right: 0 !important; + } + .pe-md-1 { + padding-right: 0.25rem !important; + } + .pe-md-2 { + padding-right: 0.5rem !important; + } + .pe-md-3 { + padding-right: 1rem !important; + } + .pe-md-4 { + padding-right: 1.5rem !important; + } + .pe-md-5 { + padding-right: 3rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 3rem !important; + } + .ps-md-0 { + padding-left: 0 !important; + } + .ps-md-1 { + padding-left: 0.25rem !important; + } + .ps-md-2 { + padding-left: 0.5rem !important; + } + .ps-md-3 { + padding-left: 1rem !important; + } + .ps-md-4 { + padding-left: 1.5rem !important; + } + .ps-md-5 { + padding-left: 3rem !important; + } + .gap-md-0 { + gap: 0 !important; + } + .gap-md-1 { + gap: 0.25rem !important; + } + .gap-md-2 { + gap: 0.5rem !important; + } + .gap-md-3 { + gap: 1rem !important; + } + .gap-md-4 { + gap: 1.5rem !important; + } + .gap-md-5 { + gap: 3rem !important; + } + .text-md-start { + text-align: left !important; + } + .text-md-end { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} +@media (min-width: 992px) { + .float-lg-start { + float: left !important; + } + .float-lg-end { + float: right !important; + } + .float-lg-none { + float: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-lg-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-lg-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-lg-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 3rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-right: 0 !important; + } + .me-lg-1 { + margin-right: 0.25rem !important; + } + .me-lg-2 { + margin-right: 0.5rem !important; + } + .me-lg-3 { + margin-right: 1rem !important; + } + .me-lg-4 { + margin-right: 1.5rem !important; + } + .me-lg-5 { + margin-right: 3rem !important; + } + .me-lg-auto { + margin-right: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 3rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-left: 0 !important; + } + .ms-lg-1 { + margin-left: 0.25rem !important; + } + .ms-lg-2 { + margin-left: 0.5rem !important; + } + .ms-lg-3 { + margin-left: 1rem !important; + } + .ms-lg-4 { + margin-left: 1.5rem !important; + } + .ms-lg-5 { + margin-left: 3rem !important; + } + .ms-lg-auto { + margin-left: auto !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-lg-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-lg-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-lg-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 3rem !important; + } + .pe-lg-0 { + padding-right: 0 !important; + } + .pe-lg-1 { + padding-right: 0.25rem !important; + } + .pe-lg-2 { + padding-right: 0.5rem !important; + } + .pe-lg-3 { + padding-right: 1rem !important; + } + .pe-lg-4 { + padding-right: 1.5rem !important; + } + .pe-lg-5 { + padding-right: 3rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 3rem !important; + } + .ps-lg-0 { + padding-left: 0 !important; + } + .ps-lg-1 { + padding-left: 0.25rem !important; + } + .ps-lg-2 { + padding-left: 0.5rem !important; + } + .ps-lg-3 { + padding-left: 1rem !important; + } + .ps-lg-4 { + padding-left: 1.5rem !important; + } + .ps-lg-5 { + padding-left: 3rem !important; + } + .gap-lg-0 { + gap: 0 !important; + } + .gap-lg-1 { + gap: 0.25rem !important; + } + .gap-lg-2 { + gap: 0.5rem !important; + } + .gap-lg-3 { + gap: 1rem !important; + } + .gap-lg-4 { + gap: 1.5rem !important; + } + .gap-lg-5 { + gap: 3rem !important; + } + .text-lg-start { + text-align: left !important; + } + .text-lg-end { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} +@media (min-width: 1200px) { + .float-xl-start { + float: left !important; + } + .float-xl-end { + float: right !important; + } + .float-xl-none { + float: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 3rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-right: 0 !important; + } + .me-xl-1 { + margin-right: 0.25rem !important; + } + .me-xl-2 { + margin-right: 0.5rem !important; + } + .me-xl-3 { + margin-right: 1rem !important; + } + .me-xl-4 { + margin-right: 1.5rem !important; + } + .me-xl-5 { + margin-right: 3rem !important; + } + .me-xl-auto { + margin-right: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 3rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-left: 0 !important; + } + .ms-xl-1 { + margin-left: 0.25rem !important; + } + .ms-xl-2 { + margin-left: 0.5rem !important; + } + .ms-xl-3 { + margin-left: 1rem !important; + } + .ms-xl-4 { + margin-left: 1.5rem !important; + } + .ms-xl-5 { + margin-left: 3rem !important; + } + .ms-xl-auto { + margin-left: auto !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 3rem !important; + } + .pe-xl-0 { + padding-right: 0 !important; + } + .pe-xl-1 { + padding-right: 0.25rem !important; + } + .pe-xl-2 { + padding-right: 0.5rem !important; + } + .pe-xl-3 { + padding-right: 1rem !important; + } + .pe-xl-4 { + padding-right: 1.5rem !important; + } + .pe-xl-5 { + padding-right: 3rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 3rem !important; + } + .ps-xl-0 { + padding-left: 0 !important; + } + .ps-xl-1 { + padding-left: 0.25rem !important; + } + .ps-xl-2 { + padding-left: 0.5rem !important; + } + .ps-xl-3 { + padding-left: 1rem !important; + } + .ps-xl-4 { + padding-left: 1.5rem !important; + } + .ps-xl-5 { + padding-left: 3rem !important; + } + .gap-xl-0 { + gap: 0 !important; + } + .gap-xl-1 { + gap: 0.25rem !important; + } + .gap-xl-2 { + gap: 0.5rem !important; + } + .gap-xl-3 { + gap: 1rem !important; + } + .gap-xl-4 { + gap: 1.5rem !important; + } + .gap-xl-5 { + gap: 3rem !important; + } + .text-xl-start { + text-align: left !important; + } + .text-xl-end { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} +@media (min-width: 1400px) { + .float-xxl-start { + float: left !important; + } + .float-xxl-end { + float: right !important; + } + .float-xxl-none { + float: none !important; + } + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 3rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xxl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xxl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xxl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 3rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-right: 0 !important; + } + .me-xxl-1 { + margin-right: 0.25rem !important; + } + .me-xxl-2 { + margin-right: 0.5rem !important; + } + .me-xxl-3 { + margin-right: 1rem !important; + } + .me-xxl-4 { + margin-right: 1.5rem !important; + } + .me-xxl-5 { + margin-right: 3rem !important; + } + .me-xxl-auto { + margin-right: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 3rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-left: 0 !important; + } + .ms-xxl-1 { + margin-left: 0.25rem !important; + } + .ms-xxl-2 { + margin-left: 0.5rem !important; + } + .ms-xxl-3 { + margin-left: 1rem !important; + } + .ms-xxl-4 { + margin-left: 1.5rem !important; + } + .ms-xxl-5 { + margin-left: 3rem !important; + } + .ms-xxl-auto { + margin-left: auto !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 3rem !important; + } + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xxl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xxl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xxl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 3rem !important; + } + .pe-xxl-0 { + padding-right: 0 !important; + } + .pe-xxl-1 { + padding-right: 0.25rem !important; + } + .pe-xxl-2 { + padding-right: 0.5rem !important; + } + .pe-xxl-3 { + padding-right: 1rem !important; + } + .pe-xxl-4 { + padding-right: 1.5rem !important; + } + .pe-xxl-5 { + padding-right: 3rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 3rem !important; + } + .ps-xxl-0 { + padding-left: 0 !important; + } + .ps-xxl-1 { + padding-left: 0.25rem !important; + } + .ps-xxl-2 { + padding-left: 0.5rem !important; + } + .ps-xxl-3 { + padding-left: 1rem !important; + } + .ps-xxl-4 { + padding-left: 1.5rem !important; + } + .ps-xxl-5 { + padding-left: 3rem !important; + } + .gap-xxl-0 { + gap: 0 !important; + } + .gap-xxl-1 { + gap: 0.25rem !important; + } + .gap-xxl-2 { + gap: 0.5rem !important; + } + .gap-xxl-3 { + gap: 1rem !important; + } + .gap-xxl-4 { + gap: 1.5rem !important; + } + .gap-xxl-5 { + gap: 3rem !important; + } + .text-xxl-start { + text-align: left !important; + } + .text-xxl-end { + text-align: right !important; + } + .text-xxl-center { + text-align: center !important; + } +} +@media (min-width: 1200px) { + .fs-1 { + font-size: 2.5rem !important; + } + .fs-2 { + font-size: 2rem !important; + } + .fs-3 { + font-size: 1.75rem !important; + } + .fs-4 { + font-size: 1.5rem !important; + } +} +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} +@font-face { + font-display: block; + font-family: "bootstrap-icons"; + src: url("./fonts/bootstrap-icons.woff2?24e3eb84d0bcaf83d77f904c78ac1f47") format("woff2"), url("./fonts/bootstrap-icons.woff?24e3eb84d0bcaf83d77f904c78ac1f47") format("woff"); +} +.bi::before, +[class^=bi-]::before, +[class*=" bi-"]::before { + display: inline-block; + font-family: "bootstrap-icons" !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -0.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bi-123::before { + content: "\f67f"; +} + +.bi-alarm-fill::before { + content: "\f101"; +} + +.bi-alarm::before { + content: "\f102"; +} + +.bi-align-bottom::before { + content: "\f103"; +} + +.bi-align-center::before { + content: "\f104"; +} + +.bi-align-end::before { + content: "\f105"; +} + +.bi-align-middle::before { + content: "\f106"; +} + +.bi-align-start::before { + content: "\f107"; +} + +.bi-align-top::before { + content: "\f108"; +} + +.bi-alt::before { + content: "\f109"; +} + +.bi-app-indicator::before { + content: "\f10a"; +} + +.bi-app::before { + content: "\f10b"; +} + +.bi-archive-fill::before { + content: "\f10c"; +} + +.bi-archive::before { + content: "\f10d"; +} + +.bi-arrow-90deg-down::before { + content: "\f10e"; +} + +.bi-arrow-90deg-left::before { + content: "\f10f"; +} + +.bi-arrow-90deg-right::before { + content: "\f110"; +} + +.bi-arrow-90deg-up::before { + content: "\f111"; +} + +.bi-arrow-bar-down::before { + content: "\f112"; +} + +.bi-arrow-bar-left::before { + content: "\f113"; +} + +.bi-arrow-bar-right::before { + content: "\f114"; +} + +.bi-arrow-bar-up::before { + content: "\f115"; +} + +.bi-arrow-clockwise::before { + content: "\f116"; +} + +.bi-arrow-counterclockwise::before { + content: "\f117"; +} + +.bi-arrow-down-circle-fill::before { + content: "\f118"; +} + +.bi-arrow-down-circle::before { + content: "\f119"; +} + +.bi-arrow-down-left-circle-fill::before { + content: "\f11a"; +} + +.bi-arrow-down-left-circle::before { + content: "\f11b"; +} + +.bi-arrow-down-left-square-fill::before { + content: "\f11c"; +} + +.bi-arrow-down-left-square::before { + content: "\f11d"; +} + +.bi-arrow-down-left::before { + content: "\f11e"; +} + +.bi-arrow-down-right-circle-fill::before { + content: "\f11f"; +} + +.bi-arrow-down-right-circle::before { + content: "\f120"; +} + +.bi-arrow-down-right-square-fill::before { + content: "\f121"; +} + +.bi-arrow-down-right-square::before { + content: "\f122"; +} + +.bi-arrow-down-right::before { + content: "\f123"; +} + +.bi-arrow-down-short::before { + content: "\f124"; +} + +.bi-arrow-down-square-fill::before { + content: "\f125"; +} + +.bi-arrow-down-square::before { + content: "\f126"; +} + +.bi-arrow-down-up::before { + content: "\f127"; +} + +.bi-arrow-down::before { + content: "\f128"; +} + +.bi-arrow-left-circle-fill::before { + content: "\f129"; +} + +.bi-arrow-left-circle::before { + content: "\f12a"; +} + +.bi-arrow-left-right::before { + content: "\f12b"; +} + +.bi-arrow-left-short::before { + content: "\f12c"; +} + +.bi-arrow-left-square-fill::before { + content: "\f12d"; +} + +.bi-arrow-left-square::before { + content: "\f12e"; +} + +.bi-arrow-left::before { + content: "\f12f"; +} + +.bi-arrow-repeat::before { + content: "\f130"; +} + +.bi-arrow-return-left::before { + content: "\f131"; +} + +.bi-arrow-return-right::before { + content: "\f132"; +} + +.bi-arrow-right-circle-fill::before { + content: "\f133"; +} + +.bi-arrow-right-circle::before { + content: "\f134"; +} + +.bi-arrow-right-short::before { + content: "\f135"; +} + +.bi-arrow-right-square-fill::before { + content: "\f136"; +} + +.bi-arrow-right-square::before { + content: "\f137"; +} + +.bi-arrow-right::before { + content: "\f138"; +} + +.bi-arrow-up-circle-fill::before { + content: "\f139"; +} + +.bi-arrow-up-circle::before { + content: "\f13a"; +} + +.bi-arrow-up-left-circle-fill::before { + content: "\f13b"; +} + +.bi-arrow-up-left-circle::before { + content: "\f13c"; +} + +.bi-arrow-up-left-square-fill::before { + content: "\f13d"; +} + +.bi-arrow-up-left-square::before { + content: "\f13e"; +} + +.bi-arrow-up-left::before { + content: "\f13f"; +} + +.bi-arrow-up-right-circle-fill::before { + content: "\f140"; +} + +.bi-arrow-up-right-circle::before { + content: "\f141"; +} + +.bi-arrow-up-right-square-fill::before { + content: "\f142"; +} + +.bi-arrow-up-right-square::before { + content: "\f143"; +} + +.bi-arrow-up-right::before { + content: "\f144"; +} + +.bi-arrow-up-short::before { + content: "\f145"; +} + +.bi-arrow-up-square-fill::before { + content: "\f146"; +} + +.bi-arrow-up-square::before { + content: "\f147"; +} + +.bi-arrow-up::before { + content: "\f148"; +} + +.bi-arrows-angle-contract::before { + content: "\f149"; +} + +.bi-arrows-angle-expand::before { + content: "\f14a"; +} + +.bi-arrows-collapse::before { + content: "\f14b"; +} + +.bi-arrows-expand::before { + content: "\f14c"; +} + +.bi-arrows-fullscreen::before { + content: "\f14d"; +} + +.bi-arrows-move::before { + content: "\f14e"; +} + +.bi-aspect-ratio-fill::before { + content: "\f14f"; +} + +.bi-aspect-ratio::before { + content: "\f150"; +} + +.bi-asterisk::before { + content: "\f151"; +} + +.bi-at::before { + content: "\f152"; +} + +.bi-award-fill::before { + content: "\f153"; +} + +.bi-award::before { + content: "\f154"; +} + +.bi-back::before { + content: "\f155"; +} + +.bi-backspace-fill::before { + content: "\f156"; +} + +.bi-backspace-reverse-fill::before { + content: "\f157"; +} + +.bi-backspace-reverse::before { + content: "\f158"; +} + +.bi-backspace::before { + content: "\f159"; +} + +.bi-badge-3d-fill::before { + content: "\f15a"; +} + +.bi-badge-3d::before { + content: "\f15b"; +} + +.bi-badge-4k-fill::before { + content: "\f15c"; +} + +.bi-badge-4k::before { + content: "\f15d"; +} + +.bi-badge-8k-fill::before { + content: "\f15e"; +} + +.bi-badge-8k::before { + content: "\f15f"; +} + +.bi-badge-ad-fill::before { + content: "\f160"; +} + +.bi-badge-ad::before { + content: "\f161"; +} + +.bi-badge-ar-fill::before { + content: "\f162"; +} + +.bi-badge-ar::before { + content: "\f163"; +} + +.bi-badge-cc-fill::before { + content: "\f164"; +} + +.bi-badge-cc::before { + content: "\f165"; +} + +.bi-badge-hd-fill::before { + content: "\f166"; +} + +.bi-badge-hd::before { + content: "\f167"; +} + +.bi-badge-tm-fill::before { + content: "\f168"; +} + +.bi-badge-tm::before { + content: "\f169"; +} + +.bi-badge-vo-fill::before { + content: "\f16a"; +} + +.bi-badge-vo::before { + content: "\f16b"; +} + +.bi-badge-vr-fill::before { + content: "\f16c"; +} + +.bi-badge-vr::before { + content: "\f16d"; +} + +.bi-badge-wc-fill::before { + content: "\f16e"; +} + +.bi-badge-wc::before { + content: "\f16f"; +} + +.bi-bag-check-fill::before { + content: "\f170"; +} + +.bi-bag-check::before { + content: "\f171"; +} + +.bi-bag-dash-fill::before { + content: "\f172"; +} + +.bi-bag-dash::before { + content: "\f173"; +} + +.bi-bag-fill::before { + content: "\f174"; +} + +.bi-bag-plus-fill::before { + content: "\f175"; +} + +.bi-bag-plus::before { + content: "\f176"; +} + +.bi-bag-x-fill::before { + content: "\f177"; +} + +.bi-bag-x::before { + content: "\f178"; +} + +.bi-bag::before { + content: "\f179"; +} + +.bi-bar-chart-fill::before { + content: "\f17a"; +} + +.bi-bar-chart-line-fill::before { + content: "\f17b"; +} + +.bi-bar-chart-line::before { + content: "\f17c"; +} + +.bi-bar-chart-steps::before { + content: "\f17d"; +} + +.bi-bar-chart::before { + content: "\f17e"; +} + +.bi-basket-fill::before { + content: "\f17f"; +} + +.bi-basket::before { + content: "\f180"; +} + +.bi-basket2-fill::before { + content: "\f181"; +} + +.bi-basket2::before { + content: "\f182"; +} + +.bi-basket3-fill::before { + content: "\f183"; +} + +.bi-basket3::before { + content: "\f184"; +} + +.bi-battery-charging::before { + content: "\f185"; +} + +.bi-battery-full::before { + content: "\f186"; +} + +.bi-battery-half::before { + content: "\f187"; +} + +.bi-battery::before { + content: "\f188"; +} + +.bi-bell-fill::before { + content: "\f189"; +} + +.bi-bell::before { + content: "\f18a"; +} + +.bi-bezier::before { + content: "\f18b"; +} + +.bi-bezier2::before { + content: "\f18c"; +} + +.bi-bicycle::before { + content: "\f18d"; +} + +.bi-binoculars-fill::before { + content: "\f18e"; +} + +.bi-binoculars::before { + content: "\f18f"; +} + +.bi-blockquote-left::before { + content: "\f190"; +} + +.bi-blockquote-right::before { + content: "\f191"; +} + +.bi-book-fill::before { + content: "\f192"; +} + +.bi-book-half::before { + content: "\f193"; +} + +.bi-book::before { + content: "\f194"; +} + +.bi-bookmark-check-fill::before { + content: "\f195"; +} + +.bi-bookmark-check::before { + content: "\f196"; +} + +.bi-bookmark-dash-fill::before { + content: "\f197"; +} + +.bi-bookmark-dash::before { + content: "\f198"; +} + +.bi-bookmark-fill::before { + content: "\f199"; +} + +.bi-bookmark-heart-fill::before { + content: "\f19a"; +} + +.bi-bookmark-heart::before { + content: "\f19b"; +} + +.bi-bookmark-plus-fill::before { + content: "\f19c"; +} + +.bi-bookmark-plus::before { + content: "\f19d"; +} + +.bi-bookmark-star-fill::before { + content: "\f19e"; +} + +.bi-bookmark-star::before { + content: "\f19f"; +} + +.bi-bookmark-x-fill::before { + content: "\f1a0"; +} + +.bi-bookmark-x::before { + content: "\f1a1"; +} + +.bi-bookmark::before { + content: "\f1a2"; +} + +.bi-bookmarks-fill::before { + content: "\f1a3"; +} + +.bi-bookmarks::before { + content: "\f1a4"; +} + +.bi-bookshelf::before { + content: "\f1a5"; +} + +.bi-bootstrap-fill::before { + content: "\f1a6"; +} + +.bi-bootstrap-reboot::before { + content: "\f1a7"; +} + +.bi-bootstrap::before { + content: "\f1a8"; +} + +.bi-border-all::before { + content: "\f1a9"; +} + +.bi-border-bottom::before { + content: "\f1aa"; +} + +.bi-border-center::before { + content: "\f1ab"; +} + +.bi-border-inner::before { + content: "\f1ac"; +} + +.bi-border-left::before { + content: "\f1ad"; +} + +.bi-border-middle::before { + content: "\f1ae"; +} + +.bi-border-outer::before { + content: "\f1af"; +} + +.bi-border-right::before { + content: "\f1b0"; +} + +.bi-border-style::before { + content: "\f1b1"; +} + +.bi-border-top::before { + content: "\f1b2"; +} + +.bi-border-width::before { + content: "\f1b3"; +} + +.bi-border::before { + content: "\f1b4"; +} + +.bi-bounding-box-circles::before { + content: "\f1b5"; +} + +.bi-bounding-box::before { + content: "\f1b6"; +} + +.bi-box-arrow-down-left::before { + content: "\f1b7"; +} + +.bi-box-arrow-down-right::before { + content: "\f1b8"; +} + +.bi-box-arrow-down::before { + content: "\f1b9"; +} + +.bi-box-arrow-in-down-left::before { + content: "\f1ba"; +} + +.bi-box-arrow-in-down-right::before { + content: "\f1bb"; +} + +.bi-box-arrow-in-down::before { + content: "\f1bc"; +} + +.bi-box-arrow-in-left::before { + content: "\f1bd"; +} + +.bi-box-arrow-in-right::before { + content: "\f1be"; +} + +.bi-box-arrow-in-up-left::before { + content: "\f1bf"; +} + +.bi-box-arrow-in-up-right::before { + content: "\f1c0"; +} + +.bi-box-arrow-in-up::before { + content: "\f1c1"; +} + +.bi-box-arrow-left::before { + content: "\f1c2"; +} + +.bi-box-arrow-right::before { + content: "\f1c3"; +} + +.bi-box-arrow-up-left::before { + content: "\f1c4"; +} + +.bi-box-arrow-up-right::before { + content: "\f1c5"; +} + +.bi-box-arrow-up::before { + content: "\f1c6"; +} + +.bi-box-seam::before { + content: "\f1c7"; +} + +.bi-box::before { + content: "\f1c8"; +} + +.bi-braces::before { + content: "\f1c9"; +} + +.bi-bricks::before { + content: "\f1ca"; +} + +.bi-briefcase-fill::before { + content: "\f1cb"; +} + +.bi-briefcase::before { + content: "\f1cc"; +} + +.bi-brightness-alt-high-fill::before { + content: "\f1cd"; +} + +.bi-brightness-alt-high::before { + content: "\f1ce"; +} + +.bi-brightness-alt-low-fill::before { + content: "\f1cf"; +} + +.bi-brightness-alt-low::before { + content: "\f1d0"; +} + +.bi-brightness-high-fill::before { + content: "\f1d1"; +} + +.bi-brightness-high::before { + content: "\f1d2"; +} + +.bi-brightness-low-fill::before { + content: "\f1d3"; +} + +.bi-brightness-low::before { + content: "\f1d4"; +} + +.bi-broadcast-pin::before { + content: "\f1d5"; +} + +.bi-broadcast::before { + content: "\f1d6"; +} + +.bi-brush-fill::before { + content: "\f1d7"; +} + +.bi-brush::before { + content: "\f1d8"; +} + +.bi-bucket-fill::before { + content: "\f1d9"; +} + +.bi-bucket::before { + content: "\f1da"; +} + +.bi-bug-fill::before { + content: "\f1db"; +} + +.bi-bug::before { + content: "\f1dc"; +} + +.bi-building::before { + content: "\f1dd"; +} + +.bi-bullseye::before { + content: "\f1de"; +} + +.bi-calculator-fill::before { + content: "\f1df"; +} + +.bi-calculator::before { + content: "\f1e0"; +} + +.bi-calendar-check-fill::before { + content: "\f1e1"; +} + +.bi-calendar-check::before { + content: "\f1e2"; +} + +.bi-calendar-date-fill::before { + content: "\f1e3"; +} + +.bi-calendar-date::before { + content: "\f1e4"; +} + +.bi-calendar-day-fill::before { + content: "\f1e5"; +} + +.bi-calendar-day::before { + content: "\f1e6"; +} + +.bi-calendar-event-fill::before { + content: "\f1e7"; +} + +.bi-calendar-event::before { + content: "\f1e8"; +} + +.bi-calendar-fill::before { + content: "\f1e9"; +} + +.bi-calendar-minus-fill::before { + content: "\f1ea"; +} + +.bi-calendar-minus::before { + content: "\f1eb"; +} + +.bi-calendar-month-fill::before { + content: "\f1ec"; +} + +.bi-calendar-month::before { + content: "\f1ed"; +} + +.bi-calendar-plus-fill::before { + content: "\f1ee"; +} + +.bi-calendar-plus::before { + content: "\f1ef"; +} + +.bi-calendar-range-fill::before { + content: "\f1f0"; +} + +.bi-calendar-range::before { + content: "\f1f1"; +} + +.bi-calendar-week-fill::before { + content: "\f1f2"; +} + +.bi-calendar-week::before { + content: "\f1f3"; +} + +.bi-calendar-x-fill::before { + content: "\f1f4"; +} + +.bi-calendar-x::before { + content: "\f1f5"; +} + +.bi-calendar::before { + content: "\f1f6"; +} + +.bi-calendar2-check-fill::before { + content: "\f1f7"; +} + +.bi-calendar2-check::before { + content: "\f1f8"; +} + +.bi-calendar2-date-fill::before { + content: "\f1f9"; +} + +.bi-calendar2-date::before { + content: "\f1fa"; +} + +.bi-calendar2-day-fill::before { + content: "\f1fb"; +} + +.bi-calendar2-day::before { + content: "\f1fc"; +} + +.bi-calendar2-event-fill::before { + content: "\f1fd"; +} + +.bi-calendar2-event::before { + content: "\f1fe"; +} + +.bi-calendar2-fill::before { + content: "\f1ff"; +} + +.bi-calendar2-minus-fill::before { + content: "\f200"; +} + +.bi-calendar2-minus::before { + content: "\f201"; +} + +.bi-calendar2-month-fill::before { + content: "\f202"; +} + +.bi-calendar2-month::before { + content: "\f203"; +} + +.bi-calendar2-plus-fill::before { + content: "\f204"; +} + +.bi-calendar2-plus::before { + content: "\f205"; +} + +.bi-calendar2-range-fill::before { + content: "\f206"; +} + +.bi-calendar2-range::before { + content: "\f207"; +} + +.bi-calendar2-week-fill::before { + content: "\f208"; +} + +.bi-calendar2-week::before { + content: "\f209"; +} + +.bi-calendar2-x-fill::before { + content: "\f20a"; +} + +.bi-calendar2-x::before { + content: "\f20b"; +} + +.bi-calendar2::before { + content: "\f20c"; +} + +.bi-calendar3-event-fill::before { + content: "\f20d"; +} + +.bi-calendar3-event::before { + content: "\f20e"; +} + +.bi-calendar3-fill::before { + content: "\f20f"; +} + +.bi-calendar3-range-fill::before { + content: "\f210"; +} + +.bi-calendar3-range::before { + content: "\f211"; +} + +.bi-calendar3-week-fill::before { + content: "\f212"; +} + +.bi-calendar3-week::before { + content: "\f213"; +} + +.bi-calendar3::before { + content: "\f214"; +} + +.bi-calendar4-event::before { + content: "\f215"; +} + +.bi-calendar4-range::before { + content: "\f216"; +} + +.bi-calendar4-week::before { + content: "\f217"; +} + +.bi-calendar4::before { + content: "\f218"; +} + +.bi-camera-fill::before { + content: "\f219"; +} + +.bi-camera-reels-fill::before { + content: "\f21a"; +} + +.bi-camera-reels::before { + content: "\f21b"; +} + +.bi-camera-video-fill::before { + content: "\f21c"; +} + +.bi-camera-video-off-fill::before { + content: "\f21d"; +} + +.bi-camera-video-off::before { + content: "\f21e"; +} + +.bi-camera-video::before { + content: "\f21f"; +} + +.bi-camera::before { + content: "\f220"; +} + +.bi-camera2::before { + content: "\f221"; +} + +.bi-capslock-fill::before { + content: "\f222"; +} + +.bi-capslock::before { + content: "\f223"; +} + +.bi-card-checklist::before { + content: "\f224"; +} + +.bi-card-heading::before { + content: "\f225"; +} + +.bi-card-image::before { + content: "\f226"; +} + +.bi-card-list::before { + content: "\f227"; +} + +.bi-card-text::before { + content: "\f228"; +} + +.bi-caret-down-fill::before { + content: "\f229"; +} + +.bi-caret-down-square-fill::before { + content: "\f22a"; +} + +.bi-caret-down-square::before { + content: "\f22b"; +} + +.bi-caret-down::before { + content: "\f22c"; +} + +.bi-caret-left-fill::before { + content: "\f22d"; +} + +.bi-caret-left-square-fill::before { + content: "\f22e"; +} + +.bi-caret-left-square::before { + content: "\f22f"; +} + +.bi-caret-left::before { + content: "\f230"; +} + +.bi-caret-right-fill::before { + content: "\f231"; +} + +.bi-caret-right-square-fill::before { + content: "\f232"; +} + +.bi-caret-right-square::before { + content: "\f233"; +} + +.bi-caret-right::before { + content: "\f234"; +} + +.bi-caret-up-fill::before { + content: "\f235"; +} + +.bi-caret-up-square-fill::before { + content: "\f236"; +} + +.bi-caret-up-square::before { + content: "\f237"; +} + +.bi-caret-up::before { + content: "\f238"; +} + +.bi-cart-check-fill::before { + content: "\f239"; +} + +.bi-cart-check::before { + content: "\f23a"; +} + +.bi-cart-dash-fill::before { + content: "\f23b"; +} + +.bi-cart-dash::before { + content: "\f23c"; +} + +.bi-cart-fill::before { + content: "\f23d"; +} + +.bi-cart-plus-fill::before { + content: "\f23e"; +} + +.bi-cart-plus::before { + content: "\f23f"; +} + +.bi-cart-x-fill::before { + content: "\f240"; +} + +.bi-cart-x::before { + content: "\f241"; +} + +.bi-cart::before { + content: "\f242"; +} + +.bi-cart2::before { + content: "\f243"; +} + +.bi-cart3::before { + content: "\f244"; +} + +.bi-cart4::before { + content: "\f245"; +} + +.bi-cash-stack::before { + content: "\f246"; +} + +.bi-cash::before { + content: "\f247"; +} + +.bi-cast::before { + content: "\f248"; +} + +.bi-chat-dots-fill::before { + content: "\f249"; +} + +.bi-chat-dots::before { + content: "\f24a"; +} + +.bi-chat-fill::before { + content: "\f24b"; +} + +.bi-chat-left-dots-fill::before { + content: "\f24c"; +} + +.bi-chat-left-dots::before { + content: "\f24d"; +} + +.bi-chat-left-fill::before { + content: "\f24e"; +} + +.bi-chat-left-quote-fill::before { + content: "\f24f"; +} + +.bi-chat-left-quote::before { + content: "\f250"; +} + +.bi-chat-left-text-fill::before { + content: "\f251"; +} + +.bi-chat-left-text::before { + content: "\f252"; +} + +.bi-chat-left::before { + content: "\f253"; +} + +.bi-chat-quote-fill::before { + content: "\f254"; +} + +.bi-chat-quote::before { + content: "\f255"; +} + +.bi-chat-right-dots-fill::before { + content: "\f256"; +} + +.bi-chat-right-dots::before { + content: "\f257"; +} + +.bi-chat-right-fill::before { + content: "\f258"; +} + +.bi-chat-right-quote-fill::before { + content: "\f259"; +} + +.bi-chat-right-quote::before { + content: "\f25a"; +} + +.bi-chat-right-text-fill::before { + content: "\f25b"; +} + +.bi-chat-right-text::before { + content: "\f25c"; +} + +.bi-chat-right::before { + content: "\f25d"; +} + +.bi-chat-square-dots-fill::before { + content: "\f25e"; +} + +.bi-chat-square-dots::before { + content: "\f25f"; +} + +.bi-chat-square-fill::before { + content: "\f260"; +} + +.bi-chat-square-quote-fill::before { + content: "\f261"; +} + +.bi-chat-square-quote::before { + content: "\f262"; +} + +.bi-chat-square-text-fill::before { + content: "\f263"; +} + +.bi-chat-square-text::before { + content: "\f264"; +} + +.bi-chat-square::before { + content: "\f265"; +} + +.bi-chat-text-fill::before { + content: "\f266"; +} + +.bi-chat-text::before { + content: "\f267"; +} + +.bi-chat::before { + content: "\f268"; +} + +.bi-check-all::before { + content: "\f269"; +} + +.bi-check-circle-fill::before { + content: "\f26a"; +} + +.bi-check-circle::before { + content: "\f26b"; +} + +.bi-check-square-fill::before { + content: "\f26c"; +} + +.bi-check-square::before { + content: "\f26d"; +} + +.bi-check::before { + content: "\f26e"; +} + +.bi-check2-all::before { + content: "\f26f"; +} + +.bi-check2-circle::before { + content: "\f270"; +} + +.bi-check2-square::before { + content: "\f271"; +} + +.bi-check2::before { + content: "\f272"; +} + +.bi-chevron-bar-contract::before { + content: "\f273"; +} + +.bi-chevron-bar-down::before { + content: "\f274"; +} + +.bi-chevron-bar-expand::before { + content: "\f275"; +} + +.bi-chevron-bar-left::before { + content: "\f276"; +} + +.bi-chevron-bar-right::before { + content: "\f277"; +} + +.bi-chevron-bar-up::before { + content: "\f278"; +} + +.bi-chevron-compact-down::before { + content: "\f279"; +} + +.bi-chevron-compact-left::before { + content: "\f27a"; +} + +.bi-chevron-compact-right::before { + content: "\f27b"; +} + +.bi-chevron-compact-up::before { + content: "\f27c"; +} + +.bi-chevron-contract::before { + content: "\f27d"; +} + +.bi-chevron-double-down::before { + content: "\f27e"; +} + +.bi-chevron-double-left::before { + content: "\f27f"; +} + +.bi-chevron-double-right::before { + content: "\f280"; +} + +.bi-chevron-double-up::before { + content: "\f281"; +} + +.bi-chevron-down::before { + content: "\f282"; +} + +.bi-chevron-expand::before { + content: "\f283"; +} + +.bi-chevron-left::before { + content: "\f284"; +} + +.bi-chevron-right::before { + content: "\f285"; +} + +.bi-chevron-up::before { + content: "\f286"; +} + +.bi-circle-fill::before { + content: "\f287"; +} + +.bi-circle-half::before { + content: "\f288"; +} + +.bi-circle-square::before { + content: "\f289"; +} + +.bi-circle::before { + content: "\f28a"; +} + +.bi-clipboard-check::before { + content: "\f28b"; +} + +.bi-clipboard-data::before { + content: "\f28c"; +} + +.bi-clipboard-minus::before { + content: "\f28d"; +} + +.bi-clipboard-plus::before { + content: "\f28e"; +} + +.bi-clipboard-x::before { + content: "\f28f"; +} + +.bi-clipboard::before { + content: "\f290"; +} + +.bi-clock-fill::before { + content: "\f291"; +} + +.bi-clock-history::before { + content: "\f292"; +} + +.bi-clock::before { + content: "\f293"; +} + +.bi-cloud-arrow-down-fill::before { + content: "\f294"; +} + +.bi-cloud-arrow-down::before { + content: "\f295"; +} + +.bi-cloud-arrow-up-fill::before { + content: "\f296"; +} + +.bi-cloud-arrow-up::before { + content: "\f297"; +} + +.bi-cloud-check-fill::before { + content: "\f298"; +} + +.bi-cloud-check::before { + content: "\f299"; +} + +.bi-cloud-download-fill::before { + content: "\f29a"; +} + +.bi-cloud-download::before { + content: "\f29b"; +} + +.bi-cloud-drizzle-fill::before { + content: "\f29c"; +} + +.bi-cloud-drizzle::before { + content: "\f29d"; +} + +.bi-cloud-fill::before { + content: "\f29e"; +} + +.bi-cloud-fog-fill::before { + content: "\f29f"; +} + +.bi-cloud-fog::before { + content: "\f2a0"; +} + +.bi-cloud-fog2-fill::before { + content: "\f2a1"; +} + +.bi-cloud-fog2::before { + content: "\f2a2"; +} + +.bi-cloud-hail-fill::before { + content: "\f2a3"; +} + +.bi-cloud-hail::before { + content: "\f2a4"; +} + +.bi-cloud-haze-1::before { + content: "\f2a5"; +} + +.bi-cloud-haze-fill::before { + content: "\f2a6"; +} + +.bi-cloud-haze::before { + content: "\f2a7"; +} + +.bi-cloud-haze2-fill::before { + content: "\f2a8"; +} + +.bi-cloud-lightning-fill::before { + content: "\f2a9"; +} + +.bi-cloud-lightning-rain-fill::before { + content: "\f2aa"; +} + +.bi-cloud-lightning-rain::before { + content: "\f2ab"; +} + +.bi-cloud-lightning::before { + content: "\f2ac"; +} + +.bi-cloud-minus-fill::before { + content: "\f2ad"; +} + +.bi-cloud-minus::before { + content: "\f2ae"; +} + +.bi-cloud-moon-fill::before { + content: "\f2af"; +} + +.bi-cloud-moon::before { + content: "\f2b0"; +} + +.bi-cloud-plus-fill::before { + content: "\f2b1"; +} + +.bi-cloud-plus::before { + content: "\f2b2"; +} + +.bi-cloud-rain-fill::before { + content: "\f2b3"; +} + +.bi-cloud-rain-heavy-fill::before { + content: "\f2b4"; +} + +.bi-cloud-rain-heavy::before { + content: "\f2b5"; +} + +.bi-cloud-rain::before { + content: "\f2b6"; +} + +.bi-cloud-slash-fill::before { + content: "\f2b7"; +} + +.bi-cloud-slash::before { + content: "\f2b8"; +} + +.bi-cloud-sleet-fill::before { + content: "\f2b9"; +} + +.bi-cloud-sleet::before { + content: "\f2ba"; +} + +.bi-cloud-snow-fill::before { + content: "\f2bb"; +} + +.bi-cloud-snow::before { + content: "\f2bc"; +} + +.bi-cloud-sun-fill::before { + content: "\f2bd"; +} + +.bi-cloud-sun::before { + content: "\f2be"; +} + +.bi-cloud-upload-fill::before { + content: "\f2bf"; +} + +.bi-cloud-upload::before { + content: "\f2c0"; +} + +.bi-cloud::before { + content: "\f2c1"; +} + +.bi-clouds-fill::before { + content: "\f2c2"; +} + +.bi-clouds::before { + content: "\f2c3"; +} + +.bi-cloudy-fill::before { + content: "\f2c4"; +} + +.bi-cloudy::before { + content: "\f2c5"; +} + +.bi-code-slash::before { + content: "\f2c6"; +} + +.bi-code-square::before { + content: "\f2c7"; +} + +.bi-code::before { + content: "\f2c8"; +} + +.bi-collection-fill::before { + content: "\f2c9"; +} + +.bi-collection-play-fill::before { + content: "\f2ca"; +} + +.bi-collection-play::before { + content: "\f2cb"; +} + +.bi-collection::before { + content: "\f2cc"; +} + +.bi-columns-gap::before { + content: "\f2cd"; +} + +.bi-columns::before { + content: "\f2ce"; +} + +.bi-command::before { + content: "\f2cf"; +} + +.bi-compass-fill::before { + content: "\f2d0"; +} + +.bi-compass::before { + content: "\f2d1"; +} + +.bi-cone-striped::before { + content: "\f2d2"; +} + +.bi-cone::before { + content: "\f2d3"; +} + +.bi-controller::before { + content: "\f2d4"; +} + +.bi-cpu-fill::before { + content: "\f2d5"; +} + +.bi-cpu::before { + content: "\f2d6"; +} + +.bi-credit-card-2-back-fill::before { + content: "\f2d7"; +} + +.bi-credit-card-2-back::before { + content: "\f2d8"; +} + +.bi-credit-card-2-front-fill::before { + content: "\f2d9"; +} + +.bi-credit-card-2-front::before { + content: "\f2da"; +} + +.bi-credit-card-fill::before { + content: "\f2db"; +} + +.bi-credit-card::before { + content: "\f2dc"; +} + +.bi-crop::before { + content: "\f2dd"; +} + +.bi-cup-fill::before { + content: "\f2de"; +} + +.bi-cup-straw::before { + content: "\f2df"; +} + +.bi-cup::before { + content: "\f2e0"; +} + +.bi-cursor-fill::before { + content: "\f2e1"; +} + +.bi-cursor-text::before { + content: "\f2e2"; +} + +.bi-cursor::before { + content: "\f2e3"; +} + +.bi-dash-circle-dotted::before { + content: "\f2e4"; +} + +.bi-dash-circle-fill::before { + content: "\f2e5"; +} + +.bi-dash-circle::before { + content: "\f2e6"; +} + +.bi-dash-square-dotted::before { + content: "\f2e7"; +} + +.bi-dash-square-fill::before { + content: "\f2e8"; +} + +.bi-dash-square::before { + content: "\f2e9"; +} + +.bi-dash::before { + content: "\f2ea"; +} + +.bi-diagram-2-fill::before { + content: "\f2eb"; +} + +.bi-diagram-2::before { + content: "\f2ec"; +} + +.bi-diagram-3-fill::before { + content: "\f2ed"; +} + +.bi-diagram-3::before { + content: "\f2ee"; +} + +.bi-diamond-fill::before { + content: "\f2ef"; +} + +.bi-diamond-half::before { + content: "\f2f0"; +} + +.bi-diamond::before { + content: "\f2f1"; +} + +.bi-dice-1-fill::before { + content: "\f2f2"; +} + +.bi-dice-1::before { + content: "\f2f3"; +} + +.bi-dice-2-fill::before { + content: "\f2f4"; +} + +.bi-dice-2::before { + content: "\f2f5"; +} + +.bi-dice-3-fill::before { + content: "\f2f6"; +} + +.bi-dice-3::before { + content: "\f2f7"; +} + +.bi-dice-4-fill::before { + content: "\f2f8"; +} + +.bi-dice-4::before { + content: "\f2f9"; +} + +.bi-dice-5-fill::before { + content: "\f2fa"; +} + +.bi-dice-5::before { + content: "\f2fb"; +} + +.bi-dice-6-fill::before { + content: "\f2fc"; +} + +.bi-dice-6::before { + content: "\f2fd"; +} + +.bi-disc-fill::before { + content: "\f2fe"; +} + +.bi-disc::before { + content: "\f2ff"; +} + +.bi-discord::before { + content: "\f300"; +} + +.bi-display-fill::before { + content: "\f301"; +} + +.bi-display::before { + content: "\f302"; +} + +.bi-distribute-horizontal::before { + content: "\f303"; +} + +.bi-distribute-vertical::before { + content: "\f304"; +} + +.bi-door-closed-fill::before { + content: "\f305"; +} + +.bi-door-closed::before { + content: "\f306"; +} + +.bi-door-open-fill::before { + content: "\f307"; +} + +.bi-door-open::before { + content: "\f308"; +} + +.bi-dot::before { + content: "\f309"; +} + +.bi-download::before { + content: "\f30a"; +} + +.bi-droplet-fill::before { + content: "\f30b"; +} + +.bi-droplet-half::before { + content: "\f30c"; +} + +.bi-droplet::before { + content: "\f30d"; +} + +.bi-earbuds::before { + content: "\f30e"; +} + +.bi-easel-fill::before { + content: "\f30f"; +} + +.bi-easel::before { + content: "\f310"; +} + +.bi-egg-fill::before { + content: "\f311"; +} + +.bi-egg-fried::before { + content: "\f312"; +} + +.bi-egg::before { + content: "\f313"; +} + +.bi-eject-fill::before { + content: "\f314"; +} + +.bi-eject::before { + content: "\f315"; +} + +.bi-emoji-angry-fill::before { + content: "\f316"; +} + +.bi-emoji-angry::before { + content: "\f317"; +} + +.bi-emoji-dizzy-fill::before { + content: "\f318"; +} + +.bi-emoji-dizzy::before { + content: "\f319"; +} + +.bi-emoji-expressionless-fill::before { + content: "\f31a"; +} + +.bi-emoji-expressionless::before { + content: "\f31b"; +} + +.bi-emoji-frown-fill::before { + content: "\f31c"; +} + +.bi-emoji-frown::before { + content: "\f31d"; +} + +.bi-emoji-heart-eyes-fill::before { + content: "\f31e"; +} + +.bi-emoji-heart-eyes::before { + content: "\f31f"; +} + +.bi-emoji-laughing-fill::before { + content: "\f320"; +} + +.bi-emoji-laughing::before { + content: "\f321"; +} + +.bi-emoji-neutral-fill::before { + content: "\f322"; +} + +.bi-emoji-neutral::before { + content: "\f323"; +} + +.bi-emoji-smile-fill::before { + content: "\f324"; +} + +.bi-emoji-smile-upside-down-fill::before { + content: "\f325"; +} + +.bi-emoji-smile-upside-down::before { + content: "\f326"; +} + +.bi-emoji-smile::before { + content: "\f327"; +} + +.bi-emoji-sunglasses-fill::before { + content: "\f328"; +} + +.bi-emoji-sunglasses::before { + content: "\f329"; +} + +.bi-emoji-wink-fill::before { + content: "\f32a"; +} + +.bi-emoji-wink::before { + content: "\f32b"; +} + +.bi-envelope-fill::before { + content: "\f32c"; +} + +.bi-envelope-open-fill::before { + content: "\f32d"; +} + +.bi-envelope-open::before { + content: "\f32e"; +} + +.bi-envelope::before { + content: "\f32f"; +} + +.bi-eraser-fill::before { + content: "\f330"; +} + +.bi-eraser::before { + content: "\f331"; +} + +.bi-exclamation-circle-fill::before { + content: "\f332"; +} + +.bi-exclamation-circle::before { + content: "\f333"; +} + +.bi-exclamation-diamond-fill::before { + content: "\f334"; +} + +.bi-exclamation-diamond::before { + content: "\f335"; +} + +.bi-exclamation-octagon-fill::before { + content: "\f336"; +} + +.bi-exclamation-octagon::before { + content: "\f337"; +} + +.bi-exclamation-square-fill::before { + content: "\f338"; +} + +.bi-exclamation-square::before { + content: "\f339"; +} + +.bi-exclamation-triangle-fill::before { + content: "\f33a"; +} + +.bi-exclamation-triangle::before { + content: "\f33b"; +} + +.bi-exclamation::before { + content: "\f33c"; +} + +.bi-exclude::before { + content: "\f33d"; +} + +.bi-eye-fill::before { + content: "\f33e"; +} + +.bi-eye-slash-fill::before { + content: "\f33f"; +} + +.bi-eye-slash::before { + content: "\f340"; +} + +.bi-eye::before { + content: "\f341"; +} + +.bi-eyedropper::before { + content: "\f342"; +} + +.bi-eyeglasses::before { + content: "\f343"; +} + +.bi-facebook::before { + content: "\f344"; +} + +.bi-file-arrow-down-fill::before { + content: "\f345"; +} + +.bi-file-arrow-down::before { + content: "\f346"; +} + +.bi-file-arrow-up-fill::before { + content: "\f347"; +} + +.bi-file-arrow-up::before { + content: "\f348"; +} + +.bi-file-bar-graph-fill::before { + content: "\f349"; +} + +.bi-file-bar-graph::before { + content: "\f34a"; +} + +.bi-file-binary-fill::before { + content: "\f34b"; +} + +.bi-file-binary::before { + content: "\f34c"; +} + +.bi-file-break-fill::before { + content: "\f34d"; +} + +.bi-file-break::before { + content: "\f34e"; +} + +.bi-file-check-fill::before { + content: "\f34f"; +} + +.bi-file-check::before { + content: "\f350"; +} + +.bi-file-code-fill::before { + content: "\f351"; +} + +.bi-file-code::before { + content: "\f352"; +} + +.bi-file-diff-fill::before { + content: "\f353"; +} + +.bi-file-diff::before { + content: "\f354"; +} + +.bi-file-earmark-arrow-down-fill::before { + content: "\f355"; +} + +.bi-file-earmark-arrow-down::before { + content: "\f356"; +} + +.bi-file-earmark-arrow-up-fill::before { + content: "\f357"; +} + +.bi-file-earmark-arrow-up::before { + content: "\f358"; +} + +.bi-file-earmark-bar-graph-fill::before { + content: "\f359"; +} + +.bi-file-earmark-bar-graph::before { + content: "\f35a"; +} + +.bi-file-earmark-binary-fill::before { + content: "\f35b"; +} + +.bi-file-earmark-binary::before { + content: "\f35c"; +} + +.bi-file-earmark-break-fill::before { + content: "\f35d"; +} + +.bi-file-earmark-break::before { + content: "\f35e"; +} + +.bi-file-earmark-check-fill::before { + content: "\f35f"; +} + +.bi-file-earmark-check::before { + content: "\f360"; +} + +.bi-file-earmark-code-fill::before { + content: "\f361"; +} + +.bi-file-earmark-code::before { + content: "\f362"; +} + +.bi-file-earmark-diff-fill::before { + content: "\f363"; +} + +.bi-file-earmark-diff::before { + content: "\f364"; +} + +.bi-file-earmark-easel-fill::before { + content: "\f365"; +} + +.bi-file-earmark-easel::before { + content: "\f366"; +} + +.bi-file-earmark-excel-fill::before { + content: "\f367"; +} + +.bi-file-earmark-excel::before { + content: "\f368"; +} + +.bi-file-earmark-fill::before { + content: "\f369"; +} + +.bi-file-earmark-font-fill::before { + content: "\f36a"; +} + +.bi-file-earmark-font::before { + content: "\f36b"; +} + +.bi-file-earmark-image-fill::before { + content: "\f36c"; +} + +.bi-file-earmark-image::before { + content: "\f36d"; +} + +.bi-file-earmark-lock-fill::before { + content: "\f36e"; +} + +.bi-file-earmark-lock::before { + content: "\f36f"; +} + +.bi-file-earmark-lock2-fill::before { + content: "\f370"; +} + +.bi-file-earmark-lock2::before { + content: "\f371"; +} + +.bi-file-earmark-medical-fill::before { + content: "\f372"; +} + +.bi-file-earmark-medical::before { + content: "\f373"; +} + +.bi-file-earmark-minus-fill::before { + content: "\f374"; +} + +.bi-file-earmark-minus::before { + content: "\f375"; +} + +.bi-file-earmark-music-fill::before { + content: "\f376"; +} + +.bi-file-earmark-music::before { + content: "\f377"; +} + +.bi-file-earmark-person-fill::before { + content: "\f378"; +} + +.bi-file-earmark-person::before { + content: "\f379"; +} + +.bi-file-earmark-play-fill::before { + content: "\f37a"; +} + +.bi-file-earmark-play::before { + content: "\f37b"; +} + +.bi-file-earmark-plus-fill::before { + content: "\f37c"; +} + +.bi-file-earmark-plus::before { + content: "\f37d"; +} + +.bi-file-earmark-post-fill::before { + content: "\f37e"; +} + +.bi-file-earmark-post::before { + content: "\f37f"; +} + +.bi-file-earmark-ppt-fill::before { + content: "\f380"; +} + +.bi-file-earmark-ppt::before { + content: "\f381"; +} + +.bi-file-earmark-richtext-fill::before { + content: "\f382"; +} + +.bi-file-earmark-richtext::before { + content: "\f383"; +} + +.bi-file-earmark-ruled-fill::before { + content: "\f384"; +} + +.bi-file-earmark-ruled::before { + content: "\f385"; +} + +.bi-file-earmark-slides-fill::before { + content: "\f386"; +} + +.bi-file-earmark-slides::before { + content: "\f387"; +} + +.bi-file-earmark-spreadsheet-fill::before { + content: "\f388"; +} + +.bi-file-earmark-spreadsheet::before { + content: "\f389"; +} + +.bi-file-earmark-text-fill::before { + content: "\f38a"; +} + +.bi-file-earmark-text::before { + content: "\f38b"; +} + +.bi-file-earmark-word-fill::before { + content: "\f38c"; +} + +.bi-file-earmark-word::before { + content: "\f38d"; +} + +.bi-file-earmark-x-fill::before { + content: "\f38e"; +} + +.bi-file-earmark-x::before { + content: "\f38f"; +} + +.bi-file-earmark-zip-fill::before { + content: "\f390"; +} + +.bi-file-earmark-zip::before { + content: "\f391"; +} + +.bi-file-earmark::before { + content: "\f392"; +} + +.bi-file-easel-fill::before { + content: "\f393"; +} + +.bi-file-easel::before { + content: "\f394"; +} + +.bi-file-excel-fill::before { + content: "\f395"; +} + +.bi-file-excel::before { + content: "\f396"; +} + +.bi-file-fill::before { + content: "\f397"; +} + +.bi-file-font-fill::before { + content: "\f398"; +} + +.bi-file-font::before { + content: "\f399"; +} + +.bi-file-image-fill::before { + content: "\f39a"; +} + +.bi-file-image::before { + content: "\f39b"; +} + +.bi-file-lock-fill::before { + content: "\f39c"; +} + +.bi-file-lock::before { + content: "\f39d"; +} + +.bi-file-lock2-fill::before { + content: "\f39e"; +} + +.bi-file-lock2::before { + content: "\f39f"; +} + +.bi-file-medical-fill::before { + content: "\f3a0"; +} + +.bi-file-medical::before { + content: "\f3a1"; +} + +.bi-file-minus-fill::before { + content: "\f3a2"; +} + +.bi-file-minus::before { + content: "\f3a3"; +} + +.bi-file-music-fill::before { + content: "\f3a4"; +} + +.bi-file-music::before { + content: "\f3a5"; +} + +.bi-file-person-fill::before { + content: "\f3a6"; +} + +.bi-file-person::before { + content: "\f3a7"; +} + +.bi-file-play-fill::before { + content: "\f3a8"; +} + +.bi-file-play::before { + content: "\f3a9"; +} + +.bi-file-plus-fill::before { + content: "\f3aa"; +} + +.bi-file-plus::before { + content: "\f3ab"; +} + +.bi-file-post-fill::before { + content: "\f3ac"; +} + +.bi-file-post::before { + content: "\f3ad"; +} + +.bi-file-ppt-fill::before { + content: "\f3ae"; +} + +.bi-file-ppt::before { + content: "\f3af"; +} + +.bi-file-richtext-fill::before { + content: "\f3b0"; +} + +.bi-file-richtext::before { + content: "\f3b1"; +} + +.bi-file-ruled-fill::before { + content: "\f3b2"; +} + +.bi-file-ruled::before { + content: "\f3b3"; +} + +.bi-file-slides-fill::before { + content: "\f3b4"; +} + +.bi-file-slides::before { + content: "\f3b5"; +} + +.bi-file-spreadsheet-fill::before { + content: "\f3b6"; +} + +.bi-file-spreadsheet::before { + content: "\f3b7"; +} + +.bi-file-text-fill::before { + content: "\f3b8"; +} + +.bi-file-text::before { + content: "\f3b9"; +} + +.bi-file-word-fill::before { + content: "\f3ba"; +} + +.bi-file-word::before { + content: "\f3bb"; +} + +.bi-file-x-fill::before { + content: "\f3bc"; +} + +.bi-file-x::before { + content: "\f3bd"; +} + +.bi-file-zip-fill::before { + content: "\f3be"; +} + +.bi-file-zip::before { + content: "\f3bf"; +} + +.bi-file::before { + content: "\f3c0"; +} + +.bi-files-alt::before { + content: "\f3c1"; +} + +.bi-files::before { + content: "\f3c2"; +} + +.bi-film::before { + content: "\f3c3"; +} + +.bi-filter-circle-fill::before { + content: "\f3c4"; +} + +.bi-filter-circle::before { + content: "\f3c5"; +} + +.bi-filter-left::before { + content: "\f3c6"; +} + +.bi-filter-right::before { + content: "\f3c7"; +} + +.bi-filter-square-fill::before { + content: "\f3c8"; +} + +.bi-filter-square::before { + content: "\f3c9"; +} + +.bi-filter::before { + content: "\f3ca"; +} + +.bi-flag-fill::before { + content: "\f3cb"; +} + +.bi-flag::before { + content: "\f3cc"; +} + +.bi-flower1::before { + content: "\f3cd"; +} + +.bi-flower2::before { + content: "\f3ce"; +} + +.bi-flower3::before { + content: "\f3cf"; +} + +.bi-folder-check::before { + content: "\f3d0"; +} + +.bi-folder-fill::before { + content: "\f3d1"; +} + +.bi-folder-minus::before { + content: "\f3d2"; +} + +.bi-folder-plus::before { + content: "\f3d3"; +} + +.bi-folder-symlink-fill::before { + content: "\f3d4"; +} + +.bi-folder-symlink::before { + content: "\f3d5"; +} + +.bi-folder-x::before { + content: "\f3d6"; +} + +.bi-folder::before { + content: "\f3d7"; +} + +.bi-folder2-open::before { + content: "\f3d8"; +} + +.bi-folder2::before { + content: "\f3d9"; +} + +.bi-fonts::before { + content: "\f3da"; +} + +.bi-forward-fill::before { + content: "\f3db"; +} + +.bi-forward::before { + content: "\f3dc"; +} + +.bi-front::before { + content: "\f3dd"; +} + +.bi-fullscreen-exit::before { + content: "\f3de"; +} + +.bi-fullscreen::before { + content: "\f3df"; +} + +.bi-funnel-fill::before { + content: "\f3e0"; +} + +.bi-funnel::before { + content: "\f3e1"; +} + +.bi-gear-fill::before { + content: "\f3e2"; +} + +.bi-gear-wide-connected::before { + content: "\f3e3"; +} + +.bi-gear-wide::before { + content: "\f3e4"; +} + +.bi-gear::before { + content: "\f3e5"; +} + +.bi-gem::before { + content: "\f3e6"; +} + +.bi-geo-alt-fill::before { + content: "\f3e7"; +} + +.bi-geo-alt::before { + content: "\f3e8"; +} + +.bi-geo-fill::before { + content: "\f3e9"; +} + +.bi-geo::before { + content: "\f3ea"; +} + +.bi-gift-fill::before { + content: "\f3eb"; +} + +.bi-gift::before { + content: "\f3ec"; +} + +.bi-github::before { + content: "\f3ed"; +} + +.bi-globe::before { + content: "\f3ee"; +} + +.bi-globe2::before { + content: "\f3ef"; +} + +.bi-google::before { + content: "\f3f0"; +} + +.bi-graph-down::before { + content: "\f3f1"; +} + +.bi-graph-up::before { + content: "\f3f2"; +} + +.bi-grid-1x2-fill::before { + content: "\f3f3"; +} + +.bi-grid-1x2::before { + content: "\f3f4"; +} + +.bi-grid-3x2-gap-fill::before { + content: "\f3f5"; +} + +.bi-grid-3x2-gap::before { + content: "\f3f6"; +} + +.bi-grid-3x2::before { + content: "\f3f7"; +} + +.bi-grid-3x3-gap-fill::before { + content: "\f3f8"; +} + +.bi-grid-3x3-gap::before { + content: "\f3f9"; +} + +.bi-grid-3x3::before { + content: "\f3fa"; +} + +.bi-grid-fill::before { + content: "\f3fb"; +} + +.bi-grid::before { + content: "\f3fc"; +} + +.bi-grip-horizontal::before { + content: "\f3fd"; +} + +.bi-grip-vertical::before { + content: "\f3fe"; +} + +.bi-hammer::before { + content: "\f3ff"; +} + +.bi-hand-index-fill::before { + content: "\f400"; +} + +.bi-hand-index-thumb-fill::before { + content: "\f401"; +} + +.bi-hand-index-thumb::before { + content: "\f402"; +} + +.bi-hand-index::before { + content: "\f403"; +} + +.bi-hand-thumbs-down-fill::before { + content: "\f404"; +} + +.bi-hand-thumbs-down::before { + content: "\f405"; +} + +.bi-hand-thumbs-up-fill::before { + content: "\f406"; +} + +.bi-hand-thumbs-up::before { + content: "\f407"; +} + +.bi-handbag-fill::before { + content: "\f408"; +} + +.bi-handbag::before { + content: "\f409"; +} + +.bi-hash::before { + content: "\f40a"; +} + +.bi-hdd-fill::before { + content: "\f40b"; +} + +.bi-hdd-network-fill::before { + content: "\f40c"; +} + +.bi-hdd-network::before { + content: "\f40d"; +} + +.bi-hdd-rack-fill::before { + content: "\f40e"; +} + +.bi-hdd-rack::before { + content: "\f40f"; +} + +.bi-hdd-stack-fill::before { + content: "\f410"; +} + +.bi-hdd-stack::before { + content: "\f411"; +} + +.bi-hdd::before { + content: "\f412"; +} + +.bi-headphones::before { + content: "\f413"; +} + +.bi-headset::before { + content: "\f414"; +} + +.bi-heart-fill::before { + content: "\f415"; +} + +.bi-heart-half::before { + content: "\f416"; +} + +.bi-heart::before { + content: "\f417"; +} + +.bi-heptagon-fill::before { + content: "\f418"; +} + +.bi-heptagon-half::before { + content: "\f419"; +} + +.bi-heptagon::before { + content: "\f41a"; +} + +.bi-hexagon-fill::before { + content: "\f41b"; +} + +.bi-hexagon-half::before { + content: "\f41c"; +} + +.bi-hexagon::before { + content: "\f41d"; +} + +.bi-hourglass-bottom::before { + content: "\f41e"; +} + +.bi-hourglass-split::before { + content: "\f41f"; +} + +.bi-hourglass-top::before { + content: "\f420"; +} + +.bi-hourglass::before { + content: "\f421"; +} + +.bi-house-door-fill::before { + content: "\f422"; +} + +.bi-house-door::before { + content: "\f423"; +} + +.bi-house-fill::before { + content: "\f424"; +} + +.bi-house::before { + content: "\f425"; +} + +.bi-hr::before { + content: "\f426"; +} + +.bi-hurricane::before { + content: "\f427"; +} + +.bi-image-alt::before { + content: "\f428"; +} + +.bi-image-fill::before { + content: "\f429"; +} + +.bi-image::before { + content: "\f42a"; +} + +.bi-images::before { + content: "\f42b"; +} + +.bi-inbox-fill::before { + content: "\f42c"; +} + +.bi-inbox::before { + content: "\f42d"; +} + +.bi-inboxes-fill::before { + content: "\f42e"; +} + +.bi-inboxes::before { + content: "\f42f"; +} + +.bi-info-circle-fill::before { + content: "\f430"; +} + +.bi-info-circle::before { + content: "\f431"; +} + +.bi-info-square-fill::before { + content: "\f432"; +} + +.bi-info-square::before { + content: "\f433"; +} + +.bi-info::before { + content: "\f434"; +} + +.bi-input-cursor-text::before { + content: "\f435"; +} + +.bi-input-cursor::before { + content: "\f436"; +} + +.bi-instagram::before { + content: "\f437"; +} + +.bi-intersect::before { + content: "\f438"; +} + +.bi-journal-album::before { + content: "\f439"; +} + +.bi-journal-arrow-down::before { + content: "\f43a"; +} + +.bi-journal-arrow-up::before { + content: "\f43b"; +} + +.bi-journal-bookmark-fill::before { + content: "\f43c"; +} + +.bi-journal-bookmark::before { + content: "\f43d"; +} + +.bi-journal-check::before { + content: "\f43e"; +} + +.bi-journal-code::before { + content: "\f43f"; +} + +.bi-journal-medical::before { + content: "\f440"; +} + +.bi-journal-minus::before { + content: "\f441"; +} + +.bi-journal-plus::before { + content: "\f442"; +} + +.bi-journal-richtext::before { + content: "\f443"; +} + +.bi-journal-text::before { + content: "\f444"; +} + +.bi-journal-x::before { + content: "\f445"; +} + +.bi-journal::before { + content: "\f446"; +} + +.bi-journals::before { + content: "\f447"; +} + +.bi-joystick::before { + content: "\f448"; +} + +.bi-justify-left::before { + content: "\f449"; +} + +.bi-justify-right::before { + content: "\f44a"; +} + +.bi-justify::before { + content: "\f44b"; +} + +.bi-kanban-fill::before { + content: "\f44c"; +} + +.bi-kanban::before { + content: "\f44d"; +} + +.bi-key-fill::before { + content: "\f44e"; +} + +.bi-key::before { + content: "\f44f"; +} + +.bi-keyboard-fill::before { + content: "\f450"; +} + +.bi-keyboard::before { + content: "\f451"; +} + +.bi-ladder::before { + content: "\f452"; +} + +.bi-lamp-fill::before { + content: "\f453"; +} + +.bi-lamp::before { + content: "\f454"; +} + +.bi-laptop-fill::before { + content: "\f455"; +} + +.bi-laptop::before { + content: "\f456"; +} + +.bi-layer-backward::before { + content: "\f457"; +} + +.bi-layer-forward::before { + content: "\f458"; +} + +.bi-layers-fill::before { + content: "\f459"; +} + +.bi-layers-half::before { + content: "\f45a"; +} + +.bi-layers::before { + content: "\f45b"; +} + +.bi-layout-sidebar-inset-reverse::before { + content: "\f45c"; +} + +.bi-layout-sidebar-inset::before { + content: "\f45d"; +} + +.bi-layout-sidebar-reverse::before { + content: "\f45e"; +} + +.bi-layout-sidebar::before { + content: "\f45f"; +} + +.bi-layout-split::before { + content: "\f460"; +} + +.bi-layout-text-sidebar-reverse::before { + content: "\f461"; +} + +.bi-layout-text-sidebar::before { + content: "\f462"; +} + +.bi-layout-text-window-reverse::before { + content: "\f463"; +} + +.bi-layout-text-window::before { + content: "\f464"; +} + +.bi-layout-three-columns::before { + content: "\f465"; +} + +.bi-layout-wtf::before { + content: "\f466"; +} + +.bi-life-preserver::before { + content: "\f467"; +} + +.bi-lightbulb-fill::before { + content: "\f468"; +} + +.bi-lightbulb-off-fill::before { + content: "\f469"; +} + +.bi-lightbulb-off::before { + content: "\f46a"; +} + +.bi-lightbulb::before { + content: "\f46b"; +} + +.bi-lightning-charge-fill::before { + content: "\f46c"; +} + +.bi-lightning-charge::before { + content: "\f46d"; +} + +.bi-lightning-fill::before { + content: "\f46e"; +} + +.bi-lightning::before { + content: "\f46f"; +} + +.bi-link-45deg::before { + content: "\f470"; +} + +.bi-link::before { + content: "\f471"; +} + +.bi-linkedin::before { + content: "\f472"; +} + +.bi-list-check::before { + content: "\f473"; +} + +.bi-list-nested::before { + content: "\f474"; +} + +.bi-list-ol::before { + content: "\f475"; +} + +.bi-list-stars::before { + content: "\f476"; +} + +.bi-list-task::before { + content: "\f477"; +} + +.bi-list-ul::before { + content: "\f478"; +} + +.bi-list::before { + content: "\f479"; +} + +.bi-lock-fill::before { + content: "\f47a"; +} + +.bi-lock::before { + content: "\f47b"; +} + +.bi-mailbox::before { + content: "\f47c"; +} + +.bi-mailbox2::before { + content: "\f47d"; +} + +.bi-map-fill::before { + content: "\f47e"; +} + +.bi-map::before { + content: "\f47f"; +} + +.bi-markdown-fill::before { + content: "\f480"; +} + +.bi-markdown::before { + content: "\f481"; +} + +.bi-mask::before { + content: "\f482"; +} + +.bi-megaphone-fill::before { + content: "\f483"; +} + +.bi-megaphone::before { + content: "\f484"; +} + +.bi-menu-app-fill::before { + content: "\f485"; +} + +.bi-menu-app::before { + content: "\f486"; +} + +.bi-menu-button-fill::before { + content: "\f487"; +} + +.bi-menu-button-wide-fill::before { + content: "\f488"; +} + +.bi-menu-button-wide::before { + content: "\f489"; +} + +.bi-menu-button::before { + content: "\f48a"; +} + +.bi-menu-down::before { + content: "\f48b"; +} + +.bi-menu-up::before { + content: "\f48c"; +} + +.bi-mic-fill::before { + content: "\f48d"; +} + +.bi-mic-mute-fill::before { + content: "\f48e"; +} + +.bi-mic-mute::before { + content: "\f48f"; +} + +.bi-mic::before { + content: "\f490"; +} + +.bi-minecart-loaded::before { + content: "\f491"; +} + +.bi-minecart::before { + content: "\f492"; +} + +.bi-moisture::before { + content: "\f493"; +} + +.bi-moon-fill::before { + content: "\f494"; +} + +.bi-moon-stars-fill::before { + content: "\f495"; +} + +.bi-moon-stars::before { + content: "\f496"; +} + +.bi-moon::before { + content: "\f497"; +} + +.bi-mouse-fill::before { + content: "\f498"; +} + +.bi-mouse::before { + content: "\f499"; +} + +.bi-mouse2-fill::before { + content: "\f49a"; +} + +.bi-mouse2::before { + content: "\f49b"; +} + +.bi-mouse3-fill::before { + content: "\f49c"; +} + +.bi-mouse3::before { + content: "\f49d"; +} + +.bi-music-note-beamed::before { + content: "\f49e"; +} + +.bi-music-note-list::before { + content: "\f49f"; +} + +.bi-music-note::before { + content: "\f4a0"; +} + +.bi-music-player-fill::before { + content: "\f4a1"; +} + +.bi-music-player::before { + content: "\f4a2"; +} + +.bi-newspaper::before { + content: "\f4a3"; +} + +.bi-node-minus-fill::before { + content: "\f4a4"; +} + +.bi-node-minus::before { + content: "\f4a5"; +} + +.bi-node-plus-fill::before { + content: "\f4a6"; +} + +.bi-node-plus::before { + content: "\f4a7"; +} + +.bi-nut-fill::before { + content: "\f4a8"; +} + +.bi-nut::before { + content: "\f4a9"; +} + +.bi-octagon-fill::before { + content: "\f4aa"; +} + +.bi-octagon-half::before { + content: "\f4ab"; +} + +.bi-octagon::before { + content: "\f4ac"; +} + +.bi-option::before { + content: "\f4ad"; +} + +.bi-outlet::before { + content: "\f4ae"; +} + +.bi-paint-bucket::before { + content: "\f4af"; +} + +.bi-palette-fill::before { + content: "\f4b0"; +} + +.bi-palette::before { + content: "\f4b1"; +} + +.bi-palette2::before { + content: "\f4b2"; +} + +.bi-paperclip::before { + content: "\f4b3"; +} + +.bi-paragraph::before { + content: "\f4b4"; +} + +.bi-patch-check-fill::before { + content: "\f4b5"; +} + +.bi-patch-check::before { + content: "\f4b6"; +} + +.bi-patch-exclamation-fill::before { + content: "\f4b7"; +} + +.bi-patch-exclamation::before { + content: "\f4b8"; +} + +.bi-patch-minus-fill::before { + content: "\f4b9"; +} + +.bi-patch-minus::before { + content: "\f4ba"; +} + +.bi-patch-plus-fill::before { + content: "\f4bb"; +} + +.bi-patch-plus::before { + content: "\f4bc"; +} + +.bi-patch-question-fill::before { + content: "\f4bd"; +} + +.bi-patch-question::before { + content: "\f4be"; +} + +.bi-pause-btn-fill::before { + content: "\f4bf"; +} + +.bi-pause-btn::before { + content: "\f4c0"; +} + +.bi-pause-circle-fill::before { + content: "\f4c1"; +} + +.bi-pause-circle::before { + content: "\f4c2"; +} + +.bi-pause-fill::before { + content: "\f4c3"; +} + +.bi-pause::before { + content: "\f4c4"; +} + +.bi-peace-fill::before { + content: "\f4c5"; +} + +.bi-peace::before { + content: "\f4c6"; +} + +.bi-pen-fill::before { + content: "\f4c7"; +} + +.bi-pen::before { + content: "\f4c8"; +} + +.bi-pencil-fill::before { + content: "\f4c9"; +} + +.bi-pencil-square::before { + content: "\f4ca"; +} + +.bi-pencil::before { + content: "\f4cb"; +} + +.bi-pentagon-fill::before { + content: "\f4cc"; +} + +.bi-pentagon-half::before { + content: "\f4cd"; +} + +.bi-pentagon::before { + content: "\f4ce"; +} + +.bi-people-fill::before { + content: "\f4cf"; +} + +.bi-people::before { + content: "\f4d0"; +} + +.bi-percent::before { + content: "\f4d1"; +} + +.bi-person-badge-fill::before { + content: "\f4d2"; +} + +.bi-person-badge::before { + content: "\f4d3"; +} + +.bi-person-bounding-box::before { + content: "\f4d4"; +} + +.bi-person-check-fill::before { + content: "\f4d5"; +} + +.bi-person-check::before { + content: "\f4d6"; +} + +.bi-person-circle::before { + content: "\f4d7"; +} + +.bi-person-dash-fill::before { + content: "\f4d8"; +} + +.bi-person-dash::before { + content: "\f4d9"; +} + +.bi-person-fill::before { + content: "\f4da"; +} + +.bi-person-lines-fill::before { + content: "\f4db"; +} + +.bi-person-plus-fill::before { + content: "\f4dc"; +} + +.bi-person-plus::before { + content: "\f4dd"; +} + +.bi-person-square::before { + content: "\f4de"; +} + +.bi-person-x-fill::before { + content: "\f4df"; +} + +.bi-person-x::before { + content: "\f4e0"; +} + +.bi-person::before { + content: "\f4e1"; +} + +.bi-phone-fill::before { + content: "\f4e2"; +} + +.bi-phone-landscape-fill::before { + content: "\f4e3"; +} + +.bi-phone-landscape::before { + content: "\f4e4"; +} + +.bi-phone-vibrate-fill::before { + content: "\f4e5"; +} + +.bi-phone-vibrate::before { + content: "\f4e6"; +} + +.bi-phone::before { + content: "\f4e7"; +} + +.bi-pie-chart-fill::before { + content: "\f4e8"; +} + +.bi-pie-chart::before { + content: "\f4e9"; +} + +.bi-pin-angle-fill::before { + content: "\f4ea"; +} + +.bi-pin-angle::before { + content: "\f4eb"; +} + +.bi-pin-fill::before { + content: "\f4ec"; +} + +.bi-pin::before { + content: "\f4ed"; +} + +.bi-pip-fill::before { + content: "\f4ee"; +} + +.bi-pip::before { + content: "\f4ef"; +} + +.bi-play-btn-fill::before { + content: "\f4f0"; +} + +.bi-play-btn::before { + content: "\f4f1"; +} + +.bi-play-circle-fill::before { + content: "\f4f2"; +} + +.bi-play-circle::before { + content: "\f4f3"; +} + +.bi-play-fill::before { + content: "\f4f4"; +} + +.bi-play::before { + content: "\f4f5"; +} + +.bi-plug-fill::before { + content: "\f4f6"; +} + +.bi-plug::before { + content: "\f4f7"; +} + +.bi-plus-circle-dotted::before { + content: "\f4f8"; +} + +.bi-plus-circle-fill::before { + content: "\f4f9"; +} + +.bi-plus-circle::before { + content: "\f4fa"; +} + +.bi-plus-square-dotted::before { + content: "\f4fb"; +} + +.bi-plus-square-fill::before { + content: "\f4fc"; +} + +.bi-plus-square::before { + content: "\f4fd"; +} + +.bi-plus::before { + content: "\f4fe"; +} + +.bi-power::before { + content: "\f4ff"; +} + +.bi-printer-fill::before { + content: "\f500"; +} + +.bi-printer::before { + content: "\f501"; +} + +.bi-puzzle-fill::before { + content: "\f502"; +} + +.bi-puzzle::before { + content: "\f503"; +} + +.bi-question-circle-fill::before { + content: "\f504"; +} + +.bi-question-circle::before { + content: "\f505"; +} + +.bi-question-diamond-fill::before { + content: "\f506"; +} + +.bi-question-diamond::before { + content: "\f507"; +} + +.bi-question-octagon-fill::before { + content: "\f508"; +} + +.bi-question-octagon::before { + content: "\f509"; +} + +.bi-question-square-fill::before { + content: "\f50a"; +} + +.bi-question-square::before { + content: "\f50b"; +} + +.bi-question::before { + content: "\f50c"; +} + +.bi-rainbow::before { + content: "\f50d"; +} + +.bi-receipt-cutoff::before { + content: "\f50e"; +} + +.bi-receipt::before { + content: "\f50f"; +} + +.bi-reception-0::before { + content: "\f510"; +} + +.bi-reception-1::before { + content: "\f511"; +} + +.bi-reception-2::before { + content: "\f512"; +} + +.bi-reception-3::before { + content: "\f513"; +} + +.bi-reception-4::before { + content: "\f514"; +} + +.bi-record-btn-fill::before { + content: "\f515"; +} + +.bi-record-btn::before { + content: "\f516"; +} + +.bi-record-circle-fill::before { + content: "\f517"; +} + +.bi-record-circle::before { + content: "\f518"; +} + +.bi-record-fill::before { + content: "\f519"; +} + +.bi-record::before { + content: "\f51a"; +} + +.bi-record2-fill::before { + content: "\f51b"; +} + +.bi-record2::before { + content: "\f51c"; +} + +.bi-reply-all-fill::before { + content: "\f51d"; +} + +.bi-reply-all::before { + content: "\f51e"; +} + +.bi-reply-fill::before { + content: "\f51f"; +} + +.bi-reply::before { + content: "\f520"; +} + +.bi-rss-fill::before { + content: "\f521"; +} + +.bi-rss::before { + content: "\f522"; +} + +.bi-rulers::before { + content: "\f523"; +} + +.bi-save-fill::before { + content: "\f524"; +} + +.bi-save::before { + content: "\f525"; +} + +.bi-save2-fill::before { + content: "\f526"; +} + +.bi-save2::before { + content: "\f527"; +} + +.bi-scissors::before { + content: "\f528"; +} + +.bi-screwdriver::before { + content: "\f529"; +} + +.bi-search::before { + content: "\f52a"; +} + +.bi-segmented-nav::before { + content: "\f52b"; +} + +.bi-server::before { + content: "\f52c"; +} + +.bi-share-fill::before { + content: "\f52d"; +} + +.bi-share::before { + content: "\f52e"; +} + +.bi-shield-check::before { + content: "\f52f"; +} + +.bi-shield-exclamation::before { + content: "\f530"; +} + +.bi-shield-fill-check::before { + content: "\f531"; +} + +.bi-shield-fill-exclamation::before { + content: "\f532"; +} + +.bi-shield-fill-minus::before { + content: "\f533"; +} + +.bi-shield-fill-plus::before { + content: "\f534"; +} + +.bi-shield-fill-x::before { + content: "\f535"; +} + +.bi-shield-fill::before { + content: "\f536"; +} + +.bi-shield-lock-fill::before { + content: "\f537"; +} + +.bi-shield-lock::before { + content: "\f538"; +} + +.bi-shield-minus::before { + content: "\f539"; +} + +.bi-shield-plus::before { + content: "\f53a"; +} + +.bi-shield-shaded::before { + content: "\f53b"; +} + +.bi-shield-slash-fill::before { + content: "\f53c"; +} + +.bi-shield-slash::before { + content: "\f53d"; +} + +.bi-shield-x::before { + content: "\f53e"; +} + +.bi-shield::before { + content: "\f53f"; +} + +.bi-shift-fill::before { + content: "\f540"; +} + +.bi-shift::before { + content: "\f541"; +} + +.bi-shop-window::before { + content: "\f542"; +} + +.bi-shop::before { + content: "\f543"; +} + +.bi-shuffle::before { + content: "\f544"; +} + +.bi-signpost-2-fill::before { + content: "\f545"; +} + +.bi-signpost-2::before { + content: "\f546"; +} + +.bi-signpost-fill::before { + content: "\f547"; +} + +.bi-signpost-split-fill::before { + content: "\f548"; +} + +.bi-signpost-split::before { + content: "\f549"; +} + +.bi-signpost::before { + content: "\f54a"; +} + +.bi-sim-fill::before { + content: "\f54b"; +} + +.bi-sim::before { + content: "\f54c"; +} + +.bi-skip-backward-btn-fill::before { + content: "\f54d"; +} + +.bi-skip-backward-btn::before { + content: "\f54e"; +} + +.bi-skip-backward-circle-fill::before { + content: "\f54f"; +} + +.bi-skip-backward-circle::before { + content: "\f550"; +} + +.bi-skip-backward-fill::before { + content: "\f551"; +} + +.bi-skip-backward::before { + content: "\f552"; +} + +.bi-skip-end-btn-fill::before { + content: "\f553"; +} + +.bi-skip-end-btn::before { + content: "\f554"; +} + +.bi-skip-end-circle-fill::before { + content: "\f555"; +} + +.bi-skip-end-circle::before { + content: "\f556"; +} + +.bi-skip-end-fill::before { + content: "\f557"; +} + +.bi-skip-end::before { + content: "\f558"; +} + +.bi-skip-forward-btn-fill::before { + content: "\f559"; +} + +.bi-skip-forward-btn::before { + content: "\f55a"; +} + +.bi-skip-forward-circle-fill::before { + content: "\f55b"; +} + +.bi-skip-forward-circle::before { + content: "\f55c"; +} + +.bi-skip-forward-fill::before { + content: "\f55d"; +} + +.bi-skip-forward::before { + content: "\f55e"; +} + +.bi-skip-start-btn-fill::before { + content: "\f55f"; +} + +.bi-skip-start-btn::before { + content: "\f560"; +} + +.bi-skip-start-circle-fill::before { + content: "\f561"; +} + +.bi-skip-start-circle::before { + content: "\f562"; +} + +.bi-skip-start-fill::before { + content: "\f563"; +} + +.bi-skip-start::before { + content: "\f564"; +} + +.bi-slack::before { + content: "\f565"; +} + +.bi-slash-circle-fill::before { + content: "\f566"; +} + +.bi-slash-circle::before { + content: "\f567"; +} + +.bi-slash-square-fill::before { + content: "\f568"; +} + +.bi-slash-square::before { + content: "\f569"; +} + +.bi-slash::before { + content: "\f56a"; +} + +.bi-sliders::before { + content: "\f56b"; +} + +.bi-smartwatch::before { + content: "\f56c"; +} + +.bi-snow::before { + content: "\f56d"; +} + +.bi-snow2::before { + content: "\f56e"; +} + +.bi-snow3::before { + content: "\f56f"; +} + +.bi-sort-alpha-down-alt::before { + content: "\f570"; +} + +.bi-sort-alpha-down::before { + content: "\f571"; +} + +.bi-sort-alpha-up-alt::before { + content: "\f572"; +} + +.bi-sort-alpha-up::before { + content: "\f573"; +} + +.bi-sort-down-alt::before { + content: "\f574"; +} + +.bi-sort-down::before { + content: "\f575"; +} + +.bi-sort-numeric-down-alt::before { + content: "\f576"; +} + +.bi-sort-numeric-down::before { + content: "\f577"; +} + +.bi-sort-numeric-up-alt::before { + content: "\f578"; +} + +.bi-sort-numeric-up::before { + content: "\f579"; +} + +.bi-sort-up-alt::before { + content: "\f57a"; +} + +.bi-sort-up::before { + content: "\f57b"; +} + +.bi-soundwave::before { + content: "\f57c"; +} + +.bi-speaker-fill::before { + content: "\f57d"; +} + +.bi-speaker::before { + content: "\f57e"; +} + +.bi-speedometer::before { + content: "\f57f"; +} + +.bi-speedometer2::before { + content: "\f580"; +} + +.bi-spellcheck::before { + content: "\f581"; +} + +.bi-square-fill::before { + content: "\f582"; +} + +.bi-square-half::before { + content: "\f583"; +} + +.bi-square::before { + content: "\f584"; +} + +.bi-stack::before { + content: "\f585"; +} + +.bi-star-fill::before { + content: "\f586"; +} + +.bi-star-half::before { + content: "\f587"; +} + +.bi-star::before { + content: "\f588"; +} + +.bi-stars::before { + content: "\f589"; +} + +.bi-stickies-fill::before { + content: "\f58a"; +} + +.bi-stickies::before { + content: "\f58b"; +} + +.bi-sticky-fill::before { + content: "\f58c"; +} + +.bi-sticky::before { + content: "\f58d"; +} + +.bi-stop-btn-fill::before { + content: "\f58e"; +} + +.bi-stop-btn::before { + content: "\f58f"; +} + +.bi-stop-circle-fill::before { + content: "\f590"; +} + +.bi-stop-circle::before { + content: "\f591"; +} + +.bi-stop-fill::before { + content: "\f592"; +} + +.bi-stop::before { + content: "\f593"; +} + +.bi-stoplights-fill::before { + content: "\f594"; +} + +.bi-stoplights::before { + content: "\f595"; +} + +.bi-stopwatch-fill::before { + content: "\f596"; +} + +.bi-stopwatch::before { + content: "\f597"; +} + +.bi-subtract::before { + content: "\f598"; +} + +.bi-suit-club-fill::before { + content: "\f599"; +} + +.bi-suit-club::before { + content: "\f59a"; +} + +.bi-suit-diamond-fill::before { + content: "\f59b"; +} + +.bi-suit-diamond::before { + content: "\f59c"; +} + +.bi-suit-heart-fill::before { + content: "\f59d"; +} + +.bi-suit-heart::before { + content: "\f59e"; +} + +.bi-suit-spade-fill::before { + content: "\f59f"; +} + +.bi-suit-spade::before { + content: "\f5a0"; +} + +.bi-sun-fill::before { + content: "\f5a1"; +} + +.bi-sun::before { + content: "\f5a2"; +} + +.bi-sunglasses::before { + content: "\f5a3"; +} + +.bi-sunrise-fill::before { + content: "\f5a4"; +} + +.bi-sunrise::before { + content: "\f5a5"; +} + +.bi-sunset-fill::before { + content: "\f5a6"; +} + +.bi-sunset::before { + content: "\f5a7"; +} + +.bi-symmetry-horizontal::before { + content: "\f5a8"; +} + +.bi-symmetry-vertical::before { + content: "\f5a9"; +} + +.bi-table::before { + content: "\f5aa"; +} + +.bi-tablet-fill::before { + content: "\f5ab"; +} + +.bi-tablet-landscape-fill::before { + content: "\f5ac"; +} + +.bi-tablet-landscape::before { + content: "\f5ad"; +} + +.bi-tablet::before { + content: "\f5ae"; +} + +.bi-tag-fill::before { + content: "\f5af"; +} + +.bi-tag::before { + content: "\f5b0"; +} + +.bi-tags-fill::before { + content: "\f5b1"; +} + +.bi-tags::before { + content: "\f5b2"; +} + +.bi-telegram::before { + content: "\f5b3"; +} + +.bi-telephone-fill::before { + content: "\f5b4"; +} + +.bi-telephone-forward-fill::before { + content: "\f5b5"; +} + +.bi-telephone-forward::before { + content: "\f5b6"; +} + +.bi-telephone-inbound-fill::before { + content: "\f5b7"; +} + +.bi-telephone-inbound::before { + content: "\f5b8"; +} + +.bi-telephone-minus-fill::before { + content: "\f5b9"; +} + +.bi-telephone-minus::before { + content: "\f5ba"; +} + +.bi-telephone-outbound-fill::before { + content: "\f5bb"; +} + +.bi-telephone-outbound::before { + content: "\f5bc"; +} + +.bi-telephone-plus-fill::before { + content: "\f5bd"; +} + +.bi-telephone-plus::before { + content: "\f5be"; +} + +.bi-telephone-x-fill::before { + content: "\f5bf"; +} + +.bi-telephone-x::before { + content: "\f5c0"; +} + +.bi-telephone::before { + content: "\f5c1"; +} + +.bi-terminal-fill::before { + content: "\f5c2"; +} + +.bi-terminal::before { + content: "\f5c3"; +} + +.bi-text-center::before { + content: "\f5c4"; +} + +.bi-text-indent-left::before { + content: "\f5c5"; +} + +.bi-text-indent-right::before { + content: "\f5c6"; +} + +.bi-text-left::before { + content: "\f5c7"; +} + +.bi-text-paragraph::before { + content: "\f5c8"; +} + +.bi-text-right::before { + content: "\f5c9"; +} + +.bi-textarea-resize::before { + content: "\f5ca"; +} + +.bi-textarea-t::before { + content: "\f5cb"; +} + +.bi-textarea::before { + content: "\f5cc"; +} + +.bi-thermometer-half::before { + content: "\f5cd"; +} + +.bi-thermometer-high::before { + content: "\f5ce"; +} + +.bi-thermometer-low::before { + content: "\f5cf"; +} + +.bi-thermometer-snow::before { + content: "\f5d0"; +} + +.bi-thermometer-sun::before { + content: "\f5d1"; +} + +.bi-thermometer::before { + content: "\f5d2"; +} + +.bi-three-dots-vertical::before { + content: "\f5d3"; +} + +.bi-three-dots::before { + content: "\f5d4"; +} + +.bi-toggle-off::before { + content: "\f5d5"; +} + +.bi-toggle-on::before { + content: "\f5d6"; +} + +.bi-toggle2-off::before { + content: "\f5d7"; +} + +.bi-toggle2-on::before { + content: "\f5d8"; +} + +.bi-toggles::before { + content: "\f5d9"; +} + +.bi-toggles2::before { + content: "\f5da"; +} + +.bi-tools::before { + content: "\f5db"; +} + +.bi-tornado::before { + content: "\f5dc"; +} + +.bi-trash-fill::before { + content: "\f5dd"; +} + +.bi-trash::before { + content: "\f5de"; +} + +.bi-trash2-fill::before { + content: "\f5df"; +} + +.bi-trash2::before { + content: "\f5e0"; +} + +.bi-tree-fill::before { + content: "\f5e1"; +} + +.bi-tree::before { + content: "\f5e2"; +} + +.bi-triangle-fill::before { + content: "\f5e3"; +} + +.bi-triangle-half::before { + content: "\f5e4"; +} + +.bi-triangle::before { + content: "\f5e5"; +} + +.bi-trophy-fill::before { + content: "\f5e6"; +} + +.bi-trophy::before { + content: "\f5e7"; +} + +.bi-tropical-storm::before { + content: "\f5e8"; +} + +.bi-truck-flatbed::before { + content: "\f5e9"; +} + +.bi-truck::before { + content: "\f5ea"; +} + +.bi-tsunami::before { + content: "\f5eb"; +} + +.bi-tv-fill::before { + content: "\f5ec"; +} + +.bi-tv::before { + content: "\f5ed"; +} + +.bi-twitch::before { + content: "\f5ee"; +} + +.bi-twitter::before { + content: "\f5ef"; +} + +.bi-type-bold::before { + content: "\f5f0"; +} + +.bi-type-h1::before { + content: "\f5f1"; +} + +.bi-type-h2::before { + content: "\f5f2"; +} + +.bi-type-h3::before { + content: "\f5f3"; +} + +.bi-type-italic::before { + content: "\f5f4"; +} + +.bi-type-strikethrough::before { + content: "\f5f5"; +} + +.bi-type-underline::before { + content: "\f5f6"; +} + +.bi-type::before { + content: "\f5f7"; +} + +.bi-ui-checks-grid::before { + content: "\f5f8"; +} + +.bi-ui-checks::before { + content: "\f5f9"; +} + +.bi-ui-radios-grid::before { + content: "\f5fa"; +} + +.bi-ui-radios::before { + content: "\f5fb"; +} + +.bi-umbrella-fill::before { + content: "\f5fc"; +} + +.bi-umbrella::before { + content: "\f5fd"; +} + +.bi-union::before { + content: "\f5fe"; +} + +.bi-unlock-fill::before { + content: "\f5ff"; +} + +.bi-unlock::before { + content: "\f600"; +} + +.bi-upc-scan::before { + content: "\f601"; +} + +.bi-upc::before { + content: "\f602"; +} + +.bi-upload::before { + content: "\f603"; +} + +.bi-vector-pen::before { + content: "\f604"; +} + +.bi-view-list::before { + content: "\f605"; +} + +.bi-view-stacked::before { + content: "\f606"; +} + +.bi-vinyl-fill::before { + content: "\f607"; +} + +.bi-vinyl::before { + content: "\f608"; +} + +.bi-voicemail::before { + content: "\f609"; +} + +.bi-volume-down-fill::before { + content: "\f60a"; +} + +.bi-volume-down::before { + content: "\f60b"; +} + +.bi-volume-mute-fill::before { + content: "\f60c"; +} + +.bi-volume-mute::before { + content: "\f60d"; +} + +.bi-volume-off-fill::before { + content: "\f60e"; +} + +.bi-volume-off::before { + content: "\f60f"; +} + +.bi-volume-up-fill::before { + content: "\f610"; +} + +.bi-volume-up::before { + content: "\f611"; +} + +.bi-vr::before { + content: "\f612"; +} + +.bi-wallet-fill::before { + content: "\f613"; +} + +.bi-wallet::before { + content: "\f614"; +} + +.bi-wallet2::before { + content: "\f615"; +} + +.bi-watch::before { + content: "\f616"; +} + +.bi-water::before { + content: "\f617"; +} + +.bi-whatsapp::before { + content: "\f618"; +} + +.bi-wifi-1::before { + content: "\f619"; +} + +.bi-wifi-2::before { + content: "\f61a"; +} + +.bi-wifi-off::before { + content: "\f61b"; +} + +.bi-wifi::before { + content: "\f61c"; +} + +.bi-wind::before { + content: "\f61d"; +} + +.bi-window-dock::before { + content: "\f61e"; +} + +.bi-window-sidebar::before { + content: "\f61f"; +} + +.bi-window::before { + content: "\f620"; +} + +.bi-wrench::before { + content: "\f621"; +} + +.bi-x-circle-fill::before { + content: "\f622"; +} + +.bi-x-circle::before { + content: "\f623"; +} + +.bi-x-diamond-fill::before { + content: "\f624"; +} + +.bi-x-diamond::before { + content: "\f625"; +} + +.bi-x-octagon-fill::before { + content: "\f626"; +} + +.bi-x-octagon::before { + content: "\f627"; +} + +.bi-x-square-fill::before { + content: "\f628"; +} + +.bi-x-square::before { + content: "\f629"; +} + +.bi-x::before { + content: "\f62a"; +} + +.bi-youtube::before { + content: "\f62b"; +} + +.bi-zoom-in::before { + content: "\f62c"; +} + +.bi-zoom-out::before { + content: "\f62d"; +} + +.bi-bank::before { + content: "\f62e"; +} + +.bi-bank2::before { + content: "\f62f"; +} + +.bi-bell-slash-fill::before { + content: "\f630"; +} + +.bi-bell-slash::before { + content: "\f631"; +} + +.bi-cash-coin::before { + content: "\f632"; +} + +.bi-check-lg::before { + content: "\f633"; +} + +.bi-coin::before { + content: "\f634"; +} + +.bi-currency-bitcoin::before { + content: "\f635"; +} + +.bi-currency-dollar::before { + content: "\f636"; +} + +.bi-currency-euro::before { + content: "\f637"; +} + +.bi-currency-exchange::before { + content: "\f638"; +} + +.bi-currency-pound::before { + content: "\f639"; +} + +.bi-currency-yen::before { + content: "\f63a"; +} + +.bi-dash-lg::before { + content: "\f63b"; +} + +.bi-exclamation-lg::before { + content: "\f63c"; +} + +.bi-file-earmark-pdf-fill::before { + content: "\f63d"; +} + +.bi-file-earmark-pdf::before { + content: "\f63e"; +} + +.bi-file-pdf-fill::before { + content: "\f63f"; +} + +.bi-file-pdf::before { + content: "\f640"; +} + +.bi-gender-ambiguous::before { + content: "\f641"; +} + +.bi-gender-female::before { + content: "\f642"; +} + +.bi-gender-male::before { + content: "\f643"; +} + +.bi-gender-trans::before { + content: "\f644"; +} + +.bi-headset-vr::before { + content: "\f645"; +} + +.bi-info-lg::before { + content: "\f646"; +} + +.bi-mastodon::before { + content: "\f647"; +} + +.bi-messenger::before { + content: "\f648"; +} + +.bi-piggy-bank-fill::before { + content: "\f649"; +} + +.bi-piggy-bank::before { + content: "\f64a"; +} + +.bi-pin-map-fill::before { + content: "\f64b"; +} + +.bi-pin-map::before { + content: "\f64c"; +} + +.bi-plus-lg::before { + content: "\f64d"; +} + +.bi-question-lg::before { + content: "\f64e"; +} + +.bi-recycle::before { + content: "\f64f"; +} + +.bi-reddit::before { + content: "\f650"; +} + +.bi-safe-fill::before { + content: "\f651"; +} + +.bi-safe2-fill::before { + content: "\f652"; +} + +.bi-safe2::before { + content: "\f653"; +} + +.bi-sd-card-fill::before { + content: "\f654"; +} + +.bi-sd-card::before { + content: "\f655"; +} + +.bi-skype::before { + content: "\f656"; +} + +.bi-slash-lg::before { + content: "\f657"; +} + +.bi-translate::before { + content: "\f658"; +} + +.bi-x-lg::before { + content: "\f659"; +} + +.bi-safe::before { + content: "\f65a"; +} + +.bi-apple::before { + content: "\f65b"; +} + +.bi-microsoft::before { + content: "\f65d"; +} + +.bi-windows::before { + content: "\f65e"; +} + +.bi-behance::before { + content: "\f65c"; +} + +.bi-dribbble::before { + content: "\f65f"; +} + +.bi-line::before { + content: "\f660"; +} + +.bi-medium::before { + content: "\f661"; +} + +.bi-paypal::before { + content: "\f662"; +} + +.bi-pinterest::before { + content: "\f663"; +} + +.bi-signal::before { + content: "\f664"; +} + +.bi-snapchat::before { + content: "\f665"; +} + +.bi-spotify::before { + content: "\f666"; +} + +.bi-stack-overflow::before { + content: "\f667"; +} + +.bi-strava::before { + content: "\f668"; +} + +.bi-wordpress::before { + content: "\f669"; +} + +.bi-vimeo::before { + content: "\f66a"; +} + +.bi-activity::before { + content: "\f66b"; +} + +.bi-easel2-fill::before { + content: "\f66c"; +} + +.bi-easel2::before { + content: "\f66d"; +} + +.bi-easel3-fill::before { + content: "\f66e"; +} + +.bi-easel3::before { + content: "\f66f"; +} + +.bi-fan::before { + content: "\f670"; +} + +.bi-fingerprint::before { + content: "\f671"; +} + +.bi-graph-down-arrow::before { + content: "\f672"; +} + +.bi-graph-up-arrow::before { + content: "\f673"; +} + +.bi-hypnotize::before { + content: "\f674"; +} + +.bi-magic::before { + content: "\f675"; +} + +.bi-person-rolodex::before { + content: "\f676"; +} + +.bi-person-video::before { + content: "\f677"; +} + +.bi-person-video2::before { + content: "\f678"; +} + +.bi-person-video3::before { + content: "\f679"; +} + +.bi-person-workspace::before { + content: "\f67a"; +} + +.bi-radioactive::before { + content: "\f67b"; +} + +.bi-webcam-fill::before { + content: "\f67c"; +} + +.bi-webcam::before { + content: "\f67d"; +} + +.bi-yin-yang::before { + content: "\f67e"; +} + +.bi-bandaid-fill::before { + content: "\f680"; +} + +.bi-bandaid::before { + content: "\f681"; +} + +.bi-bluetooth::before { + content: "\f682"; +} + +.bi-body-text::before { + content: "\f683"; +} + +.bi-boombox::before { + content: "\f684"; +} + +.bi-boxes::before { + content: "\f685"; +} + +.bi-dpad-fill::before { + content: "\f686"; +} + +.bi-dpad::before { + content: "\f687"; +} + +.bi-ear-fill::before { + content: "\f688"; +} + +.bi-ear::before { + content: "\f689"; +} + +.bi-envelope-check-1::before { + content: "\f68a"; +} + +.bi-envelope-check-fill::before { + content: "\f68b"; +} + +.bi-envelope-check::before { + content: "\f68c"; +} + +.bi-envelope-dash-1::before { + content: "\f68d"; +} + +.bi-envelope-dash-fill::before { + content: "\f68e"; +} + +.bi-envelope-dash::before { + content: "\f68f"; +} + +.bi-envelope-exclamation-1::before { + content: "\f690"; +} + +.bi-envelope-exclamation-fill::before { + content: "\f691"; +} + +.bi-envelope-exclamation::before { + content: "\f692"; +} + +.bi-envelope-plus-fill::before { + content: "\f693"; +} + +.bi-envelope-plus::before { + content: "\f694"; +} + +.bi-envelope-slash-1::before { + content: "\f695"; +} + +.bi-envelope-slash-fill::before { + content: "\f696"; +} + +.bi-envelope-slash::before { + content: "\f697"; +} + +.bi-envelope-x-1::before { + content: "\f698"; +} + +.bi-envelope-x-fill::before { + content: "\f699"; +} + +.bi-envelope-x::before { + content: "\f69a"; +} + +.bi-explicit-fill::before { + content: "\f69b"; +} + +.bi-explicit::before { + content: "\f69c"; +} + +.bi-git::before { + content: "\f69d"; +} + +.bi-infinity::before { + content: "\f69e"; +} + +.bi-list-columns-reverse::before { + content: "\f69f"; +} + +.bi-list-columns::before { + content: "\f6a0"; +} + +.bi-meta::before { + content: "\f6a1"; +} + +.bi-mortorboard-fill::before { + content: "\f6a2"; +} + +.bi-mortorboard::before { + content: "\f6a3"; +} + +.bi-nintendo-switch::before { + content: "\f6a4"; +} + +.bi-pc-display-horizontal::before { + content: "\f6a5"; +} + +.bi-pc-display::before { + content: "\f6a6"; +} + +.bi-pc-horizontal::before { + content: "\f6a7"; +} + +.bi-pc::before { + content: "\f6a8"; +} + +.bi-playstation::before { + content: "\f6a9"; +} + +.bi-plus-slash-minus::before { + content: "\f6aa"; +} + +.bi-projector-fill::before { + content: "\f6ab"; +} + +.bi-projector::before { + content: "\f6ac"; +} + +.bi-qr-code-scan::before { + content: "\f6ad"; +} + +.bi-qr-code::before { + content: "\f6ae"; +} + +.bi-quora::before { + content: "\f6af"; +} + +.bi-quote::before { + content: "\f6b0"; +} + +.bi-robot::before { + content: "\f6b1"; +} + +.bi-send-check-fill::before { + content: "\f6b2"; +} + +.bi-send-check::before { + content: "\f6b3"; +} + +.bi-send-dash-fill::before { + content: "\f6b4"; +} + +.bi-send-dash::before { + content: "\f6b5"; +} + +.bi-send-exclamation-1::before { + content: "\f6b6"; +} + +.bi-send-exclamation-fill::before { + content: "\f6b7"; +} + +.bi-send-exclamation::before { + content: "\f6b8"; +} + +.bi-send-fill::before { + content: "\f6b9"; +} + +.bi-send-plus-fill::before { + content: "\f6ba"; +} + +.bi-send-plus::before { + content: "\f6bb"; +} + +.bi-send-slash-fill::before { + content: "\f6bc"; +} + +.bi-send-slash::before { + content: "\f6bd"; +} + +.bi-send-x-fill::before { + content: "\f6be"; +} + +.bi-send-x::before { + content: "\f6bf"; +} + +.bi-send::before { + content: "\f6c0"; +} + +.bi-steam::before { + content: "\f6c1"; +} + +.bi-terminal-dash-1::before { + content: "\f6c2"; +} + +.bi-terminal-dash::before { + content: "\f6c3"; +} + +.bi-terminal-plus::before { + content: "\f6c4"; +} + +.bi-terminal-split::before { + content: "\f6c5"; +} + +.bi-ticket-detailed-fill::before { + content: "\f6c6"; +} + +.bi-ticket-detailed::before { + content: "\f6c7"; +} + +.bi-ticket-fill::before { + content: "\f6c8"; +} + +.bi-ticket-perforated-fill::before { + content: "\f6c9"; +} + +.bi-ticket-perforated::before { + content: "\f6ca"; +} + +.bi-ticket::before { + content: "\f6cb"; +} + +.bi-tiktok::before { + content: "\f6cc"; +} + +.bi-window-dash::before { + content: "\f6cd"; +} + +.bi-window-desktop::before { + content: "\f6ce"; +} + +.bi-window-fullscreen::before { + content: "\f6cf"; +} + +.bi-window-plus::before { + content: "\f6d0"; +} + +.bi-window-split::before { + content: "\f6d1"; +} + +.bi-window-stack::before { + content: "\f6d2"; +} + +.bi-window-x::before { + content: "\f6d3"; +} + +.bi-xbox::before { + content: "\f6d4"; +} + +.bi-ethernet::before { + content: "\f6d5"; +} + +.bi-hdmi-fill::before { + content: "\f6d6"; +} + +.bi-hdmi::before { + content: "\f6d7"; +} + +.bi-usb-c-fill::before { + content: "\f6d8"; +} + +.bi-usb-c::before { + content: "\f6d9"; +} + +.bi-usb-fill::before { + content: "\f6da"; +} + +.bi-usb-plug-fill::before { + content: "\f6db"; +} + +.bi-usb-plug::before { + content: "\f6dc"; +} + +.bi-usb-symbol::before { + content: "\f6dd"; +} + +.bi-usb::before { + content: "\f6de"; +} + +.bi-boombox-fill::before { + content: "\f6df"; +} + +.bi-displayport-1::before { + content: "\f6e0"; +} + +.bi-displayport::before { + content: "\f6e1"; +} + +.bi-gpu-card::before { + content: "\f6e2"; +} + +.bi-memory::before { + content: "\f6e3"; +} + +.bi-modem-fill::before { + content: "\f6e4"; +} + +.bi-modem::before { + content: "\f6e5"; +} + +.bi-motherboard-fill::before { + content: "\f6e6"; +} + +.bi-motherboard::before { + content: "\f6e7"; +} + +.bi-optical-audio-fill::before { + content: "\f6e8"; +} + +.bi-optical-audio::before { + content: "\f6e9"; +} + +.bi-pci-card::before { + content: "\f6ea"; +} + +.bi-router-fill::before { + content: "\f6eb"; +} + +.bi-router::before { + content: "\f6ec"; +} + +.bi-ssd-fill::before { + content: "\f6ed"; +} + +.bi-ssd::before { + content: "\f6ee"; +} + +.bi-thunderbolt-fill::before { + content: "\f6ef"; +} + +.bi-thunderbolt::before { + content: "\f6f0"; +} + +.bi-usb-drive-fill::before { + content: "\f6f1"; +} + +.bi-usb-drive::before { + content: "\f6f2"; +} + +.bi-usb-micro-fill::before { + content: "\f6f3"; +} + +.bi-usb-micro::before { + content: "\f6f4"; +} + +.bi-usb-mini-fill::before { + content: "\f6f5"; +} + +.bi-usb-mini::before { + content: "\f6f6"; +} + +.bi-cloud-haze2::before { + content: "\f6f7"; +} + +.bi-device-hdd-fill::before { + content: "\f6f8"; +} + +.bi-device-hdd::before { + content: "\f6f9"; +} + +.bi-device-ssd-fill::before { + content: "\f6fa"; +} + +.bi-device-ssd::before { + content: "\f6fb"; +} + +.bi-displayport-fill::before { + content: "\f6fc"; +} + +.bi-mortarboard-fill::before { + content: "\f6fd"; +} + +.bi-mortarboard::before { + content: "\f6fe"; +} + +.bi-terminal-x::before { + content: "\f6ff"; +} + +.bi-arrow-through-heart-fill::before { + content: "\f700"; +} + +.bi-arrow-through-heart::before { + content: "\f701"; +} + +.bi-badge-sd-fill::before { + content: "\f702"; +} + +.bi-badge-sd::before { + content: "\f703"; +} + +.bi-bag-heart-fill::before { + content: "\f704"; +} + +.bi-bag-heart::before { + content: "\f705"; +} + +.bi-balloon-fill::before { + content: "\f706"; +} + +.bi-balloon-heart-fill::before { + content: "\f707"; +} + +.bi-balloon-heart::before { + content: "\f708"; +} + +.bi-balloon::before { + content: "\f709"; +} + +.bi-box2-fill::before { + content: "\f70a"; +} + +.bi-box2-heart-fill::before { + content: "\f70b"; +} + +.bi-box2-heart::before { + content: "\f70c"; +} + +.bi-box2::before { + content: "\f70d"; +} + +.bi-braces-asterisk::before { + content: "\f70e"; +} + +.bi-calendar-heart-fill::before { + content: "\f70f"; +} + +.bi-calendar-heart::before { + content: "\f710"; +} + +.bi-calendar2-heart-fill::before { + content: "\f711"; +} + +.bi-calendar2-heart::before { + content: "\f712"; +} + +.bi-chat-heart-fill::before { + content: "\f713"; +} + +.bi-chat-heart::before { + content: "\f714"; +} + +.bi-chat-left-heart-fill::before { + content: "\f715"; +} + +.bi-chat-left-heart::before { + content: "\f716"; +} + +.bi-chat-right-heart-fill::before { + content: "\f717"; +} + +.bi-chat-right-heart::before { + content: "\f718"; +} + +.bi-chat-square-heart-fill::before { + content: "\f719"; +} + +.bi-chat-square-heart::before { + content: "\f71a"; +} + +.bi-clipboard-check-fill::before { + content: "\f71b"; +} + +.bi-clipboard-data-fill::before { + content: "\f71c"; +} + +.bi-clipboard-fill::before { + content: "\f71d"; +} + +.bi-clipboard-heart-fill::before { + content: "\f71e"; +} + +.bi-clipboard-heart::before { + content: "\f71f"; +} + +.bi-clipboard-minus-fill::before { + content: "\f720"; +} + +.bi-clipboard-plus-fill::before { + content: "\f721"; +} + +.bi-clipboard-pulse::before { + content: "\f722"; +} + +.bi-clipboard-x-fill::before { + content: "\f723"; +} + +.bi-clipboard2-check-fill::before { + content: "\f724"; +} + +.bi-clipboard2-check::before { + content: "\f725"; +} + +.bi-clipboard2-data-fill::before { + content: "\f726"; +} + +.bi-clipboard2-data::before { + content: "\f727"; +} + +.bi-clipboard2-fill::before { + content: "\f728"; +} + +.bi-clipboard2-heart-fill::before { + content: "\f729"; +} + +.bi-clipboard2-heart::before { + content: "\f72a"; +} + +.bi-clipboard2-minus-fill::before { + content: "\f72b"; +} + +.bi-clipboard2-minus::before { + content: "\f72c"; +} + +.bi-clipboard2-plus-fill::before { + content: "\f72d"; +} + +.bi-clipboard2-plus::before { + content: "\f72e"; +} + +.bi-clipboard2-pulse-fill::before { + content: "\f72f"; +} + +.bi-clipboard2-pulse::before { + content: "\f730"; +} + +.bi-clipboard2-x-fill::before { + content: "\f731"; +} + +.bi-clipboard2-x::before { + content: "\f732"; +} + +.bi-clipboard2::before { + content: "\f733"; +} + +.bi-emoji-kiss-fill::before { + content: "\f734"; +} + +.bi-emoji-kiss::before { + content: "\f735"; +} + +.bi-envelope-heart-fill::before { + content: "\f736"; +} + +.bi-envelope-heart::before { + content: "\f737"; +} + +.bi-envelope-open-heart-fill::before { + content: "\f738"; +} + +.bi-envelope-open-heart::before { + content: "\f739"; +} + +.bi-envelope-paper-fill::before { + content: "\f73a"; +} + +.bi-envelope-paper-heart-fill::before { + content: "\f73b"; +} + +.bi-envelope-paper-heart::before { + content: "\f73c"; +} + +.bi-envelope-paper::before { + content: "\f73d"; +} + +.bi-filetype-aac::before { + content: "\f73e"; +} + +.bi-filetype-ai::before { + content: "\f73f"; +} + +.bi-filetype-bmp::before { + content: "\f740"; +} + +.bi-filetype-cs::before { + content: "\f741"; +} + +.bi-filetype-css::before { + content: "\f742"; +} + +.bi-filetype-csv::before { + content: "\f743"; +} + +.bi-filetype-doc::before { + content: "\f744"; +} + +.bi-filetype-docx::before { + content: "\f745"; +} + +.bi-filetype-exe::before { + content: "\f746"; +} + +.bi-filetype-gif::before { + content: "\f747"; +} + +.bi-filetype-heic::before { + content: "\f748"; +} + +.bi-filetype-html::before { + content: "\f749"; +} + +.bi-filetype-java::before { + content: "\f74a"; +} + +.bi-filetype-jpg::before { + content: "\f74b"; +} + +.bi-filetype-js::before { + content: "\f74c"; +} + +.bi-filetype-jsx::before { + content: "\f74d"; +} + +.bi-filetype-key::before { + content: "\f74e"; +} + +.bi-filetype-m4p::before { + content: "\f74f"; +} + +.bi-filetype-md::before { + content: "\f750"; +} + +.bi-filetype-mdx::before { + content: "\f751"; +} + +.bi-filetype-mov::before { + content: "\f752"; +} + +.bi-filetype-mp3::before { + content: "\f753"; +} + +.bi-filetype-mp4::before { + content: "\f754"; +} + +.bi-filetype-otf::before { + content: "\f755"; +} + +.bi-filetype-pdf::before { + content: "\f756"; +} + +.bi-filetype-php::before { + content: "\f757"; +} + +.bi-filetype-png::before { + content: "\f758"; +} + +.bi-filetype-ppt-1::before { + content: "\f759"; +} + +.bi-filetype-ppt::before { + content: "\f75a"; +} + +.bi-filetype-psd::before { + content: "\f75b"; +} + +.bi-filetype-py::before { + content: "\f75c"; +} + +.bi-filetype-raw::before { + content: "\f75d"; +} + +.bi-filetype-rb::before { + content: "\f75e"; +} + +.bi-filetype-sass::before { + content: "\f75f"; +} + +.bi-filetype-scss::before { + content: "\f760"; +} + +.bi-filetype-sh::before { + content: "\f761"; +} + +.bi-filetype-svg::before { + content: "\f762"; +} + +.bi-filetype-tiff::before { + content: "\f763"; +} + +.bi-filetype-tsx::before { + content: "\f764"; +} + +.bi-filetype-ttf::before { + content: "\f765"; +} + +.bi-filetype-txt::before { + content: "\f766"; +} + +.bi-filetype-wav::before { + content: "\f767"; +} + +.bi-filetype-woff::before { + content: "\f768"; +} + +.bi-filetype-xls-1::before { + content: "\f769"; +} + +.bi-filetype-xls::before { + content: "\f76a"; +} + +.bi-filetype-xml::before { + content: "\f76b"; +} + +.bi-filetype-yml::before { + content: "\f76c"; +} + +.bi-heart-arrow::before { + content: "\f76d"; +} + +.bi-heart-pulse-fill::before { + content: "\f76e"; +} + +.bi-heart-pulse::before { + content: "\f76f"; +} + +.bi-heartbreak-fill::before { + content: "\f770"; +} + +.bi-heartbreak::before { + content: "\f771"; +} + +.bi-hearts::before { + content: "\f772"; +} + +.bi-hospital-fill::before { + content: "\f773"; +} + +.bi-hospital::before { + content: "\f774"; +} + +.bi-house-heart-fill::before { + content: "\f775"; +} + +.bi-house-heart::before { + content: "\f776"; +} + +.bi-incognito::before { + content: "\f777"; +} + +.bi-magnet-fill::before { + content: "\f778"; +} + +.bi-magnet::before { + content: "\f779"; +} + +.bi-person-heart::before { + content: "\f77a"; +} + +.bi-person-hearts::before { + content: "\f77b"; +} + +.bi-phone-flip::before { + content: "\f77c"; +} + +.bi-plugin::before { + content: "\f77d"; +} + +.bi-postage-fill::before { + content: "\f77e"; +} + +.bi-postage-heart-fill::before { + content: "\f77f"; +} + +.bi-postage-heart::before { + content: "\f780"; +} + +.bi-postage::before { + content: "\f781"; +} + +.bi-postcard-fill::before { + content: "\f782"; +} + +.bi-postcard-heart-fill::before { + content: "\f783"; +} + +.bi-postcard-heart::before { + content: "\f784"; +} + +.bi-postcard::before { + content: "\f785"; +} + +.bi-search-heart-fill::before { + content: "\f786"; +} + +.bi-search-heart::before { + content: "\f787"; +} + +.bi-sliders2-vertical::before { + content: "\f788"; +} + +.bi-sliders2::before { + content: "\f789"; +} + +.bi-trash3-fill::before { + content: "\f78a"; +} + +.bi-trash3::before { + content: "\f78b"; +} + +.bi-valentine::before { + content: "\f78c"; +} + +.bi-valentine2::before { + content: "\f78d"; +} + +.bi-wrench-adjustable-circle-fill::before { + content: "\f78e"; +} + +.bi-wrench-adjustable-circle::before { + content: "\f78f"; +} + +.bi-wrench-adjustable::before { + content: "\f790"; +} + +.bi-filetype-json::before { + content: "\f791"; +} + +.bi-filetype-pptx::before { + content: "\f792"; +} + +.bi-filetype-xlsx::before { + content: "\f793"; +} + +.bi-1-circle-1::before { + content: "\f794"; +} + +.bi-1-circle-fill-1::before { + content: "\f795"; +} + +.bi-1-circle-fill::before { + content: "\f796"; +} + +.bi-1-circle::before { + content: "\f797"; +} + +.bi-1-square-fill::before { + content: "\f798"; +} + +.bi-1-square::before { + content: "\f799"; +} + +.bi-2-circle-1::before { + content: "\f79a"; +} + +.bi-2-circle-fill-1::before { + content: "\f79b"; +} + +.bi-2-circle-fill::before { + content: "\f79c"; +} + +.bi-2-circle::before { + content: "\f79d"; +} + +.bi-2-square-fill::before { + content: "\f79e"; +} + +.bi-2-square::before { + content: "\f79f"; +} + +.bi-3-circle-1::before { + content: "\f7a0"; +} + +.bi-3-circle-fill-1::before { + content: "\f7a1"; +} + +.bi-3-circle-fill::before { + content: "\f7a2"; +} + +.bi-3-circle::before { + content: "\f7a3"; +} + +.bi-3-square-fill::before { + content: "\f7a4"; +} + +.bi-3-square::before { + content: "\f7a5"; +} + +.bi-4-circle-1::before { + content: "\f7a6"; +} + +.bi-4-circle-fill-1::before { + content: "\f7a7"; +} + +.bi-4-circle-fill::before { + content: "\f7a8"; +} + +.bi-4-circle::before { + content: "\f7a9"; +} + +.bi-4-square-fill::before { + content: "\f7aa"; +} + +.bi-4-square::before { + content: "\f7ab"; +} + +.bi-5-circle-1::before { + content: "\f7ac"; +} + +.bi-5-circle-fill-1::before { + content: "\f7ad"; +} + +.bi-5-circle-fill::before { + content: "\f7ae"; +} + +.bi-5-circle::before { + content: "\f7af"; +} + +.bi-5-square-fill::before { + content: "\f7b0"; +} + +.bi-5-square::before { + content: "\f7b1"; +} + +.bi-6-circle-1::before { + content: "\f7b2"; +} + +.bi-6-circle-fill-1::before { + content: "\f7b3"; +} + +.bi-6-circle-fill::before { + content: "\f7b4"; +} + +.bi-6-circle::before { + content: "\f7b5"; +} + +.bi-6-square-fill::before { + content: "\f7b6"; +} + +.bi-6-square::before { + content: "\f7b7"; +} + +.bi-7-circle-1::before { + content: "\f7b8"; +} + +.bi-7-circle-fill-1::before { + content: "\f7b9"; +} + +.bi-7-circle-fill::before { + content: "\f7ba"; +} + +.bi-7-circle::before { + content: "\f7bb"; +} + +.bi-7-square-fill::before { + content: "\f7bc"; +} + +.bi-7-square::before { + content: "\f7bd"; +} + +.bi-8-circle-1::before { + content: "\f7be"; +} + +.bi-8-circle-fill-1::before { + content: "\f7bf"; +} + +.bi-8-circle-fill::before { + content: "\f7c0"; +} + +.bi-8-circle::before { + content: "\f7c1"; +} + +.bi-8-square-fill::before { + content: "\f7c2"; +} + +.bi-8-square::before { + content: "\f7c3"; +} + +.bi-9-circle-1::before { + content: "\f7c4"; +} + +.bi-9-circle-fill-1::before { + content: "\f7c5"; +} + +.bi-9-circle-fill::before { + content: "\f7c6"; +} + +.bi-9-circle::before { + content: "\f7c7"; +} + +.bi-9-square-fill::before { + content: "\f7c8"; +} + +.bi-9-square::before { + content: "\f7c9"; +} + +.bi-airplane-engines-fill::before { + content: "\f7ca"; +} + +.bi-airplane-engines::before { + content: "\f7cb"; +} + +.bi-airplane-fill::before { + content: "\f7cc"; +} + +.bi-airplane::before { + content: "\f7cd"; +} + +.bi-alexa::before { + content: "\f7ce"; +} + +.bi-alipay::before { + content: "\f7cf"; +} + +.bi-android::before { + content: "\f7d0"; +} + +.bi-android2::before { + content: "\f7d1"; +} + +.bi-box-fill::before { + content: "\f7d2"; +} + +.bi-box-seam-fill::before { + content: "\f7d3"; +} + +.bi-browser-chrome::before { + content: "\f7d4"; +} + +.bi-browser-edge::before { + content: "\f7d5"; +} + +.bi-browser-firefox::before { + content: "\f7d6"; +} + +.bi-browser-safari::before { + content: "\f7d7"; +} + +.bi-c-circle-1::before { + content: "\f7d8"; +} + +.bi-c-circle-fill-1::before { + content: "\f7d9"; +} + +.bi-c-circle-fill::before { + content: "\f7da"; +} + +.bi-c-circle::before { + content: "\f7db"; +} + +.bi-c-square-fill::before { + content: "\f7dc"; +} + +.bi-c-square::before { + content: "\f7dd"; +} + +.bi-capsule-pill::before { + content: "\f7de"; +} + +.bi-capsule::before { + content: "\f7df"; +} + +.bi-car-front-fill::before { + content: "\f7e0"; +} + +.bi-car-front::before { + content: "\f7e1"; +} + +.bi-cassette-fill::before { + content: "\f7e2"; +} + +.bi-cassette::before { + content: "\f7e3"; +} + +.bi-cc-circle-1::before { + content: "\f7e4"; +} + +.bi-cc-circle-fill-1::before { + content: "\f7e5"; +} + +.bi-cc-circle-fill::before { + content: "\f7e6"; +} + +.bi-cc-circle::before { + content: "\f7e7"; +} + +.bi-cc-square-fill::before { + content: "\f7e8"; +} + +.bi-cc-square::before { + content: "\f7e9"; +} + +.bi-cup-hot-fill::before { + content: "\f7ea"; +} + +.bi-cup-hot::before { + content: "\f7eb"; +} + +.bi-currency-rupee::before { + content: "\f7ec"; +} + +.bi-dropbox::before { + content: "\f7ed"; +} + +.bi-escape::before { + content: "\f7ee"; +} + +.bi-fast-forward-btn-fill::before { + content: "\f7ef"; +} + +.bi-fast-forward-btn::before { + content: "\f7f0"; +} + +.bi-fast-forward-circle-fill::before { + content: "\f7f1"; +} + +.bi-fast-forward-circle::before { + content: "\f7f2"; +} + +.bi-fast-forward-fill::before { + content: "\f7f3"; +} + +.bi-fast-forward::before { + content: "\f7f4"; +} + +.bi-filetype-sql::before { + content: "\f7f5"; +} + +.bi-fire::before { + content: "\f7f6"; +} + +.bi-google-play::before { + content: "\f7f7"; +} + +.bi-h-circle-1::before { + content: "\f7f8"; +} + +.bi-h-circle-fill-1::before { + content: "\f7f9"; +} + +.bi-h-circle-fill::before { + content: "\f7fa"; +} + +.bi-h-circle::before { + content: "\f7fb"; +} + +.bi-h-square-fill::before { + content: "\f7fc"; +} + +.bi-h-square::before { + content: "\f7fd"; +} + +.bi-indent::before { + content: "\f7fe"; +} + +.bi-lungs-fill::before { + content: "\f7ff"; +} + +.bi-lungs::before { + content: "\f800"; +} + +.bi-microsoft-teams::before { + content: "\f801"; +} + +.bi-p-circle-1::before { + content: "\f802"; +} + +.bi-p-circle-fill-1::before { + content: "\f803"; +} + +.bi-p-circle-fill::before { + content: "\f804"; +} + +.bi-p-circle::before { + content: "\f805"; +} + +.bi-p-square-fill::before { + content: "\f806"; +} + +.bi-p-square::before { + content: "\f807"; +} + +.bi-pass-fill::before { + content: "\f808"; +} + +.bi-pass::before { + content: "\f809"; +} + +.bi-prescription::before { + content: "\f80a"; +} + +.bi-prescription2::before { + content: "\f80b"; +} + +.bi-r-circle-1::before { + content: "\f80c"; +} + +.bi-r-circle-fill-1::before { + content: "\f80d"; +} + +.bi-r-circle-fill::before { + content: "\f80e"; +} + +.bi-r-circle::before { + content: "\f80f"; +} + +.bi-r-square-fill::before { + content: "\f810"; +} + +.bi-r-square::before { + content: "\f811"; +} + +.bi-repeat-1::before { + content: "\f812"; +} + +.bi-repeat::before { + content: "\f813"; +} + +.bi-rewind-btn-fill::before { + content: "\f814"; +} + +.bi-rewind-btn::before { + content: "\f815"; +} + +.bi-rewind-circle-fill::before { + content: "\f816"; +} + +.bi-rewind-circle::before { + content: "\f817"; +} + +.bi-rewind-fill::before { + content: "\f818"; +} + +.bi-rewind::before { + content: "\f819"; +} + +.bi-train-freight-front-fill::before { + content: "\f81a"; +} + +.bi-train-freight-front::before { + content: "\f81b"; +} + +.bi-train-front-fill::before { + content: "\f81c"; +} + +.bi-train-front::before { + content: "\f81d"; +} + +.bi-train-lightrail-front-fill::before { + content: "\f81e"; +} + +.bi-train-lightrail-front::before { + content: "\f81f"; +} + +.bi-truck-front-fill::before { + content: "\f820"; +} + +.bi-truck-front::before { + content: "\f821"; +} + +.bi-ubuntu::before { + content: "\f822"; +} + +.bi-unindent::before { + content: "\f823"; +} + +.bi-unity::before { + content: "\f824"; +} + +.bi-universal-access-circle::before { + content: "\f825"; +} + +.bi-universal-access::before { + content: "\f826"; +} + +.bi-virus::before { + content: "\f827"; +} + +.bi-virus2::before { + content: "\f828"; +} + +.bi-wechat::before { + content: "\f829"; +} + +.bi-yelp::before { + content: "\f82a"; +} + +.bi-sign-stop-fill::before { + content: "\f82b"; +} + +.bi-sign-stop-lights-fill::before { + content: "\f82c"; +} + +.bi-sign-stop-lights::before { + content: "\f82d"; +} + +.bi-sign-stop::before { + content: "\f82e"; +} + +.bi-sign-turn-left-fill::before { + content: "\f82f"; +} + +.bi-sign-turn-left::before { + content: "\f830"; +} + +.bi-sign-turn-right-fill::before { + content: "\f831"; +} + +.bi-sign-turn-right::before { + content: "\f832"; +} + +.bi-sign-turn-slight-left-fill::before { + content: "\f833"; +} + +.bi-sign-turn-slight-left::before { + content: "\f834"; +} + +.bi-sign-turn-slight-right-fill::before { + content: "\f835"; +} + +.bi-sign-turn-slight-right::before { + content: "\f836"; +} + +.bi-sign-yield-fill::before { + content: "\f837"; +} + +.bi-sign-yield::before { + content: "\f838"; +} + +.bi-ev-station-fill::before { + content: "\f839"; +} + +.bi-ev-station::before { + content: "\f83a"; +} + +.bi-fuel-pump-diesel-fill::before { + content: "\f83b"; +} + +.bi-fuel-pump-diesel::before { + content: "\f83c"; +} + +.bi-fuel-pump-fill::before { + content: "\f83d"; +} + +.bi-fuel-pump::before { + content: "\f83e"; +} + +.bi-0-circle-fill::before { + content: "\f83f"; +} + +.bi-0-circle::before { + content: "\f840"; +} + +.bi-0-square-fill::before { + content: "\f841"; +} + +.bi-0-square::before { + content: "\f842"; +} + +.bi-rocket-fill::before { + content: "\f843"; +} + +.bi-rocket-takeoff-fill::before { + content: "\f844"; +} + +.bi-rocket-takeoff::before { + content: "\f845"; +} + +.bi-rocket::before { + content: "\f846"; +} + +.bi-stripe::before { + content: "\f847"; +} + +.bi-subscript::before { + content: "\f848"; +} + +.bi-superscript::before { + content: "\f849"; +} + +.bi-trello::before { + content: "\f84a"; +} + +.bi-envelope-at-fill::before { + content: "\f84b"; +} + +.bi-envelope-at::before { + content: "\f84c"; +} + +.bi-regex::before { + content: "\f84d"; +} + +.bi-text-wrap::before { + content: "\f84e"; +} + +.bi-sign-dead-end-fill::before { + content: "\f84f"; +} + +.bi-sign-dead-end::before { + content: "\f850"; +} + +.bi-sign-do-not-enter-fill::before { + content: "\f851"; +} + +.bi-sign-do-not-enter::before { + content: "\f852"; +} + +.bi-sign-intersection-fill::before { + content: "\f853"; +} + +.bi-sign-intersection-side-fill::before { + content: "\f854"; +} + +.bi-sign-intersection-side::before { + content: "\f855"; +} + +.bi-sign-intersection-t-fill::before { + content: "\f856"; +} + +.bi-sign-intersection-t::before { + content: "\f857"; +} + +.bi-sign-intersection-y-fill::before { + content: "\f858"; +} + +.bi-sign-intersection-y::before { + content: "\f859"; +} + +.bi-sign-intersection::before { + content: "\f85a"; +} + +.bi-sign-merge-left-fill::before { + content: "\f85b"; +} + +.bi-sign-merge-left::before { + content: "\f85c"; +} + +.bi-sign-merge-right-fill::before { + content: "\f85d"; +} + +.bi-sign-merge-right::before { + content: "\f85e"; +} + +.bi-sign-no-left-turn-fill::before { + content: "\f85f"; +} + +.bi-sign-no-left-turn::before { + content: "\f860"; +} + +.bi-sign-no-parking-fill::before { + content: "\f861"; +} + +.bi-sign-no-parking::before { + content: "\f862"; +} + +.bi-sign-no-right-turn-fill::before { + content: "\f863"; +} + +.bi-sign-no-right-turn::before { + content: "\f864"; +} + +.bi-sign-railroad-fill::before { + content: "\f865"; +} + +.bi-sign-railroad::before { + content: "\f866"; +} + +.bi-building-add::before { + content: "\f867"; +} + +.bi-building-check::before { + content: "\f868"; +} + +.bi-building-dash::before { + content: "\f869"; +} + +.bi-building-down::before { + content: "\f86a"; +} + +.bi-building-exclamation::before { + content: "\f86b"; +} + +.bi-building-fill-add::before { + content: "\f86c"; +} + +.bi-building-fill-check::before { + content: "\f86d"; +} + +.bi-building-fill-dash::before { + content: "\f86e"; +} + +.bi-building-fill-down::before { + content: "\f86f"; +} + +.bi-building-fill-exclamation::before { + content: "\f870"; +} + +.bi-building-fill-gear::before { + content: "\f871"; +} + +.bi-building-fill-lock::before { + content: "\f872"; +} + +.bi-building-fill-slash::before { + content: "\f873"; +} + +.bi-building-fill-up::before { + content: "\f874"; +} + +.bi-building-fill-x::before { + content: "\f875"; +} + +.bi-building-fill::before { + content: "\f876"; +} + +.bi-building-gear::before { + content: "\f877"; +} + +.bi-building-lock::before { + content: "\f878"; +} + +.bi-building-slash::before { + content: "\f879"; +} + +.bi-building-up::before { + content: "\f87a"; +} + +.bi-building-x::before { + content: "\f87b"; +} + +.bi-buildings-fill::before { + content: "\f87c"; +} + +.bi-buildings::before { + content: "\f87d"; +} + +.bi-bus-front-fill::before { + content: "\f87e"; +} + +.bi-bus-front::before { + content: "\f87f"; +} + +.bi-ev-front-fill::before { + content: "\f880"; +} + +.bi-ev-front::before { + content: "\f881"; +} + +.bi-globe-americas::before { + content: "\f882"; +} + +.bi-globe-asia-australia::before { + content: "\f883"; +} + +.bi-globe-central-south-asia::before { + content: "\f884"; +} + +.bi-globe-europe-africa::before { + content: "\f885"; +} + +.bi-house-add-fill::before { + content: "\f886"; +} + +.bi-house-add::before { + content: "\f887"; +} + +.bi-house-check-fill::before { + content: "\f888"; +} + +.bi-house-check::before { + content: "\f889"; +} + +.bi-house-dash-fill::before { + content: "\f88a"; +} + +.bi-house-dash::before { + content: "\f88b"; +} + +.bi-house-down-fill::before { + content: "\f88c"; +} + +.bi-house-down::before { + content: "\f88d"; +} + +.bi-house-exclamation-fill::before { + content: "\f88e"; +} + +.bi-house-exclamation::before { + content: "\f88f"; +} + +.bi-house-gear-fill::before { + content: "\f890"; +} + +.bi-house-gear::before { + content: "\f891"; +} + +.bi-house-lock-fill::before { + content: "\f892"; +} + +.bi-house-lock::before { + content: "\f893"; +} + +.bi-house-slash-fill::before { + content: "\f894"; +} + +.bi-house-slash::before { + content: "\f895"; +} + +.bi-house-up-fill::before { + content: "\f896"; +} + +.bi-house-up::before { + content: "\f897"; +} + +.bi-house-x-fill::before { + content: "\f898"; +} + +.bi-house-x::before { + content: "\f899"; +} + +.bi-person-add::before { + content: "\f89a"; +} + +.bi-person-down::before { + content: "\f89b"; +} + +.bi-person-exclamation::before { + content: "\f89c"; +} + +.bi-person-fill-add::before { + content: "\f89d"; +} + +.bi-person-fill-check::before { + content: "\f89e"; +} + +.bi-person-fill-dash::before { + content: "\f89f"; +} + +.bi-person-fill-down::before { + content: "\f8a0"; +} + +.bi-person-fill-exclamation::before { + content: "\f8a1"; +} + +.bi-person-fill-gear::before { + content: "\f8a2"; +} + +.bi-person-fill-lock::before { + content: "\f8a3"; +} + +.bi-person-fill-slash::before { + content: "\f8a4"; +} + +.bi-person-fill-up::before { + content: "\f8a5"; +} + +.bi-person-fill-x::before { + content: "\f8a6"; +} + +.bi-person-gear::before { + content: "\f8a7"; +} + +.bi-person-lock::before { + content: "\f8a8"; +} + +.bi-person-slash::before { + content: "\f8a9"; +} + +.bi-person-up::before { + content: "\f8aa"; +} + +.bi-scooter::before { + content: "\f8ab"; +} + +.bi-taxi-front-fill::before { + content: "\f8ac"; +} + +.bi-taxi-front::before { + content: "\f8ad"; +} + +.bi-amd::before { + content: "\f8ae"; +} + +.bi-database-add::before { + content: "\f8af"; +} + +.bi-database-check::before { + content: "\f8b0"; +} + +.bi-database-dash::before { + content: "\f8b1"; +} + +.bi-database-down::before { + content: "\f8b2"; +} + +.bi-database-exclamation::before { + content: "\f8b3"; +} + +.bi-database-fill-add::before { + content: "\f8b4"; +} + +.bi-database-fill-check::before { + content: "\f8b5"; +} + +.bi-database-fill-dash::before { + content: "\f8b6"; +} + +.bi-database-fill-down::before { + content: "\f8b7"; +} + +.bi-database-fill-exclamation::before { + content: "\f8b8"; +} + +.bi-database-fill-gear::before { + content: "\f8b9"; +} + +.bi-database-fill-lock::before { + content: "\f8ba"; +} + +.bi-database-fill-slash::before { + content: "\f8bb"; +} + +.bi-database-fill-up::before { + content: "\f8bc"; +} + +.bi-database-fill-x::before { + content: "\f8bd"; +} + +.bi-database-fill::before { + content: "\f8be"; +} + +.bi-database-gear::before { + content: "\f8bf"; +} + +.bi-database-lock::before { + content: "\f8c0"; +} + +.bi-database-slash::before { + content: "\f8c1"; +} + +.bi-database-up::before { + content: "\f8c2"; +} + +.bi-database-x::before { + content: "\f8c3"; +} + +.bi-database::before { + content: "\f8c4"; +} + +.bi-houses-fill::before { + content: "\f8c5"; +} + +.bi-houses::before { + content: "\f8c6"; +} + +.bi-nvidia::before { + content: "\f8c7"; +} + +.bi-person-vcard-fill::before { + content: "\f8c8"; +} + +.bi-person-vcard::before { + content: "\f8c9"; +} + +.bi-sina-weibo::before { + content: "\f8ca"; +} + +.bi-tencent-qq::before { + content: "\f8cb"; +} + +.bi-wikipedia::before { + content: "\f8cc"; +} diff --git a/week_3/football/app/assets/builds/application.js b/week_3/football/app/assets/builds/application.js new file mode 100644 index 00000000..f65952ea --- /dev/null +++ b/week_3/football/app/assets/builds/application.js @@ -0,0 +1,3 @@ +(() => { +})(); +//# sourceMappingURL=assets/application.js.map diff --git a/week_3/football/app/assets/builds/application.js.map b/week_3/football/app/assets/builds/application.js.map new file mode 100644 index 00000000..98652118 --- /dev/null +++ b/week_3/football/app/assets/builds/application.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": [], + "sourcesContent": [], + "mappings": "", + "names": [] +} diff --git a/week_3/football/app/assets/config/manifest.js b/week_3/football/app/assets/config/manifest.js new file mode 100644 index 00000000..9a99757a --- /dev/null +++ b/week_3/football/app/assets/config/manifest.js @@ -0,0 +1,2 @@ +//= link_tree ../images +//= link_tree ../builds diff --git a/week_3/football/app/assets/images/.keep b/week_3/football/app/assets/images/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/app/assets/stylesheets/application.bootstrap.scss b/week_3/football/app/assets/stylesheets/application.bootstrap.scss new file mode 100644 index 00000000..b61b612b --- /dev/null +++ b/week_3/football/app/assets/stylesheets/application.bootstrap.scss @@ -0,0 +1,2 @@ +@import 'bootstrap/scss/bootstrap'; +@import 'bootstrap-icons/font/bootstrap-icons'; diff --git a/week_3/football/app/channels/application_cable/channel.rb b/week_3/football/app/channels/application_cable/channel.rb new file mode 100644 index 00000000..d6726972 --- /dev/null +++ b/week_3/football/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/week_3/football/app/channels/application_cable/connection.rb b/week_3/football/app/channels/application_cable/connection.rb new file mode 100644 index 00000000..0ff5442f --- /dev/null +++ b/week_3/football/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/week_3/football/app/controllers/application_controller.rb b/week_3/football/app/controllers/application_controller.rb new file mode 100644 index 00000000..09705d12 --- /dev/null +++ b/week_3/football/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/week_3/football/app/controllers/concerns/.keep b/week_3/football/app/controllers/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/app/controllers/football_players_controller.rb b/week_3/football/app/controllers/football_players_controller.rb new file mode 100644 index 00000000..a46a7e8e --- /dev/null +++ b/week_3/football/app/controllers/football_players_controller.rb @@ -0,0 +1,70 @@ +class FootballPlayersController < ApplicationController + before_action :set_football_player, only: %i[ show edit update destroy ] + + # GET /football_players or /football_players.json + def index + @football_players = FootballPlayer.all + end + + # GET /football_players/1 or /football_players/1.json + def show + end + + # GET /football_players/new + def new + @football_player = FootballPlayer.new + end + + # GET /football_players/1/edit + def edit + end + + # POST /football_players or /football_players.json + def create + @football_player = FootballPlayer.new(football_player_params) + + respond_to do |format| + if @football_player.save + format.html { redirect_to football_player_url(@football_player), notice: "Football player was successfully created." } + format.json { render :show, status: :created, location: @football_player } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @football_player.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /football_players/1 or /football_players/1.json + def update + respond_to do |format| + if @football_player.update(football_player_params) + format.html { redirect_to football_player_url(@football_player), notice: "Football player was successfully updated." } + format.json { render :show, status: :ok, location: @football_player } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @football_player.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /football_players/1 or /football_players/1.json + def destroy + @football_player.destroy + + respond_to do |format| + format.html { redirect_to football_players_url, notice: "Football player was successfully destroyed." } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_football_player + @football_player = FootballPlayer.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def football_player_params + params.require(:football_player).permit(:name, :rank, :country, :position, :squad, :league, :age, :born, :minutes_played, :goals, :penalty_kicks_made, :matches_played, :corner_kicks, :yellow_card, :red_card, :penalty_kicks_won, :fouls_committed) + end +end diff --git a/week_3/football/app/helpers/application_helper.rb b/week_3/football/app/helpers/application_helper.rb new file mode 100644 index 00000000..de6be794 --- /dev/null +++ b/week_3/football/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/week_3/football/app/helpers/football_players_helper.rb b/week_3/football/app/helpers/football_players_helper.rb new file mode 100644 index 00000000..ee81da4a --- /dev/null +++ b/week_3/football/app/helpers/football_players_helper.rb @@ -0,0 +1,2 @@ +module FootballPlayersHelper +end diff --git a/week_3/football/app/javascript/application.js b/week_3/football/app/javascript/application.js new file mode 100644 index 00000000..3016c21a --- /dev/null +++ b/week_3/football/app/javascript/application.js @@ -0,0 +1,4 @@ +// Entry point for the build script in your package.json +import "@hotwired/turbo-rails" +import "./controllers" +import * as bootstrap from "bootstrap" diff --git a/week_3/football/app/javascript/controllers/application.js b/week_3/football/app/javascript/controllers/application.js new file mode 100644 index 00000000..1213e85c --- /dev/null +++ b/week_3/football/app/javascript/controllers/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +// Configure Stimulus development experience +application.debug = false +window.Stimulus = application + +export { application } diff --git a/week_3/football/app/javascript/controllers/hello_controller.js b/week_3/football/app/javascript/controllers/hello_controller.js new file mode 100644 index 00000000..5975c078 --- /dev/null +++ b/week_3/football/app/javascript/controllers/hello_controller.js @@ -0,0 +1,7 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + this.element.textContent = "Hello World!" + } +} diff --git a/week_3/football/app/javascript/controllers/index.js b/week_3/football/app/javascript/controllers/index.js new file mode 100644 index 00000000..d0685d3b --- /dev/null +++ b/week_3/football/app/javascript/controllers/index.js @@ -0,0 +1,8 @@ +// This file is auto-generated by ./bin/rails stimulus:manifest:update +// Run that command whenever you add a new controller or create them with +// ./bin/rails generate stimulus controllerName + +import { application } from "./application" + +import HelloController from "./hello_controller" +application.register("hello", HelloController) diff --git a/week_3/football/app/jobs/application_job.rb b/week_3/football/app/jobs/application_job.rb new file mode 100644 index 00000000..d394c3d1 --- /dev/null +++ b/week_3/football/app/jobs/application_job.rb @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/week_3/football/app/mailers/application_mailer.rb b/week_3/football/app/mailers/application_mailer.rb new file mode 100644 index 00000000..3c34c814 --- /dev/null +++ b/week_3/football/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/week_3/football/app/models/application_record.rb b/week_3/football/app/models/application_record.rb new file mode 100644 index 00000000..b63caeb8 --- /dev/null +++ b/week_3/football/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/week_3/football/app/models/concerns/.keep b/week_3/football/app/models/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/app/models/football_player.rb b/week_3/football/app/models/football_player.rb new file mode 100644 index 00000000..c68d49a4 --- /dev/null +++ b/week_3/football/app/models/football_player.rb @@ -0,0 +1,2 @@ +class FootballPlayer < ApplicationRecord +end diff --git a/week_3/football/app/views/football_players/_football_player.html.erb b/week_3/football/app/views/football_players/_football_player.html.erb new file mode 100644 index 00000000..594ca14c --- /dev/null +++ b/week_3/football/app/views/football_players/_football_player.html.erb @@ -0,0 +1,87 @@ +
+

+ Name: + <%= football_player.name %> +

+ +

+ Rank: + <%= football_player.rank %> +

+ +

+ Country: + <%= football_player.country %> +

+ +

+ Position: + <%= football_player.position %> +

+ +

+ Squad: + <%= football_player.squad %> +

+ +

+ League: + <%= football_player.league %> +

+ +

+ Age: + <%= football_player.age %> +

+ +

+ Born: + <%= football_player.born %> +

+ +

+ Minutes played: + <%= football_player.minutes_played %> +

+ +

+ Goals: + <%= football_player.goals %> +

+ +

+ Penalty kicks made: + <%= football_player.penalty_kicks_made %> +

+ +

+ Matches played: + <%= football_player.matches_played %> +

+ +

+ Corner kicks: + <%= football_player.corner_kicks %> +

+ +

+ Yellow card: + <%= football_player.yellow_card %> +

+ +

+ Red card: + <%= football_player.red_card %> +

+ +

+ Penalty kicks won: + <%= football_player.penalty_kicks_won %> +

+ +

+ Fouls committed: + <%= football_player.fouls_committed %> +

+ +
diff --git a/week_3/football/app/views/football_players/_football_player.json.jbuilder b/week_3/football/app/views/football_players/_football_player.json.jbuilder new file mode 100644 index 00000000..23b06918 --- /dev/null +++ b/week_3/football/app/views/football_players/_football_player.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! football_player, :id, :name, :rank, :country, :position, :squad, :league, :age, :born, :minutes_played, :goals, :penalty_kicks_made, :matches_played, :corner_kicks, :yellow_card, :red_card, :penalty_kicks_won, :fouls_committed, :created_at, :updated_at +json.url football_player_url(football_player, format: :json) diff --git a/week_3/football/app/views/football_players/_form.html.erb b/week_3/football/app/views/football_players/_form.html.erb new file mode 100644 index 00000000..eb8dc057 --- /dev/null +++ b/week_3/football/app/views/football_players/_form.html.erb @@ -0,0 +1,102 @@ +<%= form_with(model: football_player) do |form| %> + <% if football_player.errors.any? %> +
+

<%= pluralize(football_player.errors.count, "error") %> prohibited this football_player from being saved:

+ +
    + <% football_player.errors.each do |error| %> +
  • <%= error.full_message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= form.label :name, style: "display: block" %> + <%= form.text_field :name %> +
+ +
+ <%= form.label :rank, style: "display: block" %> + <%= form.number_field :rank %> +
+ +
+ <%= form.label :country, style: "display: block" %> + <%= form.text_field :country %> +
+ +
+ <%= form.label :position, style: "display: block" %> + <%= form.text_field :position %> +
+ +
+ <%= form.label :squad, style: "display: block" %> + <%= form.text_field :squad %> +
+ +
+ <%= form.label :league, style: "display: block" %> + <%= form.text_field :league %> +
+ +
+ <%= form.label :age, style: "display: block" %> + <%= form.number_field :age %> +
+ +
+ <%= form.label :born, style: "display: block" %> + <%= form.number_field :born %> +
+ +
+ <%= form.label :minutes_played, style: "display: block" %> + <%= form.number_field :minutes_played %> +
+ +
+ <%= form.label :goals, style: "display: block" %> + <%= form.number_field :goals %> +
+ +
+ <%= form.label :penalty_kicks_made, style: "display: block" %> + <%= form.number_field :penalty_kicks_made %> +
+ +
+ <%= form.label :matches_played, style: "display: block" %> + <%= form.number_field :matches_played %> +
+ +
+ <%= form.label :corner_kicks, style: "display: block" %> + <%= form.number_field :corner_kicks %> +
+ +
+ <%= form.label :yellow_card, style: "display: block" %> + <%= form.number_field :yellow_card %> +
+ +
+ <%= form.label :red_card, style: "display: block" %> + <%= form.number_field :red_card %> +
+ +
+ <%= form.label :penalty_kicks_won, style: "display: block" %> + <%= form.number_field :penalty_kicks_won %> +
+ +
+ <%= form.label :fouls_committed, style: "display: block" %> + <%= form.number_field :fouls_committed %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/week_3/football/app/views/football_players/edit.html.erb b/week_3/football/app/views/football_players/edit.html.erb new file mode 100644 index 00000000..02af439f --- /dev/null +++ b/week_3/football/app/views/football_players/edit.html.erb @@ -0,0 +1,10 @@ +

Editing football player

+ +<%= render "form", football_player: @football_player %> + +
+ +
+ <%= link_to "Show this football player", @football_player %> | + <%= link_to "Back to football players", football_players_path %> +
diff --git a/week_3/football/app/views/football_players/index.html.erb b/week_3/football/app/views/football_players/index.html.erb new file mode 100644 index 00000000..2e0de158 --- /dev/null +++ b/week_3/football/app/views/football_players/index.html.erb @@ -0,0 +1,14 @@ +

<%= notice %>

+ +

Football players

+ +
+ <% @football_players.each do |football_player| %> + <%= render football_player %> +

+ <%= link_to "Show this football player", football_player %> +

+ <% end %> +
+ +<%= link_to "New football player", new_football_player_path %> diff --git a/week_3/football/app/views/football_players/index.json.jbuilder b/week_3/football/app/views/football_players/index.json.jbuilder new file mode 100644 index 00000000..41d48d95 --- /dev/null +++ b/week_3/football/app/views/football_players/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @football_players, partial: "football_players/football_player", as: :football_player diff --git a/week_3/football/app/views/football_players/new.html.erb b/week_3/football/app/views/football_players/new.html.erb new file mode 100644 index 00000000..48b3b5c1 --- /dev/null +++ b/week_3/football/app/views/football_players/new.html.erb @@ -0,0 +1,9 @@ +

New football player

+ +<%= render "form", football_player: @football_player %> + +
+ +
+ <%= link_to "Back to football players", football_players_path %> +
diff --git a/week_3/football/app/views/football_players/show.html.erb b/week_3/football/app/views/football_players/show.html.erb new file mode 100644 index 00000000..87b4597d --- /dev/null +++ b/week_3/football/app/views/football_players/show.html.erb @@ -0,0 +1,10 @@ +

<%= notice %>

+ +<%= render @football_player %> + +
+ <%= link_to "Edit this football player", edit_football_player_path(@football_player) %> | + <%= link_to "Back to football players", football_players_path %> + + <%= button_to "Destroy this football player", @football_player, method: :delete %> +
diff --git a/week_3/football/app/views/football_players/show.json.jbuilder b/week_3/football/app/views/football_players/show.json.jbuilder new file mode 100644 index 00000000..d13f58cb --- /dev/null +++ b/week_3/football/app/views/football_players/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "football_players/football_player", football_player: @football_player diff --git a/week_3/football/app/views/layouts/application.html.erb b/week_3/football/app/views/layouts/application.html.erb new file mode 100644 index 00000000..3cb4ac95 --- /dev/null +++ b/week_3/football/app/views/layouts/application.html.erb @@ -0,0 +1,16 @@ + + + + Football + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> + <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %> + + + + <%= yield %> + + diff --git a/week_3/football/app/views/layouts/mailer.html.erb b/week_3/football/app/views/layouts/mailer.html.erb new file mode 100644 index 00000000..cbd34d2e --- /dev/null +++ b/week_3/football/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/week_3/football/app/views/layouts/mailer.text.erb b/week_3/football/app/views/layouts/mailer.text.erb new file mode 100644 index 00000000..37f0bddb --- /dev/null +++ b/week_3/football/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/week_3/football/bin/bundle b/week_3/football/bin/bundle new file mode 100755 index 00000000..374a0a1f --- /dev/null +++ b/week_3/football/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/week_3/football/bin/dev b/week_3/football/bin/dev new file mode 100755 index 00000000..74ade166 --- /dev/null +++ b/week_3/football/bin/dev @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +if ! gem list foreman -i --silent; then + echo "Installing foreman..." + gem install foreman +fi + +exec foreman start -f Procfile.dev "$@" diff --git a/week_3/football/bin/rails b/week_3/football/bin/rails new file mode 100755 index 00000000..efc03774 --- /dev/null +++ b/week_3/football/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/week_3/football/bin/rake b/week_3/football/bin/rake new file mode 100755 index 00000000..4fbf10b9 --- /dev/null +++ b/week_3/football/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/week_3/football/bin/setup b/week_3/football/bin/setup new file mode 100755 index 00000000..ec47b79b --- /dev/null +++ b/week_3/football/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/week_3/football/config.ru b/week_3/football/config.ru new file mode 100644 index 00000000..4a3c09a6 --- /dev/null +++ b/week_3/football/config.ru @@ -0,0 +1,6 @@ +# This file is used by Rack-based servers to start the application. + +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/week_3/football/config/application.rb b/week_3/football/config/application.rb new file mode 100644 index 00000000..3fc4b2d6 --- /dev/null +++ b/week_3/football/config/application.rb @@ -0,0 +1,22 @@ +require_relative "boot" + +require "rails/all" + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module Football + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 7.0 + + # Configuration for the application, engines, and railties goes here. + # + # These settings can be overridden in specific environments using the files + # in config/environments, which are processed later. + # + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + end +end diff --git a/week_3/football/config/boot.rb b/week_3/football/config/boot.rb new file mode 100644 index 00000000..988a5ddc --- /dev/null +++ b/week_3/football/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" # Set up gems listed in the Gemfile. +require "bootsnap/setup" # Speed up boot time by caching expensive operations. diff --git a/week_3/football/config/cable.yml b/week_3/football/config/cable.yml new file mode 100644 index 00000000..c358e65c --- /dev/null +++ b/week_3/football/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: football_production diff --git a/week_3/football/config/credentials.yml.enc b/week_3/football/config/credentials.yml.enc new file mode 100644 index 00000000..11e4708f --- /dev/null +++ b/week_3/football/config/credentials.yml.enc @@ -0,0 +1 @@ +XrH0yGlAwVYmS409V2dvISbAMNj5Wp+//Nx12VfVzCw/8mg7QK2LSM97VnF8Pi07p89i12l7ZBJgxGvDaTZwlIbkwufWKfZp1nhDkLuWkQdkFpBgNbGCGq/m9FkSEa+uYsuV0MzDIDKvjnA66QKijY0o7HSo7FCkpIOfGqohVnCKGbZBi/kIE9+Q34tM0ngvoXAmFI7v5lf5cI3btliAw17Ao9/uoUORGvr5f4vNb03nfSPcVzNnhOUoDy/x41QlA0PvVf4c25TxKfzPdFVqbjfWcjKLvbxRtxkz/VN1OyQ6ehs90dfh5ahE9paUN84P85R3n3iYGnFHyyikFU1zp6epRmfuD0RUJRmt+cyyyramGvh/KWhq16wZOKtYCINzLsbJN/DZxUz3HQnbQJrHsDjqwkxlOKJeERcT--FA5s5VD6qj2oWVM5--jyYXkT+E3VMpYTYlmQQcwg== \ No newline at end of file diff --git a/week_3/football/config/database.yml b/week_3/football/config/database.yml new file mode 100644 index 00000000..fcba57f1 --- /dev/null +++ b/week_3/football/config/database.yml @@ -0,0 +1,25 @@ +# SQLite. Versions 3.8.0 and up are supported. +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem "sqlite3" +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/week_3/football/config/environment.rb b/week_3/football/config/environment.rb new file mode 100644 index 00000000..cac53157 --- /dev/null +++ b/week_3/football/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative "application" + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/week_3/football/config/environments/development.rb b/week_3/football/config/environments/development.rb new file mode 100644 index 00000000..8500f459 --- /dev/null +++ b/week_3/football/config/environments/development.rb @@ -0,0 +1,70 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable server timing + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true +end diff --git a/week_3/football/config/environments/production.rb b/week_3/football/config/environments/production.rb new file mode 100644 index 00000000..feb249b2 --- /dev/null +++ b/week_3/football/config/environments/production.rb @@ -0,0 +1,93 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "football_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/week_3/football/config/environments/test.rb b/week_3/football/config/environments/test.rb new file mode 100644 index 00000000..6ea4d1e7 --- /dev/null +++ b/week_3/football/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/week_3/football/config/initializers/assets.rb b/week_3/football/config/initializers/assets.rb new file mode 100644 index 00000000..58275b40 --- /dev/null +++ b/week_3/football/config/initializers/assets.rb @@ -0,0 +1,13 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = "1.0" + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +Rails.application.config.assets.paths << Rails.root.join("node_modules/bootstrap-icons/font") + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/week_3/football/config/initializers/content_security_policy.rb b/week_3/football/config/initializers/content_security_policy.rb new file mode 100644 index 00000000..54f47cf1 --- /dev/null +++ b/week_3/football/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header + +# Rails.application.configure do +# config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end +# +# # Generate session nonces for permitted importmap and inline scripts +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true +# end diff --git a/week_3/football/config/initializers/filter_parameter_logging.rb b/week_3/football/config/initializers/filter_parameter_logging.rb new file mode 100644 index 00000000..adc6568c --- /dev/null +++ b/week_3/football/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/week_3/football/config/initializers/inflections.rb b/week_3/football/config/initializers/inflections.rb new file mode 100644 index 00000000..3860f659 --- /dev/null +++ b/week_3/football/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/week_3/football/config/initializers/permissions_policy.rb b/week_3/football/config/initializers/permissions_policy.rb new file mode 100644 index 00000000..00f64d71 --- /dev/null +++ b/week_3/football/config/initializers/permissions_policy.rb @@ -0,0 +1,11 @@ +# Define an application-wide HTTP permissions policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.permissions_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/week_3/football/config/locales/en.yml b/week_3/football/config/locales/en.yml new file mode 100644 index 00000000..8ca56fc7 --- /dev/null +++ b/week_3/football/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/week_3/football/config/master.key b/week_3/football/config/master.key new file mode 100644 index 00000000..2f496ac8 --- /dev/null +++ b/week_3/football/config/master.key @@ -0,0 +1 @@ +a7e48275772fed7f3361a427cafaeb01 \ No newline at end of file diff --git a/week_3/football/config/puma.rb b/week_3/football/config/puma.rb new file mode 100644 index 00000000..daaf0369 --- /dev/null +++ b/week_3/football/config/puma.rb @@ -0,0 +1,43 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +# Specifies the `worker_timeout` threshold that Puma will use to wait before +# terminating a worker in development environments. +# +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked web server processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart diff --git a/week_3/football/config/routes.rb b/week_3/football/config/routes.rb new file mode 100644 index 00000000..dd3a4646 --- /dev/null +++ b/week_3/football/config/routes.rb @@ -0,0 +1,7 @@ +Rails.application.routes.draw do + resources :football_players + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + # Defines the root path route ("/") + # root "articles#index" +end diff --git a/week_3/football/config/storage.yml b/week_3/football/config/storage.yml new file mode 100644 index 00000000..4942ab66 --- /dev/null +++ b/week_3/football/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/week_3/football/db/migrate/20230110105345_create_football_players.rb b/week_3/football/db/migrate/20230110105345_create_football_players.rb new file mode 100644 index 00000000..082e0deb --- /dev/null +++ b/week_3/football/db/migrate/20230110105345_create_football_players.rb @@ -0,0 +1,25 @@ +class CreateFootballPlayers < ActiveRecord::Migration[7.0] + def change + create_table :football_players do |t| + t.string :name + t.integer :rank + t.string :country + t.string :position + t.string :squad + t.string :league + t.integer :age + t.integer :born + t.integer :minutes_played + t.integer :goals + t.integer :penalty_kicks_made + t.integer :matches_played + t.integer :corner_kicks + t.integer :yellow_card + t.integer :red_card + t.integer :penalty_kicks_won + t.integer :fouls_committed + + t.timestamps + end + end +end diff --git a/week_3/football/db/schema.rb b/week_3/football/db/schema.rb new file mode 100644 index 00000000..14d7cf72 --- /dev/null +++ b/week_3/football/db/schema.rb @@ -0,0 +1,36 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2023_01_10_105345) do + create_table "football_players", force: :cascade do |t| + t.string "name" + t.integer "rank" + t.string "country" + t.string "position" + t.string "squad" + t.string "league" + t.integer "age" + t.integer "born" + t.integer "minutes_played" + t.integer "goals" + t.integer "penalty_kicks_made" + t.integer "matches_played" + t.integer "corner_kicks" + t.integer "yellow_card" + t.integer "red_card" + t.integer "penalty_kicks_won" + t.integer "fouls_committed" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/week_3/football/db/seeds.rb b/week_3/football/db/seeds.rb new file mode 100644 index 00000000..bc25fce3 --- /dev/null +++ b/week_3/football/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). +# +# Examples: +# +# movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) +# Character.create(name: "Luke", movie: movies.first) diff --git a/week_3/football/lib/assets/.keep b/week_3/football/lib/assets/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/lib/tasks/.keep b/week_3/football/lib/tasks/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/package.json b/week_3/football/package.json new file mode 100644 index 00000000..33536687 --- /dev/null +++ b/week_3/football/package.json @@ -0,0 +1,17 @@ +{ + "name": "app", + "private": "true", + "dependencies": { + "@hotwired/stimulus": "^3.2.1", + "@hotwired/turbo-rails": "^7.2.4", + "@popperjs/core": "^2.11.6", + "bootstrap": "^5.2.3", + "bootstrap-icons": "^1.10.3", + "esbuild": "^0.16.16", + "sass": "^1.57.1" + }, + "scripts": { + "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets", + "build:css": "sass ./app/assets/stylesheets/application.bootstrap.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules" + } +} diff --git a/week_3/football/public/404.html b/week_3/football/public/404.html new file mode 100644 index 00000000..2be3af26 --- /dev/null +++ b/week_3/football/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
+
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_3/football/public/422.html b/week_3/football/public/422.html new file mode 100644 index 00000000..c08eac0d --- /dev/null +++ b/week_3/football/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
+
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_3/football/public/500.html b/week_3/football/public/500.html new file mode 100644 index 00000000..78a030af --- /dev/null +++ b/week_3/football/public/500.html @@ -0,0 +1,66 @@ + + + + We're sorry, but something went wrong (500) + + + + + + +
+
+

We're sorry, but something went wrong.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_3/football/public/apple-touch-icon-precomposed.png b/week_3/football/public/apple-touch-icon-precomposed.png new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/public/apple-touch-icon.png b/week_3/football/public/apple-touch-icon.png new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/public/favicon.ico b/week_3/football/public/favicon.ico new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/public/robots.txt b/week_3/football/public/robots.txt new file mode 100644 index 00000000..c19f78ab --- /dev/null +++ b/week_3/football/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/week_3/football/storage/.keep b/week_3/football/storage/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/application_system_test_case.rb b/week_3/football/test/application_system_test_case.rb new file mode 100644 index 00000000..d19212ab --- /dev/null +++ b/week_3/football/test/application_system_test_case.rb @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/week_3/football/test/channels/application_cable/connection_test.rb b/week_3/football/test/channels/application_cable/connection_test.rb new file mode 100644 index 00000000..800405f1 --- /dev/null +++ b/week_3/football/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/week_3/football/test/controllers/.keep b/week_3/football/test/controllers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/controllers/football_players_controller_test.rb b/week_3/football/test/controllers/football_players_controller_test.rb new file mode 100644 index 00000000..7e5e3bc3 --- /dev/null +++ b/week_3/football/test/controllers/football_players_controller_test.rb @@ -0,0 +1,48 @@ +require "test_helper" + +class FootballPlayersControllerTest < ActionDispatch::IntegrationTest + setup do + @football_player = football_players(:one) + end + + test "should get index" do + get football_players_url + assert_response :success + end + + test "should get new" do + get new_football_player_url + assert_response :success + end + + test "should create football_player" do + assert_difference("FootballPlayer.count") do + post football_players_url, params: { football_player: { age: @football_player.age, born: @football_player.born, corner_kicks: @football_player.corner_kicks, country: @football_player.country, fouls_committed: @football_player.fouls_committed, goals: @football_player.goals, league: @football_player.league, matches_played: @football_player.matches_played, minutes_played: @football_player.minutes_played, name: @football_player.name, penalty_kicks_made: @football_player.penalty_kicks_made, penalty_kicks_won: @football_player.penalty_kicks_won, position: @football_player.position, rank: @football_player.rank, red_card: @football_player.red_card, squad: @football_player.squad, yellow_card: @football_player.yellow_card } } + end + + assert_redirected_to football_player_url(FootballPlayer.last) + end + + test "should show football_player" do + get football_player_url(@football_player) + assert_response :success + end + + test "should get edit" do + get edit_football_player_url(@football_player) + assert_response :success + end + + test "should update football_player" do + patch football_player_url(@football_player), params: { football_player: { age: @football_player.age, born: @football_player.born, corner_kicks: @football_player.corner_kicks, country: @football_player.country, fouls_committed: @football_player.fouls_committed, goals: @football_player.goals, league: @football_player.league, matches_played: @football_player.matches_played, minutes_played: @football_player.minutes_played, name: @football_player.name, penalty_kicks_made: @football_player.penalty_kicks_made, penalty_kicks_won: @football_player.penalty_kicks_won, position: @football_player.position, rank: @football_player.rank, red_card: @football_player.red_card, squad: @football_player.squad, yellow_card: @football_player.yellow_card } } + assert_redirected_to football_player_url(@football_player) + end + + test "should destroy football_player" do + assert_difference("FootballPlayer.count", -1) do + delete football_player_url(@football_player) + end + + assert_redirected_to football_players_url + end +end diff --git a/week_3/football/test/fixtures/files/.keep b/week_3/football/test/fixtures/files/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/fixtures/football_players.yml b/week_3/football/test/fixtures/football_players.yml new file mode 100644 index 00000000..68f03ef7 --- /dev/null +++ b/week_3/football/test/fixtures/football_players.yml @@ -0,0 +1,1746 @@ +Alisson: + age: 29.0 + born: 1992 + corner_kicks: 47 + country: BRA + fouls_committed: 252 + goals: 240 + league: Premier League + matches_played: 36 + minutes_played: 3240 + name: Alisson + penalty_kicks_made: 891 + penalty_kicks_won: 297 + position: GK + rank: 66 + red_card: 56 + squad: Liverpool + yellow_card: 145 +Allan: + age: 31.0 + born: 1991 + corner_kicks: 226 + country: BRA + fouls_committed: 118 + goals: 133 + league: Premier League + matches_played: 28 + minutes_played: 2183 + name: Allan + penalty_kicks_made: 381 + penalty_kicks_won: 127 + position: MF + rank: 67 + red_card: 197 + squad: Everton + yellow_card: 237 +Amath: + age: 25.0 + born: 1996 + corner_kicks: 115 + country: SEN + fouls_committed: 28 + goals: 10 + league: La Liga + matches_played: 19 + minutes_played: 884 + name: Amath + penalty_kicks_made: 858 + penalty_kicks_won: 286 + position: FWMF + rank: 81 + red_card: 186 + squad: Mallorca + yellow_card: 248 +Amine Adli: + age: 22.0 + born: 2000 + corner_kicks: 232 + country: FRA + fouls_committed: 214 + goals: 279 + league: Bundesliga + matches_played: 25 + minutes_played: 1256 + name: Amine Adli + penalty_kicks_made: 684 + penalty_kicks_won: 228 + position: FWMF + rank: 18 + red_card: 220 + squad: Leverkusen + yellow_card: 156 +"Andr\xE9s Andrade Cede\xF1o": + age: 23.0 + born: 1998 + corner_kicks: 206 + country: PAN + fouls_committed: 83 + goals: 200 + league: Bundesliga + matches_played: 17 + minutes_played: 1046 + name: "Andr\xE9s Andrade Cede\xF1o" + penalty_kicks_made: 600 + penalty_kicks_won: 200 + position: DF + rank: 94 + red_card: 268 + squad: Arminia + yellow_card: 13 +Anel Ahmedhodzic: + age: 23.0 + born: 1999 + corner_kicks: 202 + country: BIH + fouls_committed: 157 + goals: 295 + league: Ligue 1 + matches_played: 15 + minutes_played: 1350 + name: Anel Ahmedhodzic + penalty_kicks_made: 447 + penalty_kicks_won: 149 + position: DF + rank: 31 + red_card: 230 + squad: Bordeaux + yellow_card: 129 +"Angeli\xF1o": + age: 25.0 + born: 1997 + corner_kicks: 162 + country: ESP + fouls_committed: 185 + goals: 64 + league: Bundesliga + matches_played: 29 + minutes_played: 2298 + name: "Angeli\xF1o" + penalty_kicks_made: 351 + penalty_kicks_won: 117 + position: DF + rank: 99 + red_card: 172 + squad: RB Leipzig + yellow_card: 277 +"Benjamin Andr\xE9": + age: 31.0 + born: 1990 + corner_kicks: 197 + country: FRA + fouls_committed: 232 + goals: 261 + league: Ligue 1 + matches_played: 33 + minutes_played: 2752 + name: "Benjamin Andr\xE9" + penalty_kicks_made: 249 + penalty_kicks_won: 83 + position: MF + rank: 96 + red_card: 272 + squad: Lille + yellow_card: 246 +"Carles Ale\xF1\xE1": + age: 24.0 + born: 1998 + corner_kicks: 131 + country: ESP + fouls_committed: 60 + goals: 229 + league: La Liga + matches_played: 33 + minutes_played: 2320 + name: "Carles Ale\xF1\xE1" + penalty_kicks_made: 486 + penalty_kicks_won: 162 + position: MF + rank: 62 + red_card: 251 + squad: Getafe + yellow_card: 271 +Carlos Akapo: + age: 29.0 + born: 1993 + corner_kicks: 201 + country: EQG + fouls_committed: 255 + goals: 102 + league: La Liga + matches_played: 25 + minutes_played: 1844 + name: Carlos Akapo + penalty_kicks_made: 42 + penalty_kicks_won: 14 + position: DF + rank: 39 + red_card: 51 + squad: "C\xE1diz" + yellow_card: 74 +Charles Abi: + age: 22.0 + born: 2000 + corner_kicks: 111 + country: FRA + fouls_committed: 273 + goals: 93 + league: Ligue 1 + matches_played: 1 + minutes_played: 45 + name: Charles Abi + penalty_kicks_made: 30 + penalty_kicks_won: 10 + position: FW + rank: 5 + red_card: 27 + squad: "Saint-\xC9tienne" + yellow_card: 39 +Che Adams: + age: 25.0 + born: 1996 + corner_kicks: 256 + country: SCO + fouls_committed: 99 + goals: 134 + league: Premier League + matches_played: 30 + minutes_played: 2039 + name: Che Adams + penalty_kicks_made: 711 + penalty_kicks_won: 237 + position: FW + rank: 14 + red_card: 154 + squad: Southampton + yellow_card: 121 +Dani Alves: + age: 39.0 + born: 1983 + corner_kicks: 31 + country: BRA + fouls_committed: 271 + goals: 236 + league: La Liga + matches_played: 14 + minutes_played: 1098 + name: Dani Alves + penalty_kicks_made: 480 + penalty_kicks_won: 160 + position: DF + rank: 76 + red_card: 136 + squad: Barcelona + yellow_card: 191 +Daniel Amartey: + age: 27.0 + born: 1994 + corner_kicks: 198 + country: GHA + fouls_committed: 34 + goals: 18 + league: Premier League + matches_played: 28 + minutes_played: 2123 + name: Daniel Amartey + penalty_kicks_made: 144 + penalty_kicks_won: 48 + position: DF + rank: 80 + red_card: 59 + squad: Leicester City + yellow_card: 163 +David Alaba: + age: 29.0 + born: 1992 + corner_kicks: 297 + country: AUT + fouls_committed: 15 + goals: 183 + league: La Liga + matches_played: 30 + minutes_played: 2642 + name: David Alaba + penalty_kicks_made: 855 + penalty_kicks_won: 285 + position: DF + rank: 47 + red_card: 178 + squad: Real Madrid + yellow_card: 76 +Dele Alli: + age: 26.0 + born: 1996 + corner_kicks: 199 + country: ENG + fouls_committed: 20 + goals: 287 + league: Premier League + matches_played: 10 + minutes_played: 657 + name: Dele Alli + penalty_kicks_made: 534 + penalty_kicks_won: 178 + position: MFFW + rank: 70 + red_card: 234 + squad: Tottenham + yellow_card: 71 +Dickson Abiama: + age: 23.0 + born: 1998 + corner_kicks: 53 + country: NGA + fouls_committed: 269 + goals: 244 + league: Bundesliga + matches_played: 24 + minutes_played: 726 + name: Dickson Abiama + penalty_kicks_made: 450 + penalty_kicks_won: 150 + position: FW + rank: 6 + red_card: 187 + squad: "Greuther F\xFCrth" + yellow_card: 260 +"Do\xF0an Alemdar": + age: 19.0 + born: 2002 + corner_kicks: 192 + country: TUR + fouls_committed: 152 + goals: 281 + league: Ligue 1 + matches_played: 12 + minutes_played: 1080 + name: "Do\xF0an Alemdar" + penalty_kicks_made: 450 + penalty_kicks_won: 150 + position: GK + rank: 61 + red_card: 209 + squad: Rennes + yellow_card: 45 +Ebenezer Annan: + age: 19.0 + born: 2002 + corner_kicks: 15 + country: GHA + fouls_committed: 206 + goals: 286 + league: Serie A + matches_played: 1 + minutes_played: 25 + name: Ebenezer Annan + penalty_kicks_made: 417 + penalty_kicks_won: 139 + position: DF + rank: 100 + red_card: 40 + squad: Bologna + yellow_card: 128 +Emmanuel Amankwaa Akurugu: + age: 20.0 + born: 2001 + corner_kicks: 174 + country: GHA + fouls_committed: 100 + goals: 37 + league: La Liga + matches_played: 3 + minutes_played: 79 + name: Emmanuel Amankwaa Akurugu + penalty_kicks_made: 48 + penalty_kicks_won: 16 + position: DF + rank: 79 + red_card: 89 + squad: Getafe + yellow_card: 162 +Ethan Ampadu: + age: 21.0 + born: 2000 + corner_kicks: 80 + country: WAL + fouls_committed: 231 + goals: 55 + league: Serie A + matches_played: 29 + minutes_played: 2282 + name: Ethan Ampadu + penalty_kicks_made: 687 + penalty_kicks_won: 229 + position: MFDF + rank: 88 + red_card: 217 + squad: Venezia + yellow_card: 151 +Felipe Anderson: + age: 29.0 + born: 1993 + corner_kicks: 38 + country: BRA + fouls_committed: 42 + goals: 287 + league: Serie A + matches_played: 38 + minutes_played: 2888 + name: Felipe Anderson + penalty_kicks_made: 546 + penalty_kicks_won: 182 + position: FW + rank: 91 + red_card: 80 + squad: Lazio + yellow_card: 269 +Felix Afena-Gyan: + age: 19.0 + born: 2003 + corner_kicks: 42 + country: GHA + fouls_committed: 13 + goals: 131 + league: Serie A + matches_played: 17 + minutes_played: 668 + name: Felix Afena-Gyan + penalty_kicks_made: 702 + penalty_kicks_won: 234 + position: FWMF + rank: 21 + red_card: 211 + squad: Roma + yellow_card: 245 +Florin Andone: + age: 29.0 + born: 1993 + corner_kicks: 243 + country: ROU + fouls_committed: 58 + goals: 60 + league: La Liga + matches_played: 5 + minutes_played: 176 + name: Florin Andone + penalty_kicks_made: 747 + penalty_kicks_won: 249 + position: FW + rank: 93 + red_card: 218 + squad: "C\xE1diz" + yellow_card: 297 +Francesco Acerbi: + age: 34.0 + born: 1988 + corner_kicks: 66 + country: ITA + fouls_committed: 212 + goals: 147 + league: Serie A + matches_played: 30 + minutes_played: 2536 + name: Francesco Acerbi + penalty_kicks_made: 381 + penalty_kicks_won: 127 + position: DF + rank: 10 + red_card: 152 + squad: Lazio + yellow_card: 18 +"Fredrik Andr\xE9 Bj\xF8rkan": + age: 23.0 + born: 1998 + corner_kicks: 10 + country: NOR + fouls_committed: 292 + goals: 289 + league: Bundesliga + matches_played: 9 + minutes_played: 353 + name: "Fredrik Andr\xE9 Bj\xF8rkan" + penalty_kicks_made: 573 + penalty_kicks_won: 191 + position: DF + rank: 95 + red_card: 155 + squad: Hertha BSC + yellow_card: 57 +Giorgio Altare: + age: 23.0 + born: 1998 + corner_kicks: 239 + country: ITA + fouls_committed: 215 + goals: 45 + league: Serie A + matches_played: 19 + minutes_played: 1466 + name: Giorgio Altare + penalty_kicks_made: 330 + penalty_kicks_won: 110 + position: DF + rank: 73 + red_card: 110 + squad: Cagliari + yellow_card: 114 +"Hugo \xC1lvarez": + age: 36.0 + born: 1985 + corner_kicks: 141 + country: ESP + fouls_committed: 58 + goals: 165 + league: La Liga + matches_played: 1 + minutes_played: 11 + name: "Hugo \xC1lvarez" + penalty_kicks_made: 501 + penalty_kicks_won: 167 + position: FW + rank: 74 + red_card: 195 + squad: Celta Vigo + yellow_card: 280 +Ibrahim Amadou: + age: 29.0 + born: 1993 + corner_kicks: 116 + country: FRA + fouls_committed: 113 + goals: 277 + league: Ligue 1 + matches_played: 10 + minutes_played: 812 + name: Ibrahim Amadou + penalty_kicks_made: 309 + penalty_kicks_won: 103 + position: DFMF + rank: 78 + red_card: 247 + squad: Metz + yellow_card: 28 +Ilias Akhomach: + age: 18.0 + born: 2004 + corner_kicks: 27 + country: ESP + fouls_committed: 222 + goals: 78 + league: La Liga + matches_played: 2 + minutes_played: 124 + name: Ilias Akhomach + penalty_kicks_made: 861 + penalty_kicks_won: 287 + position: FW + rank: 42 + red_card: 66 + squad: Barcelona + yellow_card: 177 +"Iv\xE1n Alejo": + age: 27.0 + born: 1995 + corner_kicks: 128 + country: ESP + fouls_committed: 264 + goals: 190 + league: La Liga + matches_played: 20 + minutes_played: 1065 + name: "Iv\xE1n Alejo" + penalty_kicks_made: 747 + penalty_kicks_won: 249 + position: MFFW + rank: 60 + red_card: 109 + squad: "C\xE1diz" + yellow_card: 75 +Jean-Daniel Akpa-Akpro: + age: 29.0 + born: 1992 + corner_kicks: 152 + country: CIV + fouls_committed: 213 + goals: 203 + league: Serie A + matches_played: 10 + minutes_played: 315 + name: Jean-Daniel Akpa-Akpro + penalty_kicks_made: 111 + penalty_kicks_won: 37 + position: MF + rank: 45 + red_card: 112 + squad: Lazio + yellow_card: 131 +Jean-Eudes Aholou: + age: 28.0 + born: 1994 + corner_kicks: 224 + country: CIV + fouls_committed: 58 + goals: 214 + league: Ligue 1 + matches_played: 25 + minutes_played: 1004 + name: Jean-Eudes Aholou + penalty_kicks_made: 633 + penalty_kicks_won: 211 + position: MF + rank: 32 + red_card: 30 + squad: Strasbourg + yellow_card: 121 +Jim Allevinah: + age: 27.0 + born: 1995 + corner_kicks: 266 + country: GAB + fouls_committed: 250 + goals: 275 + league: Ligue 1 + matches_played: 30 + minutes_played: 1488 + name: Jim Allevinah + penalty_kicks_made: 342 + penalty_kicks_won: 114 + position: FW + rank: 68 + red_card: 98 + squad: Clermont Foot + yellow_card: 255 +Joachim Andersen: + age: 25.0 + born: 1996 + corner_kicks: 24 + country: DEN + fouls_committed: 46 + goals: 104 + league: Premier League + matches_played: 34 + minutes_played: 2916 + name: Joachim Andersen + penalty_kicks_made: 585 + penalty_kicks_won: 195 + position: DF + rank: 90 + red_card: 74 + squad: Crystal Palace + yellow_card: 71 +Jordan Amavi: + age: 28.0 + born: 1994 + corner_kicks: 150 + country: FRA + fouls_committed: 117 + goals: 66 + league: Ligue 1 + matches_played: 8 + minutes_played: 413 + name: Jordan Amavi + penalty_kicks_made: 306 + penalty_kicks_won: 102 + position: DF + rank: 83 + red_card: 81 + squad: Nice + yellow_card: 120 +Jordi Alba: + age: 33.0 + born: 1989 + corner_kicks: 128 + country: ESP + fouls_committed: 246 + goals: 151 + league: La Liga + matches_played: 30 + minutes_played: 2644 + name: Jordi Alba + penalty_kicks_made: 405 + penalty_kicks_won: 135 + position: DF + rank: 51 + red_card: 252 + squad: Barcelona + yellow_card: 109 +Joseph Aidoo: + age: 26.0 + born: 1995 + corner_kicks: 158 + country: GHA + fouls_committed: 110 + goals: 254 + league: La Liga + matches_played: 32 + minutes_played: 2637 + name: Joseph Aidoo + penalty_kicks_made: 504 + penalty_kicks_won: 168 + position: DF + rank: 33 + red_card: 191 + squad: Celta Vigo + yellow_card: 69 +"Josu\xE9 Albert": + age: 30.0 + born: 1992 + corner_kicks: 47 + country: GUF + fouls_committed: 288 + goals: 298 + league: Ligue 1 + matches_played: 2 + minutes_played: 22 + name: "Josu\xE9 Albert" + penalty_kicks_made: 888 + penalty_kicks_won: 296 + position: DF + rank: 52 + red_card: 292 + squad: Clermont Foot + yellow_card: 67 +"Jos\xE9 \xC1ngel": + age: 32.0 + born: 1989 + corner_kicks: 91 + country: ESP + fouls_committed: 55 + goals: 90 + league: La Liga + matches_played: 23 + minutes_played: 1083 + name: "Jos\xE9 \xC1ngel" + penalty_kicks_made: 177 + penalty_kicks_won: 59 + position: DF + rank: 98 + red_card: 112 + squad: Osasuna + yellow_card: 128 +Julen Agirrezabala: + age: 21.0 + born: 2000 + corner_kicks: 237 + country: ESP + fouls_committed: 297 + goals: 36 + league: La Liga + matches_played: 4 + minutes_played: 360 + name: Julen Agirrezabala + penalty_kicks_made: 795 + penalty_kicks_won: 265 + position: GK + rank: 23 + red_card: 12 + squad: Athletic Club + yellow_card: 108 +Kelvin Amian: + age: 24.0 + born: 1998 + corner_kicks: 39 + country: FRA + fouls_committed: 102 + goals: 203 + league: Serie A + matches_played: 32 + minutes_played: 2646 + name: Kelvin Amian + penalty_kicks_made: 879 + penalty_kicks_won: 293 + position: DF + rank: 85 + red_card: 278 + squad: Spezia + yellow_card: 173 +Kevin Agudelo: + age: 23.0 + born: 1998 + corner_kicks: 111 + country: COL + fouls_committed: 121 + goals: 225 + league: Serie A + matches_played: 23 + minutes_played: 1237 + name: Kevin Agudelo + penalty_kicks_made: 843 + penalty_kicks_won: 281 + position: MFFW + rank: 25 + red_card: 190 + squad: Spezia + yellow_card: 224 +Kevin Akpoguma: + age: 27.0 + born: 1995 + corner_kicks: 194 + country: NGA + fouls_committed: 85 + goals: 124 + league: Bundesliga + matches_played: 26 + minutes_played: 1527 + name: Kevin Akpoguma + penalty_kicks_made: 420 + penalty_kicks_won: 140 + position: DF + rank: 46 + red_card: 60 + squad: Hoffenheim + yellow_card: 79 +Kristoffer Ajer: + age: 24.0 + born: 1998 + corner_kicks: 278 + country: NOR + fouls_committed: 120 + goals: 279 + league: Premier League + matches_played: 24 + minutes_played: 1995 + name: Kristoffer Ajer + penalty_kicks_made: 375 + penalty_kicks_won: 125 + position: DF + rank: 36 + red_card: 126 + squad: Brentford + yellow_card: 69 +Laurent Abergel: + age: 29.0 + born: 1993 + corner_kicks: 257 + country: FRA + fouls_committed: 270 + goals: 224 + league: Ligue 1 + matches_played: 34 + minutes_played: 2956 + name: Laurent Abergel + penalty_kicks_made: 162 + penalty_kicks_won: 54 + position: MF + rank: 4 + red_card: 200 + squad: Lorient + yellow_card: 122 +Lucas Alario: + age: 29.0 + born: 1992 + corner_kicks: 236 + country: ARG + fouls_committed: 48 + goals: 43 + league: Bundesliga + matches_played: 27 + minutes_played: 655 + name: Lucas Alario + penalty_kicks_made: 90 + penalty_kicks_won: 30 + position: FW + rank: 50 + red_card: 104 + squad: Leverkusen + yellow_card: 240 +Lucien Agoume: + age: 20.0 + born: 2002 + corner_kicks: 158 + country: FRA + fouls_committed: 192 + goals: 60 + league: Ligue 1 + matches_played: 27 + minutes_played: 1868 + name: Lucien Agoume + penalty_kicks_made: 753 + penalty_kicks_won: 251 + position: MF + rank: 24 + red_card: 75 + squad: Brest + yellow_card: 131 +Ludovic Ajorque: + age: 28.0 + born: 1994 + corner_kicks: 102 + country: REU + fouls_committed: 150 + goals: 106 + league: Ligue 1 + matches_played: 36 + minutes_played: 2738 + name: Ludovic Ajorque + penalty_kicks_made: 693 + penalty_kicks_won: 231 + position: FW + rank: 37 + red_card: 131 + squad: Strasbourg + yellow_card: 41 +Luis Abram: + age: 26.0 + born: 1996 + corner_kicks: 192 + country: PER + fouls_committed: 38 + goals: 48 + league: La Liga + matches_played: 8 + minutes_played: 560 + name: Luis Abram + penalty_kicks_made: 678 + penalty_kicks_won: 226 + position: DF + rank: 9 + red_card: 19 + squad: Granada + yellow_card: 216 +Luis Alberto: + age: 29.0 + born: 1992 + corner_kicks: 214 + country: ESP + fouls_committed: 285 + goals: 284 + league: Serie A + matches_played: 34 + minutes_played: 2353 + name: Luis Alberto + penalty_kicks_made: 762 + penalty_kicks_won: 254 + position: MF + rank: 53 + red_card: 134 + squad: Lazio + yellow_card: 42 +Maghnes Akliouche: + age: 20.0 + born: 2002 + corner_kicks: 56 + country: FRA + fouls_committed: 135 + goals: 289 + league: Ligue 1 + matches_played: 7 + minutes_played: 54 + name: Maghnes Akliouche + penalty_kicks_made: 162 + penalty_kicks_won: 54 + position: MFFW + rank: 43 + red_card: 120 + squad: Monaco + yellow_card: 56 +Manuel Akanji: + age: 26.0 + born: 1995 + corner_kicks: 188 + country: SUI + fouls_committed: 269 + goals: 273 + league: Bundesliga + matches_played: 26 + minutes_played: 2261 + name: Manuel Akanji + penalty_kicks_made: 582 + penalty_kicks_won: 194 + position: DF + rank: 38 + red_card: 165 + squad: Dortmund + yellow_card: 199 +Marc Albrighton: + age: 32.0 + born: 1989 + corner_kicks: 107 + country: ENG + fouls_committed: 219 + goals: 55 + league: Premier League + matches_played: 17 + minutes_played: 1132 + name: Marc Albrighton + penalty_kicks_made: 432 + penalty_kicks_won: 144 + position: FWDF + rank: 55 + red_card: 194 + squad: Leicester City + yellow_card: 174 +"Marcos Acu\xF1a": + age: 30.0 + born: 1991 + corner_kicks: 78 + country: ARG + fouls_committed: 240 + goals: 245 + league: La Liga + matches_played: 31 + minutes_played: 2260 + name: "Marcos Acu\xF1a" + penalty_kicks_made: 279 + penalty_kicks_won: 93 + position: DF + rank: 13 + red_card: 117 + squad: Sevilla + yellow_card: 69 +Marcos Alonso: + age: 31.0 + born: 1990 + corner_kicks: 240 + country: ESP + fouls_committed: 227 + goals: 277 + league: Premier League + matches_played: 28 + minutes_played: 2167 + name: Marcos Alonso + penalty_kicks_made: 201 + penalty_kicks_won: 67 + position: DF + rank: 72 + red_card: 204 + squad: Chelsea + yellow_card: 67 +"Marley Ak\xE9": + age: 21.0 + born: 2001 + corner_kicks: 71 + country: FRA + fouls_committed: 230 + goals: 66 + league: Serie A + matches_played: 4 + minutes_played: 77 + name: "Marley Ak\xE9" + penalty_kicks_made: 576 + penalty_kicks_won: 192 + position: MFFW + rank: 40 + red_card: 16 + squad: Juventus + yellow_card: 65 +Martin Adeline: + age: 18.0 + born: 2003 + corner_kicks: 35 + country: FRA + fouls_committed: 68 + goals: 242 + league: Ligue 1 + matches_played: 8 + minutes_played: 352 + name: Martin Adeline + penalty_kicks_made: 684 + penalty_kicks_won: 228 + position: MFFW + rank: 17 + red_card: 246 + squad: Reims + yellow_card: 108 +Martin Agirregabiria: + age: 26.0 + born: 1996 + corner_kicks: 69 + country: ESP + fouls_committed: 261 + goals: 125 + league: La Liga + matches_played: 24 + minutes_played: 1616 + name: Martin Agirregabiria + penalty_kicks_made: 894 + penalty_kicks_won: 298 + position: DF + rank: 22 + red_card: 152 + squad: "Alav\xE9s" + yellow_card: 175 +Matthis Abline: + age: 19.0 + born: 2003 + corner_kicks: 83 + country: FRA + fouls_committed: 286 + goals: 117 + league: Ligue 1 + matches_played: 7 + minutes_played: 103 + name: Matthis Abline + penalty_kicks_made: 252 + penalty_kicks_won: 84 + position: FW + rank: 7 + red_card: 155 + squad: Rennes + yellow_card: 276 +Max Aarons: + age: 22.0 + born: 2000 + corner_kicks: 20 + country: ENG + fouls_committed: 208 + goals: 71 + league: Premier League + matches_played: 34 + minutes_played: 2881 + name: Max Aarons + penalty_kicks_made: 33 + penalty_kicks_won: 11 + position: DF + rank: 1 + red_card: 297 + squad: Norwich City + yellow_card: 41 +Michel Aebischer: + age: 25.0 + born: 1997 + corner_kicks: 117 + country: SUI + fouls_committed: 270 + goals: 265 + league: Serie A + matches_played: 12 + minutes_played: 443 + name: Michel Aebischer + penalty_kicks_made: 219 + penalty_kicks_won: 73 + position: MF + rank: 20 + red_card: 250 + squad: Bologna + yellow_card: 38 +"Miguel Almir\xF3n": + age: 28.0 + born: 1994 + corner_kicks: 241 + country: PAR + fouls_committed: 24 + goals: 67 + league: Premier League + matches_played: 30 + minutes_played: 1716 + name: "Miguel Almir\xF3n" + penalty_kicks_made: 429 + penalty_kicks_won: 143 + position: MFFW + rank: 71 + red_card: 122 + squad: Newcastle Utd + yellow_card: 172 +Mircea Alexandru Tirlea: + age: 22.0 + born: 2000 + corner_kicks: 26 + country: ROU + fouls_committed: 208 + goals: 185 + league: La Liga + matches_played: 1 + minutes_played: 15 + name: Mircea Alexandru Tirlea + penalty_kicks_made: 732 + penalty_kicks_won: 244 + position: DF + rank: 64 + red_card: 189 + squad: "Alav\xE9s" + yellow_card: 257 +Mohamed Achi: + age: 20.0 + born: 2002 + corner_kicks: 247 + country: FRA + fouls_committed: 208 + goals: 45 + league: Ligue 1 + matches_played: 1 + minutes_played: 10 + name: Mohamed Achi + penalty_kicks_made: 426 + penalty_kicks_won: 142 + position: MF + rank: 12 + red_card: 225 + squad: Nantes + yellow_card: 94 +Mohamed Ali Cho: + age: 18.0 + born: 2004 + corner_kicks: 173 + country: FRA + fouls_committed: 139 + goals: 69 + league: Ligue 1 + matches_played: 32 + minutes_played: 1837 + name: Mohamed Ali Cho + penalty_kicks_made: 189 + penalty_kicks_won: 63 + position: FW + rank: 65 + red_card: 269 + squad: Angers + yellow_card: 239 +Nadiem Amiri: + age: 25.0 + born: 1996 + corner_kicks: 121 + country: GER + fouls_committed: 299 + goals: 208 + league: Bundesliga + matches_played: 13 + minutes_played: 369 + name: Nadiem Amiri + penalty_kicks_made: 456 + penalty_kicks_won: 152 + position: MFFW + rank: 87 + red_card: 266 + squad: Leverkusen + yellow_card: 132 +Naouirou Ahamada: + age: 20.0 + born: 2002 + corner_kicks: 185 + country: FRA + fouls_committed: 222 + goals: 244 + league: Bundesliga + matches_played: 3 + minutes_played: 61 + name: Naouirou Ahamada + penalty_kicks_made: 342 + penalty_kicks_won: 114 + position: MF + rank: 30 + red_card: 42 + squad: Stuttgart + yellow_card: 63 +"Nathan Ak\xE9": + age: 27.0 + born: 1995 + corner_kicks: 286 + country: NED + fouls_committed: 101 + goals: 41 + league: Premier League + matches_played: 14 + minutes_played: 923 + name: "Nathan Ak\xE9" + penalty_kicks_made: 882 + penalty_kicks_won: 294 + position: DF + rank: 41 + red_card: 93 + squad: Manchester City + yellow_card: 287 +Nayef Aguerd: + age: 26.0 + born: 1996 + corner_kicks: 11 + country: MAR + fouls_committed: 158 + goals: 44 + league: Ligue 1 + matches_played: 31 + minutes_played: 2735 + name: Nayef Aguerd + penalty_kicks_made: 39 + penalty_kicks_won: 13 + position: DF + rank: 26 + red_card: 162 + squad: Rennes + yellow_card: 87 +Ola Aina: + age: 25.0 + born: 1996 + corner_kicks: 38 + country: NGA + fouls_committed: 228 + goals: 75 + league: Serie A + matches_played: 21 + minutes_played: 1437 + name: Ola Aina + penalty_kicks_made: 636 + penalty_kicks_won: 212 + position: DF + rank: 34 + red_card: 294 + squad: Torino + yellow_card: 109 +Omar Alderete: + age: 25.0 + born: 1996 + corner_kicks: 160 + country: PAR + fouls_committed: 112 + goals: 103 + league: La Liga + matches_played: 29 + minutes_played: 2403 + name: Omar Alderete + penalty_kicks_made: 720 + penalty_kicks_won: 240 + position: DF + rank: 59 + red_card: 66 + squad: Valencia + yellow_card: 134 +"Paco Alc\xE1cer": + age: 28.0 + born: 1993 + corner_kicks: 148 + country: ESP + fouls_committed: 67 + goals: 252 + league: La Liga + matches_played: 18 + minutes_played: 787 + name: "Paco Alc\xE1cer" + penalty_kicks_made: 327 + penalty_kicks_won: 109 + position: FW + rank: 56 + red_card: 167 + squad: Villarreal + yellow_card: 230 +Paul Akouokou: + age: 24.0 + born: 1997 + corner_kicks: 83 + country: CIV + fouls_committed: 139 + goals: 122 + league: La Liga + matches_played: 8 + minutes_played: 516 + name: Paul Akouokou + penalty_kicks_made: 780 + penalty_kicks_won: 260 + position: MF + rank: 44 + red_card: 166 + squad: Betis + yellow_card: 21 +Ragnar Ache: + age: 23.0 + born: 1998 + corner_kicks: 86 + country: GER + fouls_committed: 230 + goals: 201 + league: Bundesliga + matches_played: 13 + minutes_played: 259 + name: Ragnar Ache + penalty_kicks_made: 777 + penalty_kicks_won: 259 + position: MFFW + rank: 11 + red_card: 85 + squad: Eint Frankfurt + yellow_card: 137 +"Rayan A\xEFt Nouri": + age: 20.0 + born: 2001 + corner_kicks: 75 + country: FRA + fouls_committed: 82 + goals: 78 + league: Premier League + matches_played: 23 + minutes_played: 1828 + name: "Rayan A\xEFt Nouri" + penalty_kicks_made: 351 + penalty_kicks_won: 117 + position: DF + rank: 35 + red_card: 214 + squad: Wolves + yellow_card: 217 +"Ra\xFAl Albiol": + age: 36.0 + born: 1985 + corner_kicks: 195 + country: ESP + fouls_committed: 190 + goals: 33 + league: La Liga + matches_played: 28 + minutes_played: 2465 + name: "Ra\xFAl Albiol" + penalty_kicks_made: 837 + penalty_kicks_won: 279 + position: DF + rank: 54 + red_card: 256 + squad: Villarreal + yellow_card: 108 +Robert Andrich: + age: 27.0 + born: 1994 + corner_kicks: 194 + country: GER + fouls_committed: 194 + goals: 263 + league: Bundesliga + matches_played: 26 + minutes_played: 1817 + name: Robert Andrich + penalty_kicks_made: 141 + penalty_kicks_won: 47 + position: MF + rank: 97 + red_card: 257 + squad: Leverkusen + yellow_card: 172 +Ruben Aguilar: + age: 29.0 + born: 1993 + corner_kicks: 155 + country: FRA + fouls_committed: 272 + goals: 261 + league: Ligue 1 + matches_played: 28 + minutes_played: 2140 + name: Ruben Aguilar + penalty_kicks_made: 549 + penalty_kicks_won: 183 + position: DF + rank: 28 + red_card: 139 + squad: Monaco + yellow_card: 80 +"Rub\xE9n Alcaraz": + age: 31.0 + born: 1991 + corner_kicks: 49 + country: ESP + fouls_committed: 223 + goals: 74 + league: La Liga + matches_played: 14 + minutes_played: 1105 + name: "Rub\xE9n Alcaraz" + penalty_kicks_made: 381 + penalty_kicks_won: 127 + position: MF + rank: 58 + red_card: 132 + squad: "C\xE1diz" + yellow_card: 26 +Salis Abdul Samed: + age: 22.0 + born: 2000 + corner_kicks: 56 + country: GHA + fouls_committed: 134 + goals: 259 + league: Ligue 1 + matches_played: 31 + minutes_played: 2462 + name: Salis Abdul Samed + penalty_kicks_made: 711 + penalty_kicks_won: 237 + position: MF + rank: 3 + red_card: 209 + squad: Clermont Foot + yellow_card: 75 +Sargis Adamyan: + age: 29.0 + born: 1993 + corner_kicks: 159 + country: ARM + fouls_committed: 256 + goals: 147 + league: Bundesliga + matches_played: 13 + minutes_played: 331 + name: Sargis Adamyan + penalty_kicks_made: 225 + penalty_kicks_won: 75 + position: FWMF + rank: 16 + red_card: 66 + squad: Hoffenheim + yellow_card: 188 +Sebastian Andersson: + age: 30.0 + born: 1991 + corner_kicks: 162 + country: SWE + fouls_committed: 259 + goals: 136 + league: Bundesliga + matches_played: 26 + minutes_played: 1257 + name: Sebastian Andersson + penalty_kicks_made: 678 + penalty_kicks_won: 226 + position: FW + rank: 92 + red_card: 107 + squad: "K\xF6ln" + yellow_card: 131 +"Sergio Ag\xFCero": + age: 33.0 + born: 1988 + corner_kicks: 63 + country: ARG + fouls_committed: 98 + goals: 138 + league: La Liga + matches_played: 4 + minutes_played: 151 + name: "Sergio Ag\xFCero" + penalty_kicks_made: 447 + penalty_kicks_won: 149 + position: FW + rank: 27 + red_card: 195 + squad: Barcelona + yellow_card: 217 +Sofiane Alakouch: + age: 23.0 + born: 1998 + corner_kicks: 175 + country: MAR + fouls_committed: 92 + goals: 232 + league: Ligue 1 + matches_played: 4 + minutes_played: 158 + name: Sofiane Alakouch + penalty_kicks_made: 618 + penalty_kicks_won: 206 + position: DFMF + rank: 48 + red_card: 284 + squad: Metz + yellow_card: 74 +Sofyan Amrabat: + age: 25.0 + born: 1996 + corner_kicks: 198 + country: MAR + fouls_committed: 47 + goals: 89 + league: Serie A + matches_played: 23 + minutes_played: 944 + name: Sofyan Amrabat + penalty_kicks_made: 708 + penalty_kicks_won: 236 + position: MF + rank: 89 + red_card: 200 + squad: Fiorentina + yellow_card: 33 +Steven Alzate: + age: 23.0 + born: 1998 + corner_kicks: 129 + country: COL + fouls_committed: 102 + goals: 109 + league: Premier League + matches_played: 9 + minutes_played: 404 + name: Steven Alzate + penalty_kicks_made: 498 + penalty_kicks_won: 166 + position: MF + rank: 77 + red_card: 50 + squad: Brighton + yellow_card: 224 +Tammy Abraham: + age: 24.0 + born: 1997 + corner_kicks: 283 + country: ENG + fouls_committed: 203 + goals: 49 + league: Serie A + matches_played: 37 + minutes_played: 3084 + name: Tammy Abraham + penalty_kicks_made: 780 + penalty_kicks_won: 260 + position: FW + rank: 8 + red_card: 201 + squad: Roma + yellow_card: 191 +"Thiago Alc\xE1ntara": + age: 31.0 + born: 1991 + corner_kicks: 292 + country: ESP + fouls_committed: 282 + goals: 198 + league: Premier League + matches_played: 25 + minutes_played: 1534 + name: "Thiago Alc\xE1ntara" + penalty_kicks_made: 408 + penalty_kicks_won: 136 + position: MF + rank: 57 + red_card: 38 + squad: Liverpool + yellow_card: 291 +"Tom\xE1s Alarc\xF3n": + age: 23.0 + born: 1999 + corner_kicks: 252 + country: CHI + fouls_committed: 185 + goals: 132 + league: La Liga + matches_played: 23 + minutes_played: 1425 + name: "Tom\xE1s Alarc\xF3n" + penalty_kicks_made: 612 + penalty_kicks_won: 204 + position: MF + rank: 49 + red_card: 56 + squad: "C\xE1diz" + yellow_card: 10 +Trent Alexander-Arnold: + age: 23.0 + born: 1998 + corner_kicks: 37 + country: ENG + fouls_committed: 111 + goals: 162 + league: Premier League + matches_played: 32 + minutes_played: 2853 + name: Trent Alexander-Arnold + penalty_kicks_made: 159 + penalty_kicks_won: 53 + position: DF + rank: 63 + red_card: 125 + squad: Liverpool + yellow_card: 125 +Tyler Adams: + age: 23.0 + born: 1999 + corner_kicks: 99 + country: USA + fouls_committed: 25 + goals: 135 + league: Bundesliga + matches_played: 24 + minutes_played: 1351 + name: Tyler Adams + penalty_kicks_made: 87 + penalty_kicks_won: 29 + position: MF + rank: 15 + red_card: 210 + squad: RB Leipzig + yellow_card: 209 +Wisdom Amey: + age: 16.0 + born: 2005 + corner_kicks: 59 + country: ITA + fouls_committed: 84 + goals: 284 + league: Serie A + matches_played: 1 + minutes_played: 71 + name: Wisdom Amey + penalty_kicks_made: 456 + penalty_kicks_won: 152 + position: DF + rank: 84 + red_card: 194 + squad: Bologna + yellow_card: 225 +Yacine Adli: + age: 21.0 + born: 2000 + corner_kicks: 42 + country: FRA + fouls_committed: 293 + goals: 59 + league: Ligue 1 + matches_played: 36 + minutes_played: 2260 + name: Yacine Adli + penalty_kicks_made: 144 + penalty_kicks_won: 48 + position: MFFW + rank: 19 + red_card: 268 + squad: Bordeaux + yellow_card: 150 +"Yeray \xC1lvarez": + age: 27.0 + born: 1995 + corner_kicks: 238 + country: ESP + fouls_committed: 89 + goals: 273 + league: La Liga + matches_played: 22 + minutes_played: 1860 + name: "Yeray \xC1lvarez" + penalty_kicks_made: 315 + penalty_kicks_won: 105 + position: DF + rank: 75 + red_card: 67 + squad: Athletic Club + yellow_card: 287 +Yunis Abdelhamid: + age: 34.0 + born: 1987 + corner_kicks: 85 + country: MAR + fouls_committed: 169 + goals: 49 + league: Ligue 1 + matches_played: 34 + minutes_played: 2983 + name: Yunis Abdelhamid + penalty_kicks_made: 441 + penalty_kicks_won: 147 + position: DF + rank: 2 + red_card: 10 + squad: Reims + yellow_card: 82 +"\xC1lvaro Aguirre": + age: 22.0 + born: 2000 + corner_kicks: 87 + country: ESP + fouls_committed: 295 + goals: 197 + league: La Liga + matches_played: 1 + minutes_played: 9 + name: "\xC1lvaro Aguirre" + penalty_kicks_made: 396 + penalty_kicks_won: 132 + position: FW + rank: 29 + red_card: 39 + squad: Rayo Vallecano + yellow_card: 53 diff --git a/week_3/football/test/helpers/.keep b/week_3/football/test/helpers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/integration/.keep b/week_3/football/test/integration/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/mailers/.keep b/week_3/football/test/mailers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/models/.keep b/week_3/football/test/models/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/models/football_player_test.rb b/week_3/football/test/models/football_player_test.rb new file mode 100644 index 00000000..d90364f6 --- /dev/null +++ b/week_3/football/test/models/football_player_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class FootballPlayerTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/week_3/football/test/system/.keep b/week_3/football/test/system/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/test/system/football_players_test.rb b/week_3/football/test/system/football_players_test.rb new file mode 100644 index 00000000..58d5e880 --- /dev/null +++ b/week_3/football/test/system/football_players_test.rb @@ -0,0 +1,73 @@ +require "application_system_test_case" + +class FootballPlayersTest < ApplicationSystemTestCase + setup do + @football_player = football_players(:one) + end + + test "visiting the index" do + visit football_players_url + assert_selector "h1", text: "Football players" + end + + test "should create football player" do + visit football_players_url + click_on "New football player" + + fill_in "Age", with: @football_player.age + fill_in "Born", with: @football_player.born + fill_in "Corner kicks", with: @football_player.corner_kicks + fill_in "Country", with: @football_player.country + fill_in "Fouls committed", with: @football_player.fouls_committed + fill_in "Goals", with: @football_player.goals + fill_in "League", with: @football_player.league + fill_in "Matches played", with: @football_player.matches_played + fill_in "Minutes played", with: @football_player.minutes_played + fill_in "Name", with: @football_player.name + fill_in "Penalty kicks made", with: @football_player.penalty_kicks_made + fill_in "Penalty kicks won", with: @football_player.penalty_kicks_won + fill_in "Position", with: @football_player.position + fill_in "Rank", with: @football_player.rank + fill_in "Red card", with: @football_player.red_card + fill_in "Squad", with: @football_player.squad + fill_in "Yellow card", with: @football_player.yellow_card + click_on "Create Football player" + + assert_text "Football player was successfully created" + click_on "Back" + end + + test "should update Football player" do + visit football_player_url(@football_player) + click_on "Edit this football player", match: :first + + fill_in "Age", with: @football_player.age + fill_in "Born", with: @football_player.born + fill_in "Corner kicks", with: @football_player.corner_kicks + fill_in "Country", with: @football_player.country + fill_in "Fouls committed", with: @football_player.fouls_committed + fill_in "Goals", with: @football_player.goals + fill_in "League", with: @football_player.league + fill_in "Matches played", with: @football_player.matches_played + fill_in "Minutes played", with: @football_player.minutes_played + fill_in "Name", with: @football_player.name + fill_in "Penalty kicks made", with: @football_player.penalty_kicks_made + fill_in "Penalty kicks won", with: @football_player.penalty_kicks_won + fill_in "Position", with: @football_player.position + fill_in "Rank", with: @football_player.rank + fill_in "Red card", with: @football_player.red_card + fill_in "Squad", with: @football_player.squad + fill_in "Yellow card", with: @football_player.yellow_card + click_on "Update Football player" + + assert_text "Football player was successfully updated" + click_on "Back" + end + + test "should destroy Football player" do + visit football_player_url(@football_player) + click_on "Destroy this football player", match: :first + + assert_text "Football player was successfully destroyed" + end +end diff --git a/week_3/football/test/test_helper.rb b/week_3/football/test/test_helper.rb new file mode 100644 index 00000000..d713e377 --- /dev/null +++ b/week_3/football/test/test_helper.rb @@ -0,0 +1,13 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + # Run tests in parallel with specified workers + parallelize(workers: :number_of_processors) + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + fixtures :all + + # Add more helper methods to be used by all tests here... +end diff --git a/week_3/football/vendor/.keep b/week_3/football/vendor/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/football/yarn.lock b/week_3/football/yarn.lock new file mode 100644 index 00000000..4b6cabcb --- /dev/null +++ b/week_3/football/yarn.lock @@ -0,0 +1,300 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@esbuild/android-arm64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.16.tgz#833184b8a0a96f9c85105c53d0a67e6d3c5c3f07" + integrity sha512-hFHVAzUKp9Tf8psGq+bDVv+6hTy1bAOoV/jJMUWwhUnIHsh6WbFMhw0ZTkqDuh7TdpffFoHOiIOIxmHc7oYRBQ== + +"@esbuild/android-arm@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.16.tgz#23761b2fd1dfa4806161dbfc9e0824f04061cb95" + integrity sha512-BUuWMlt4WSXod1HSl7aGK8fJOsi+Tab/M0IDK1V1/GstzoOpqc/v3DqmN8MkuapPKQ9Br1WtLAN4uEgWR8x64A== + +"@esbuild/android-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.16.tgz#ffa09f04c0ffea5b594ab7655fc9ca1220365e9b" + integrity sha512-9WhxJpeb6XumlfivldxqmkJepEcELekmSw3NkGrs+Edq6sS5KRxtUBQuKYDD7KqP59dDkxVbaoPIQFKWQG0KLg== + +"@esbuild/darwin-arm64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.16.tgz#62ed2b4bfab594b9e5e708580361f1d059b53b26" + integrity sha512-8Z+wld+vr/prHPi2O0X7o1zQOfMbXWGAw9hT0jEyU/l/Yrg+0Z3FO9pjPho72dVkZs4ewZk0bDOFLdZHm8jEfw== + +"@esbuild/darwin-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.16.tgz#e9756d34cd9b3737a5354e89ca0fdca32d8df64c" + integrity sha512-CYkxVvkZzGCqFrt7EgjFxQKhlUPyDkuR9P0Y5wEcmJqVI8ncerOIY5Kej52MhZyzOBXkYrJgZeVZC9xXXoEg9A== + +"@esbuild/freebsd-arm64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.16.tgz#db7bce444d372e5a213a3f359c42aee3acc0dd45" + integrity sha512-fxrw4BYqQ39z/3Ja9xj/a1gMsVq0xEjhSyI4a9MjfvDDD8fUV8IYliac96i7tzZc3+VytyXX+XNsnpEk5sw5Wg== + +"@esbuild/freebsd-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.16.tgz#02e8a81b7e56040b5eb883896de445a6cd3501f0" + integrity sha512-8p3v1D+du2jiDvSoNVimHhj7leSfST9YlKsAEO7etBfuqjaBMndo0fmjNLp0JCMld+XIx9L80tooOkyUv1a1PQ== + +"@esbuild/linux-arm64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.16.tgz#ea8c3df172644fa6437f0083c2a38b50f89e5b98" + integrity sha512-N3u6BBbCVY3xeP2D8Db7QY8I+nZ+2AgOopUIqk+5yCoLnsWkcVxD2ay5E9iIdvApFi1Vg1lZiiwaVp8bOpAc4A== + +"@esbuild/linux-arm@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.16.tgz#c1c2e97e67bb7247e6f60e2644de057bfedb8cbb" + integrity sha512-bYaocE1/PTMRmkgSckZ0D0Xn2nox8v2qlk+MVVqm+VECNKDdZvghVZtH41dNtBbwADSvA6qkCHGYeWm9LrNCBw== + +"@esbuild/linux-ia32@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.16.tgz#9a0b0e926926f891a3e7f7c50bb38e3db49c2c9a" + integrity sha512-dxjqLKUW8GqGemoRT9v8IgHk+T4tRm1rn1gUcArsp26W9EkK/27VSjBVUXhEG5NInHZ92JaQ3SSMdTwv/r9a2A== + +"@esbuild/linux-loong64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.16.tgz#c5a50ff5981d457ed45f42c3f06a60086759c79b" + integrity sha512-MdUFggHjRiCCwNE9+1AibewoNq6wf94GLB9Q9aXwl+a75UlRmbRK3h6WJyrSGA6ZstDJgaD2wiTSP7tQNUYxwA== + +"@esbuild/linux-mips64el@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.16.tgz#e85b7e3c25000be2ae373e5208e55e282a9763e0" + integrity sha512-CO3YmO7jYMlGqGoeFeKzdwx/bx8Vtq/SZaMAi+ZLDUnDUdfC7GmGwXzIwDJ70Sg+P9pAemjJyJ1icKJ9R3q/Fg== + +"@esbuild/linux-ppc64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.16.tgz#24a0013bf727830df44fece571172ebe31b5c5e6" + integrity sha512-DSl5Czh5hCy/7azX0Wl9IdzPHX2H8clC6G87tBnZnzUpNgRxPFhfmArbaHoAysu4JfqCqbB/33u/GL9dUgCBAw== + +"@esbuild/linux-riscv64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.16.tgz#b080998d8d0480e8235f1384c585ae505e98a19d" + integrity sha512-sSVVMEXsqf1fQu0j7kkhXMViroixU5XoaJXl1u/u+jbXvvhhCt9YvA/B6VM3aM/77HuRQ94neS5bcisijGnKFQ== + +"@esbuild/linux-s390x@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.16.tgz#5042de05b9b653dfd134f05e1b37b61704c14c42" + integrity sha512-jRqBCre9gZGoCdCN/UWCCMwCMsOg65IpY9Pyj56mKCF5zXy9d60kkNRdDN6YXGjr3rzcC4DXnS/kQVCGcC4yPQ== + +"@esbuild/linux-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.16.tgz#b7c0750f2276c9dcf41f0f2229adca46ef22f698" + integrity sha512-G1+09TopOzo59/55lk5Q0UokghYLyHTKKzD5lXsAOOlGDbieGEFJpJBr3BLDbf7cz89KX04sBeExAR/pL/26sA== + +"@esbuild/netbsd-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.16.tgz#e2a0ee181fbbe834174d26e24ce1b258232bb3eb" + integrity sha512-xwjGJB5wwDEujLaJIrSMRqWkbigALpBNcsF9SqszoNKc+wY4kPTdKrSxiY5ik3IatojePP+WV108MvF6q6np4w== + +"@esbuild/openbsd-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.16.tgz#87a84c1932e00f52ab3380c31facf0e48086ffb9" + integrity sha512-yeERkoxG2nR2oxO5n+Ms7MsCeNk23zrby2GXCqnfCpPp7KNc0vxaaacIxb21wPMfXXRhGBrNP4YLIupUBrWdlg== + +"@esbuild/sunos-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.16.tgz#996bcd2603cd345733c3aa5f52bfd5b8fa7d1d36" + integrity sha512-nHfbEym0IObXPhtX6Va3H5GaKBty2kdhlAhKmyCj9u255ktAj0b1YACUs9j5H88NRn9cJCthD1Ik/k9wn8YKVg== + +"@esbuild/win32-arm64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.16.tgz#404a9411d12533d0f2ce0a85df6ddb32e851ef04" + integrity sha512-pdD+M1ZOFy4hE15ZyPX09fd5g4DqbbL1wXGY90YmleVS6Y5YlraW4BvHjim/X/4yuCpTsAFvsT4Nca2lbyDH/A== + +"@esbuild/win32-ia32@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.16.tgz#bb5655a48f5f87fee870061883411f5149bc5e44" + integrity sha512-IPEMfU9p0c3Vb8PqxaPX6BM9rYwlTZGYOf9u+kMdhoILZkVKEjq6PKZO0lB+isojWwAnAqh4ZxshD96njTXajg== + +"@esbuild/win32-x64@0.16.16": + version "0.16.16" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.16.tgz#ee22fed0b2e0c00ce895cdfae9d32ef069a12e04" + integrity sha512-1YYpoJ39WV/2bnShPwgdzJklc+XS0bysN6Tpnt1cWPdeoKOG4RMEY1g7i534QxXX/rPvNx/NLJQTTCeORYzipg== + +"@hotwired/stimulus@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.1.tgz#e3de23623b0c52c247aba4cd5d530d257008676b" + integrity sha512-HGlzDcf9vv/EQrMJ5ZG6VWNs8Z/xMN+1o2OhV1gKiSG6CqZt5MCBB1gRg5ILiN3U0jEAxuDTNPRfBcnZBDmupQ== + +"@hotwired/turbo-rails@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-7.2.4.tgz#d155533e79c4ebdac23e8fe12697d821d5c06307" + integrity sha512-givDUQqaccd19BvErz1Cf2j6MXF74m0G6I75oqFJGeXAa7vwkz9nDplefVNrALCR9Xi9j9gy32xmSI6wD0tZyA== + dependencies: + "@hotwired/turbo" "^7.2.4" + "@rails/actioncable" "^7.0" + +"@hotwired/turbo@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-7.2.4.tgz#0d35541be32cfae3b4f78c6ab9138f5b21f28a21" + integrity sha512-c3xlOroHp/cCZHDOuLp6uzQYEbvXBUVaal0puXoGJ9M8L/KHwZ3hQozD4dVeSN9msHWLxxtmPT1TlCN7gFhj4w== + +"@popperjs/core@^2.11.6": + version "2.11.6" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" + integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== + +"@rails/actioncable@^7.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.4.tgz#70a3ca56809f7aaabb80af2f9c01ae51e1a8ed41" + integrity sha512-tz4oM+Zn9CYsvtyicsa/AwzKZKL+ITHWkhiu7x+xF77clh2b4Rm+s6xnOgY/sGDWoFWZmtKsE95hxBPkgQQNnQ== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bootstrap-icons@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/bootstrap-icons/-/bootstrap-icons-1.10.3.tgz#c587b078ca6743bef4653fe90434b4aebfba53b2" + integrity sha512-7Qvj0j0idEm/DdX9Q0CpxAnJYqBCFCiUI6qzSPYfERMcokVuV9Mdm/AJiVZI8+Gawe4h/l6zFcOzvV7oXCZArw== + +bootstrap@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.3.tgz#54739f4414de121b9785c5da3c87b37ff008322b" + integrity sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ== + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +"chokidar@>=3.0.0 <4.0.0": + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +esbuild@^0.16.16: + version "0.16.16" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.16.tgz#e8a27820a30cc1449066f9bbe8916b145dbc9046" + integrity sha512-24JyKq10KXM5EBIgPotYIJ2fInNWVVqflv3gicIyQqfmUqi4HvDW1VR790cBgLJHCl96Syy7lhoz7tLFcmuRmg== + optionalDependencies: + "@esbuild/android-arm" "0.16.16" + "@esbuild/android-arm64" "0.16.16" + "@esbuild/android-x64" "0.16.16" + "@esbuild/darwin-arm64" "0.16.16" + "@esbuild/darwin-x64" "0.16.16" + "@esbuild/freebsd-arm64" "0.16.16" + "@esbuild/freebsd-x64" "0.16.16" + "@esbuild/linux-arm" "0.16.16" + "@esbuild/linux-arm64" "0.16.16" + "@esbuild/linux-ia32" "0.16.16" + "@esbuild/linux-loong64" "0.16.16" + "@esbuild/linux-mips64el" "0.16.16" + "@esbuild/linux-ppc64" "0.16.16" + "@esbuild/linux-riscv64" "0.16.16" + "@esbuild/linux-s390x" "0.16.16" + "@esbuild/linux-x64" "0.16.16" + "@esbuild/netbsd-x64" "0.16.16" + "@esbuild/openbsd-x64" "0.16.16" + "@esbuild/sunos-x64" "0.16.16" + "@esbuild/win32-arm64" "0.16.16" + "@esbuild/win32-ia32" "0.16.16" + "@esbuild/win32-x64" "0.16.16" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +immutable@^4.0.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.2.tgz#2da9ff4384a4330c36d4d1bc88e90f9e0b0ccd16" + integrity sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +sass@^1.57.1: + version "1.57.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.57.1.tgz#dfafd46eb3ab94817145e8825208ecf7281119b5" + integrity sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +"source-map-js@>=0.6.2 <2.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" From 43a71232b06843ed3260e9e2600d673ad540a4a5 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Tue, 10 Jan 2023 16:34:23 +0530 Subject: [PATCH 14/34] add hello_world test --- week_3/page_controller_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 week_3/page_controller_test.rb diff --git a/week_3/page_controller_test.rb b/week_3/page_controller_test.rb new file mode 100644 index 00000000..01f7db83 --- /dev/null +++ b/week_3/page_controller_test.rb @@ -0,0 +1,15 @@ +require "test_helper" + +class PageControllerTest < ActionDispatch::IntegrationTest + test "should get root" do + get '/' + assert_response :success + + assert_select "h1", "Hello, World!" + end + + test "should get about_me" do + get "/about_me" + assert_response :success + end +end From 6409413da5739dfc11c2e752b11711a1be43d44e Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Tue, 10 Jan 2023 16:38:13 +0530 Subject: [PATCH 15/34] Update README.md --- week_3/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/week_3/README.md b/week_3/README.md index 2b817a8e..3fa2a354 100644 --- a/week_3/README.md +++ b/week_3/README.md @@ -69,3 +69,16 @@ The routes file specifies the URLs that are recognized by the application. - You should be able to see see your changes at `http://localhost:3000` and `http://localhost:3000/about_me`. +- Copy the test file from session_1 directory to hello_world/test/controllers: +```bash +cp page_controller_test.rb hello_world/test/controllers +``` + +- Execute the test suite to ensure the page works as expected. + +```bash +rails test +``` +- If the test fails, check the view files and debug the application. + +- Once the test works locally, submit your changes. From 14066df187df5f4b0060e9c34d46b70d9b7bc30d Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Tue, 10 Jan 2023 19:09:38 +0530 Subject: [PATCH 16/34] Update README.md --- week_3/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/week_3/README.md b/week_3/README.md index 3fa2a354..ad54d346 100644 --- a/week_3/README.md +++ b/week_3/README.md @@ -69,7 +69,7 @@ The routes file specifies the URLs that are recognized by the application. - You should be able to see see your changes at `http://localhost:3000` and `http://localhost:3000/about_me`. -- Copy the test file from session_1 directory to hello_world/test/controllers: +- Copy the test file from week_3 directory to hello_world/test/controllers: ```bash cp page_controller_test.rb hello_world/test/controllers ``` From a73e7fedb4a8e3e85600f88d93599ba220b8d617 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Tue, 10 Jan 2023 20:00:39 +0530 Subject: [PATCH 17/34] update gitignore --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7b6d8d72..2e4da91b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ capybara-*.html /db/*.sqlite3 /db/*.sqlite3-journal /db/*.sqlite3-[0-9]* +**/db/*.sqlite3 +**/db/*.sqlite3-journal +**/db/*.sqlite3-[0-9]* /public/system /coverage/ /spec/tmp @@ -51,4 +54,7 @@ yarn-debug.log* **/imp.rb -**/p_imp.rb \ No newline at end of file +**/p_imp.rb + +**/log/* +**/tmp/* From 231ad3146cde781fd2f064bed45a9d77341f0ced Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Wed, 11 Jan 2023 15:08:15 +0530 Subject: [PATCH 18/34] Update README.md --- week_3/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/week_3/README.md b/week_3/README.md index ad54d346..77b391d7 100644 --- a/week_3/README.md +++ b/week_3/README.md @@ -68,6 +68,9 @@ The routes file specifies the URLs that are recognized by the application. - You should be able to see see your changes at `http://localhost:3000` and `http://localhost:3000/about_me`. + +![image](https://user-images.githubusercontent.com/66632353/211770375-4cc14806-7e60-4135-9e40-7b73e3c4ed23.png) +![image](https://user-images.githubusercontent.com/66632353/211770741-56dfaea8-2095-474b-974a-2b151953a3de.png) - Copy the test file from week_3 directory to hello_world/test/controllers: ```bash From 1c2644fddb932c36780e8506393966b39e0b447b Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 01:44:33 +0530 Subject: [PATCH 19/34] Add football assignment --- week_3/football/README.md | 217 ++- week_3/football/app/models/football_player.rb | 64 + .../test/fixtures/football_players.yml | 1544 ++++++++--------- 3 files changed, 1040 insertions(+), 785 deletions(-) diff --git a/week_3/football/README.md b/week_3/football/README.md index 7db80e4c..121b9cc0 100644 --- a/week_3/football/README.md +++ b/week_3/football/README.md @@ -1,24 +1,215 @@ -# README +# Working with Records +A record is a unique row of a database table. SQL restricts our +operations on a row: +- Creating a record +- Reading a record +- Updating a record +- Deleting a record. -This README would normally document whatever steps are necessary to get the -application up and running. +The four operations are commonly referred with the acronym *CRUD*. Any +change to the data stored must be made up of these operations. Each of +the operations map to a different SQL statement and Rails construct -Things you may want to cover: +- [Active Record Basics ](https://guides.rubyonrails.org/active_record_basics.html#crud-reading-and-writing-data) -* Ruby version +In this assignment we will be seeing how data can created and queried from the +database. -* System dependencies +## Steps -* Configuration +- Create the database +Create the `football_players` table using +[migration](https://guides.rubyonrails.org/active_record_migrations.html) +file in 'week_3/football/db/migrate'. -* Database creation +- Change directory to rails project. +```bash +cd week_3/football +``` -* Database initialization +- Create the database +```bash +rails db:create +``` -* How to run the test suite +You should see two new files are created if not present already - +`week_3/football/db/development.sqlite3` and `week_3/football/db/test.sqlite3` -* Services (job queues, cache servers, search engines, etc.) +- Run the migrations +```bash +rails db:migrate +``` -* Deployment instructions +The schema file (db/schema.rb) should look like this + +```ruby +ActiveRecord::Schema[7.0].define(version: 2023_01_10_105345) do + create_table "football_players", force: :cascade do |t| + t.string "name" + t.integer "rank" + t.string "country" + t.string "position" + t.string "squad" + t.string "league" + t.integer "age" + t.integer "born" + t.integer "minutes_played" + t.integer "goals" + t.integer "penalty_kicks_made" + t.integer "matches_played" + t.integer "corner_kicks" + t.integer "yellow_card" + t.integer "red_card" + t.integer "penalty_kicks_won" + t.integer "fouls_committed" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end +``` + +- Load the sample data +```bash +rails db:fixtures:load +``` +This adds some sample data(/test/fixtures/football_players.yml) to the database. + +### Creating Records +The INSERT INTO statement is used to insert new records in a table + +```sql +INSERT INTO football_players (id, name, rank, country, position, squad, league, age, born, minutes_played, goals, penalty_kicks_made, matches_played, corner_kicks, yellow_card, red_card, penalty_kicks_won, fouls_committed) VALUES (1, Sergio Agüero, 20, "ARG", , "forward", "Barcelona", "La Liga", 33, 1988, 151, 179, 10, 4, 4, 3, 4, 1,) +``` + +In Rails + +```ruby +FootballPlayer.create( + id: 1061760504, + name: "Sergio Agüero", + rank: 27, + country: "ARG", + position: "forward", + squad: "Barcelona", + league: "La Liga", + age: 33, + born: 1988, + minutes_played: 151, + goals: 179, + penalty_kicks_made: 402, + matches_played: 4, + corner_kicks: 4, + yellow_card: 4, + red_card: 3, + penalty_kicks_won: 4, + fouls_committed: 1 +) +``` + +Implement the function `import_argentinian_players` in +`app/models/football_player.rb` to add the following players. + +|name|rank|country|position|squad|league|age|born|minutes_played|goals|penalty_kicks_made|matches_played|corner_kicks|yellow_card|red_card|penalty_kicks_won|fouls_committed| +|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| +|Marcos Acuna|13|ARG|defender|Sevilla|La Liga|30|1991|2260|105|705|31|248|81|267|235|237| +|Lucas Alario|50|ARG|forward|Leverkusen|Bundesliga|29|1992|655|79|192|27|193|148|263|64|172| +|Sergio Agüero|27|ARG|forward|Barcelona|La Liga|33|1988|151|179|402|4|52|74|81|134|146| + +- [Insert Into](https://www.w3schools.com/sql/sql_insert.asp) +- [Create | Active Record](https://guides.rubyonrails.org/active_record_basics.html#create) + + +### Selecting Records + +The `SELECT` statement is used to select data from a database. For +example: + +```sql +SELECT * FROM football_players WHERE name = "Messi"; +``` + +There are many differents ways to select records in Rails with: +- `all`: Select all records. +- `where`: Selects all records satisfying given conditions. +- `find_by`: Selects the _first_ record fullfilling conditions. +- `first`, `last` + +```ruby +# Select all players +FootballPlayer.all + +# Selects all forwarders +FootballPlayer.where(postion: 'forward') + +# Selects all french forwarders +FootballPlayer.where(postion: 'forward', county: 'FRA') + +# Selects first players +FootballPlayer.first + +# Selects first players with name Messi +FootballPlayer.find_by(name: 'Messi') + +# Selects last players +FootballPlayer.last +``` + +- [Ordering in rails](https://guides.rubyonrails.org/active_record_querying.html#ordering) + +[Scopes](https://guides.rubyonrails.org/active_record_querying.html#scopes) +allow you to specify commonly-used queries and mix-and-match as +you go. + +```ruby +scope :midfielders, -> { where(position: 'midfielder') } + +FootballPlayer.midfielders +``` + +Implement the scopes in `app/models/football_player.rb`. + +- [Select SQL Statement](https://www.w3schools.com/sql/sql_select.asp) +- [Read | Active Record Basics](https://guides.rubyonrails.org/active_record_basics.html#read) +- [Active Record Query Interface](https://guides.rubyonrails.org/active_record_querying.html) +- [Scopes](https://guides.rubyonrails.org/active_record_querying.html#scopes) + +### Updating Records + +The `UPDATE` statement is used to modify the existing records in a +table. + +```sql +UPDATE football_players SET goals = 41 WHERE name = "Messi"; +``` + +In Rails + +```ruby +player = FootballPlayer.find_by(name: "Messi") +player.goals = 41 +player.save + +# OR +FootballPlayer.where(name: "Messi").update(goals: 41) +``` + +- [SQL UPDATE Statement](https://www.w3schools.com/sql/sql_update.asp) +- [Update | Active Record Basics](https://guides.rubyonrails.org/active_record_basics.html#update) + +### Deleting Records + +The `DELETE` statement is used to delete existing records in a table. + +```sql + DELETE FROM football_players WHERE name = "Messi"; +``` + +The Rails equivalent: + +```ruby +FootballPlayer.find_by(name: "Messi").destroy +``` + +- [DELETE | ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html#delete) -* ... diff --git a/week_3/football/app/models/football_player.rb b/week_3/football/app/models/football_player.rb index c68d49a4..c0ca949e 100644 --- a/week_3/football/app/models/football_player.rb +++ b/week_3/football/app/models/football_player.rb @@ -1,2 +1,66 @@ class FootballPlayer < ApplicationRecord + # select players who have postion as forward + scope :forwarders, -> { raise NotImplementedError } + + # select goalkeepers + scope :goalkeepers, -> { raise NotImplementedError } + + # select players from the country France + # + # Note - France country code is 'FRA' + scope :french_players, -> { raise NotImplementedError } + + # Sort players by their rank + scope :order_by_rank, -> { raise NotImplementedError } + + # Average goals per game = (total matches) / (total goals) + # + # If total matches or total goals is missing return nil + def average_goals_per_game + raise NotImplementedError + end + + # Total penalty cards given = red_card + yellow_card + # + # If red_card or yellow_card is missing return nil + def total_penalty_cards + raise NotImplementedError + end + + # Return the penalty succes rate of the player + # penalty_success_rate = (penalty_kicks_won * 100) / penalty_kicks_made + def penalty_success_rate + raise NotImplementedError + end + + # create argentinian players + def self.import_argentinian_players + raise NotImplementedError + end + + # Update the statistics of a player after a game + # + # The data is given as an array of the following type: + # [player name, goals, minutes_played, red_card, yellow_card] + + # Eg- + # [ + # ["Sergio Aguero", 2, 30, 0, 0] + # ["Messi", 1, 30, 1, 0] + # ... + # ... + # ["Ronaldo", 3, 20, 1, 0] + # ] + # + # Note: If you cannot find a player with given name, raise an + # `ActiveRecord::RecordNotFound` exception with the player's name as + # the message. + def self.update_statistics(stat) + raise NotImplementedError + end + + # Delete the record associated with a player. + def self.ban(name) + raise NotImplementedError + end end diff --git a/week_3/football/test/fixtures/football_players.yml b/week_3/football/test/fixtures/football_players.yml index 68f03ef7..7b72fad0 100644 --- a/week_3/football/test/fixtures/football_players.yml +++ b/week_3/football/test/fixtures/football_players.yml @@ -1,1746 +1,1746 @@ Alisson: age: 29.0 born: 1992 - corner_kicks: 47 + corner_kicks: 144 country: BRA - fouls_committed: 252 - goals: 240 + fouls_committed: 48 + goals: 27 league: Premier League matches_played: 36 minutes_played: 3240 name: Alisson - penalty_kicks_made: 891 - penalty_kicks_won: 297 - position: GK + penalty_kicks_made: 426 + penalty_kicks_won: 142 + position: goalkeeper rank: 66 - red_card: 56 + red_card: 163 squad: Liverpool - yellow_card: 145 + yellow_card: 225 Allan: age: 31.0 born: 1991 - corner_kicks: 226 + corner_kicks: 27 country: BRA - fouls_committed: 118 - goals: 133 + fouls_committed: 232 + goals: 76 league: Premier League matches_played: 28 minutes_played: 2183 name: Allan - penalty_kicks_made: 381 - penalty_kicks_won: 127 - position: MF + penalty_kicks_made: 180 + penalty_kicks_won: 60 + position: midfielder rank: 67 - red_card: 197 + red_card: 300 squad: Everton - yellow_card: 237 + yellow_card: 181 Amath: age: 25.0 born: 1996 - corner_kicks: 115 + corner_kicks: 210 country: SEN - fouls_committed: 28 - goals: 10 + fouls_committed: 122 + goals: 40 league: La Liga matches_played: 19 minutes_played: 884 name: Amath - penalty_kicks_made: 858 - penalty_kicks_won: 286 - position: FWMF + penalty_kicks_made: 72 + penalty_kicks_won: 24 + position: forward rank: 81 - red_card: 186 + red_card: 284 squad: Mallorca - yellow_card: 248 + yellow_card: 204 Amine Adli: age: 22.0 born: 2000 - corner_kicks: 232 + corner_kicks: 211 country: FRA - fouls_committed: 214 - goals: 279 + fouls_committed: 235 + goals: 294 league: Bundesliga matches_played: 25 minutes_played: 1256 name: Amine Adli - penalty_kicks_made: 684 - penalty_kicks_won: 228 - position: FWMF + penalty_kicks_made: 237 + penalty_kicks_won: 79 + position: forward rank: 18 - red_card: 220 + red_card: 207 squad: Leverkusen - yellow_card: 156 + yellow_card: 231 "Andr\xE9s Andrade Cede\xF1o": age: 23.0 born: 1998 - corner_kicks: 206 + corner_kicks: 271 country: PAN - fouls_committed: 83 - goals: 200 + fouls_committed: 110 + goals: 71 league: Bundesliga matches_played: 17 minutes_played: 1046 name: "Andr\xE9s Andrade Cede\xF1o" - penalty_kicks_made: 600 - penalty_kicks_won: 200 - position: DF + penalty_kicks_made: 51 + penalty_kicks_won: 17 + position: defender rank: 94 - red_card: 268 + red_card: 165 squad: Arminia - yellow_card: 13 + yellow_card: 160 Anel Ahmedhodzic: age: 23.0 born: 1999 - corner_kicks: 202 + corner_kicks: 161 country: BIH - fouls_committed: 157 - goals: 295 + fouls_committed: 243 + goals: 244 league: Ligue 1 matches_played: 15 minutes_played: 1350 name: Anel Ahmedhodzic - penalty_kicks_made: 447 - penalty_kicks_won: 149 - position: DF + penalty_kicks_made: 147 + penalty_kicks_won: 49 + position: defender rank: 31 - red_card: 230 + red_card: 80 squad: Bordeaux - yellow_card: 129 + yellow_card: 179 "Angeli\xF1o": age: 25.0 born: 1997 - corner_kicks: 162 + corner_kicks: 199 country: ESP - fouls_committed: 185 - goals: 64 + fouls_committed: 241 + goals: 190 league: Bundesliga matches_played: 29 minutes_played: 2298 name: "Angeli\xF1o" - penalty_kicks_made: 351 - penalty_kicks_won: 117 - position: DF + penalty_kicks_made: 531 + penalty_kicks_won: 177 + position: defender rank: 99 - red_card: 172 + red_card: 267 squad: RB Leipzig - yellow_card: 277 + yellow_card: 248 "Benjamin Andr\xE9": age: 31.0 born: 1990 - corner_kicks: 197 + corner_kicks: 98 country: FRA - fouls_committed: 232 - goals: 261 + fouls_committed: 89 + goals: 207 league: Ligue 1 matches_played: 33 minutes_played: 2752 name: "Benjamin Andr\xE9" - penalty_kicks_made: 249 - penalty_kicks_won: 83 - position: MF + penalty_kicks_made: 339 + penalty_kicks_won: 113 + position: midfielder rank: 96 - red_card: 272 + red_card: 197 squad: Lille - yellow_card: 246 + yellow_card: 12 "Carles Ale\xF1\xE1": age: 24.0 born: 1998 - corner_kicks: 131 + corner_kicks: 183 country: ESP - fouls_committed: 60 - goals: 229 + fouls_committed: 91 + goals: 102 league: La Liga matches_played: 33 minutes_played: 2320 name: "Carles Ale\xF1\xE1" - penalty_kicks_made: 486 - penalty_kicks_won: 162 - position: MF + penalty_kicks_made: 378 + penalty_kicks_won: 126 + position: midfielder rank: 62 - red_card: 251 + red_card: 289 squad: Getafe - yellow_card: 271 + yellow_card: 55 Carlos Akapo: age: 29.0 born: 1993 - corner_kicks: 201 + corner_kicks: 92 country: EQG - fouls_committed: 255 - goals: 102 + fouls_committed: 151 + goals: 259 league: La Liga matches_played: 25 minutes_played: 1844 name: Carlos Akapo - penalty_kicks_made: 42 - penalty_kicks_won: 14 - position: DF + penalty_kicks_made: 897 + penalty_kicks_won: 299 + position: defender rank: 39 - red_card: 51 + red_card: 223 squad: "C\xE1diz" - yellow_card: 74 + yellow_card: 143 Charles Abi: age: 22.0 born: 2000 - corner_kicks: 111 + corner_kicks: 108 country: FRA - fouls_committed: 273 - goals: 93 + fouls_committed: 272 + goals: 73 league: Ligue 1 matches_played: 1 minutes_played: 45 name: Charles Abi - penalty_kicks_made: 30 - penalty_kicks_won: 10 - position: FW + penalty_kicks_made: 768 + penalty_kicks_won: 256 + position: forward rank: 5 - red_card: 27 + red_card: 148 squad: "Saint-\xC9tienne" - yellow_card: 39 + yellow_card: 75 Che Adams: age: 25.0 born: 1996 - corner_kicks: 256 + corner_kicks: 130 country: SCO - fouls_committed: 99 - goals: 134 + fouls_committed: 271 + goals: 162 league: Premier League matches_played: 30 minutes_played: 2039 name: Che Adams - penalty_kicks_made: 711 - penalty_kicks_won: 237 - position: FW + penalty_kicks_made: 468 + penalty_kicks_won: 156 + position: forward rank: 14 - red_card: 154 + red_card: 34 squad: Southampton - yellow_card: 121 + yellow_card: 268 Dani Alves: age: 39.0 born: 1983 - corner_kicks: 31 + corner_kicks: 106 country: BRA - fouls_committed: 271 - goals: 236 + fouls_committed: 273 + goals: 21 league: La Liga matches_played: 14 minutes_played: 1098 name: Dani Alves - penalty_kicks_made: 480 - penalty_kicks_won: 160 - position: DF + penalty_kicks_made: 642 + penalty_kicks_won: 214 + position: defender rank: 76 - red_card: 136 + red_card: 56 squad: Barcelona - yellow_card: 191 + yellow_card: 227 Daniel Amartey: age: 27.0 born: 1994 - corner_kicks: 198 + corner_kicks: 243 country: GHA - fouls_committed: 34 - goals: 18 + fouls_committed: 130 + goals: 44 league: Premier League matches_played: 28 minutes_played: 2123 name: Daniel Amartey - penalty_kicks_made: 144 - penalty_kicks_won: 48 - position: DF + penalty_kicks_made: 246 + penalty_kicks_won: 82 + position: defender rank: 80 - red_card: 59 + red_card: 77 squad: Leicester City - yellow_card: 163 + yellow_card: 269 David Alaba: age: 29.0 born: 1992 - corner_kicks: 297 + corner_kicks: 201 country: AUT - fouls_committed: 15 - goals: 183 + fouls_committed: 46 + goals: 89 league: La Liga matches_played: 30 minutes_played: 2642 name: David Alaba - penalty_kicks_made: 855 - penalty_kicks_won: 285 - position: DF + penalty_kicks_made: 189 + penalty_kicks_won: 63 + position: defender rank: 47 - red_card: 178 + red_card: 112 squad: Real Madrid - yellow_card: 76 + yellow_card: 103 Dele Alli: age: 26.0 born: 1996 - corner_kicks: 199 + corner_kicks: 118 country: ENG - fouls_committed: 20 - goals: 287 + fouls_committed: 261 + goals: 225 league: Premier League matches_played: 10 minutes_played: 657 name: Dele Alli - penalty_kicks_made: 534 - penalty_kicks_won: 178 - position: MFFW + penalty_kicks_made: 147 + penalty_kicks_won: 49 + position: midfielder rank: 70 - red_card: 234 + red_card: 91 squad: Tottenham - yellow_card: 71 + yellow_card: 102 Dickson Abiama: age: 23.0 born: 1998 - corner_kicks: 53 + corner_kicks: 162 country: NGA - fouls_committed: 269 - goals: 244 + fouls_committed: 70 + goals: 30 league: Bundesliga matches_played: 24 minutes_played: 726 name: Dickson Abiama - penalty_kicks_made: 450 - penalty_kicks_won: 150 - position: FW + penalty_kicks_made: 90 + penalty_kicks_won: 30 + position: forward rank: 6 - red_card: 187 + red_card: 296 squad: "Greuther F\xFCrth" - yellow_card: 260 + yellow_card: 113 "Do\xF0an Alemdar": age: 19.0 born: 2002 - corner_kicks: 192 + corner_kicks: 40 country: TUR - fouls_committed: 152 - goals: 281 + fouls_committed: 211 + goals: 58 league: Ligue 1 matches_played: 12 minutes_played: 1080 name: "Do\xF0an Alemdar" - penalty_kicks_made: 450 - penalty_kicks_won: 150 - position: GK + penalty_kicks_made: 711 + penalty_kicks_won: 237 + position: goalkeeper rank: 61 - red_card: 209 + red_card: 257 squad: Rennes - yellow_card: 45 + yellow_card: 35 Ebenezer Annan: age: 19.0 born: 2002 - corner_kicks: 15 + corner_kicks: 20 country: GHA - fouls_committed: 206 - goals: 286 + fouls_committed: 192 + goals: 300 league: Serie A matches_played: 1 minutes_played: 25 name: Ebenezer Annan - penalty_kicks_made: 417 - penalty_kicks_won: 139 - position: DF + penalty_kicks_made: 456 + penalty_kicks_won: 152 + position: defender rank: 100 - red_card: 40 + red_card: 283 squad: Bologna - yellow_card: 128 + yellow_card: 194 Emmanuel Amankwaa Akurugu: age: 20.0 born: 2001 - corner_kicks: 174 + corner_kicks: 205 country: GHA - fouls_committed: 100 - goals: 37 + fouls_committed: 250 + goals: 184 league: La Liga matches_played: 3 minutes_played: 79 name: Emmanuel Amankwaa Akurugu - penalty_kicks_made: 48 - penalty_kicks_won: 16 - position: DF + penalty_kicks_made: 171 + penalty_kicks_won: 57 + position: defender rank: 79 - red_card: 89 + red_card: 176 squad: Getafe - yellow_card: 162 + yellow_card: 220 Ethan Ampadu: age: 21.0 born: 2000 - corner_kicks: 80 + corner_kicks: 219 country: WAL - fouls_committed: 231 - goals: 55 + fouls_committed: 92 + goals: 200 league: Serie A matches_played: 29 minutes_played: 2282 name: Ethan Ampadu - penalty_kicks_made: 687 - penalty_kicks_won: 229 - position: MFDF + penalty_kicks_made: 807 + penalty_kicks_won: 269 + position: midfielder rank: 88 - red_card: 217 + red_card: 100 squad: Venezia - yellow_card: 151 + yellow_card: 172 Felipe Anderson: age: 29.0 born: 1993 - corner_kicks: 38 + corner_kicks: 150 country: BRA - fouls_committed: 42 - goals: 287 + fouls_committed: 271 + goals: 235 league: Serie A matches_played: 38 minutes_played: 2888 name: Felipe Anderson - penalty_kicks_made: 546 - penalty_kicks_won: 182 - position: FW + penalty_kicks_made: 678 + penalty_kicks_won: 226 + position: forward rank: 91 - red_card: 80 + red_card: 206 squad: Lazio - yellow_card: 269 + yellow_card: 253 Felix Afena-Gyan: age: 19.0 born: 2003 - corner_kicks: 42 + corner_kicks: 27 country: GHA - fouls_committed: 13 - goals: 131 + fouls_committed: 261 + goals: 143 league: Serie A matches_played: 17 minutes_played: 668 name: Felix Afena-Gyan - penalty_kicks_made: 702 - penalty_kicks_won: 234 - position: FWMF + penalty_kicks_made: 594 + penalty_kicks_won: 198 + position: forward rank: 21 red_card: 211 squad: Roma - yellow_card: 245 + yellow_card: 266 Florin Andone: age: 29.0 born: 1993 - corner_kicks: 243 + corner_kicks: 226 country: ROU - fouls_committed: 58 - goals: 60 + fouls_committed: 189 + goals: 37 league: La Liga matches_played: 5 minutes_played: 176 name: Florin Andone - penalty_kicks_made: 747 - penalty_kicks_won: 249 - position: FW + penalty_kicks_made: 174 + penalty_kicks_won: 58 + position: forward rank: 93 - red_card: 218 + red_card: 297 squad: "C\xE1diz" - yellow_card: 297 + yellow_card: 231 Francesco Acerbi: age: 34.0 born: 1988 - corner_kicks: 66 + corner_kicks: 274 country: ITA - fouls_committed: 212 - goals: 147 + fouls_committed: 177 + goals: 40 league: Serie A matches_played: 30 minutes_played: 2536 name: Francesco Acerbi - penalty_kicks_made: 381 - penalty_kicks_won: 127 - position: DF + penalty_kicks_made: 342 + penalty_kicks_won: 114 + position: defender rank: 10 - red_card: 152 + red_card: 248 squad: Lazio - yellow_card: 18 + yellow_card: 107 "Fredrik Andr\xE9 Bj\xF8rkan": age: 23.0 born: 1998 - corner_kicks: 10 + corner_kicks: 215 country: NOR - fouls_committed: 292 - goals: 289 + fouls_committed: 123 + goals: 172 league: Bundesliga matches_played: 9 minutes_played: 353 name: "Fredrik Andr\xE9 Bj\xF8rkan" - penalty_kicks_made: 573 - penalty_kicks_won: 191 - position: DF + penalty_kicks_made: 471 + penalty_kicks_won: 157 + position: defender rank: 95 - red_card: 155 + red_card: 132 squad: Hertha BSC - yellow_card: 57 + yellow_card: 171 Giorgio Altare: age: 23.0 born: 1998 - corner_kicks: 239 + corner_kicks: 169 country: ITA - fouls_committed: 215 - goals: 45 + fouls_committed: 35 + goals: 111 league: Serie A matches_played: 19 minutes_played: 1466 name: Giorgio Altare - penalty_kicks_made: 330 - penalty_kicks_won: 110 - position: DF + penalty_kicks_made: 240 + penalty_kicks_won: 80 + position: defender rank: 73 - red_card: 110 + red_card: 221 squad: Cagliari - yellow_card: 114 + yellow_card: 98 "Hugo \xC1lvarez": age: 36.0 born: 1985 - corner_kicks: 141 + corner_kicks: 30 country: ESP - fouls_committed: 58 - goals: 165 + fouls_committed: 52 + goals: 22 league: La Liga matches_played: 1 minutes_played: 11 name: "Hugo \xC1lvarez" - penalty_kicks_made: 501 - penalty_kicks_won: 167 - position: FW + penalty_kicks_made: 639 + penalty_kicks_won: 213 + position: forward rank: 74 - red_card: 195 + red_card: 36 squad: Celta Vigo - yellow_card: 280 + yellow_card: 106 Ibrahim Amadou: age: 29.0 born: 1993 - corner_kicks: 116 + corner_kicks: 103 country: FRA - fouls_committed: 113 - goals: 277 + fouls_committed: 59 + goals: 260 league: Ligue 1 matches_played: 10 minutes_played: 812 name: Ibrahim Amadou - penalty_kicks_made: 309 - penalty_kicks_won: 103 - position: DFMF + penalty_kicks_made: 285 + penalty_kicks_won: 95 + position: defender rank: 78 - red_card: 247 + red_card: 217 squad: Metz - yellow_card: 28 + yellow_card: 133 Ilias Akhomach: age: 18.0 born: 2004 - corner_kicks: 27 + corner_kicks: 194 country: ESP - fouls_committed: 222 - goals: 78 + fouls_committed: 44 + goals: 70 league: La Liga matches_played: 2 minutes_played: 124 name: Ilias Akhomach - penalty_kicks_made: 861 - penalty_kicks_won: 287 - position: FW + penalty_kicks_made: 249 + penalty_kicks_won: 83 + position: forward rank: 42 - red_card: 66 + red_card: 79 squad: Barcelona - yellow_card: 177 + yellow_card: 19 "Iv\xE1n Alejo": age: 27.0 born: 1995 - corner_kicks: 128 + corner_kicks: 49 country: ESP - fouls_committed: 264 - goals: 190 + fouls_committed: 40 + goals: 10 league: La Liga matches_played: 20 minutes_played: 1065 name: "Iv\xE1n Alejo" - penalty_kicks_made: 747 - penalty_kicks_won: 249 - position: MFFW + penalty_kicks_made: 495 + penalty_kicks_won: 165 + position: midfielder rank: 60 - red_card: 109 + red_card: 102 squad: "C\xE1diz" - yellow_card: 75 + yellow_card: 167 Jean-Daniel Akpa-Akpro: age: 29.0 born: 1992 - corner_kicks: 152 + corner_kicks: 17 country: CIV fouls_committed: 213 - goals: 203 + goals: 232 league: Serie A matches_played: 10 minutes_played: 315 name: Jean-Daniel Akpa-Akpro - penalty_kicks_made: 111 - penalty_kicks_won: 37 - position: MF + penalty_kicks_made: 765 + penalty_kicks_won: 255 + position: midfielder rank: 45 - red_card: 112 + red_card: 31 squad: Lazio - yellow_card: 131 + yellow_card: 108 Jean-Eudes Aholou: age: 28.0 born: 1994 - corner_kicks: 224 + corner_kicks: 167 country: CIV - fouls_committed: 58 - goals: 214 + fouls_committed: 109 + goals: 260 league: Ligue 1 matches_played: 25 minutes_played: 1004 name: Jean-Eudes Aholou - penalty_kicks_made: 633 - penalty_kicks_won: 211 - position: MF + penalty_kicks_made: 699 + penalty_kicks_won: 233 + position: midfielder rank: 32 - red_card: 30 + red_card: 33 squad: Strasbourg - yellow_card: 121 + yellow_card: 107 Jim Allevinah: age: 27.0 born: 1995 - corner_kicks: 266 + corner_kicks: 221 country: GAB - fouls_committed: 250 - goals: 275 + fouls_committed: 85 + goals: 219 league: Ligue 1 matches_played: 30 minutes_played: 1488 name: Jim Allevinah - penalty_kicks_made: 342 - penalty_kicks_won: 114 - position: FW + penalty_kicks_made: 528 + penalty_kicks_won: 176 + position: forward rank: 68 - red_card: 98 + red_card: 184 squad: Clermont Foot - yellow_card: 255 + yellow_card: 12 Joachim Andersen: age: 25.0 born: 1996 - corner_kicks: 24 + corner_kicks: 64 country: DEN - fouls_committed: 46 - goals: 104 + fouls_committed: 280 + goals: 119 league: Premier League matches_played: 34 minutes_played: 2916 name: Joachim Andersen - penalty_kicks_made: 585 - penalty_kicks_won: 195 - position: DF + penalty_kicks_made: 90 + penalty_kicks_won: 30 + position: defender rank: 90 - red_card: 74 + red_card: 106 squad: Crystal Palace - yellow_card: 71 + yellow_card: 84 Jordan Amavi: age: 28.0 born: 1994 - corner_kicks: 150 + corner_kicks: 163 country: FRA - fouls_committed: 117 - goals: 66 + fouls_committed: 156 + goals: 289 league: Ligue 1 matches_played: 8 minutes_played: 413 name: Jordan Amavi - penalty_kicks_made: 306 - penalty_kicks_won: 102 - position: DF + penalty_kicks_made: 900 + penalty_kicks_won: 300 + position: defender rank: 83 - red_card: 81 + red_card: 50 squad: Nice - yellow_card: 120 + yellow_card: 189 Jordi Alba: age: 33.0 born: 1989 - corner_kicks: 128 + corner_kicks: 271 country: ESP - fouls_committed: 246 - goals: 151 + fouls_committed: 226 + goals: 192 league: La Liga matches_played: 30 minutes_played: 2644 name: Jordi Alba - penalty_kicks_made: 405 - penalty_kicks_won: 135 - position: DF + penalty_kicks_made: 600 + penalty_kicks_won: 200 + position: defender rank: 51 - red_card: 252 + red_card: 187 squad: Barcelona - yellow_card: 109 + yellow_card: 294 Joseph Aidoo: age: 26.0 born: 1995 - corner_kicks: 158 + corner_kicks: 55 country: GHA - fouls_committed: 110 - goals: 254 + fouls_committed: 19 + goals: 188 league: La Liga matches_played: 32 minutes_played: 2637 name: Joseph Aidoo - penalty_kicks_made: 504 - penalty_kicks_won: 168 - position: DF + penalty_kicks_made: 852 + penalty_kicks_won: 284 + position: defender rank: 33 - red_card: 191 + red_card: 58 squad: Celta Vigo - yellow_card: 69 + yellow_card: 175 "Josu\xE9 Albert": age: 30.0 born: 1992 - corner_kicks: 47 + corner_kicks: 76 country: GUF - fouls_committed: 288 - goals: 298 + fouls_committed: 44 + goals: 49 league: Ligue 1 matches_played: 2 minutes_played: 22 name: "Josu\xE9 Albert" - penalty_kicks_made: 888 - penalty_kicks_won: 296 - position: DF + penalty_kicks_made: 705 + penalty_kicks_won: 235 + position: defender rank: 52 - red_card: 292 + red_card: 30 squad: Clermont Foot - yellow_card: 67 + yellow_card: 162 "Jos\xE9 \xC1ngel": age: 32.0 born: 1989 - corner_kicks: 91 + corner_kicks: 36 country: ESP - fouls_committed: 55 - goals: 90 + fouls_committed: 205 + goals: 151 league: La Liga matches_played: 23 minutes_played: 1083 name: "Jos\xE9 \xC1ngel" - penalty_kicks_made: 177 - penalty_kicks_won: 59 - position: DF + penalty_kicks_made: 54 + penalty_kicks_won: 18 + position: defender rank: 98 - red_card: 112 + red_card: 262 squad: Osasuna - yellow_card: 128 + yellow_card: 167 Julen Agirrezabala: age: 21.0 born: 2000 - corner_kicks: 237 + corner_kicks: 119 country: ESP - fouls_committed: 297 - goals: 36 + fouls_committed: 53 + goals: 153 league: La Liga matches_played: 4 minutes_played: 360 name: Julen Agirrezabala - penalty_kicks_made: 795 - penalty_kicks_won: 265 - position: GK + penalty_kicks_made: 627 + penalty_kicks_won: 209 + position: goalkeeper rank: 23 - red_card: 12 + red_card: 257 squad: Athletic Club - yellow_card: 108 + yellow_card: 269 Kelvin Amian: age: 24.0 born: 1998 - corner_kicks: 39 + corner_kicks: 147 country: FRA - fouls_committed: 102 - goals: 203 + fouls_committed: 208 + goals: 103 league: Serie A matches_played: 32 minutes_played: 2646 name: Kelvin Amian - penalty_kicks_made: 879 - penalty_kicks_won: 293 - position: DF + penalty_kicks_made: 744 + penalty_kicks_won: 248 + position: defender rank: 85 - red_card: 278 + red_card: 128 squad: Spezia - yellow_card: 173 + yellow_card: 260 Kevin Agudelo: age: 23.0 born: 1998 - corner_kicks: 111 + corner_kicks: 126 country: COL - fouls_committed: 121 - goals: 225 + fouls_committed: 25 + goals: 64 league: Serie A matches_played: 23 minutes_played: 1237 name: Kevin Agudelo - penalty_kicks_made: 843 - penalty_kicks_won: 281 - position: MFFW + penalty_kicks_made: 606 + penalty_kicks_won: 202 + position: midfielder rank: 25 - red_card: 190 + red_card: 171 squad: Spezia - yellow_card: 224 + yellow_card: 91 Kevin Akpoguma: age: 27.0 born: 1995 - corner_kicks: 194 + corner_kicks: 99 country: NGA - fouls_committed: 85 - goals: 124 + fouls_committed: 56 + goals: 82 league: Bundesliga matches_played: 26 minutes_played: 1527 name: Kevin Akpoguma - penalty_kicks_made: 420 - penalty_kicks_won: 140 - position: DF + penalty_kicks_made: 588 + penalty_kicks_won: 196 + position: defender rank: 46 - red_card: 60 + red_card: 86 squad: Hoffenheim - yellow_card: 79 + yellow_card: 203 Kristoffer Ajer: age: 24.0 born: 1998 - corner_kicks: 278 + corner_kicks: 33 country: NOR - fouls_committed: 120 - goals: 279 + fouls_committed: 243 + goals: 52 league: Premier League matches_played: 24 minutes_played: 1995 name: Kristoffer Ajer - penalty_kicks_made: 375 - penalty_kicks_won: 125 - position: DF + penalty_kicks_made: 585 + penalty_kicks_won: 195 + position: defender rank: 36 - red_card: 126 + red_card: 281 squad: Brentford - yellow_card: 69 + yellow_card: 79 Laurent Abergel: age: 29.0 born: 1993 - corner_kicks: 257 + corner_kicks: 247 country: FRA - fouls_committed: 270 - goals: 224 + fouls_committed: 182 + goals: 232 league: Ligue 1 matches_played: 34 minutes_played: 2956 name: Laurent Abergel - penalty_kicks_made: 162 - penalty_kicks_won: 54 - position: MF + penalty_kicks_made: 738 + penalty_kicks_won: 246 + position: midfielder rank: 4 - red_card: 200 + red_card: 58 squad: Lorient - yellow_card: 122 + yellow_card: 24 Lucas Alario: age: 29.0 born: 1992 - corner_kicks: 236 + corner_kicks: 193 country: ARG - fouls_committed: 48 - goals: 43 + fouls_committed: 172 + goals: 79 league: Bundesliga matches_played: 27 minutes_played: 655 name: Lucas Alario - penalty_kicks_made: 90 - penalty_kicks_won: 30 - position: FW + penalty_kicks_made: 192 + penalty_kicks_won: 64 + position: forward rank: 50 - red_card: 104 + red_card: 263 squad: Leverkusen - yellow_card: 240 + yellow_card: 148 Lucien Agoume: age: 20.0 born: 2002 - corner_kicks: 158 + corner_kicks: 81 country: FRA - fouls_committed: 192 - goals: 60 + fouls_committed: 139 + goals: 63 league: Ligue 1 matches_played: 27 minutes_played: 1868 name: Lucien Agoume - penalty_kicks_made: 753 - penalty_kicks_won: 251 - position: MF + penalty_kicks_made: 216 + penalty_kicks_won: 72 + position: midfielder rank: 24 - red_card: 75 + red_card: 226 squad: Brest - yellow_card: 131 + yellow_card: 51 Ludovic Ajorque: age: 28.0 born: 1994 - corner_kicks: 102 + corner_kicks: 168 country: REU - fouls_committed: 150 - goals: 106 + fouls_committed: 122 + goals: 11 league: Ligue 1 matches_played: 36 minutes_played: 2738 name: Ludovic Ajorque - penalty_kicks_made: 693 - penalty_kicks_won: 231 - position: FW + penalty_kicks_made: 600 + penalty_kicks_won: 200 + position: forward rank: 37 - red_card: 131 + red_card: 278 squad: Strasbourg - yellow_card: 41 + yellow_card: 82 Luis Abram: age: 26.0 born: 1996 - corner_kicks: 192 + corner_kicks: 207 country: PER - fouls_committed: 38 - goals: 48 + fouls_committed: 87 + goals: 86 league: La Liga matches_played: 8 minutes_played: 560 name: Luis Abram - penalty_kicks_made: 678 - penalty_kicks_won: 226 - position: DF + penalty_kicks_made: 246 + penalty_kicks_won: 82 + position: defender rank: 9 - red_card: 19 + red_card: 215 squad: Granada - yellow_card: 216 + yellow_card: 228 Luis Alberto: age: 29.0 born: 1992 - corner_kicks: 214 + corner_kicks: 81 country: ESP - fouls_committed: 285 - goals: 284 + fouls_committed: 174 + goals: 115 league: Serie A matches_played: 34 minutes_played: 2353 name: Luis Alberto - penalty_kicks_made: 762 - penalty_kicks_won: 254 - position: MF + penalty_kicks_made: 183 + penalty_kicks_won: 61 + position: midfielder rank: 53 - red_card: 134 + red_card: 12 squad: Lazio - yellow_card: 42 + yellow_card: 192 Maghnes Akliouche: age: 20.0 born: 2002 - corner_kicks: 56 + corner_kicks: 263 country: FRA - fouls_committed: 135 - goals: 289 + fouls_committed: 175 + goals: 114 league: Ligue 1 matches_played: 7 minutes_played: 54 name: Maghnes Akliouche - penalty_kicks_made: 162 - penalty_kicks_won: 54 - position: MFFW + penalty_kicks_made: 540 + penalty_kicks_won: 180 + position: midfielder rank: 43 - red_card: 120 + red_card: 88 squad: Monaco - yellow_card: 56 + yellow_card: 49 Manuel Akanji: age: 26.0 born: 1995 - corner_kicks: 188 + corner_kicks: 161 country: SUI - fouls_committed: 269 - goals: 273 + fouls_committed: 270 + goals: 286 league: Bundesliga matches_played: 26 minutes_played: 2261 name: Manuel Akanji - penalty_kicks_made: 582 - penalty_kicks_won: 194 - position: DF + penalty_kicks_made: 888 + penalty_kicks_won: 296 + position: defender rank: 38 - red_card: 165 + red_card: 25 squad: Dortmund - yellow_card: 199 + yellow_card: 77 Marc Albrighton: age: 32.0 born: 1989 - corner_kicks: 107 + corner_kicks: 127 country: ENG - fouls_committed: 219 - goals: 55 + fouls_committed: 195 + goals: 137 league: Premier League matches_played: 17 minutes_played: 1132 name: Marc Albrighton - penalty_kicks_made: 432 - penalty_kicks_won: 144 - position: FWDF + penalty_kicks_made: 417 + penalty_kicks_won: 139 + position: forward rank: 55 - red_card: 194 + red_card: 179 squad: Leicester City - yellow_card: 174 + yellow_card: 272 "Marcos Acu\xF1a": age: 30.0 born: 1991 - corner_kicks: 78 + corner_kicks: 248 country: ARG - fouls_committed: 240 - goals: 245 + fouls_committed: 237 + goals: 105 league: La Liga matches_played: 31 minutes_played: 2260 name: "Marcos Acu\xF1a" - penalty_kicks_made: 279 - penalty_kicks_won: 93 - position: DF + penalty_kicks_made: 705 + penalty_kicks_won: 235 + position: defender rank: 13 - red_card: 117 + red_card: 267 squad: Sevilla - yellow_card: 69 + yellow_card: 81 Marcos Alonso: age: 31.0 born: 1990 - corner_kicks: 240 + corner_kicks: 21 country: ESP - fouls_committed: 227 - goals: 277 + fouls_committed: 255 + goals: 36 league: Premier League matches_played: 28 minutes_played: 2167 name: Marcos Alonso - penalty_kicks_made: 201 - penalty_kicks_won: 67 - position: DF + penalty_kicks_made: 636 + penalty_kicks_won: 212 + position: defender rank: 72 - red_card: 204 + red_card: 134 squad: Chelsea - yellow_card: 67 + yellow_card: 10 "Marley Ak\xE9": age: 21.0 born: 2001 - corner_kicks: 71 + corner_kicks: 278 country: FRA - fouls_committed: 230 - goals: 66 + fouls_committed: 143 + goals: 217 league: Serie A matches_played: 4 minutes_played: 77 name: "Marley Ak\xE9" - penalty_kicks_made: 576 - penalty_kicks_won: 192 - position: MFFW + penalty_kicks_made: 708 + penalty_kicks_won: 236 + position: midfielder rank: 40 - red_card: 16 + red_card: 94 squad: Juventus - yellow_card: 65 + yellow_card: 219 Martin Adeline: age: 18.0 born: 2003 - corner_kicks: 35 + corner_kicks: 50 country: FRA - fouls_committed: 68 - goals: 242 + fouls_committed: 163 + goals: 145 league: Ligue 1 matches_played: 8 minutes_played: 352 name: Martin Adeline - penalty_kicks_made: 684 - penalty_kicks_won: 228 - position: MFFW + penalty_kicks_made: 225 + penalty_kicks_won: 75 + position: midfielder rank: 17 - red_card: 246 + red_card: 74 squad: Reims - yellow_card: 108 + yellow_card: 183 Martin Agirregabiria: age: 26.0 born: 1996 - corner_kicks: 69 + corner_kicks: 140 country: ESP - fouls_committed: 261 - goals: 125 + fouls_committed: 153 + goals: 114 league: La Liga matches_played: 24 minutes_played: 1616 name: Martin Agirregabiria - penalty_kicks_made: 894 - penalty_kicks_won: 298 - position: DF + penalty_kicks_made: 150 + penalty_kicks_won: 50 + position: defender rank: 22 - red_card: 152 + red_card: 13 squad: "Alav\xE9s" - yellow_card: 175 + yellow_card: 126 Matthis Abline: age: 19.0 born: 2003 - corner_kicks: 83 + corner_kicks: 235 country: FRA - fouls_committed: 286 - goals: 117 + fouls_committed: 108 + goals: 207 league: Ligue 1 matches_played: 7 minutes_played: 103 name: Matthis Abline - penalty_kicks_made: 252 - penalty_kicks_won: 84 - position: FW + penalty_kicks_made: 426 + penalty_kicks_won: 142 + position: forward rank: 7 - red_card: 155 + red_card: 24 squad: Rennes - yellow_card: 276 + yellow_card: 282 Max Aarons: age: 22.0 born: 2000 - corner_kicks: 20 + corner_kicks: 208 country: ENG - fouls_committed: 208 - goals: 71 + fouls_committed: 256 + goals: 265 league: Premier League matches_played: 34 minutes_played: 2881 name: Max Aarons - penalty_kicks_made: 33 - penalty_kicks_won: 11 - position: DF + penalty_kicks_made: 864 + penalty_kicks_won: 288 + position: defender rank: 1 - red_card: 297 + red_card: 132 squad: Norwich City - yellow_card: 41 + yellow_card: 104 Michel Aebischer: age: 25.0 born: 1997 - corner_kicks: 117 + corner_kicks: 138 country: SUI - fouls_committed: 270 - goals: 265 + fouls_committed: 63 + goals: 122 league: Serie A matches_played: 12 minutes_played: 443 name: Michel Aebischer - penalty_kicks_made: 219 - penalty_kicks_won: 73 - position: MF + penalty_kicks_made: 42 + penalty_kicks_won: 14 + position: midfielder rank: 20 - red_card: 250 + red_card: 15 squad: Bologna - yellow_card: 38 + yellow_card: 144 "Miguel Almir\xF3n": age: 28.0 born: 1994 - corner_kicks: 241 + corner_kicks: 136 country: PAR - fouls_committed: 24 - goals: 67 + fouls_committed: 206 + goals: 199 league: Premier League matches_played: 30 minutes_played: 1716 name: "Miguel Almir\xF3n" - penalty_kicks_made: 429 - penalty_kicks_won: 143 - position: MFFW + penalty_kicks_made: 480 + penalty_kicks_won: 160 + position: midfielder rank: 71 - red_card: 122 + red_card: 66 squad: Newcastle Utd - yellow_card: 172 + yellow_card: 278 Mircea Alexandru Tirlea: age: 22.0 born: 2000 - corner_kicks: 26 + corner_kicks: 278 country: ROU - fouls_committed: 208 - goals: 185 + fouls_committed: 72 + goals: 117 league: La Liga matches_played: 1 minutes_played: 15 name: Mircea Alexandru Tirlea - penalty_kicks_made: 732 - penalty_kicks_won: 244 - position: DF + penalty_kicks_made: 81 + penalty_kicks_won: 27 + position: defender rank: 64 - red_card: 189 + red_card: 269 squad: "Alav\xE9s" - yellow_card: 257 + yellow_card: 115 Mohamed Achi: age: 20.0 born: 2002 - corner_kicks: 247 + corner_kicks: 93 country: FRA - fouls_committed: 208 - goals: 45 + fouls_committed: 33 + goals: 143 league: Ligue 1 matches_played: 1 minutes_played: 10 name: Mohamed Achi - penalty_kicks_made: 426 - penalty_kicks_won: 142 - position: MF + penalty_kicks_made: 840 + penalty_kicks_won: 280 + position: midfielder rank: 12 - red_card: 225 + red_card: 141 squad: Nantes - yellow_card: 94 + yellow_card: 106 Mohamed Ali Cho: age: 18.0 born: 2004 - corner_kicks: 173 + corner_kicks: 71 country: FRA - fouls_committed: 139 - goals: 69 + fouls_committed: 279 + goals: 108 league: Ligue 1 matches_played: 32 minutes_played: 1837 name: Mohamed Ali Cho - penalty_kicks_made: 189 - penalty_kicks_won: 63 - position: FW + penalty_kicks_made: 876 + penalty_kicks_won: 292 + position: forward rank: 65 red_card: 269 squad: Angers - yellow_card: 239 + yellow_card: 96 Nadiem Amiri: age: 25.0 born: 1996 - corner_kicks: 121 + corner_kicks: 99 country: GER - fouls_committed: 299 - goals: 208 + fouls_committed: 249 + goals: 65 league: Bundesliga matches_played: 13 minutes_played: 369 name: Nadiem Amiri - penalty_kicks_made: 456 - penalty_kicks_won: 152 - position: MFFW + penalty_kicks_made: 723 + penalty_kicks_won: 241 + position: midfielder rank: 87 - red_card: 266 + red_card: 120 squad: Leverkusen - yellow_card: 132 + yellow_card: 70 Naouirou Ahamada: age: 20.0 born: 2002 - corner_kicks: 185 + corner_kicks: 56 country: FRA - fouls_committed: 222 + fouls_committed: 227 goals: 244 league: Bundesliga matches_played: 3 minutes_played: 61 name: Naouirou Ahamada - penalty_kicks_made: 342 - penalty_kicks_won: 114 - position: MF + penalty_kicks_made: 42 + penalty_kicks_won: 14 + position: midfielder rank: 30 - red_card: 42 + red_card: 252 squad: Stuttgart - yellow_card: 63 + yellow_card: 218 "Nathan Ak\xE9": age: 27.0 born: 1995 - corner_kicks: 286 + corner_kicks: 175 country: NED - fouls_committed: 101 - goals: 41 + fouls_committed: 56 + goals: 60 league: Premier League matches_played: 14 minutes_played: 923 name: "Nathan Ak\xE9" - penalty_kicks_made: 882 - penalty_kicks_won: 294 - position: DF + penalty_kicks_made: 729 + penalty_kicks_won: 243 + position: defender rank: 41 - red_card: 93 + red_card: 253 squad: Manchester City - yellow_card: 287 + yellow_card: 21 Nayef Aguerd: age: 26.0 born: 1996 - corner_kicks: 11 + corner_kicks: 118 country: MAR - fouls_committed: 158 - goals: 44 + fouls_committed: 296 + goals: 62 league: Ligue 1 matches_played: 31 minutes_played: 2735 name: Nayef Aguerd - penalty_kicks_made: 39 - penalty_kicks_won: 13 - position: DF + penalty_kicks_made: 87 + penalty_kicks_won: 29 + position: defender rank: 26 - red_card: 162 + red_card: 177 squad: Rennes - yellow_card: 87 + yellow_card: 233 Ola Aina: age: 25.0 born: 1996 - corner_kicks: 38 + corner_kicks: 238 country: NGA - fouls_committed: 228 - goals: 75 + fouls_committed: 224 + goals: 238 league: Serie A matches_played: 21 minutes_played: 1437 name: Ola Aina - penalty_kicks_made: 636 - penalty_kicks_won: 212 - position: DF + penalty_kicks_made: 357 + penalty_kicks_won: 119 + position: defender rank: 34 - red_card: 294 + red_card: 38 squad: Torino - yellow_card: 109 + yellow_card: 178 Omar Alderete: age: 25.0 born: 1996 - corner_kicks: 160 + corner_kicks: 205 country: PAR - fouls_committed: 112 - goals: 103 + fouls_committed: 171 + goals: 175 league: La Liga matches_played: 29 minutes_played: 2403 name: Omar Alderete - penalty_kicks_made: 720 - penalty_kicks_won: 240 - position: DF + penalty_kicks_made: 573 + penalty_kicks_won: 191 + position: defender rank: 59 - red_card: 66 + red_card: 300 squad: Valencia - yellow_card: 134 + yellow_card: 71 "Paco Alc\xE1cer": age: 28.0 born: 1993 - corner_kicks: 148 + corner_kicks: 122 country: ESP - fouls_committed: 67 - goals: 252 + fouls_committed: 211 + goals: 250 league: La Liga matches_played: 18 minutes_played: 787 name: "Paco Alc\xE1cer" - penalty_kicks_made: 327 - penalty_kicks_won: 109 - position: FW + penalty_kicks_made: 318 + penalty_kicks_won: 106 + position: forward rank: 56 - red_card: 167 + red_card: 137 squad: Villarreal - yellow_card: 230 + yellow_card: 125 Paul Akouokou: age: 24.0 born: 1997 - corner_kicks: 83 + corner_kicks: 118 country: CIV - fouls_committed: 139 - goals: 122 + fouls_committed: 265 + goals: 134 league: La Liga matches_played: 8 minutes_played: 516 name: Paul Akouokou - penalty_kicks_made: 780 - penalty_kicks_won: 260 - position: MF + penalty_kicks_made: 702 + penalty_kicks_won: 234 + position: midfielder rank: 44 - red_card: 166 + red_card: 117 squad: Betis - yellow_card: 21 + yellow_card: 45 Ragnar Ache: age: 23.0 born: 1998 - corner_kicks: 86 + corner_kicks: 294 country: GER - fouls_committed: 230 - goals: 201 + fouls_committed: 161 + goals: 43 league: Bundesliga matches_played: 13 minutes_played: 259 name: Ragnar Ache - penalty_kicks_made: 777 - penalty_kicks_won: 259 - position: MFFW + penalty_kicks_made: 66 + penalty_kicks_won: 22 + position: midfielder rank: 11 - red_card: 85 + red_card: 14 squad: Eint Frankfurt - yellow_card: 137 + yellow_card: 211 "Rayan A\xEFt Nouri": age: 20.0 born: 2001 - corner_kicks: 75 + corner_kicks: 232 country: FRA - fouls_committed: 82 - goals: 78 + fouls_committed: 99 + goals: 74 league: Premier League matches_played: 23 minutes_played: 1828 name: "Rayan A\xEFt Nouri" - penalty_kicks_made: 351 - penalty_kicks_won: 117 - position: DF + penalty_kicks_made: 294 + penalty_kicks_won: 98 + position: defender rank: 35 - red_card: 214 + red_card: 180 squad: Wolves - yellow_card: 217 + yellow_card: 32 "Ra\xFAl Albiol": age: 36.0 born: 1985 - corner_kicks: 195 + corner_kicks: 230 country: ESP - fouls_committed: 190 - goals: 33 + fouls_committed: 34 + goals: 26 league: La Liga matches_played: 28 minutes_played: 2465 name: "Ra\xFAl Albiol" - penalty_kicks_made: 837 - penalty_kicks_won: 279 - position: DF + penalty_kicks_made: 705 + penalty_kicks_won: 235 + position: defender rank: 54 - red_card: 256 + red_card: 29 squad: Villarreal - yellow_card: 108 + yellow_card: 276 Robert Andrich: age: 27.0 born: 1994 - corner_kicks: 194 + corner_kicks: 264 country: GER - fouls_committed: 194 - goals: 263 + fouls_committed: 247 + goals: 298 league: Bundesliga matches_played: 26 minutes_played: 1817 name: Robert Andrich - penalty_kicks_made: 141 - penalty_kicks_won: 47 - position: MF + penalty_kicks_made: 138 + penalty_kicks_won: 46 + position: midfielder rank: 97 - red_card: 257 + red_card: 91 squad: Leverkusen - yellow_card: 172 + yellow_card: 298 Ruben Aguilar: age: 29.0 born: 1993 - corner_kicks: 155 + corner_kicks: 279 country: FRA - fouls_committed: 272 - goals: 261 + fouls_committed: 31 + goals: 169 league: Ligue 1 matches_played: 28 minutes_played: 2140 name: Ruben Aguilar - penalty_kicks_made: 549 - penalty_kicks_won: 183 - position: DF + penalty_kicks_made: 465 + penalty_kicks_won: 155 + position: defender rank: 28 - red_card: 139 + red_card: 15 squad: Monaco - yellow_card: 80 + yellow_card: 131 "Rub\xE9n Alcaraz": age: 31.0 born: 1991 - corner_kicks: 49 + corner_kicks: 133 country: ESP - fouls_committed: 223 - goals: 74 + fouls_committed: 300 + goals: 101 league: La Liga matches_played: 14 minutes_played: 1105 name: "Rub\xE9n Alcaraz" - penalty_kicks_made: 381 - penalty_kicks_won: 127 - position: MF + penalty_kicks_made: 837 + penalty_kicks_won: 279 + position: midfielder rank: 58 - red_card: 132 + red_card: 153 squad: "C\xE1diz" - yellow_card: 26 + yellow_card: 172 Salis Abdul Samed: age: 22.0 born: 2000 - corner_kicks: 56 + corner_kicks: 48 country: GHA - fouls_committed: 134 - goals: 259 + fouls_committed: 57 + goals: 64 league: Ligue 1 matches_played: 31 minutes_played: 2462 name: Salis Abdul Samed - penalty_kicks_made: 711 - penalty_kicks_won: 237 - position: MF + penalty_kicks_made: 489 + penalty_kicks_won: 163 + position: midfielder rank: 3 - red_card: 209 + red_card: 42 squad: Clermont Foot - yellow_card: 75 + yellow_card: 99 Sargis Adamyan: age: 29.0 born: 1993 - corner_kicks: 159 + corner_kicks: 222 country: ARM - fouls_committed: 256 - goals: 147 + fouls_committed: 99 + goals: 65 league: Bundesliga matches_played: 13 minutes_played: 331 name: Sargis Adamyan - penalty_kicks_made: 225 - penalty_kicks_won: 75 - position: FWMF + penalty_kicks_made: 714 + penalty_kicks_won: 238 + position: forward rank: 16 - red_card: 66 + red_card: 229 squad: Hoffenheim - yellow_card: 188 + yellow_card: 70 Sebastian Andersson: age: 30.0 born: 1991 - corner_kicks: 162 + corner_kicks: 237 country: SWE - fouls_committed: 259 - goals: 136 + fouls_committed: 122 + goals: 83 league: Bundesliga matches_played: 26 minutes_played: 1257 name: Sebastian Andersson - penalty_kicks_made: 678 - penalty_kicks_won: 226 - position: FW + penalty_kicks_made: 48 + penalty_kicks_won: 16 + position: forward rank: 92 - red_card: 107 + red_card: 58 squad: "K\xF6ln" - yellow_card: 131 + yellow_card: 217 "Sergio Ag\xFCero": age: 33.0 born: 1988 - corner_kicks: 63 + corner_kicks: 52 country: ARG - fouls_committed: 98 - goals: 138 + fouls_committed: 146 + goals: 179 league: La Liga matches_played: 4 minutes_played: 151 name: "Sergio Ag\xFCero" - penalty_kicks_made: 447 - penalty_kicks_won: 149 - position: FW + penalty_kicks_made: 402 + penalty_kicks_won: 134 + position: forward rank: 27 - red_card: 195 + red_card: 81 squad: Barcelona - yellow_card: 217 + yellow_card: 74 Sofiane Alakouch: age: 23.0 born: 1998 - corner_kicks: 175 + corner_kicks: 79 country: MAR - fouls_committed: 92 - goals: 232 + fouls_committed: 91 + goals: 293 league: Ligue 1 matches_played: 4 minutes_played: 158 name: Sofiane Alakouch - penalty_kicks_made: 618 - penalty_kicks_won: 206 - position: DFMF + penalty_kicks_made: 105 + penalty_kicks_won: 35 + position: defender rank: 48 - red_card: 284 + red_card: 276 squad: Metz - yellow_card: 74 + yellow_card: 168 Sofyan Amrabat: age: 25.0 born: 1996 - corner_kicks: 198 + corner_kicks: 14 country: MAR - fouls_committed: 47 - goals: 89 + fouls_committed: 219 + goals: 29 league: Serie A matches_played: 23 minutes_played: 944 name: Sofyan Amrabat - penalty_kicks_made: 708 - penalty_kicks_won: 236 - position: MF + penalty_kicks_made: 417 + penalty_kicks_won: 139 + position: midfielder rank: 89 - red_card: 200 + red_card: 75 squad: Fiorentina - yellow_card: 33 + yellow_card: 195 Steven Alzate: age: 23.0 born: 1998 - corner_kicks: 129 + corner_kicks: 198 country: COL - fouls_committed: 102 - goals: 109 + fouls_committed: 44 + goals: 227 league: Premier League matches_played: 9 minutes_played: 404 name: Steven Alzate - penalty_kicks_made: 498 - penalty_kicks_won: 166 - position: MF + penalty_kicks_made: 108 + penalty_kicks_won: 36 + position: midfielder rank: 77 - red_card: 50 + red_card: 230 squad: Brighton - yellow_card: 224 + yellow_card: 45 Tammy Abraham: age: 24.0 born: 1997 - corner_kicks: 283 + corner_kicks: 95 country: ENG - fouls_committed: 203 - goals: 49 + fouls_committed: 41 + goals: 39 league: Serie A matches_played: 37 minutes_played: 3084 name: Tammy Abraham - penalty_kicks_made: 780 - penalty_kicks_won: 260 - position: FW + penalty_kicks_made: 639 + penalty_kicks_won: 213 + position: forward rank: 8 - red_card: 201 + red_card: 166 squad: Roma - yellow_card: 191 + yellow_card: 103 "Thiago Alc\xE1ntara": age: 31.0 born: 1991 - corner_kicks: 292 + corner_kicks: 231 country: ESP - fouls_committed: 282 - goals: 198 + fouls_committed: 48 + goals: 155 league: Premier League matches_played: 25 minutes_played: 1534 name: "Thiago Alc\xE1ntara" - penalty_kicks_made: 408 - penalty_kicks_won: 136 - position: MF + penalty_kicks_made: 144 + penalty_kicks_won: 48 + position: midfielder rank: 57 - red_card: 38 + red_card: 299 squad: Liverpool - yellow_card: 291 + yellow_card: 118 "Tom\xE1s Alarc\xF3n": age: 23.0 born: 1999 - corner_kicks: 252 + corner_kicks: 211 country: CHI - fouls_committed: 185 - goals: 132 + fouls_committed: 193 + goals: 119 league: La Liga matches_played: 23 minutes_played: 1425 name: "Tom\xE1s Alarc\xF3n" - penalty_kicks_made: 612 - penalty_kicks_won: 204 - position: MF + penalty_kicks_made: 831 + penalty_kicks_won: 277 + position: midfielder rank: 49 - red_card: 56 + red_card: 96 squad: "C\xE1diz" - yellow_card: 10 + yellow_card: 231 Trent Alexander-Arnold: age: 23.0 born: 1998 - corner_kicks: 37 + corner_kicks: 253 country: ENG - fouls_committed: 111 - goals: 162 + fouls_committed: 82 + goals: 139 league: Premier League matches_played: 32 minutes_played: 2853 name: Trent Alexander-Arnold - penalty_kicks_made: 159 - penalty_kicks_won: 53 - position: DF + penalty_kicks_made: 123 + penalty_kicks_won: 41 + position: defender rank: 63 - red_card: 125 + red_card: 103 squad: Liverpool - yellow_card: 125 + yellow_card: 83 Tyler Adams: age: 23.0 born: 1999 - corner_kicks: 99 + corner_kicks: 92 country: USA - fouls_committed: 25 - goals: 135 + fouls_committed: 287 + goals: 194 league: Bundesliga matches_played: 24 minutes_played: 1351 name: Tyler Adams - penalty_kicks_made: 87 - penalty_kicks_won: 29 - position: MF + penalty_kicks_made: 180 + penalty_kicks_won: 60 + position: midfielder rank: 15 - red_card: 210 + red_card: 226 squad: RB Leipzig - yellow_card: 209 + yellow_card: 28 Wisdom Amey: age: 16.0 born: 2005 - corner_kicks: 59 + corner_kicks: 268 country: ITA - fouls_committed: 84 - goals: 284 + fouls_committed: 223 + goals: 144 league: Serie A matches_played: 1 minutes_played: 71 name: Wisdom Amey - penalty_kicks_made: 456 - penalty_kicks_won: 152 - position: DF + penalty_kicks_made: 297 + penalty_kicks_won: 99 + position: defender rank: 84 - red_card: 194 + red_card: 141 squad: Bologna - yellow_card: 225 + yellow_card: 189 Yacine Adli: age: 21.0 born: 2000 - corner_kicks: 42 + corner_kicks: 156 country: FRA - fouls_committed: 293 - goals: 59 + fouls_committed: 284 + goals: 68 league: Ligue 1 matches_played: 36 minutes_played: 2260 name: Yacine Adli - penalty_kicks_made: 144 - penalty_kicks_won: 48 - position: MFFW + penalty_kicks_made: 360 + penalty_kicks_won: 120 + position: midfielder rank: 19 - red_card: 268 + red_card: 162 squad: Bordeaux - yellow_card: 150 + yellow_card: 163 "Yeray \xC1lvarez": age: 27.0 born: 1995 - corner_kicks: 238 + corner_kicks: 192 country: ESP - fouls_committed: 89 - goals: 273 + fouls_committed: 241 + goals: 132 league: La Liga matches_played: 22 minutes_played: 1860 name: "Yeray \xC1lvarez" - penalty_kicks_made: 315 - penalty_kicks_won: 105 - position: DF + penalty_kicks_made: 546 + penalty_kicks_won: 182 + position: defender rank: 75 - red_card: 67 + red_card: 236 squad: Athletic Club - yellow_card: 287 + yellow_card: 275 Yunis Abdelhamid: age: 34.0 born: 1987 - corner_kicks: 85 + corner_kicks: 100 country: MAR - fouls_committed: 169 - goals: 49 + fouls_committed: 58 + goals: 210 league: Ligue 1 matches_played: 34 minutes_played: 2983 name: Yunis Abdelhamid - penalty_kicks_made: 441 - penalty_kicks_won: 147 - position: DF + penalty_kicks_made: 369 + penalty_kicks_won: 123 + position: defender rank: 2 - red_card: 10 + red_card: 232 squad: Reims - yellow_card: 82 + yellow_card: 175 "\xC1lvaro Aguirre": age: 22.0 born: 2000 - corner_kicks: 87 + corner_kicks: 279 country: ESP - fouls_committed: 295 - goals: 197 + fouls_committed: 283 + goals: 25 league: La Liga matches_played: 1 minutes_played: 9 name: "\xC1lvaro Aguirre" - penalty_kicks_made: 396 - penalty_kicks_won: 132 - position: FW + penalty_kicks_made: 855 + penalty_kicks_won: 285 + position: forward rank: 29 - red_card: 39 + red_card: 196 squad: Rayo Vallecano - yellow_card: 53 + yellow_card: 161 From 8ce42c00b1331480cee00f845d2884525db086f3 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 01:52:50 +0530 Subject: [PATCH 20/34] Add football assignment --- README.md | 5 +++++ week_3/README.md | 3 +++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index 198473e6..aa3fc22b 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,11 @@ In the first week, we will introduce you to basic concepts related to Web Develo ## [Week 2 - Ruby](/week_2) In this week, we'll take a look at Ruby and instructions to get your device ready for creating Ruby on Rails projects. +## [Week 3 - Getting Started with Rails and Model](/week_3) +In this we will learn how to install Ruby and Rails, +create a new Rails project and build a simple website. + +Later we will take a closer look at Model of the MVC Architecture and talk about databases and working with records. ## Contact In case of doubts related to the Bootcamp, feel free to reach out to the mentors on the [**#doubts**](https://discord.com/channels/1052463702558908416/1052467811143913552) channel on [Discord](https://discord.gg/HQKpB6XH). diff --git a/week_3/README.md b/week_3/README.md index 77b391d7..d7b18080 100644 --- a/week_3/README.md +++ b/week_3/README.md @@ -85,3 +85,6 @@ rails test - If the test fails, check the view files and debug the application. - Once the test works locally, submit your changes. + +# Model +Once done head over to [football](./football) directory to learn more about models. \ No newline at end of file From 41b465e3c8a4603fb4f123548d6a1cc05aa62408 Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Fri, 13 Jan 2023 01:53:49 +0530 Subject: [PATCH 21/34] Update README.md --- week_3/football/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/week_3/football/README.md b/week_3/football/README.md index 121b9cc0..f8b68466 100644 --- a/week_3/football/README.md +++ b/week_3/football/README.md @@ -79,7 +79,10 @@ This adds some sample data(/test/fixtures/football_players.yml) to the database. The INSERT INTO statement is used to insert new records in a table ```sql -INSERT INTO football_players (id, name, rank, country, position, squad, league, age, born, minutes_played, goals, penalty_kicks_made, matches_played, corner_kicks, yellow_card, red_card, penalty_kicks_won, fouls_committed) VALUES (1, Sergio Agüero, 20, "ARG", , "forward", "Barcelona", "La Liga", 33, 1988, 151, 179, 10, 4, 4, 3, 4, 1,) +INSERT INTO football_players (id, name, rank, country, position, squad, league, age, born, +minutes_played, goals, penalty_kicks_made, matches_played, corner_kicks, yellow_card, +red_card, penalty_kicks_won, fouls_committed) +VALUES (1, Sergio Agüero, 20, "ARG", , "forward", "Barcelona", "La Liga", 33, 1988, 151, 179, 10, 4, 4, 3, 4, 1,) ``` In Rails From 8b67128330b0f53ec29d18a90814f904c7af7cae Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 16:12:38 +0530 Subject: [PATCH 22/34] add tests --- week_3/football/README.md | 2 +- week_3/football/app/models/football_player.rb | 4 +- .../football_players_controller_test.rb | 48 - .../test/fixtures/football_players.yml | 1670 ++--------------- .../test/models/football_player_test.rb | 88 +- 5 files changed, 222 insertions(+), 1590 deletions(-) delete mode 100644 week_3/football/test/controllers/football_players_controller_test.rb diff --git a/week_3/football/README.md b/week_3/football/README.md index f8b68466..24e18349 100644 --- a/week_3/football/README.md +++ b/week_3/football/README.md @@ -117,7 +117,7 @@ Implement the function `import_argentinian_players` in |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| |Marcos Acuna|13|ARG|defender|Sevilla|La Liga|30|1991|2260|105|705|31|248|81|267|235|237| |Lucas Alario|50|ARG|forward|Leverkusen|Bundesliga|29|1992|655|79|192|27|193|148|263|64|172| -|Sergio Agüero|27|ARG|forward|Barcelona|La Liga|33|1988|151|179|402|4|52|74|81|134|146| +|Sergio Aguero|27|ARG|forward|Barcelona|La Liga|33|1988|151|179|402|4|52|74|81|134|146| - [Insert Into](https://www.w3schools.com/sql/sql_insert.asp) - [Create | Active Record](https://guides.rubyonrails.org/active_record_basics.html#create) diff --git a/week_3/football/app/models/football_player.rb b/week_3/football/app/models/football_player.rb index c0ca949e..9b4a8b9a 100644 --- a/week_3/football/app/models/football_player.rb +++ b/week_3/football/app/models/football_player.rb @@ -13,7 +13,7 @@ class FootballPlayer < ApplicationRecord # Sort players by their rank scope :order_by_rank, -> { raise NotImplementedError } - # Average goals per game = (total matches) / (total goals) + # Average goals per game = (total goals) / (total matches) # # If total matches or total goals is missing return nil def average_goals_per_game @@ -29,6 +29,8 @@ def total_penalty_cards # Return the penalty succes rate of the player # penalty_success_rate = (penalty_kicks_won * 100) / penalty_kicks_made + # + # if data is missing return nil def penalty_success_rate raise NotImplementedError end diff --git a/week_3/football/test/controllers/football_players_controller_test.rb b/week_3/football/test/controllers/football_players_controller_test.rb deleted file mode 100644 index 7e5e3bc3..00000000 --- a/week_3/football/test/controllers/football_players_controller_test.rb +++ /dev/null @@ -1,48 +0,0 @@ -require "test_helper" - -class FootballPlayersControllerTest < ActionDispatch::IntegrationTest - setup do - @football_player = football_players(:one) - end - - test "should get index" do - get football_players_url - assert_response :success - end - - test "should get new" do - get new_football_player_url - assert_response :success - end - - test "should create football_player" do - assert_difference("FootballPlayer.count") do - post football_players_url, params: { football_player: { age: @football_player.age, born: @football_player.born, corner_kicks: @football_player.corner_kicks, country: @football_player.country, fouls_committed: @football_player.fouls_committed, goals: @football_player.goals, league: @football_player.league, matches_played: @football_player.matches_played, minutes_played: @football_player.minutes_played, name: @football_player.name, penalty_kicks_made: @football_player.penalty_kicks_made, penalty_kicks_won: @football_player.penalty_kicks_won, position: @football_player.position, rank: @football_player.rank, red_card: @football_player.red_card, squad: @football_player.squad, yellow_card: @football_player.yellow_card } } - end - - assert_redirected_to football_player_url(FootballPlayer.last) - end - - test "should show football_player" do - get football_player_url(@football_player) - assert_response :success - end - - test "should get edit" do - get edit_football_player_url(@football_player) - assert_response :success - end - - test "should update football_player" do - patch football_player_url(@football_player), params: { football_player: { age: @football_player.age, born: @football_player.born, corner_kicks: @football_player.corner_kicks, country: @football_player.country, fouls_committed: @football_player.fouls_committed, goals: @football_player.goals, league: @football_player.league, matches_played: @football_player.matches_played, minutes_played: @football_player.minutes_played, name: @football_player.name, penalty_kicks_made: @football_player.penalty_kicks_made, penalty_kicks_won: @football_player.penalty_kicks_won, position: @football_player.position, rank: @football_player.rank, red_card: @football_player.red_card, squad: @football_player.squad, yellow_card: @football_player.yellow_card } } - assert_redirected_to football_player_url(@football_player) - end - - test "should destroy football_player" do - assert_difference("FootballPlayer.count", -1) do - delete football_player_url(@football_player) - end - - assert_redirected_to football_players_url - end -end diff --git a/week_3/football/test/fixtures/football_players.yml b/week_3/football/test/fixtures/football_players.yml index 7b72fad0..b36962e7 100644 --- a/week_3/football/test/fixtures/football_players.yml +++ b/week_3/football/test/fixtures/football_players.yml @@ -1,1746 +1,342 @@ -Alisson: - age: 29.0 - born: 1992 - corner_kicks: 144 - country: BRA - fouls_committed: 48 - goals: 27 - league: Premier League - matches_played: 36 - minutes_played: 3240 - name: Alisson - penalty_kicks_made: 426 - penalty_kicks_won: 142 - position: goalkeeper - rank: 66 - red_card: 163 - squad: Liverpool - yellow_card: 225 -Allan: - age: 31.0 - born: 1991 - corner_kicks: 27 - country: BRA - fouls_committed: 232 - goals: 76 - league: Premier League - matches_played: 28 - minutes_played: 2183 - name: Allan - penalty_kicks_made: 180 - penalty_kicks_won: 60 - position: midfielder - rank: 67 - red_card: 300 - squad: Everton - yellow_card: 181 -Amath: - age: 25.0 - born: 1996 - corner_kicks: 210 - country: SEN - fouls_committed: 122 - goals: 40 - league: La Liga - matches_played: 19 - minutes_played: 884 - name: Amath - penalty_kicks_made: 72 - penalty_kicks_won: 24 - position: forward - rank: 81 - red_card: 284 - squad: Mallorca - yellow_card: 204 Amine Adli: age: 22.0 born: 2000 - corner_kicks: 211 + corner_kicks: 31 country: FRA - fouls_committed: 235 - goals: 294 + fouls_committed: 94 + goals: 160 league: Bundesliga matches_played: 25 minutes_played: 1256 name: Amine Adli - penalty_kicks_made: 237 - penalty_kicks_won: 79 + penalty_kicks_made: 300 + penalty_kicks_won: 100 position: forward rank: 18 - red_card: 207 + red_card: 225 squad: Leverkusen - yellow_card: 231 -"Andr\xE9s Andrade Cede\xF1o": - age: 23.0 - born: 1998 - corner_kicks: 271 - country: PAN - fouls_committed: 110 - goals: 71 - league: Bundesliga - matches_played: 17 - minutes_played: 1046 - name: "Andr\xE9s Andrade Cede\xF1o" - penalty_kicks_made: 51 - penalty_kicks_won: 17 - position: defender - rank: 94 - red_card: 165 - squad: Arminia - yellow_card: 160 -Anel Ahmedhodzic: - age: 23.0 - born: 1999 - corner_kicks: 161 - country: BIH - fouls_committed: 243 - goals: 244 - league: Ligue 1 - matches_played: 15 - minutes_played: 1350 - name: Anel Ahmedhodzic - penalty_kicks_made: 147 - penalty_kicks_won: 49 - position: defender - rank: 31 - red_card: 80 - squad: Bordeaux - yellow_card: 179 -"Angeli\xF1o": - age: 25.0 - born: 1997 - corner_kicks: 199 - country: ESP - fouls_committed: 241 - goals: 190 - league: Bundesliga - matches_played: 29 - minutes_played: 2298 - name: "Angeli\xF1o" - penalty_kicks_made: 531 - penalty_kicks_won: 177 - position: defender - rank: 99 - red_card: 267 - squad: RB Leipzig - yellow_card: 248 -"Benjamin Andr\xE9": - age: 31.0 - born: 1990 - corner_kicks: 98 - country: FRA - fouls_committed: 89 - goals: 207 - league: Ligue 1 - matches_played: 33 - minutes_played: 2752 - name: "Benjamin Andr\xE9" - penalty_kicks_made: 339 - penalty_kicks_won: 113 - position: midfielder - rank: 96 - red_card: 197 - squad: Lille - yellow_card: 12 -"Carles Ale\xF1\xE1": - age: 24.0 - born: 1998 - corner_kicks: 183 - country: ESP - fouls_committed: 91 - goals: 102 - league: La Liga - matches_played: 33 - minutes_played: 2320 - name: "Carles Ale\xF1\xE1" - penalty_kicks_made: 378 - penalty_kicks_won: 126 - position: midfielder - rank: 62 - red_card: 289 - squad: Getafe - yellow_card: 55 -Carlos Akapo: - age: 29.0 - born: 1993 - corner_kicks: 92 - country: EQG - fouls_committed: 151 - goals: 259 - league: La Liga - matches_played: 25 - minutes_played: 1844 - name: Carlos Akapo - penalty_kicks_made: 897 - penalty_kicks_won: 299 - position: defender - rank: 39 - red_card: 223 - squad: "C\xE1diz" - yellow_card: 143 + yellow_card: 202 Charles Abi: age: 22.0 born: 2000 - corner_kicks: 108 + corner_kicks: 145 country: FRA - fouls_committed: 272 - goals: 73 + fouls_committed: 17 + goals: 261 league: Ligue 1 matches_played: 1 minutes_played: 45 name: Charles Abi - penalty_kicks_made: 768 - penalty_kicks_won: 256 + penalty_kicks_made: 177 + penalty_kicks_won: 59 position: forward rank: 5 - red_card: 148 + red_card: 102 squad: "Saint-\xC9tienne" - yellow_card: 75 + yellow_card: 120 Che Adams: age: 25.0 born: 1996 - corner_kicks: 130 + corner_kicks: 294 country: SCO - fouls_committed: 271 - goals: 162 + fouls_committed: 195 + goals: 43 league: Premier League matches_played: 30 minutes_played: 2039 name: Che Adams - penalty_kicks_made: 468 - penalty_kicks_won: 156 + penalty_kicks_made: 693 + penalty_kicks_won: 231 position: forward rank: 14 - red_card: 34 + red_card: 122 squad: Southampton - yellow_card: 268 -Dani Alves: - age: 39.0 - born: 1983 - corner_kicks: 106 - country: BRA - fouls_committed: 273 - goals: 21 - league: La Liga - matches_played: 14 - minutes_played: 1098 - name: Dani Alves - penalty_kicks_made: 642 - penalty_kicks_won: 214 - position: defender - rank: 76 - red_card: 56 - squad: Barcelona - yellow_card: 227 -Daniel Amartey: - age: 27.0 - born: 1994 - corner_kicks: 243 - country: GHA - fouls_committed: 130 - goals: 44 - league: Premier League - matches_played: 28 - minutes_played: 2123 - name: Daniel Amartey - penalty_kicks_made: 246 - penalty_kicks_won: 82 - position: defender - rank: 80 - red_card: 77 - squad: Leicester City - yellow_card: 269 -David Alaba: - age: 29.0 - born: 1992 - corner_kicks: 201 - country: AUT - fouls_committed: 46 - goals: 89 - league: La Liga - matches_played: 30 - minutes_played: 2642 - name: David Alaba - penalty_kicks_made: 189 - penalty_kicks_won: 63 - position: defender - rank: 47 - red_card: 112 - squad: Real Madrid - yellow_card: 103 -Dele Alli: - age: 26.0 - born: 1996 - corner_kicks: 118 - country: ENG - fouls_committed: 261 - goals: 225 - league: Premier League - matches_played: 10 - minutes_played: 657 - name: Dele Alli - penalty_kicks_made: 147 - penalty_kicks_won: 49 - position: midfielder - rank: 70 - red_card: 91 - squad: Tottenham - yellow_card: 102 + yellow_card: 76 Dickson Abiama: age: 23.0 born: 1998 - corner_kicks: 162 + corner_kicks: 13 country: NGA - fouls_committed: 70 - goals: 30 + fouls_committed: 31 + goals: 33 league: Bundesliga matches_played: 24 minutes_played: 726 name: Dickson Abiama - penalty_kicks_made: 90 - penalty_kicks_won: 30 + penalty_kicks_made: 132 + penalty_kicks_won: 44 position: forward rank: 6 - red_card: 296 + red_card: 120 squad: "Greuther F\xFCrth" - yellow_card: 113 -"Do\xF0an Alemdar": - age: 19.0 - born: 2002 - corner_kicks: 40 - country: TUR - fouls_committed: 211 - goals: 58 - league: Ligue 1 - matches_played: 12 - minutes_played: 1080 - name: "Do\xF0an Alemdar" - penalty_kicks_made: 711 - penalty_kicks_won: 237 - position: goalkeeper - rank: 61 - red_card: 257 - squad: Rennes - yellow_card: 35 -Ebenezer Annan: - age: 19.0 - born: 2002 - corner_kicks: 20 - country: GHA - fouls_committed: 192 - goals: 300 - league: Serie A - matches_played: 1 - minutes_played: 25 - name: Ebenezer Annan - penalty_kicks_made: 456 - penalty_kicks_won: 152 - position: defender - rank: 100 - red_card: 283 - squad: Bologna - yellow_card: 194 -Emmanuel Amankwaa Akurugu: - age: 20.0 - born: 2001 - corner_kicks: 205 - country: GHA - fouls_committed: 250 - goals: 184 - league: La Liga - matches_played: 3 - minutes_played: 79 - name: Emmanuel Amankwaa Akurugu - penalty_kicks_made: 171 - penalty_kicks_won: 57 - position: defender - rank: 79 - red_card: 176 - squad: Getafe - yellow_card: 220 -Ethan Ampadu: - age: 21.0 - born: 2000 - corner_kicks: 219 - country: WAL - fouls_committed: 92 - goals: 200 - league: Serie A - matches_played: 29 - minutes_played: 2282 - name: Ethan Ampadu - penalty_kicks_made: 807 - penalty_kicks_won: 269 - position: midfielder - rank: 88 - red_card: 100 - squad: Venezia - yellow_card: 172 -Felipe Anderson: - age: 29.0 - born: 1993 - corner_kicks: 150 - country: BRA - fouls_committed: 271 - goals: 235 - league: Serie A - matches_played: 38 - minutes_played: 2888 - name: Felipe Anderson - penalty_kicks_made: 678 - penalty_kicks_won: 226 - position: forward - rank: 91 - red_card: 206 - squad: Lazio - yellow_card: 253 -Felix Afena-Gyan: - age: 19.0 - born: 2003 - corner_kicks: 27 - country: GHA - fouls_committed: 261 - goals: 143 - league: Serie A - matches_played: 17 - minutes_played: 668 - name: Felix Afena-Gyan - penalty_kicks_made: 594 - penalty_kicks_won: 198 - position: forward - rank: 21 - red_card: 211 - squad: Roma - yellow_card: 266 -Florin Andone: - age: 29.0 - born: 1993 - corner_kicks: 226 - country: ROU - fouls_committed: 189 - goals: 37 - league: La Liga - matches_played: 5 - minutes_played: 176 - name: Florin Andone - penalty_kicks_made: 174 - penalty_kicks_won: 58 - position: forward - rank: 93 - red_card: 297 - squad: "C\xE1diz" - yellow_card: 231 + yellow_card: 104 Francesco Acerbi: age: 34.0 born: 1988 - corner_kicks: 274 + corner_kicks: 240 country: ITA - fouls_committed: 177 - goals: 40 + fouls_committed: 274 + goals: 94 league: Serie A matches_played: 30 minutes_played: 2536 name: Francesco Acerbi - penalty_kicks_made: 342 - penalty_kicks_won: 114 + penalty_kicks_made: 291 + penalty_kicks_won: 97 position: defender rank: 10 - red_card: 248 + red_card: 204 squad: Lazio - yellow_card: 107 -"Fredrik Andr\xE9 Bj\xF8rkan": - age: 23.0 - born: 1998 - corner_kicks: 215 - country: NOR - fouls_committed: 123 - goals: 172 - league: Bundesliga - matches_played: 9 - minutes_played: 353 - name: "Fredrik Andr\xE9 Bj\xF8rkan" - penalty_kicks_made: 471 - penalty_kicks_won: 157 - position: defender - rank: 95 - red_card: 132 - squad: Hertha BSC - yellow_card: 171 -Giorgio Altare: - age: 23.0 - born: 1998 - corner_kicks: 169 - country: ITA - fouls_committed: 35 - goals: 111 - league: Serie A - matches_played: 19 - minutes_played: 1466 - name: Giorgio Altare - penalty_kicks_made: 240 - penalty_kicks_won: 80 - position: defender - rank: 73 - red_card: 221 - squad: Cagliari - yellow_card: 98 -"Hugo \xC1lvarez": - age: 36.0 - born: 1985 - corner_kicks: 30 - country: ESP - fouls_committed: 52 - goals: 22 - league: La Liga - matches_played: 1 - minutes_played: 11 - name: "Hugo \xC1lvarez" - penalty_kicks_made: 639 - penalty_kicks_won: 213 - position: forward - rank: 74 - red_card: 36 - squad: Celta Vigo - yellow_card: 106 -Ibrahim Amadou: - age: 29.0 - born: 1993 - corner_kicks: 103 - country: FRA - fouls_committed: 59 - goals: 260 - league: Ligue 1 - matches_played: 10 - minutes_played: 812 - name: Ibrahim Amadou - penalty_kicks_made: 285 - penalty_kicks_won: 95 - position: defender - rank: 78 - red_card: 217 - squad: Metz - yellow_card: 133 -Ilias Akhomach: - age: 18.0 - born: 2004 - corner_kicks: 194 - country: ESP - fouls_committed: 44 - goals: 70 - league: La Liga - matches_played: 2 - minutes_played: 124 - name: Ilias Akhomach - penalty_kicks_made: 249 - penalty_kicks_won: 83 - position: forward - rank: 42 - red_card: 79 - squad: Barcelona - yellow_card: 19 -"Iv\xE1n Alejo": - age: 27.0 - born: 1995 - corner_kicks: 49 - country: ESP - fouls_committed: 40 - goals: 10 - league: La Liga - matches_played: 20 - minutes_played: 1065 - name: "Iv\xE1n Alejo" - penalty_kicks_made: 495 - penalty_kicks_won: 165 - position: midfielder - rank: 60 - red_card: 102 - squad: "C\xE1diz" - yellow_card: 167 -Jean-Daniel Akpa-Akpro: - age: 29.0 - born: 1992 - corner_kicks: 17 - country: CIV - fouls_committed: 213 - goals: 232 - league: Serie A - matches_played: 10 - minutes_played: 315 - name: Jean-Daniel Akpa-Akpro - penalty_kicks_made: 765 - penalty_kicks_won: 255 - position: midfielder - rank: 45 - red_card: 31 - squad: Lazio - yellow_card: 108 -Jean-Eudes Aholou: - age: 28.0 - born: 1994 - corner_kicks: 167 - country: CIV - fouls_committed: 109 - goals: 260 - league: Ligue 1 - matches_played: 25 - minutes_played: 1004 - name: Jean-Eudes Aholou - penalty_kicks_made: 699 - penalty_kicks_won: 233 - position: midfielder - rank: 32 - red_card: 33 - squad: Strasbourg - yellow_card: 107 -Jim Allevinah: - age: 27.0 - born: 1995 - corner_kicks: 221 - country: GAB - fouls_committed: 85 - goals: 219 - league: Ligue 1 - matches_played: 30 - minutes_played: 1488 - name: Jim Allevinah - penalty_kicks_made: 528 - penalty_kicks_won: 176 - position: forward - rank: 68 - red_card: 184 - squad: Clermont Foot - yellow_card: 12 -Joachim Andersen: - age: 25.0 - born: 1996 - corner_kicks: 64 - country: DEN - fouls_committed: 280 - goals: 119 - league: Premier League - matches_played: 34 - minutes_played: 2916 - name: Joachim Andersen - penalty_kicks_made: 90 - penalty_kicks_won: 30 - position: defender - rank: 90 - red_card: 106 - squad: Crystal Palace - yellow_card: 84 -Jordan Amavi: - age: 28.0 - born: 1994 - corner_kicks: 163 - country: FRA - fouls_committed: 156 - goals: 289 - league: Ligue 1 - matches_played: 8 - minutes_played: 413 - name: Jordan Amavi - penalty_kicks_made: 900 - penalty_kicks_won: 300 - position: defender - rank: 83 - red_card: 50 - squad: Nice - yellow_card: 189 -Jordi Alba: - age: 33.0 - born: 1989 - corner_kicks: 271 - country: ESP - fouls_committed: 226 - goals: 192 - league: La Liga - matches_played: 30 - minutes_played: 2644 - name: Jordi Alba - penalty_kicks_made: 600 - penalty_kicks_won: 200 - position: defender - rank: 51 - red_card: 187 - squad: Barcelona - yellow_card: 294 -Joseph Aidoo: - age: 26.0 - born: 1995 - corner_kicks: 55 - country: GHA - fouls_committed: 19 - goals: 188 - league: La Liga - matches_played: 32 - minutes_played: 2637 - name: Joseph Aidoo - penalty_kicks_made: 852 - penalty_kicks_won: 284 - position: defender - rank: 33 - red_card: 58 - squad: Celta Vigo - yellow_card: 175 -"Josu\xE9 Albert": - age: 30.0 - born: 1992 - corner_kicks: 76 - country: GUF - fouls_committed: 44 - goals: 49 - league: Ligue 1 - matches_played: 2 - minutes_played: 22 - name: "Josu\xE9 Albert" - penalty_kicks_made: 705 - penalty_kicks_won: 235 - position: defender - rank: 52 - red_card: 30 - squad: Clermont Foot - yellow_card: 162 -"Jos\xE9 \xC1ngel": - age: 32.0 - born: 1989 - corner_kicks: 36 - country: ESP - fouls_committed: 205 - goals: 151 - league: La Liga - matches_played: 23 - minutes_played: 1083 - name: "Jos\xE9 \xC1ngel" - penalty_kicks_made: 54 - penalty_kicks_won: 18 - position: defender - rank: 98 - red_card: 262 - squad: Osasuna - yellow_card: 167 -Julen Agirrezabala: - age: 21.0 - born: 2000 - corner_kicks: 119 - country: ESP - fouls_committed: 53 - goals: 153 - league: La Liga - matches_played: 4 - minutes_played: 360 - name: Julen Agirrezabala - penalty_kicks_made: 627 - penalty_kicks_won: 209 - position: goalkeeper - rank: 23 - red_card: 257 - squad: Athletic Club - yellow_card: 269 -Kelvin Amian: - age: 24.0 - born: 1998 - corner_kicks: 147 - country: FRA - fouls_committed: 208 - goals: 103 - league: Serie A - matches_played: 32 - minutes_played: 2646 - name: Kelvin Amian - penalty_kicks_made: 744 - penalty_kicks_won: 248 - position: defender - rank: 85 - red_card: 128 - squad: Spezia - yellow_card: 260 -Kevin Agudelo: - age: 23.0 - born: 1998 - corner_kicks: 126 - country: COL - fouls_committed: 25 - goals: 64 - league: Serie A - matches_played: 23 - minutes_played: 1237 - name: Kevin Agudelo - penalty_kicks_made: 606 - penalty_kicks_won: 202 - position: midfielder - rank: 25 - red_card: 171 - squad: Spezia - yellow_card: 91 -Kevin Akpoguma: - age: 27.0 - born: 1995 - corner_kicks: 99 - country: NGA - fouls_committed: 56 - goals: 82 - league: Bundesliga - matches_played: 26 - minutes_played: 1527 - name: Kevin Akpoguma - penalty_kicks_made: 588 - penalty_kicks_won: 196 - position: defender - rank: 46 - red_card: 86 - squad: Hoffenheim - yellow_card: 203 -Kristoffer Ajer: - age: 24.0 - born: 1998 - corner_kicks: 33 - country: NOR - fouls_committed: 243 - goals: 52 - league: Premier League - matches_played: 24 - minutes_played: 1995 - name: Kristoffer Ajer - penalty_kicks_made: 585 - penalty_kicks_won: 195 - position: defender - rank: 36 - red_card: 281 - squad: Brentford - yellow_card: 79 + yellow_card: 239 Laurent Abergel: age: 29.0 born: 1993 - corner_kicks: 247 + corner_kicks: 172 country: FRA - fouls_committed: 182 - goals: 232 + fouls_committed: 140 + goals: 240 league: Ligue 1 matches_played: 34 minutes_played: 2956 name: Laurent Abergel - penalty_kicks_made: 738 - penalty_kicks_won: 246 + penalty_kicks_made: 348 + penalty_kicks_won: 116 position: midfielder rank: 4 - red_card: 58 + red_card: 123 squad: Lorient - yellow_card: 24 -Lucas Alario: - age: 29.0 - born: 1992 - corner_kicks: 193 - country: ARG - fouls_committed: 172 - goals: 79 - league: Bundesliga - matches_played: 27 - minutes_played: 655 - name: Lucas Alario - penalty_kicks_made: 192 - penalty_kicks_won: 64 - position: forward - rank: 50 - red_card: 263 - squad: Leverkusen - yellow_card: 148 -Lucien Agoume: - age: 20.0 - born: 2002 - corner_kicks: 81 - country: FRA - fouls_committed: 139 - goals: 63 - league: Ligue 1 - matches_played: 27 - minutes_played: 1868 - name: Lucien Agoume - penalty_kicks_made: 216 - penalty_kicks_won: 72 - position: midfielder - rank: 24 - red_card: 226 - squad: Brest - yellow_card: 51 -Ludovic Ajorque: - age: 28.0 - born: 1994 - corner_kicks: 168 - country: REU - fouls_committed: 122 - goals: 11 - league: Ligue 1 - matches_played: 36 - minutes_played: 2738 - name: Ludovic Ajorque - penalty_kicks_made: 600 - penalty_kicks_won: 200 - position: forward - rank: 37 - red_card: 278 - squad: Strasbourg - yellow_card: 82 + yellow_card: 107 Luis Abram: age: 26.0 born: 1996 - corner_kicks: 207 + corner_kicks: 70 country: PER - fouls_committed: 87 - goals: 86 + fouls_committed: 218 + goals: 104 league: La Liga matches_played: 8 minutes_played: 560 name: Luis Abram - penalty_kicks_made: 246 - penalty_kicks_won: 82 + penalty_kicks_made: 99 + penalty_kicks_won: 33 position: defender rank: 9 - red_card: 215 + red_card: 104 squad: Granada - yellow_card: 228 -Luis Alberto: - age: 29.0 - born: 1992 - corner_kicks: 81 - country: ESP - fouls_committed: 174 - goals: 115 - league: Serie A - matches_played: 34 - minutes_played: 2353 - name: Luis Alberto - penalty_kicks_made: 183 - penalty_kicks_won: 61 - position: midfielder - rank: 53 - red_card: 12 - squad: Lazio - yellow_card: 192 -Maghnes Akliouche: - age: 20.0 - born: 2002 - corner_kicks: 263 - country: FRA - fouls_committed: 175 - goals: 114 - league: Ligue 1 - matches_played: 7 - minutes_played: 54 - name: Maghnes Akliouche - penalty_kicks_made: 540 - penalty_kicks_won: 180 - position: midfielder - rank: 43 - red_card: 88 - squad: Monaco - yellow_card: 49 -Manuel Akanji: - age: 26.0 - born: 1995 - corner_kicks: 161 - country: SUI - fouls_committed: 270 - goals: 286 - league: Bundesliga - matches_played: 26 - minutes_played: 2261 - name: Manuel Akanji - penalty_kicks_made: 888 - penalty_kicks_won: 296 - position: defender - rank: 38 - red_card: 25 - squad: Dortmund - yellow_card: 77 -Marc Albrighton: - age: 32.0 - born: 1989 - corner_kicks: 127 - country: ENG - fouls_committed: 195 - goals: 137 - league: Premier League - matches_played: 17 - minutes_played: 1132 - name: Marc Albrighton - penalty_kicks_made: 417 - penalty_kicks_won: 139 - position: forward - rank: 55 - red_card: 179 - squad: Leicester City - yellow_card: 272 -"Marcos Acu\xF1a": - age: 30.0 - born: 1991 - corner_kicks: 248 - country: ARG - fouls_committed: 237 - goals: 105 - league: La Liga - matches_played: 31 - minutes_played: 2260 - name: "Marcos Acu\xF1a" - penalty_kicks_made: 705 - penalty_kicks_won: 235 - position: defender - rank: 13 - red_card: 267 - squad: Sevilla - yellow_card: 81 -Marcos Alonso: - age: 31.0 - born: 1990 - corner_kicks: 21 - country: ESP - fouls_committed: 255 - goals: 36 - league: Premier League - matches_played: 28 - minutes_played: 2167 - name: Marcos Alonso - penalty_kicks_made: 636 - penalty_kicks_won: 212 - position: defender - rank: 72 - red_card: 134 - squad: Chelsea - yellow_card: 10 -"Marley Ak\xE9": - age: 21.0 - born: 2001 - corner_kicks: 278 - country: FRA - fouls_committed: 143 - goals: 217 - league: Serie A - matches_played: 4 - minutes_played: 77 - name: "Marley Ak\xE9" - penalty_kicks_made: 708 - penalty_kicks_won: 236 - position: midfielder - rank: 40 - red_card: 94 - squad: Juventus - yellow_card: 219 + yellow_card: 119 Martin Adeline: age: 18.0 born: 2003 - corner_kicks: 50 + corner_kicks: 18 country: FRA - fouls_committed: 163 - goals: 145 + fouls_committed: 89 + goals: 15 league: Ligue 1 matches_played: 8 minutes_played: 352 name: Martin Adeline - penalty_kicks_made: 225 - penalty_kicks_won: 75 + penalty_kicks_made: 393 + penalty_kicks_won: 131 position: midfielder rank: 17 - red_card: 74 + red_card: 109 squad: Reims - yellow_card: 183 -Martin Agirregabiria: - age: 26.0 - born: 1996 - corner_kicks: 140 - country: ESP - fouls_committed: 153 - goals: 114 - league: La Liga - matches_played: 24 - minutes_played: 1616 - name: Martin Agirregabiria - penalty_kicks_made: 150 - penalty_kicks_won: 50 - position: defender - rank: 22 - red_card: 13 - squad: "Alav\xE9s" - yellow_card: 126 + yellow_card: 288 Matthis Abline: age: 19.0 born: 2003 - corner_kicks: 235 + corner_kicks: 279 country: FRA - fouls_committed: 108 - goals: 207 + fouls_committed: 294 + goals: 212 league: Ligue 1 matches_played: 7 minutes_played: 103 name: Matthis Abline - penalty_kicks_made: 426 - penalty_kicks_won: 142 + penalty_kicks_made: 618 + penalty_kicks_won: 206 position: forward rank: 7 - red_card: 24 + red_card: 268 squad: Rennes - yellow_card: 282 + yellow_card: 131 Max Aarons: age: 22.0 born: 2000 - corner_kicks: 208 + corner_kicks: 285 country: ENG - fouls_committed: 256 - goals: 265 + fouls_committed: 89 + goals: 11 league: Premier League matches_played: 34 minutes_played: 2881 name: Max Aarons - penalty_kicks_made: 864 - penalty_kicks_won: 288 + penalty_kicks_made: 363 + penalty_kicks_won: 121 position: defender rank: 1 - red_card: 132 + red_card: 247 squad: Norwich City - yellow_card: 104 + yellow_card: 85 Michel Aebischer: age: 25.0 born: 1997 - corner_kicks: 138 + corner_kicks: 98 country: SUI - fouls_committed: 63 - goals: 122 + fouls_committed: 115 + goals: 275 league: Serie A matches_played: 12 minutes_played: 443 name: Michel Aebischer - penalty_kicks_made: 42 - penalty_kicks_won: 14 + penalty_kicks_made: 723 + penalty_kicks_won: 241 position: midfielder rank: 20 - red_card: 15 + red_card: 150 squad: Bologna - yellow_card: 144 -"Miguel Almir\xF3n": - age: 28.0 - born: 1994 - corner_kicks: 136 - country: PAR - fouls_committed: 206 - goals: 199 - league: Premier League - matches_played: 30 - minutes_played: 1716 - name: "Miguel Almir\xF3n" - penalty_kicks_made: 480 - penalty_kicks_won: 160 - position: midfielder - rank: 71 - red_card: 66 - squad: Newcastle Utd - yellow_card: 278 -Mircea Alexandru Tirlea: - age: 22.0 - born: 2000 - corner_kicks: 278 - country: ROU - fouls_committed: 72 - goals: 117 - league: La Liga - matches_played: 1 - minutes_played: 15 - name: Mircea Alexandru Tirlea - penalty_kicks_made: 81 - penalty_kicks_won: 27 - position: defender - rank: 64 - red_card: 269 - squad: "Alav\xE9s" - yellow_card: 115 + yellow_card: 207 Mohamed Achi: age: 20.0 born: 2002 - corner_kicks: 93 + corner_kicks: 75 country: FRA - fouls_committed: 33 - goals: 143 + fouls_committed: 142 + goals: 179 league: Ligue 1 matches_played: 1 minutes_played: 10 name: Mohamed Achi - penalty_kicks_made: 840 - penalty_kicks_won: 280 + penalty_kicks_made: 816 + penalty_kicks_won: 272 position: midfielder rank: 12 - red_card: 141 + red_card: 291 squad: Nantes - yellow_card: 106 -Mohamed Ali Cho: - age: 18.0 - born: 2004 - corner_kicks: 71 - country: FRA - fouls_committed: 279 - goals: 108 - league: Ligue 1 - matches_played: 32 - minutes_played: 1837 - name: Mohamed Ali Cho - penalty_kicks_made: 876 - penalty_kicks_won: 292 - position: forward - rank: 65 - red_card: 269 - squad: Angers - yellow_card: 96 -Nadiem Amiri: - age: 25.0 - born: 1996 - corner_kicks: 99 - country: GER - fouls_committed: 249 - goals: 65 - league: Bundesliga - matches_played: 13 - minutes_played: 369 - name: Nadiem Amiri - penalty_kicks_made: 723 - penalty_kicks_won: 241 - position: midfielder - rank: 87 - red_card: 120 - squad: Leverkusen - yellow_card: 70 -Naouirou Ahamada: - age: 20.0 - born: 2002 - corner_kicks: 56 - country: FRA - fouls_committed: 227 - goals: 244 - league: Bundesliga - matches_played: 3 - minutes_played: 61 - name: Naouirou Ahamada - penalty_kicks_made: 42 - penalty_kicks_won: 14 - position: midfielder - rank: 30 - red_card: 252 - squad: Stuttgart - yellow_card: 218 -"Nathan Ak\xE9": - age: 27.0 - born: 1995 - corner_kicks: 175 - country: NED - fouls_committed: 56 - goals: 60 - league: Premier League - matches_played: 14 - minutes_played: 923 - name: "Nathan Ak\xE9" - penalty_kicks_made: 729 - penalty_kicks_won: 243 - position: defender - rank: 41 - red_card: 253 - squad: Manchester City - yellow_card: 21 -Nayef Aguerd: - age: 26.0 - born: 1996 - corner_kicks: 118 - country: MAR - fouls_committed: 296 - goals: 62 - league: Ligue 1 - matches_played: 31 - minutes_played: 2735 - name: Nayef Aguerd - penalty_kicks_made: 87 - penalty_kicks_won: 29 - position: defender - rank: 26 - red_card: 177 - squad: Rennes - yellow_card: 233 -Ola Aina: - age: 25.0 - born: 1996 - corner_kicks: 238 - country: NGA - fouls_committed: 224 - goals: 238 - league: Serie A - matches_played: 21 - minutes_played: 1437 - name: Ola Aina - penalty_kicks_made: 357 - penalty_kicks_won: 119 - position: defender - rank: 34 - red_card: 38 - squad: Torino - yellow_card: 178 -Omar Alderete: - age: 25.0 - born: 1996 - corner_kicks: 205 - country: PAR - fouls_committed: 171 - goals: 175 - league: La Liga - matches_played: 29 - minutes_played: 2403 - name: Omar Alderete - penalty_kicks_made: 573 - penalty_kicks_won: 191 - position: defender - rank: 59 - red_card: 300 - squad: Valencia - yellow_card: 71 -"Paco Alc\xE1cer": - age: 28.0 - born: 1993 - corner_kicks: 122 - country: ESP - fouls_committed: 211 - goals: 250 - league: La Liga - matches_played: 18 - minutes_played: 787 - name: "Paco Alc\xE1cer" - penalty_kicks_made: 318 - penalty_kicks_won: 106 - position: forward - rank: 56 - red_card: 137 - squad: Villarreal - yellow_card: 125 -Paul Akouokou: - age: 24.0 - born: 1997 - corner_kicks: 118 - country: CIV - fouls_committed: 265 - goals: 134 - league: La Liga - matches_played: 8 - minutes_played: 516 - name: Paul Akouokou - penalty_kicks_made: 702 - penalty_kicks_won: 234 - position: midfielder - rank: 44 - red_card: 117 - squad: Betis - yellow_card: 45 + yellow_card: 73 Ragnar Ache: age: 23.0 born: 1998 - corner_kicks: 294 + corner_kicks: 286 country: GER - fouls_committed: 161 - goals: 43 + fouls_committed: 133 + goals: 265 league: Bundesliga matches_played: 13 minutes_played: 259 name: Ragnar Ache - penalty_kicks_made: 66 - penalty_kicks_won: 22 + penalty_kicks_made: 315 + penalty_kicks_won: 105 position: midfielder rank: 11 - red_card: 14 + red_card: 251 squad: Eint Frankfurt - yellow_card: 211 -"Rayan A\xEFt Nouri": - age: 20.0 - born: 2001 - corner_kicks: 232 - country: FRA - fouls_committed: 99 - goals: 74 - league: Premier League - matches_played: 23 - minutes_played: 1828 - name: "Rayan A\xEFt Nouri" - penalty_kicks_made: 294 - penalty_kicks_won: 98 - position: defender - rank: 35 - red_card: 180 - squad: Wolves - yellow_card: 32 -"Ra\xFAl Albiol": - age: 36.0 - born: 1985 - corner_kicks: 230 - country: ESP - fouls_committed: 34 - goals: 26 - league: La Liga - matches_played: 28 - minutes_played: 2465 - name: "Ra\xFAl Albiol" - penalty_kicks_made: 705 - penalty_kicks_won: 235 - position: defender - rank: 54 - red_card: 29 - squad: Villarreal - yellow_card: 276 -Robert Andrich: - age: 27.0 - born: 1994 - corner_kicks: 264 - country: GER - fouls_committed: 247 - goals: 298 - league: Bundesliga - matches_played: 26 - minutes_played: 1817 - name: Robert Andrich - penalty_kicks_made: 138 - penalty_kicks_won: 46 - position: midfielder - rank: 97 - red_card: 91 - squad: Leverkusen - yellow_card: 298 -Ruben Aguilar: - age: 29.0 - born: 1993 - corner_kicks: 279 - country: FRA - fouls_committed: 31 - goals: 169 - league: Ligue 1 - matches_played: 28 - minutes_played: 2140 - name: Ruben Aguilar - penalty_kicks_made: 465 - penalty_kicks_won: 155 - position: defender - rank: 28 - red_card: 15 - squad: Monaco - yellow_card: 131 -"Rub\xE9n Alcaraz": - age: 31.0 - born: 1991 - corner_kicks: 133 - country: ESP - fouls_committed: 300 - goals: 101 - league: La Liga - matches_played: 14 - minutes_played: 1105 - name: "Rub\xE9n Alcaraz" - penalty_kicks_made: 837 - penalty_kicks_won: 279 - position: midfielder - rank: 58 - red_card: 153 - squad: "C\xE1diz" - yellow_card: 172 + yellow_card: 90 Salis Abdul Samed: age: 22.0 born: 2000 - corner_kicks: 48 + corner_kicks: 185 country: GHA - fouls_committed: 57 - goals: 64 + fouls_committed: 166 + goals: 30 league: Ligue 1 matches_played: 31 minutes_played: 2462 name: Salis Abdul Samed - penalty_kicks_made: 489 - penalty_kicks_won: 163 + penalty_kicks_made: 84 + penalty_kicks_won: 28 position: midfielder rank: 3 - red_card: 42 + red_card: 135 squad: Clermont Foot - yellow_card: 99 + yellow_card: 269 Sargis Adamyan: age: 29.0 born: 1993 - corner_kicks: 222 + corner_kicks: 275 country: ARM - fouls_committed: 99 - goals: 65 + fouls_committed: 86 + goals: 255 league: Bundesliga matches_played: 13 minutes_played: 331 name: Sargis Adamyan - penalty_kicks_made: 714 - penalty_kicks_won: 238 + penalty_kicks_made: 645 + penalty_kicks_won: 215 position: forward rank: 16 - red_card: 229 + red_card: 278 squad: Hoffenheim - yellow_card: 70 -Sebastian Andersson: - age: 30.0 - born: 1991 - corner_kicks: 237 - country: SWE - fouls_committed: 122 - goals: 83 - league: Bundesliga - matches_played: 26 - minutes_played: 1257 - name: Sebastian Andersson - penalty_kicks_made: 48 - penalty_kicks_won: 16 - position: forward - rank: 92 - red_card: 58 - squad: "K\xF6ln" - yellow_card: 217 -"Sergio Ag\xFCero": - age: 33.0 - born: 1988 - corner_kicks: 52 - country: ARG - fouls_committed: 146 - goals: 179 - league: La Liga - matches_played: 4 - minutes_played: 151 - name: "Sergio Ag\xFCero" - penalty_kicks_made: 402 - penalty_kicks_won: 134 - position: forward - rank: 27 - red_card: 81 - squad: Barcelona - yellow_card: 74 -Sofiane Alakouch: - age: 23.0 - born: 1998 - corner_kicks: 79 - country: MAR - fouls_committed: 91 - goals: 293 - league: Ligue 1 - matches_played: 4 - minutes_played: 158 - name: Sofiane Alakouch - penalty_kicks_made: 105 - penalty_kicks_won: 35 - position: defender - rank: 48 - red_card: 276 - squad: Metz - yellow_card: 168 -Sofyan Amrabat: - age: 25.0 - born: 1996 - corner_kicks: 14 - country: MAR - fouls_committed: 219 - goals: 29 - league: Serie A - matches_played: 23 - minutes_played: 944 - name: Sofyan Amrabat - penalty_kicks_made: 417 - penalty_kicks_won: 139 - position: midfielder - rank: 89 - red_card: 75 - squad: Fiorentina - yellow_card: 195 -Steven Alzate: - age: 23.0 - born: 1998 - corner_kicks: 198 - country: COL - fouls_committed: 44 - goals: 227 - league: Premier League - matches_played: 9 - minutes_played: 404 - name: Steven Alzate - penalty_kicks_made: 108 - penalty_kicks_won: 36 - position: midfielder - rank: 77 - red_card: 230 - squad: Brighton - yellow_card: 45 + yellow_card: 41 Tammy Abraham: age: 24.0 born: 1997 - corner_kicks: 95 + corner_kicks: 261 country: ENG - fouls_committed: 41 - goals: 39 + fouls_committed: 97 + goals: 296 league: Serie A matches_played: 37 minutes_played: 3084 name: Tammy Abraham - penalty_kicks_made: 639 - penalty_kicks_won: 213 + penalty_kicks_made: 273 + penalty_kicks_won: 91 position: forward rank: 8 - red_card: 166 + red_card: 10 squad: Roma - yellow_card: 103 -"Thiago Alc\xE1ntara": - age: 31.0 - born: 1991 - corner_kicks: 231 - country: ESP - fouls_committed: 48 - goals: 155 - league: Premier League - matches_played: 25 - minutes_played: 1534 - name: "Thiago Alc\xE1ntara" - penalty_kicks_made: 144 - penalty_kicks_won: 48 - position: midfielder - rank: 57 - red_card: 299 - squad: Liverpool - yellow_card: 118 -"Tom\xE1s Alarc\xF3n": - age: 23.0 - born: 1999 - corner_kicks: 211 - country: CHI - fouls_committed: 193 - goals: 119 - league: La Liga - matches_played: 23 - minutes_played: 1425 - name: "Tom\xE1s Alarc\xF3n" - penalty_kicks_made: 831 - penalty_kicks_won: 277 - position: midfielder - rank: 49 - red_card: 96 - squad: "C\xE1diz" - yellow_card: 231 -Trent Alexander-Arnold: - age: 23.0 - born: 1998 - corner_kicks: 253 - country: ENG - fouls_committed: 82 - goals: 139 - league: Premier League - matches_played: 32 - minutes_played: 2853 - name: Trent Alexander-Arnold - penalty_kicks_made: 123 - penalty_kicks_won: 41 - position: defender - rank: 63 - red_card: 103 - squad: Liverpool - yellow_card: 83 + yellow_card: 102 Tyler Adams: age: 23.0 born: 1999 - corner_kicks: 92 + corner_kicks: 280 country: USA - fouls_committed: 287 - goals: 194 + fouls_committed: 91 + goals: 96 league: Bundesliga matches_played: 24 minutes_played: 1351 name: Tyler Adams - penalty_kicks_made: 180 - penalty_kicks_won: 60 + penalty_kicks_made: 606 + penalty_kicks_won: 202 position: midfielder rank: 15 - red_card: 226 + red_card: 251 squad: RB Leipzig - yellow_card: 28 -Wisdom Amey: - age: 16.0 - born: 2005 - corner_kicks: 268 - country: ITA - fouls_committed: 223 - goals: 144 - league: Serie A - matches_played: 1 - minutes_played: 71 - name: Wisdom Amey - penalty_kicks_made: 297 - penalty_kicks_won: 99 - position: defender - rank: 84 - red_card: 141 - squad: Bologna - yellow_card: 189 + yellow_card: 149 Yacine Adli: age: 21.0 born: 2000 - corner_kicks: 156 + corner_kicks: 246 country: FRA - fouls_committed: 284 - goals: 68 + fouls_committed: 276 + goals: 201 league: Ligue 1 matches_played: 36 minutes_played: 2260 name: Yacine Adli - penalty_kicks_made: 360 - penalty_kicks_won: 120 + penalty_kicks_made: 867 + penalty_kicks_won: 289 position: midfielder rank: 19 - red_card: 162 + red_card: 77 squad: Bordeaux - yellow_card: 163 -"Yeray \xC1lvarez": - age: 27.0 - born: 1995 - corner_kicks: 192 - country: ESP - fouls_committed: 241 - goals: 132 - league: La Liga - matches_played: 22 - minutes_played: 1860 - name: "Yeray \xC1lvarez" - penalty_kicks_made: 546 - penalty_kicks_won: 182 - position: defender - rank: 75 - red_card: 236 - squad: Athletic Club - yellow_card: 275 + yellow_card: 177 Yunis Abdelhamid: age: 34.0 born: 1987 - corner_kicks: 100 + corner_kicks: 55 country: MAR - fouls_committed: 58 - goals: 210 + fouls_committed: 228 + goals: 243 league: Ligue 1 matches_played: 34 minutes_played: 2983 name: Yunis Abdelhamid - penalty_kicks_made: 369 - penalty_kicks_won: 123 + penalty_kicks_made: 108 + penalty_kicks_won: 36 position: defender rank: 2 - red_card: 232 + red_card: 194 squad: Reims - yellow_card: 175 -"\xC1lvaro Aguirre": - age: 22.0 - born: 2000 - corner_kicks: 279 - country: ESP - fouls_committed: 283 - goals: 25 - league: La Liga - matches_played: 1 - minutes_played: 9 - name: "\xC1lvaro Aguirre" - penalty_kicks_made: 855 - penalty_kicks_won: 285 - position: forward - rank: 29 - red_card: 196 - squad: Rayo Vallecano - yellow_card: 161 + yellow_card: 42 diff --git a/week_3/football/test/models/football_player_test.rb b/week_3/football/test/models/football_player_test.rb index d90364f6..c93d823c 100644 --- a/week_3/football/test/models/football_player_test.rb +++ b/week_3/football/test/models/football_player_test.rb @@ -1,7 +1,89 @@ require "test_helper" class FootballPlayerTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end + test "has forwarders" do + names = ["Amine Adli", "Charles Abi", "Che Adams", "Dickson Abiama", "Matthis Abline", "Sargis Adamyan", "Tammy Abraham"] + + assert_equal names, FootballPlayer.forwarders.order(name: :asc).pluck(:name) + end + + test "has french_player" do + names = ["Amine Adli", "Charles Abi", "Laurent Abergel", "Martin Adeline", "Matthis Abline", "Mohamed Achi", "Yacine Adli"] + + assert_equal names, FootballPlayer.french_players.order(name: :asc).pluck(:name) + end + + test "has order_by_rank" do + names = ["Max Aarons", + "Yunis Abdelhamid", + "Salis Abdul Samed", + "Laurent Abergel", + "Charles Abi", + "Dickson Abiama", + "Matthis Abline", + "Tammy Abraham", + "Luis Abram", + "Francesco Acerbi", + "Ragnar Ache", + "Mohamed Achi", + "Che Adams", + "Tyler Adams", + "Sargis Adamyan", + "Martin Adeline", + "Amine Adli", + "Yacine Adli", + "Michel Aebischer"] + + assert_equal names, FootballPlayer.order_by_rank.pluck(:name) + end + + test "has self.import_argentinian_players" do + players = ["Lucas Alario", "Marcos Acuna", "Sergio Aguero"] + + FootballPlayer.import_argentinian_players + + assert_equal players, FootballPlayer.where(name: players).order(name: :asc).pluck(:name) + end + + test "has average_goals_per_game" do + assert_equal 2, FootballPlayer.new(matches_played: 10, goals: 20).average_goals_per_game + assert_equal 5, FootballPlayer.new(matches_played: 10, goals: 50).average_goals_per_game + end + + test "average_goals_per_game is nil when data is incomplete" do + assert_nil FootballPlayer.new(goals: 20).average_goals_per_game + assert_nil FootballPlayer.new(matches_played: 10).average_goals_per_game + end + + test "has total_penalty_cards" do + assert_equal 30, FootballPlayer.new(red_card: 10, yellow_card: 20).total_penalty_cards + assert_equal 60, FootballPlayer.new(yellow_card: 10, red_card: 50).total_penalty_cards + end + + test "total_penalty_cards is nil when data is incomplete" do + assert_nil FootballPlayer.new(red_card: 20).total_penalty_cards + assert_nil FootballPlayer.new(yellow_card: 10).total_penalty_cards + end + + test "has penalty_success_rate" do + assert_equal 50, FootballPlayer.new(penalty_kicks_won: 5, penalty_kicks_made: 10).penalty_success_rate + assert_equal 10, FootballPlayer.new(penalty_kicks_won: 1, penalty_kicks_made: 10).penalty_success_rate + end + + test "has self.ban" do + FootballPlayer.ban("Tammy Abraham") + assert_empty FootballPlayer.where(name: "Tammy Abraham") + end + + test "has self.update_statistics" do + stat = [ + ["Salis Abdul Samed", 2, 30, 1, 1], + ["Dickson Abiama", 4, 20, 1, 0] + ] + + FootballPlayer.update_statistics(stat) + + assert_equal [["Dickson Abiama", 37, 746, 121, 104]], FootballPlayer.where(name: "Dickson Abiama").pluck(:name, :goals, :minutes_played, :red_card, :yellow_card) + assert_equal [["Salis Abdul Samed", 32, 2492, 136, 270]], FootballPlayer.where(name: "Salis Abdul Samed").pluck(:name, :goals, :minutes_played, :red_card, :yellow_card) + end end From 0a1ae8ddf4d5462557f6405363f9f73563f4eb18 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 16:22:45 +0530 Subject: [PATCH 23/34] Add week 3 tests --- .github/pr-labeler.yml | 2 -- .github/workflows/pr-labeler.yml | 19 --------------- .github/workflows/week3_intro.yml | 40 +++++++++++++++++++++++++++++++ .github/workflows/week3_model.yml | 36 ++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 21 deletions(-) delete mode 100644 .github/pr-labeler.yml delete mode 100644 .github/workflows/pr-labeler.yml create mode 100644 .github/workflows/week3_intro.yml create mode 100644 .github/workflows/week3_model.yml diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml deleted file mode 100644 index 3cf06611..00000000 --- a/.github/pr-labeler.yml +++ /dev/null @@ -1,2 +0,0 @@ -Week 1: ['week1*', 'week_1*'] -Week 2: ['week2*', 'week_2*'] diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml deleted file mode 100644 index 7ddde4f9..00000000 --- a/.github/workflows/pr-labeler.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Add Label -on: - pull_request: - types: [opened] - -permissions: - contents: read - -jobs: - pr-labeler: - permissions: - contents: read - pull-requests: write - runs-on: ubuntu-latest - steps: - - uses: TimonVS/pr-labeler-action@v4 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - configuration-path: .github/pr-labeler.yml diff --git a/.github/workflows/week3_intro.yml b/.github/workflows/week3_intro.yml new file mode 100644 index 00000000..3acdee3c --- /dev/null +++ b/.github/workflows/week3_intro.yml @@ -0,0 +1,40 @@ +name: 'Week 3 getting started' + +on: + pull_request: + types: [synchronize, opened, reopened, edited] + branches: + - 'week3_*' + + workflow_dispatch: + +jobs: + week2: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.5 + working-directory: week_3/hello_world + bundler-cache: true + + - name: Install NPM packages + uses: bahmutov/npm-install@v1 + with: + working-directory: week_3/hello_world + + - name: Copy Test File + working-directory: week_3 + run: cp page_controller_test.rb hello_world/test/controllers + + - name: Test Rails + working-directory: week_3/hello_world + run: | + bundle exec rails db:create + bundle exec rails db:migrate + bundle exec rails test diff --git a/.github/workflows/week3_model.yml b/.github/workflows/week3_model.yml new file mode 100644 index 00000000..2ac537ac --- /dev/null +++ b/.github/workflows/week3_model.yml @@ -0,0 +1,36 @@ +name: 'Week 3 Model' + +on: + pull_request: + types: [synchronize, opened, reopened, edited] + branches: + - 'week3_*' + + workflow_dispatch: + +jobs: + week2: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.5 + working-directory: week_3/football + bundler-cache: true + + - name: Install NPM packages + uses: bahmutov/npm-install@v1 + with: + working-directory: week_3/football + + - name: Test FootballFPlayers + working-directory: week_3/football + run: | + bundle exec rails db:create + bundle exec rails db:migrate + bundle exec rails test:models From 27b02ad04aeb60844a1deb6676d3bb812abb041c Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 16:26:39 +0530 Subject: [PATCH 24/34] Add week 3 tests --- .github/workflows/week3_intro.yml | 2 +- .github/workflows/week3_model.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/week3_intro.yml b/.github/workflows/week3_intro.yml index 3acdee3c..11b2c77b 100644 --- a/.github/workflows/week3_intro.yml +++ b/.github/workflows/week3_intro.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: jobs: - week2: + week3: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/week3_model.yml b/.github/workflows/week3_model.yml index 2ac537ac..c940d1a1 100644 --- a/.github/workflows/week3_model.yml +++ b/.github/workflows/week3_model.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: jobs: - week2: + week3_model: runs-on: ubuntu-latest steps: From 5c5a1cd908310b14c9244a02ce8ad521376d75bb Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 16:39:31 +0530 Subject: [PATCH 25/34] Add week 3 tests --- .github/workflows/week3_intro.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/week3_intro.yml b/.github/workflows/week3_intro.yml index 11b2c77b..2ac63e1d 100644 --- a/.github/workflows/week3_intro.yml +++ b/.github/workflows/week3_intro.yml @@ -21,7 +21,6 @@ jobs: with: ruby-version: 3.0.5 working-directory: week_3/hello_world - bundler-cache: true - name: Install NPM packages uses: bahmutov/npm-install@v1 From 77ab65bc5afb6205139643bc8a0ec9b599d55319 Mon Sep 17 00:00:00 2001 From: hrushikeshj Date: Fri, 13 Jan 2023 16:44:28 +0530 Subject: [PATCH 26/34] Add week 3 tests --- .github/workflows/week3_intro.yml | 2 +- .github/workflows/week3_model.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/week3_intro.yml b/.github/workflows/week3_intro.yml index 2ac63e1d..a44c45c6 100644 --- a/.github/workflows/week3_intro.yml +++ b/.github/workflows/week3_intro.yml @@ -19,8 +19,8 @@ jobs: - name: Install Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 3.0.5 working-directory: week_3/hello_world + bundler-cache: true - name: Install NPM packages uses: bahmutov/npm-install@v1 diff --git a/.github/workflows/week3_model.yml b/.github/workflows/week3_model.yml index c940d1a1..8eb8b058 100644 --- a/.github/workflows/week3_model.yml +++ b/.github/workflows/week3_model.yml @@ -19,7 +19,6 @@ jobs: - name: Install Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 3.0.5 working-directory: week_3/football bundler-cache: true From 221d1cd2f946de782dbd21e912a72d2091a1c647 Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Fri, 13 Jan 2023 20:18:54 +0530 Subject: [PATCH 27/34] Update README.md --- week_3/football/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/week_3/football/README.md b/week_3/football/README.md index 24e18349..b6e1a06c 100644 --- a/week_3/football/README.md +++ b/week_3/football/README.md @@ -216,3 +216,11 @@ FootballPlayer.find_by(name: "Messi").destroy - [DELETE | ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html#delete) + +# Rails console +The Rails console is useful for testing out quick ideas with code and debugging applications. + +```bash +rails console +``` +![image](https://user-images.githubusercontent.com/66632353/212348259-fbf59057-7eb1-4e1a-af8c-634161164afc.png) From e31472201f100e16b37a7817760bce9a9822d5b0 Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:04:57 +0530 Subject: [PATCH 28/34] Add creating tables for week-3 (#108) * add activity-tracker app * add readme and instructions * remove conflicting files --- week_3/README.md | 108 ++++---- week_3/activity-tracker/.ruby-version | 1 + week_3/activity-tracker/Gemfile | 72 ++++++ week_3/activity-tracker/Gemfile.lock | 232 ++++++++++++++++++ week_3/activity-tracker/README.md | 151 ++++++++++++ week_3/activity-tracker/Rakefile | 6 + .../app/assets/config/manifest.js | 4 + .../activity-tracker/app/assets/images/.keep | 0 .../app/assets/stylesheets/application.css | 15 ++ .../app/channels/application_cable/channel.rb | 4 + .../channels/application_cable/connection.rb | 4 + .../app/controllers/application_controller.rb | 2 + .../app/controllers/concerns/.keep | 0 .../app/helpers/application_helper.rb | 2 + .../app/javascript/application.js | 3 + .../app/javascript/controllers/application.js | 9 + .../controllers/hello_controller.js | 7 + .../app/javascript/controllers/index.js | 11 + .../app/jobs/application_job.rb | 7 + .../app/mailers/application_mailer.rb | 4 + .../app/models/application_record.rb | 3 + .../app/models/concerns/.keep | 0 .../app/views/layouts/application.html.erb | 16 ++ .../app/views/layouts/mailer.html.erb | 13 + .../app/views/layouts/mailer.text.erb | 1 + week_3/activity-tracker/bin/bundle | 114 +++++++++ week_3/activity-tracker/bin/importmap | 4 + week_3/activity-tracker/bin/rails | 4 + week_3/activity-tracker/bin/rake | 4 + week_3/activity-tracker/bin/setup | 33 +++ week_3/activity-tracker/config.ru | 6 + week_3/activity-tracker/config/application.rb | 22 ++ week_3/activity-tracker/config/boot.rb | 4 + week_3/activity-tracker/config/cable.yml | 10 + .../config/credentials.yml.enc | 1 + week_3/activity-tracker/config/database.yml | 25 ++ week_3/activity-tracker/config/environment.rb | 5 + .../config/environments/development.rb | 72 ++++++ .../config/environments/production.rb | 93 +++++++ .../config/environments/test.rb | 60 +++++ week_3/activity-tracker/config/importmap.rb | 7 + .../config/initializers/assets.rb | 12 + .../initializers/content_security_policy.rb | 25 ++ .../initializers/filter_parameter_logging.rb | 8 + .../config/initializers/inflections.rb | 16 ++ .../config/initializers/permissions_policy.rb | 11 + week_3/activity-tracker/config/locales/en.yml | 33 +++ week_3/activity-tracker/config/master.key | 1 + week_3/activity-tracker/config/puma.rb | 43 ++++ week_3/activity-tracker/config/routes.rb | 6 + week_3/activity-tracker/config/storage.yml | 34 +++ week_3/activity-tracker/db/seeds.rb | 7 + week_3/activity-tracker/lib/assets/.keep | 0 week_3/activity-tracker/lib/tasks/.keep | 0 week_3/activity-tracker/public/404.html | 67 +++++ week_3/activity-tracker/public/422.html | 67 +++++ week_3/activity-tracker/public/500.html | 66 +++++ .../public/apple-touch-icon-precomposed.png | 0 .../public/apple-touch-icon.png | 0 week_3/activity-tracker/public/favicon.ico | 0 week_3/activity-tracker/public/robots.txt | 1 + week_3/activity-tracker/storage/.keep | 0 .../test/application_system_test_case.rb | 5 + .../application_cable/connection_test.rb | 11 + .../activity-tracker/test/controllers/.keep | 0 .../test/fixtures/files/.keep | 0 week_3/activity-tracker/test/helpers/.keep | 0 .../activity-tracker/test/integration/.keep | 0 week_3/activity-tracker/test/mailers/.keep | 0 week_3/activity-tracker/test/models/.keep | 0 .../test/models/activity_model_test.rb | 23 ++ .../test/models/activity_test.rb | 7 + week_3/activity-tracker/test/system/.keep | 0 week_3/activity-tracker/test/test_helper.rb | 13 + week_3/activity-tracker/vendor/.keep | 0 .../activity-tracker/vendor/javascript/.keep | 0 week_3/getting_started_with_rails.md | 82 +++++++ 77 files changed, 1614 insertions(+), 63 deletions(-) create mode 100644 week_3/activity-tracker/.ruby-version create mode 100644 week_3/activity-tracker/Gemfile create mode 100644 week_3/activity-tracker/Gemfile.lock create mode 100644 week_3/activity-tracker/README.md create mode 100644 week_3/activity-tracker/Rakefile create mode 100644 week_3/activity-tracker/app/assets/config/manifest.js create mode 100644 week_3/activity-tracker/app/assets/images/.keep create mode 100644 week_3/activity-tracker/app/assets/stylesheets/application.css create mode 100644 week_3/activity-tracker/app/channels/application_cable/channel.rb create mode 100644 week_3/activity-tracker/app/channels/application_cable/connection.rb create mode 100644 week_3/activity-tracker/app/controllers/application_controller.rb create mode 100644 week_3/activity-tracker/app/controllers/concerns/.keep create mode 100644 week_3/activity-tracker/app/helpers/application_helper.rb create mode 100644 week_3/activity-tracker/app/javascript/application.js create mode 100644 week_3/activity-tracker/app/javascript/controllers/application.js create mode 100644 week_3/activity-tracker/app/javascript/controllers/hello_controller.js create mode 100644 week_3/activity-tracker/app/javascript/controllers/index.js create mode 100644 week_3/activity-tracker/app/jobs/application_job.rb create mode 100644 week_3/activity-tracker/app/mailers/application_mailer.rb create mode 100644 week_3/activity-tracker/app/models/application_record.rb create mode 100644 week_3/activity-tracker/app/models/concerns/.keep create mode 100644 week_3/activity-tracker/app/views/layouts/application.html.erb create mode 100644 week_3/activity-tracker/app/views/layouts/mailer.html.erb create mode 100644 week_3/activity-tracker/app/views/layouts/mailer.text.erb create mode 100755 week_3/activity-tracker/bin/bundle create mode 100755 week_3/activity-tracker/bin/importmap create mode 100755 week_3/activity-tracker/bin/rails create mode 100755 week_3/activity-tracker/bin/rake create mode 100755 week_3/activity-tracker/bin/setup create mode 100644 week_3/activity-tracker/config.ru create mode 100644 week_3/activity-tracker/config/application.rb create mode 100644 week_3/activity-tracker/config/boot.rb create mode 100644 week_3/activity-tracker/config/cable.yml create mode 100644 week_3/activity-tracker/config/credentials.yml.enc create mode 100644 week_3/activity-tracker/config/database.yml create mode 100644 week_3/activity-tracker/config/environment.rb create mode 100644 week_3/activity-tracker/config/environments/development.rb create mode 100644 week_3/activity-tracker/config/environments/production.rb create mode 100644 week_3/activity-tracker/config/environments/test.rb create mode 100644 week_3/activity-tracker/config/importmap.rb create mode 100644 week_3/activity-tracker/config/initializers/assets.rb create mode 100644 week_3/activity-tracker/config/initializers/content_security_policy.rb create mode 100644 week_3/activity-tracker/config/initializers/filter_parameter_logging.rb create mode 100644 week_3/activity-tracker/config/initializers/inflections.rb create mode 100644 week_3/activity-tracker/config/initializers/permissions_policy.rb create mode 100644 week_3/activity-tracker/config/locales/en.yml create mode 100644 week_3/activity-tracker/config/master.key create mode 100644 week_3/activity-tracker/config/puma.rb create mode 100644 week_3/activity-tracker/config/routes.rb create mode 100644 week_3/activity-tracker/config/storage.yml create mode 100644 week_3/activity-tracker/db/seeds.rb create mode 100644 week_3/activity-tracker/lib/assets/.keep create mode 100644 week_3/activity-tracker/lib/tasks/.keep create mode 100644 week_3/activity-tracker/public/404.html create mode 100644 week_3/activity-tracker/public/422.html create mode 100644 week_3/activity-tracker/public/500.html create mode 100644 week_3/activity-tracker/public/apple-touch-icon-precomposed.png create mode 100644 week_3/activity-tracker/public/apple-touch-icon.png create mode 100644 week_3/activity-tracker/public/favicon.ico create mode 100644 week_3/activity-tracker/public/robots.txt create mode 100644 week_3/activity-tracker/storage/.keep create mode 100644 week_3/activity-tracker/test/application_system_test_case.rb create mode 100644 week_3/activity-tracker/test/channels/application_cable/connection_test.rb create mode 100644 week_3/activity-tracker/test/controllers/.keep create mode 100644 week_3/activity-tracker/test/fixtures/files/.keep create mode 100644 week_3/activity-tracker/test/helpers/.keep create mode 100644 week_3/activity-tracker/test/integration/.keep create mode 100644 week_3/activity-tracker/test/mailers/.keep create mode 100644 week_3/activity-tracker/test/models/.keep create mode 100644 week_3/activity-tracker/test/models/activity_model_test.rb create mode 100644 week_3/activity-tracker/test/models/activity_test.rb create mode 100644 week_3/activity-tracker/test/system/.keep create mode 100644 week_3/activity-tracker/test/test_helper.rb create mode 100644 week_3/activity-tracker/vendor/.keep create mode 100644 week_3/activity-tracker/vendor/javascript/.keep create mode 100644 week_3/getting_started_with_rails.md diff --git a/week_3/README.md b/week_3/README.md index d7b18080..723706cd 100644 --- a/week_3/README.md +++ b/week_3/README.md @@ -1,90 +1,72 @@ -# Week 3 - Getting Started with Rails +# Week 3 - Getting Started with Rails + Models In this week we will get started with Rails. -We will create a simple rails app with two pages, a Home Page and an About Me page. +At first, we will create a simple rails app with two pages, a Home Page and an About Me page. -## Steps -- [Set Up Local Workplace](../setup/) +Follow [these](./getting_started_with_rails.md) instructions to get started. -- Create a new [gemset](../setup/README.md#RVM) and install rails -```bash -cd week_3 -rvm gemset create week_3 -rvm use 3.0.5@week_3 -gem install rails --version 7.0.4 -``` +# Models -- Create a new Rails project `hello_world` in the directory `week_1` -```bash -rails new hello_world --css=bootstrap --skip-git -cd hello_world -rvm use 3.0.5@week_3 -``` +We take a closer look at _Model_ of the MVC architecture and talk about +databases, migrations and working with records. -> The command `rails new` initialises a Rails project. We have passed -> the flag `--skip-git` to avoid initializing Git again as we are -> already within a Git repository. +The _model_ layer is responsible for storing and processing data. -- Run the rails server using below command and go to http://localhost:3000/. -```bash -rails server -``` +We store data in a _relational database_ and process it in the +`app/models` of the Rails application. -You should see the rails logo. +A _relational database_ stores information as a set of tables with columns +and rows (_records_). The tables and their columns are together called +a _schema_. You can think of relational database as a spreadsheet with +each table on a different sheet. -### Add a controller +> There are other non-tabular databases as well, which are better suited +> to specific problems: [What is a Database | Oracle](https://www.oracle.com/in/database/what-is-database/) -- Generate a new controller `PageController` with actions `root` and - `about_me`: +_Structured Query Language_ (SQL) is used to access and manipulate +databases. SQL can retrieve, create, read, update and destroy records, +modify schema and more. Working with SQL directly is difficult, so we +usually have a Rails equivalent. -```bash -rails generate controller Page root about_me -``` +The assignment is split into different sub-tasks, each testing a +different aspect of Model layer. -> A _controller_ is responsible for making sense of request and producing -> the appropriate output. It acts as a middleman between the Data -> (Model) and Presentation (View). Controllers are stored in -> `app/controllers` directory. +> We will be using SQLite as our database program, as it requires no +> setup and is Rails's default. -> The generator creates the files and fills it with some default code. -> the above command creates a controller -> `PagesController`, creates new view files `root.html.erb` and -> `about_me.html.erb` and modifies the routes file +## Task 1 - Creating Tables -- Edit the routes file (`config/routes.rb`) as follow to add new routes: +Relational databases stores information using tables. You can think of +tables and their columns as the format in which data is stored. -```ruby -Rails.application.routes.draw do - get '/', to: 'page#root' - get 'about_me', to: 'page#about_me' -end -``` +In this sub-task, we will build an activity tracker because as programmers we spend long hours sitting and need to keep track of our health. During the course of this bootcamp, we'll build the entire application, adding functionality each week. At the end, you'll have a fully functional acticity tracker! -The routes file specifies the URLs that are recognized by the application. +Head over to [activity-tracker](./activity-tracker/README.md) to learn more. -- Edit the view files `app/views/page/root.html.erb` and `app/views/page/about_me.html.erb`. +## Task 2 - Working with Records -- You should be able to see see your changes at `http://localhost:3000` and - `http://localhost:3000/about_me`. - -![image](https://user-images.githubusercontent.com/66632353/211770375-4cc14806-7e60-4135-9e40-7b73e3c4ed23.png) -![image](https://user-images.githubusercontent.com/66632353/211770741-56dfaea8-2095-474b-974a-2b151953a3de.png) +Once a table is created, we have to fill it with actual data. In +particular, we can create, read, update and destroy records in a table. +Each operation maps to a different SQL command and a different Rails +equivalent. -- Copy the test file from week_3 directory to hello_world/test/controllers: -```bash -cp page_controller_test.rb hello_world/test/controllers -``` +In this sub-task, we will work on some statistics from Football! + +Head over to [football](football/README.md) directory to learn more. + + +## Interactive Console -- Execute the test suite to ensure the page works as expected. +The Rails console is useful for testing out quick ideas with code and +debugging applications. ```bash -rails test +rails console ``` -- If the test fails, check the view files and debug the application. -- Once the test works locally, submit your changes. +This should open a console, similar to IRB in the first session. We can +access your model functions and execute any valid ruby code. -# Model -Once done head over to [football](./football) directory to learn more about models. \ No newline at end of file +- [The Rails Command Line](https://guides.rubyonrails.org/command_line.html#bin-rails-console) diff --git a/week_3/activity-tracker/.ruby-version b/week_3/activity-tracker/.ruby-version new file mode 100644 index 00000000..316881c9 --- /dev/null +++ b/week_3/activity-tracker/.ruby-version @@ -0,0 +1 @@ +ruby-3.0.5 diff --git a/week_3/activity-tracker/Gemfile b/week_3/activity-tracker/Gemfile new file mode 100644 index 00000000..0e74c513 --- /dev/null +++ b/week_3/activity-tracker/Gemfile @@ -0,0 +1,72 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "3.0.5" + +# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" +gem "rails", "~> 7.0.4" + +# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] +gem "sprockets-rails" + +# Use sqlite3 as the database for Active Record +gem "sqlite3", "~> 1.4" + +# Use the Puma web server [https://github.com/puma/puma] +gem "puma", "~> 5.0" + +# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] +gem "importmap-rails" + +# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] +gem "turbo-rails" + +# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] +gem "stimulus-rails" + +# Build JSON APIs with ease [https://github.com/rails/jbuilder] +gem "jbuilder" + +# Use Redis adapter to run Action Cable in production +# gem "redis", "~> 4.0" + +# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] +# gem "kredis" + +# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] +# gem "bcrypt", "~> 3.1.7" + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] + +# Reduces boot times through caching; required in config/boot.rb +gem "bootsnap", require: false + +# Use Sass to process CSS +# gem "sassc-rails" + +# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] +# gem "image_processing", "~> 1.2" + +group :development, :test do + # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # Use console on exceptions pages [https://github.com/rails/web-console] + gem "web-console" + + # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] + # gem "rack-mini-profiler" + + # Speed up commands on slow machines / big apps [https://github.com/rails/spring] + # gem "spring" +end + +group :test do + # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] + gem "capybara" + gem "selenium-webdriver" + gem "webdrivers" +end diff --git a/week_3/activity-tracker/Gemfile.lock b/week_3/activity-tracker/Gemfile.lock new file mode 100644 index 00000000..2429566c --- /dev/null +++ b/week_3/activity-tracker/Gemfile.lock @@ -0,0 +1,232 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.4) + actionpack (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activesupport (= 7.0.4) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.4) + actionview (= 7.0.4) + activesupport (= 7.0.4) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.4) + actionpack (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.4) + activesupport (= 7.0.4) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.3.6) + activemodel (7.0.4) + activesupport (= 7.0.4) + activerecord (7.0.4) + activemodel (= 7.0.4) + activesupport (= 7.0.4) + activestorage (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activesupport (= 7.0.4) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + bindex (0.8.1) + bootsnap (1.15.0) + msgpack (~> 1.2) + builder (3.2.4) + capybara (3.38.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + concurrent-ruby (1.1.10) + crass (1.0.6) + date (3.3.3) + debug (1.7.1) + irb (>= 1.5.0) + reline (>= 0.3.1) + erubi (1.12.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + importmap-rails (1.1.5) + actionpack (>= 6.0.0) + railties (>= 6.0.0) + io-console (0.6.0) + irb (1.6.2) + reline (>= 0.3.0) + jbuilder (2.11.5) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + loofah (2.19.1) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.8.0.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) + matrix (0.4.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.17.0) + msgpack (1.6.0) + net-imap (0.3.4) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.1) + timeout + net-smtp (0.3.3) + net-protocol + nio4r (2.5.8) + nokogiri (1.14.0-x86_64-linux) + racc (~> 1.4) + public_suffix (5.0.1) + puma (5.6.5) + nio4r (~> 2.0) + racc (1.6.2) + rack (2.2.5) + rack-test (2.0.2) + rack (>= 1.3) + rails (7.0.4) + actioncable (= 7.0.4) + actionmailbox (= 7.0.4) + actionmailer (= 7.0.4) + actionpack (= 7.0.4) + actiontext (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activemodel (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + bundler (>= 1.15.0) + railties (= 7.0.4) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.4) + loofah (~> 2.19, >= 2.19.1) + railties (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + regexp_parser (2.6.1) + reline (0.3.2) + io-console (~> 0.5) + rexml (3.2.5) + rubyzip (2.3.2) + selenium-webdriver (4.7.1) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + sprockets (4.2.0) + concurrent-ruby (~> 1.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + sqlite3 (1.5.4-x86_64-linux) + stimulus-rails (1.2.1) + railties (>= 6.0.0) + thor (1.2.1) + timeout (0.3.1) + turbo-rails (1.3.2) + actionpack (>= 6.0.0) + activejob (>= 6.0.0) + railties (>= 6.0.0) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + webdrivers (5.2.0) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0) + websocket (1.2.9) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.6.6) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + capybara + debug + importmap-rails + jbuilder + puma (~> 5.0) + rails (~> 7.0.4) + selenium-webdriver + sprockets-rails + sqlite3 (~> 1.4) + stimulus-rails + turbo-rails + tzinfo-data + web-console + webdrivers + +RUBY VERSION + ruby 3.0.5p211 + +BUNDLED WITH + 2.2.33 diff --git a/week_3/activity-tracker/README.md b/week_3/activity-tracker/README.md new file mode 100644 index 00000000..169969be --- /dev/null +++ b/week_3/activity-tracker/README.md @@ -0,0 +1,151 @@ +# Creating Tables | Activity Tracker + +We will learn about creating tables in Rails while keeping ourselves fit! + +Tables are the database objects that contain all the data in a database. +In tables, data is locally organized in a row-and-column format similar +to a spreadsheet. Each row represents a unique record and each column +represents a field in the record. + +For example, a table that contains employee data might contain a row for +each employee and columns representing employee information such as +employee number, name, address, job title and phone number. + +Tables are created executing the SQL statement `CREATE TABLE` on the +database. For example: + +```sql +CREATE TABLE employees ( + employee_number INTEGER, + name VARCHAR(80), + address VARCHAR(255), + title VARCHAR(80), + phone_number VARCHAR(10) + salary DECIMAL +); +``` + +In Rails, each table represents a class in `app/models` and creating new +tables is simpler and more convenient, thanks to the generator and +migrations. + +Rails equivalent of the above statement would be: + +```bash +rails generate model Employee employee_number:integer name:string \ +address:string title:string phone_number:string{10} salary:decimal +``` + +For this exercise, we will create a table `activity` with the following +attributes and data-types: +- Title: `string` +- Type: `string` +- Start: `datetime` +- Duration: `decimal` +- Calories: `integer` + +## Steps + +1. ### Prepare Local Database + +- Change directory to activity-tracker + + ```bash + cd activity-tracker + ``` + +- Create the database + ``` + rails db:create + ``` + + You should see two new files are created if not present already - `development.sqlite3` and `test.sqlite3`. + + - Run the migrations + + ```bash + rails db:migrate + ``` + +2. ### Create the tables + Models can be created using Rails generator with the following syntax: + + ```bash + rails generate model NAME field[:type] field[:type]... + ``` + + So for our requirement, execute the following command: + ```bash + rails generate model Activity title:string type:string start:datetime duration:decimal calories:integer + ``` + + > Rails has great emphasis on naming conventions. The model name must be + > `CamelCase` and column names must be `snake_case`. Read about other + > [rails naming conventions](https://gist.github.com/iangreenleaf/b206d09c587e8fc6399e). + + - [Understanding the SQL Decimal data type](https://www.sqlshack.com/understanding-sql-decimal-data-type/) + - [Precision and scale for decimals](https://millarian.com/rails/precision-and-scale-for-ruby-on-rails-migrations/) + + The command creates multiple files - most important of which are + `app/models/activity.rb` and `db/migrate/_create_activities.rb` + + > The number in the beginning of the migration file is a UTC timestamp. + > Rails uses this timestamp to determine which migration should be run + > and in what order. + + The file `db/migrations/_create_activities.rb` looks like: + + ```ruby + class CreateActivities < ActiveRecord::Migration[7.0] + def change + create_table :activities do |t| + t.string :title + t.string :type + t.datetime :start + t.decimal :duration + t.integer :calories + + t.timestamps + end + end + end + ``` + + The migration roughly translates to "create table activities with the five columns and their types described above" which is exactly what we wanted! + The migration also uses the code `t.timestamps` to add timestamps `created_at` and `updated_at` to the activities table automatically. + + - Run the migration. + + ```bash + rails db:migrate + ``` + + > Running the migration commits the changes to the database. Therefore, + > your changes are not reflected in the database unless migrated. + + - Execute the test suite and submit your changes when tests pass. + + ```bash + rails test + ``` + +
+ +## Rolling Back Migrations + +If the migration was incorrect (say wrong column names or datatype), +you can "undo" the migration by the following command: + +```bash +rails db:rollback +``` + +Then, fix the migration file `db/migrations/_create_students.rb` +and re-run the migration to commit your changes to the dabase. + +Read more about migrations at: [Running Migrations | Active Record Migrations](https://edgeguides.rubyonrails.org/active_record_migrations.html#rolling-back) + +
+ +## References +- [Rails Active Record Migration](https://guides.rubyonrails.org/active_record_migrations.html) diff --git a/week_3/activity-tracker/Rakefile b/week_3/activity-tracker/Rakefile new file mode 100644 index 00000000..9a5ea738 --- /dev/null +++ b/week_3/activity-tracker/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative "config/application" + +Rails.application.load_tasks diff --git a/week_3/activity-tracker/app/assets/config/manifest.js b/week_3/activity-tracker/app/assets/config/manifest.js new file mode 100644 index 00000000..ddd546a0 --- /dev/null +++ b/week_3/activity-tracker/app/assets/config/manifest.js @@ -0,0 +1,4 @@ +//= link_tree ../images +//= link_directory ../stylesheets .css +//= link_tree ../../javascript .js +//= link_tree ../../../vendor/javascript .js diff --git a/week_3/activity-tracker/app/assets/images/.keep b/week_3/activity-tracker/app/assets/images/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/app/assets/stylesheets/application.css b/week_3/activity-tracker/app/assets/stylesheets/application.css new file mode 100644 index 00000000..288b9ab7 --- /dev/null +++ b/week_3/activity-tracker/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/week_3/activity-tracker/app/channels/application_cable/channel.rb b/week_3/activity-tracker/app/channels/application_cable/channel.rb new file mode 100644 index 00000000..d6726972 --- /dev/null +++ b/week_3/activity-tracker/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/week_3/activity-tracker/app/channels/application_cable/connection.rb b/week_3/activity-tracker/app/channels/application_cable/connection.rb new file mode 100644 index 00000000..0ff5442f --- /dev/null +++ b/week_3/activity-tracker/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/week_3/activity-tracker/app/controllers/application_controller.rb b/week_3/activity-tracker/app/controllers/application_controller.rb new file mode 100644 index 00000000..09705d12 --- /dev/null +++ b/week_3/activity-tracker/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/week_3/activity-tracker/app/controllers/concerns/.keep b/week_3/activity-tracker/app/controllers/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/app/helpers/application_helper.rb b/week_3/activity-tracker/app/helpers/application_helper.rb new file mode 100644 index 00000000..de6be794 --- /dev/null +++ b/week_3/activity-tracker/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/week_3/activity-tracker/app/javascript/application.js b/week_3/activity-tracker/app/javascript/application.js new file mode 100644 index 00000000..0d7b4940 --- /dev/null +++ b/week_3/activity-tracker/app/javascript/application.js @@ -0,0 +1,3 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +import "@hotwired/turbo-rails" +import "controllers" diff --git a/week_3/activity-tracker/app/javascript/controllers/application.js b/week_3/activity-tracker/app/javascript/controllers/application.js new file mode 100644 index 00000000..1213e85c --- /dev/null +++ b/week_3/activity-tracker/app/javascript/controllers/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +// Configure Stimulus development experience +application.debug = false +window.Stimulus = application + +export { application } diff --git a/week_3/activity-tracker/app/javascript/controllers/hello_controller.js b/week_3/activity-tracker/app/javascript/controllers/hello_controller.js new file mode 100644 index 00000000..5975c078 --- /dev/null +++ b/week_3/activity-tracker/app/javascript/controllers/hello_controller.js @@ -0,0 +1,7 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + this.element.textContent = "Hello World!" + } +} diff --git a/week_3/activity-tracker/app/javascript/controllers/index.js b/week_3/activity-tracker/app/javascript/controllers/index.js new file mode 100644 index 00000000..54ad4cad --- /dev/null +++ b/week_3/activity-tracker/app/javascript/controllers/index.js @@ -0,0 +1,11 @@ +// Import and register all your controllers from the importmap under controllers/* + +import { application } from "controllers/application" + +// Eager load all controllers defined in the import map under controllers/**/*_controller +import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +eagerLoadControllersFrom("controllers", application) + +// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!) +// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading" +// lazyLoadControllersFrom("controllers", application) diff --git a/week_3/activity-tracker/app/jobs/application_job.rb b/week_3/activity-tracker/app/jobs/application_job.rb new file mode 100644 index 00000000..d394c3d1 --- /dev/null +++ b/week_3/activity-tracker/app/jobs/application_job.rb @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/week_3/activity-tracker/app/mailers/application_mailer.rb b/week_3/activity-tracker/app/mailers/application_mailer.rb new file mode 100644 index 00000000..3c34c814 --- /dev/null +++ b/week_3/activity-tracker/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/week_3/activity-tracker/app/models/application_record.rb b/week_3/activity-tracker/app/models/application_record.rb new file mode 100644 index 00000000..b63caeb8 --- /dev/null +++ b/week_3/activity-tracker/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/week_3/activity-tracker/app/models/concerns/.keep b/week_3/activity-tracker/app/models/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/app/views/layouts/application.html.erb b/week_3/activity-tracker/app/views/layouts/application.html.erb new file mode 100644 index 00000000..5f65d83d --- /dev/null +++ b/week_3/activity-tracker/app/views/layouts/application.html.erb @@ -0,0 +1,16 @@ + + + + ActivityTracker + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> + <%= javascript_importmap_tags %> + + + + <%= yield %> + + diff --git a/week_3/activity-tracker/app/views/layouts/mailer.html.erb b/week_3/activity-tracker/app/views/layouts/mailer.html.erb new file mode 100644 index 00000000..cbd34d2e --- /dev/null +++ b/week_3/activity-tracker/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/week_3/activity-tracker/app/views/layouts/mailer.text.erb b/week_3/activity-tracker/app/views/layouts/mailer.text.erb new file mode 100644 index 00000000..37f0bddb --- /dev/null +++ b/week_3/activity-tracker/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/week_3/activity-tracker/bin/bundle b/week_3/activity-tracker/bin/bundle new file mode 100755 index 00000000..374a0a1f --- /dev/null +++ b/week_3/activity-tracker/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/week_3/activity-tracker/bin/importmap b/week_3/activity-tracker/bin/importmap new file mode 100755 index 00000000..36502ab1 --- /dev/null +++ b/week_3/activity-tracker/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/week_3/activity-tracker/bin/rails b/week_3/activity-tracker/bin/rails new file mode 100755 index 00000000..efc03774 --- /dev/null +++ b/week_3/activity-tracker/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/week_3/activity-tracker/bin/rake b/week_3/activity-tracker/bin/rake new file mode 100755 index 00000000..4fbf10b9 --- /dev/null +++ b/week_3/activity-tracker/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/week_3/activity-tracker/bin/setup b/week_3/activity-tracker/bin/setup new file mode 100755 index 00000000..ec47b79b --- /dev/null +++ b/week_3/activity-tracker/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/week_3/activity-tracker/config.ru b/week_3/activity-tracker/config.ru new file mode 100644 index 00000000..4a3c09a6 --- /dev/null +++ b/week_3/activity-tracker/config.ru @@ -0,0 +1,6 @@ +# This file is used by Rack-based servers to start the application. + +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/week_3/activity-tracker/config/application.rb b/week_3/activity-tracker/config/application.rb new file mode 100644 index 00000000..eaab4107 --- /dev/null +++ b/week_3/activity-tracker/config/application.rb @@ -0,0 +1,22 @@ +require_relative "boot" + +require "rails/all" + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module ActivityTracker + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 7.0 + + # Configuration for the application, engines, and railties goes here. + # + # These settings can be overridden in specific environments using the files + # in config/environments, which are processed later. + # + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + end +end diff --git a/week_3/activity-tracker/config/boot.rb b/week_3/activity-tracker/config/boot.rb new file mode 100644 index 00000000..988a5ddc --- /dev/null +++ b/week_3/activity-tracker/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" # Set up gems listed in the Gemfile. +require "bootsnap/setup" # Speed up boot time by caching expensive operations. diff --git a/week_3/activity-tracker/config/cable.yml b/week_3/activity-tracker/config/cable.yml new file mode 100644 index 00000000..fc223da2 --- /dev/null +++ b/week_3/activity-tracker/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: activity_tracker_production diff --git a/week_3/activity-tracker/config/credentials.yml.enc b/week_3/activity-tracker/config/credentials.yml.enc new file mode 100644 index 00000000..4410c9ad --- /dev/null +++ b/week_3/activity-tracker/config/credentials.yml.enc @@ -0,0 +1 @@ +vy9Yyajw1b8PCBzOL90ahf4dlXAdev9jaGcu43MsIEltJ9tLudTQHZhztOYwXgig6D1/W6vai5IQKKPbfBCioSi0cdsXraMUQpVx6wPgHjU4CRMYm5gbMJ8MoGpTTRO3546ceKYioiXoAtBnnM6jyHlqdqPm/xIND5SfytLSBOJrUxg8v06TISxfhIbRlGneBeEV7I8HcrBC2ulCNToXou0oojijWGkCUYjFV/0452pmrHDX+HC4Psc252O0H7emGpqjh6puxAV6aYmiNU3cvqNjUQXxHmaH7N1jgAnR/5xB1bwZHKUB7ngTufyFzt+3ZQg5UCbuuJ+4f8lSGbrJUKNJjpVVwW5jNrRCrDm8ZMbvHCus2ApGtHu/vVjxw5bo3hWda83vQhVcBI74bNo5JnbzuKNhmQi8VEHm--ByL641PQMhBRCAI2--Mnwv25FxL4SSK6RIuW8L1Q== \ No newline at end of file diff --git a/week_3/activity-tracker/config/database.yml b/week_3/activity-tracker/config/database.yml new file mode 100644 index 00000000..fcba57f1 --- /dev/null +++ b/week_3/activity-tracker/config/database.yml @@ -0,0 +1,25 @@ +# SQLite. Versions 3.8.0 and up are supported. +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem "sqlite3" +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/week_3/activity-tracker/config/environment.rb b/week_3/activity-tracker/config/environment.rb new file mode 100644 index 00000000..cac53157 --- /dev/null +++ b/week_3/activity-tracker/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative "application" + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/week_3/activity-tracker/config/environments/development.rb b/week_3/activity-tracker/config/environments/development.rb new file mode 100644 index 00000000..f2a3adc8 --- /dev/null +++ b/week_3/activity-tracker/config/environments/development.rb @@ -0,0 +1,72 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable server timing + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + config.hosts << "mittal-parth-animated-cod-gpxgvr5gwp62v4v5-3000.preview.app.github.dev" + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true +end diff --git a/week_3/activity-tracker/config/environments/production.rb b/week_3/activity-tracker/config/environments/production.rb new file mode 100644 index 00000000..86a19e32 --- /dev/null +++ b/week_3/activity-tracker/config/environments/production.rb @@ -0,0 +1,93 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "activity_tracker_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/week_3/activity-tracker/config/environments/test.rb b/week_3/activity-tracker/config/environments/test.rb new file mode 100644 index 00000000..6ea4d1e7 --- /dev/null +++ b/week_3/activity-tracker/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/week_3/activity-tracker/config/importmap.rb b/week_3/activity-tracker/config/importmap.rb new file mode 100644 index 00000000..8dce42d4 --- /dev/null +++ b/week_3/activity-tracker/config/importmap.rb @@ -0,0 +1,7 @@ +# Pin npm packages by running ./bin/importmap + +pin "application", preload: true +pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true +pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true +pin_all_from "app/javascript/controllers", under: "controllers" diff --git a/week_3/activity-tracker/config/initializers/assets.rb b/week_3/activity-tracker/config/initializers/assets.rb new file mode 100644 index 00000000..2eeef966 --- /dev/null +++ b/week_3/activity-tracker/config/initializers/assets.rb @@ -0,0 +1,12 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = "1.0" + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/week_3/activity-tracker/config/initializers/content_security_policy.rb b/week_3/activity-tracker/config/initializers/content_security_policy.rb new file mode 100644 index 00000000..54f47cf1 --- /dev/null +++ b/week_3/activity-tracker/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header + +# Rails.application.configure do +# config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end +# +# # Generate session nonces for permitted importmap and inline scripts +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true +# end diff --git a/week_3/activity-tracker/config/initializers/filter_parameter_logging.rb b/week_3/activity-tracker/config/initializers/filter_parameter_logging.rb new file mode 100644 index 00000000..adc6568c --- /dev/null +++ b/week_3/activity-tracker/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/week_3/activity-tracker/config/initializers/inflections.rb b/week_3/activity-tracker/config/initializers/inflections.rb new file mode 100644 index 00000000..3860f659 --- /dev/null +++ b/week_3/activity-tracker/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/week_3/activity-tracker/config/initializers/permissions_policy.rb b/week_3/activity-tracker/config/initializers/permissions_policy.rb new file mode 100644 index 00000000..00f64d71 --- /dev/null +++ b/week_3/activity-tracker/config/initializers/permissions_policy.rb @@ -0,0 +1,11 @@ +# Define an application-wide HTTP permissions policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.permissions_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/week_3/activity-tracker/config/locales/en.yml b/week_3/activity-tracker/config/locales/en.yml new file mode 100644 index 00000000..8ca56fc7 --- /dev/null +++ b/week_3/activity-tracker/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/week_3/activity-tracker/config/master.key b/week_3/activity-tracker/config/master.key new file mode 100644 index 00000000..3e69d63e --- /dev/null +++ b/week_3/activity-tracker/config/master.key @@ -0,0 +1 @@ +7ffae4e43de01027f283f3630db4227c \ No newline at end of file diff --git a/week_3/activity-tracker/config/puma.rb b/week_3/activity-tracker/config/puma.rb new file mode 100644 index 00000000..daaf0369 --- /dev/null +++ b/week_3/activity-tracker/config/puma.rb @@ -0,0 +1,43 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +# Specifies the `worker_timeout` threshold that Puma will use to wait before +# terminating a worker in development environments. +# +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked web server processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart diff --git a/week_3/activity-tracker/config/routes.rb b/week_3/activity-tracker/config/routes.rb new file mode 100644 index 00000000..262ffd54 --- /dev/null +++ b/week_3/activity-tracker/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + # Defines the root path route ("/") + # root "articles#index" +end diff --git a/week_3/activity-tracker/config/storage.yml b/week_3/activity-tracker/config/storage.yml new file mode 100644 index 00000000..4942ab66 --- /dev/null +++ b/week_3/activity-tracker/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/week_3/activity-tracker/db/seeds.rb b/week_3/activity-tracker/db/seeds.rb new file mode 100644 index 00000000..bc25fce3 --- /dev/null +++ b/week_3/activity-tracker/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). +# +# Examples: +# +# movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) +# Character.create(name: "Luke", movie: movies.first) diff --git a/week_3/activity-tracker/lib/assets/.keep b/week_3/activity-tracker/lib/assets/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/lib/tasks/.keep b/week_3/activity-tracker/lib/tasks/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/public/404.html b/week_3/activity-tracker/public/404.html new file mode 100644 index 00000000..2be3af26 --- /dev/null +++ b/week_3/activity-tracker/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
+
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_3/activity-tracker/public/422.html b/week_3/activity-tracker/public/422.html new file mode 100644 index 00000000..c08eac0d --- /dev/null +++ b/week_3/activity-tracker/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
+
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_3/activity-tracker/public/500.html b/week_3/activity-tracker/public/500.html new file mode 100644 index 00000000..78a030af --- /dev/null +++ b/week_3/activity-tracker/public/500.html @@ -0,0 +1,66 @@ + + + + We're sorry, but something went wrong (500) + + + + + + +
+
+

We're sorry, but something went wrong.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_3/activity-tracker/public/apple-touch-icon-precomposed.png b/week_3/activity-tracker/public/apple-touch-icon-precomposed.png new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/public/apple-touch-icon.png b/week_3/activity-tracker/public/apple-touch-icon.png new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/public/favicon.ico b/week_3/activity-tracker/public/favicon.ico new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/public/robots.txt b/week_3/activity-tracker/public/robots.txt new file mode 100644 index 00000000..c19f78ab --- /dev/null +++ b/week_3/activity-tracker/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/week_3/activity-tracker/storage/.keep b/week_3/activity-tracker/storage/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/application_system_test_case.rb b/week_3/activity-tracker/test/application_system_test_case.rb new file mode 100644 index 00000000..d19212ab --- /dev/null +++ b/week_3/activity-tracker/test/application_system_test_case.rb @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/week_3/activity-tracker/test/channels/application_cable/connection_test.rb b/week_3/activity-tracker/test/channels/application_cable/connection_test.rb new file mode 100644 index 00000000..800405f1 --- /dev/null +++ b/week_3/activity-tracker/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/week_3/activity-tracker/test/controllers/.keep b/week_3/activity-tracker/test/controllers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/fixtures/files/.keep b/week_3/activity-tracker/test/fixtures/files/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/helpers/.keep b/week_3/activity-tracker/test/helpers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/integration/.keep b/week_3/activity-tracker/test/integration/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/mailers/.keep b/week_3/activity-tracker/test/mailers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/models/.keep b/week_3/activity-tracker/test/models/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/models/activity_model_test.rb b/week_3/activity-tracker/test/models/activity_model_test.rb new file mode 100644 index 00000000..9af6029e --- /dev/null +++ b/week_3/activity-tracker/test/models/activity_model_test.rb @@ -0,0 +1,23 @@ +require "test_helper" + +class ActivityTest < ActiveSupport::TestCase + test 'has a string column title' do + assert_equal :string, Activity.type_for_attribute('title').type + end + + test 'has a string column type' do + assert_equal :string, Activity.type_for_attribute('type').type + end + + test 'has a datetime column start' do + assert_equal :datetime, Activity.type_for_attribute('start').type + end + + test 'has a decimal column duration' do + assert_equal :decimal, Activity.type_for_attribute('duration').type + end + + test 'has an integer column calories' do + assert_equal :integer, Activity.type_for_attribute('calories').type + end +end \ No newline at end of file diff --git a/week_3/activity-tracker/test/models/activity_test.rb b/week_3/activity-tracker/test/models/activity_test.rb new file mode 100644 index 00000000..c07a8b91 --- /dev/null +++ b/week_3/activity-tracker/test/models/activity_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ActivityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/week_3/activity-tracker/test/system/.keep b/week_3/activity-tracker/test/system/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/test/test_helper.rb b/week_3/activity-tracker/test/test_helper.rb new file mode 100644 index 00000000..d713e377 --- /dev/null +++ b/week_3/activity-tracker/test/test_helper.rb @@ -0,0 +1,13 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + # Run tests in parallel with specified workers + parallelize(workers: :number_of_processors) + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + fixtures :all + + # Add more helper methods to be used by all tests here... +end diff --git a/week_3/activity-tracker/vendor/.keep b/week_3/activity-tracker/vendor/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/activity-tracker/vendor/javascript/.keep b/week_3/activity-tracker/vendor/javascript/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_3/getting_started_with_rails.md b/week_3/getting_started_with_rails.md new file mode 100644 index 00000000..453ed55f --- /dev/null +++ b/week_3/getting_started_with_rails.md @@ -0,0 +1,82 @@ + +## Steps +- [Set Up Local Workplace](../setup/) + +- Create a new [gemset](../setup/README.md#RVM) and install rails +```bash +cd week_3 +rvm gemset create week_3 +rvm use 3.0.5@week_3 +gem install rails --version 7.0.4 +``` + +- Create a new Rails project `hello_world` in the directory `week_1` +```bash +rails new hello_world --css=bootstrap --skip-git +cd hello_world +rvm use 3.0.5@week_3 +``` + +> The command `rails new` initialises a Rails project. We have passed +> the flag `--skip-git` to avoid initializing Git again as we are +> already within a Git repository. + +- Run the rails server using below command and go to http://localhost:3000/. +```bash +rails server +``` + +You should see the rails logo. + +### Add a controller + +- Generate a new controller `PageController` with actions `root` and + `about_me`: + +```bash +rails generate controller Page root about_me +``` + +> A _controller_ is responsible for making sense of request and producing +> the appropriate output. It acts as a middleman between the Data +> (Model) and Presentation (View). Controllers are stored in +> `app/controllers` directory. + + +> The generator creates the files and fills it with some default code. +> the above command creates a controller +> `PagesController`, creates new view files `root.html.erb` and +> `about_me.html.erb` and modifies the routes file + +- Edit the routes file (`config/routes.rb`) as follow to add new routes: + +```ruby +Rails.application.routes.draw do + get '/', to: 'page#root' + get 'about_me', to: 'page#about_me' +end +``` + +The routes file specifies the URLs that are recognized by the application. + +- Edit the view files `app/views/page/root.html.erb` and `app/views/page/about_me.html.erb`. + +- You should be able to see see your changes at `http://localhost:3000` and + `http://localhost:3000/about_me`. + +![image](https://user-images.githubusercontent.com/66632353/211770375-4cc14806-7e60-4135-9e40-7b73e3c4ed23.png) +![image](https://user-images.githubusercontent.com/66632353/211770741-56dfaea8-2095-474b-974a-2b151953a3de.png) + +- Copy the test file from week_3 directory to hello_world/test/controllers: +```bash +cp page_controller_test.rb hello_world/test/controllers +``` + +- Execute the test suite to ensure the page works as expected. + +```bash +rails test +``` +- If the test fails, check the view files and debug the application. + +- Once the test works locally, submit your changes. \ No newline at end of file From c6dea6820595eb3621bce718bde27e491f39c4c8 Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Wed, 18 Jan 2023 21:16:48 +0530 Subject: [PATCH 29/34] Update README.md --- week_3/football/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/week_3/football/README.md b/week_3/football/README.md index b6e1a06c..9871d3b8 100644 --- a/week_3/football/README.md +++ b/week_3/football/README.md @@ -75,6 +75,9 @@ rails db:fixtures:load ``` This adds some sample data(/test/fixtures/football_players.yml) to the database. +## Assignment +> For this assignment you have to implement the function inside [app/models/football_player.rb](https://github.com/IRIS-NITK/IRIS-RoR-Bootcamp-2022/blob/main/week_3/football/app/models/football_player.rb) + ### Creating Records The INSERT INTO statement is used to insert new records in a table From 4db1b661b10dff687b325f3005f9d2c4b287ac0f Mon Sep 17 00:00:00 2001 From: Hrushikesh <66632353+hrushikeshj@users.noreply.github.com> Date: Wed, 18 Jan 2023 21:40:50 +0530 Subject: [PATCH 30/34] Update README.md --- week_3/football/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/week_3/football/README.md b/week_3/football/README.md index 9871d3b8..c642794a 100644 --- a/week_3/football/README.md +++ b/week_3/football/README.md @@ -220,6 +220,12 @@ FootballPlayer.find_by(name: "Messi").destroy - [DELETE | ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html#delete) +Once you start implementing functions in app/models/football_player.rb, you can test your code. + +```bash +rails test:models +``` + # Rails console The Rails console is useful for testing out quick ideas with code and debugging applications. From a02d6d9add6aa393e76b40e1d7fcf6ccaea0ffd7 Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Sun, 29 Jan 2023 21:18:27 +0530 Subject: [PATCH 31/34] Add Week 4 Resources (#113) Added week 4 resources - controllers and devise. Co-authored-by: Anirudh Prabhakaran --- .github/workflows/week4_assignement.yml | 35 +++ week_4/README.md | 17 ++ week_4/activity-tracker/.ruby-version | 1 + week_4/activity-tracker/.tool-versions | 2 + week_4/activity-tracker/Gemfile | 74 ++++++ week_4/activity-tracker/Gemfile.lock | 237 ++++++++++++++++++ week_4/activity-tracker/README.md | 151 +++++++++++ week_4/activity-tracker/Rakefile | 6 + .../app/assets/config/manifest.js | 4 + .../activity-tracker/app/assets/images/.keep | 0 .../app/assets/stylesheets/application.css | 15 ++ .../app/channels/application_cable/channel.rb | 4 + .../channels/application_cable/connection.rb | 4 + .../app/controllers/activities_controller.rb | 70 ++++++ .../app/controllers/application_controller.rb | 2 + .../app/controllers/concerns/.keep | 0 .../app/helpers/activities_helper.rb | 2 + .../app/helpers/application_helper.rb | 2 + .../app/javascript/application.js | 3 + .../app/javascript/controllers/application.js | 9 + .../controllers/hello_controller.js | 7 + .../app/javascript/controllers/index.js | 11 + .../app/jobs/application_job.rb | 7 + .../app/mailers/application_mailer.rb | 4 + .../activity-tracker/app/models/activity.rb | 2 + .../app/models/application_record.rb | 3 + .../app/models/concerns/.keep | 0 .../app/views/activities/_activity.html.erb | 27 ++ .../views/activities/_activity.json.jbuilder | 2 + .../app/views/activities/_form.html.erb | 42 ++++ .../app/views/activities/edit.html.erb | 10 + .../app/views/activities/index.html.erb | 14 ++ .../app/views/activities/index.json.jbuilder | 1 + .../app/views/activities/new.html.erb | 9 + .../app/views/activities/show.html.erb | 10 + .../app/views/activities/show.json.jbuilder | 1 + .../app/views/activities/stats.html.erb | 0 .../app/views/layouts/application.html.erb | 16 ++ .../app/views/layouts/mailer.html.erb | 13 + .../app/views/layouts/mailer.text.erb | 1 + week_4/activity-tracker/authentication.md | 31 +++ week_4/activity-tracker/bin/bundle | 114 +++++++++ week_4/activity-tracker/bin/importmap | 4 + week_4/activity-tracker/bin/rails | 4 + week_4/activity-tracker/bin/rake | 4 + week_4/activity-tracker/bin/setup | 33 +++ week_4/activity-tracker/config.ru | 6 + week_4/activity-tracker/config/application.rb | 22 ++ week_4/activity-tracker/config/boot.rb | 4 + week_4/activity-tracker/config/cable.yml | 10 + .../config/credentials.yml.enc | 1 + week_4/activity-tracker/config/database.yml | 25 ++ week_4/activity-tracker/config/environment.rb | 5 + .../config/environments/development.rb | 72 ++++++ .../config/environments/production.rb | 93 +++++++ .../config/environments/test.rb | 60 +++++ week_4/activity-tracker/config/importmap.rb | 7 + .../config/initializers/assets.rb | 12 + .../initializers/content_security_policy.rb | 25 ++ .../initializers/filter_parameter_logging.rb | 8 + .../config/initializers/inflections.rb | 16 ++ .../config/initializers/permissions_policy.rb | 11 + week_4/activity-tracker/config/locales/en.yml | 33 +++ week_4/activity-tracker/config/master.key | 1 + week_4/activity-tracker/config/puma.rb | 43 ++++ week_4/activity-tracker/config/routes.rb | 8 + week_4/activity-tracker/config/storage.yml | 34 +++ .../20230127184553_create_activities.rb | 13 + week_4/activity-tracker/db/schema.rb | 24 ++ week_4/activity-tracker/db/seeds.rb | 7 + week_4/activity-tracker/lib/assets/.keep | 0 week_4/activity-tracker/lib/tasks/.keep | 0 week_4/activity-tracker/public/404.html | 67 +++++ week_4/activity-tracker/public/422.html | 67 +++++ week_4/activity-tracker/public/500.html | 66 +++++ .../public/apple-touch-icon-precomposed.png | 0 .../public/apple-touch-icon.png | 0 week_4/activity-tracker/public/favicon.ico | 0 week_4/activity-tracker/public/robots.txt | 1 + week_4/activity-tracker/storage/.keep | 0 .../test/application_system_test_case.rb | 5 + .../application_cable/connection_test.rb | 11 + .../activity-tracker/test/controllers/.keep | 0 .../controllers/activities_controller_test.rb | 59 +++++ .../test/fixtures/activities.yml | 15 ++ .../test/fixtures/files/.keep | 0 week_4/activity-tracker/test/helpers/.keep | 0 .../activity-tracker/test/integration/.keep | 0 week_4/activity-tracker/test/mailers/.keep | 0 week_4/activity-tracker/test/models/.keep | 0 .../test/models/activity_model_test.rb | 23 ++ .../test/models/activity_test.rb | 7 + week_4/activity-tracker/test/system/.keep | 0 .../test/system/activities_test.rb | 49 ++++ week_4/activity-tracker/test/test_helper.rb | 13 + week_4/activity-tracker/vendor/.keep | 0 .../activity-tracker/vendor/javascript/.keep | 0 97 files changed, 1931 insertions(+) create mode 100644 .github/workflows/week4_assignement.yml create mode 100644 week_4/README.md create mode 100644 week_4/activity-tracker/.ruby-version create mode 100644 week_4/activity-tracker/.tool-versions create mode 100644 week_4/activity-tracker/Gemfile create mode 100644 week_4/activity-tracker/Gemfile.lock create mode 100644 week_4/activity-tracker/README.md create mode 100644 week_4/activity-tracker/Rakefile create mode 100644 week_4/activity-tracker/app/assets/config/manifest.js create mode 100644 week_4/activity-tracker/app/assets/images/.keep create mode 100644 week_4/activity-tracker/app/assets/stylesheets/application.css create mode 100644 week_4/activity-tracker/app/channels/application_cable/channel.rb create mode 100644 week_4/activity-tracker/app/channels/application_cable/connection.rb create mode 100644 week_4/activity-tracker/app/controllers/activities_controller.rb create mode 100644 week_4/activity-tracker/app/controllers/application_controller.rb create mode 100644 week_4/activity-tracker/app/controllers/concerns/.keep create mode 100644 week_4/activity-tracker/app/helpers/activities_helper.rb create mode 100644 week_4/activity-tracker/app/helpers/application_helper.rb create mode 100644 week_4/activity-tracker/app/javascript/application.js create mode 100644 week_4/activity-tracker/app/javascript/controllers/application.js create mode 100644 week_4/activity-tracker/app/javascript/controllers/hello_controller.js create mode 100644 week_4/activity-tracker/app/javascript/controllers/index.js create mode 100644 week_4/activity-tracker/app/jobs/application_job.rb create mode 100644 week_4/activity-tracker/app/mailers/application_mailer.rb create mode 100644 week_4/activity-tracker/app/models/activity.rb create mode 100644 week_4/activity-tracker/app/models/application_record.rb create mode 100644 week_4/activity-tracker/app/models/concerns/.keep create mode 100644 week_4/activity-tracker/app/views/activities/_activity.html.erb create mode 100644 week_4/activity-tracker/app/views/activities/_activity.json.jbuilder create mode 100644 week_4/activity-tracker/app/views/activities/_form.html.erb create mode 100644 week_4/activity-tracker/app/views/activities/edit.html.erb create mode 100644 week_4/activity-tracker/app/views/activities/index.html.erb create mode 100644 week_4/activity-tracker/app/views/activities/index.json.jbuilder create mode 100644 week_4/activity-tracker/app/views/activities/new.html.erb create mode 100644 week_4/activity-tracker/app/views/activities/show.html.erb create mode 100644 week_4/activity-tracker/app/views/activities/show.json.jbuilder create mode 100644 week_4/activity-tracker/app/views/activities/stats.html.erb create mode 100644 week_4/activity-tracker/app/views/layouts/application.html.erb create mode 100644 week_4/activity-tracker/app/views/layouts/mailer.html.erb create mode 100644 week_4/activity-tracker/app/views/layouts/mailer.text.erb create mode 100644 week_4/activity-tracker/authentication.md create mode 100755 week_4/activity-tracker/bin/bundle create mode 100755 week_4/activity-tracker/bin/importmap create mode 100755 week_4/activity-tracker/bin/rails create mode 100755 week_4/activity-tracker/bin/rake create mode 100755 week_4/activity-tracker/bin/setup create mode 100644 week_4/activity-tracker/config.ru create mode 100644 week_4/activity-tracker/config/application.rb create mode 100644 week_4/activity-tracker/config/boot.rb create mode 100644 week_4/activity-tracker/config/cable.yml create mode 100644 week_4/activity-tracker/config/credentials.yml.enc create mode 100644 week_4/activity-tracker/config/database.yml create mode 100644 week_4/activity-tracker/config/environment.rb create mode 100644 week_4/activity-tracker/config/environments/development.rb create mode 100644 week_4/activity-tracker/config/environments/production.rb create mode 100644 week_4/activity-tracker/config/environments/test.rb create mode 100644 week_4/activity-tracker/config/importmap.rb create mode 100644 week_4/activity-tracker/config/initializers/assets.rb create mode 100644 week_4/activity-tracker/config/initializers/content_security_policy.rb create mode 100644 week_4/activity-tracker/config/initializers/filter_parameter_logging.rb create mode 100644 week_4/activity-tracker/config/initializers/inflections.rb create mode 100644 week_4/activity-tracker/config/initializers/permissions_policy.rb create mode 100644 week_4/activity-tracker/config/locales/en.yml create mode 100644 week_4/activity-tracker/config/master.key create mode 100644 week_4/activity-tracker/config/puma.rb create mode 100644 week_4/activity-tracker/config/routes.rb create mode 100644 week_4/activity-tracker/config/storage.yml create mode 100644 week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb create mode 100644 week_4/activity-tracker/db/schema.rb create mode 100644 week_4/activity-tracker/db/seeds.rb create mode 100644 week_4/activity-tracker/lib/assets/.keep create mode 100644 week_4/activity-tracker/lib/tasks/.keep create mode 100644 week_4/activity-tracker/public/404.html create mode 100644 week_4/activity-tracker/public/422.html create mode 100644 week_4/activity-tracker/public/500.html create mode 100644 week_4/activity-tracker/public/apple-touch-icon-precomposed.png create mode 100644 week_4/activity-tracker/public/apple-touch-icon.png create mode 100644 week_4/activity-tracker/public/favicon.ico create mode 100644 week_4/activity-tracker/public/robots.txt create mode 100644 week_4/activity-tracker/storage/.keep create mode 100644 week_4/activity-tracker/test/application_system_test_case.rb create mode 100644 week_4/activity-tracker/test/channels/application_cable/connection_test.rb create mode 100644 week_4/activity-tracker/test/controllers/.keep create mode 100644 week_4/activity-tracker/test/controllers/activities_controller_test.rb create mode 100644 week_4/activity-tracker/test/fixtures/activities.yml create mode 100644 week_4/activity-tracker/test/fixtures/files/.keep create mode 100644 week_4/activity-tracker/test/helpers/.keep create mode 100644 week_4/activity-tracker/test/integration/.keep create mode 100644 week_4/activity-tracker/test/mailers/.keep create mode 100644 week_4/activity-tracker/test/models/.keep create mode 100644 week_4/activity-tracker/test/models/activity_model_test.rb create mode 100644 week_4/activity-tracker/test/models/activity_test.rb create mode 100644 week_4/activity-tracker/test/system/.keep create mode 100644 week_4/activity-tracker/test/system/activities_test.rb create mode 100644 week_4/activity-tracker/test/test_helper.rb create mode 100644 week_4/activity-tracker/vendor/.keep create mode 100644 week_4/activity-tracker/vendor/javascript/.keep diff --git a/.github/workflows/week4_assignement.yml b/.github/workflows/week4_assignement.yml new file mode 100644 index 00000000..12291a77 --- /dev/null +++ b/.github/workflows/week4_assignement.yml @@ -0,0 +1,35 @@ +name: 'Week 3 Model' + +on: + pull_request: + types: [synchronize, opened, reopened, edited] + branches: + - 'week4_*' + + workflow_dispatch: + +jobs: + week3_model: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + working-directory: week_4/activity-tracker + bundler-cache: true + + - name: Install NPM packages + uses: bahmutov/npm-install@v1 + with: + working-directory: week_4/activity-tracker + + - name: Test Controller Actions + working-directory: week_4/activity-tracker + run: | + bundle exec rails db:create + bundle exec rails db:migrate + bundle exec rails test diff --git a/week_4/README.md b/week_4/README.md new file mode 100644 index 00000000..c322665f --- /dev/null +++ b/week_4/README.md @@ -0,0 +1,17 @@ +# Week 4 + +Hello! Hope you are having a wonderful time at the bootcamp. For this week, we will look into controllers, routing and authentication. You can find the links to the documents below. + +- [Controllers](./activity-tracker/README.md) +- [Authentication](./activity-tracker/authentication.md) + +## Assignement 1 +After going through the resource on controllers, it is time to make your own! Create a contoller action called `stats` that is invoked from the URL `/activities/stats/`. This controller action should define at least two *instance variables*: + +- `total_duration`: The total duration of all activity logged. +- `total_calories`: The total amount of calories burnt. + +Please ensure that you are able to access the URL from a browser. Also make sure that the variables are named **exactly** that. + +## Assignment 2 +Now that you have a functioning app ready, you need to protect it. You can't have anyone in the world access your activity logs, right? The task is simple - setup authentication! diff --git a/week_4/activity-tracker/.ruby-version b/week_4/activity-tracker/.ruby-version new file mode 100644 index 00000000..316881c9 --- /dev/null +++ b/week_4/activity-tracker/.ruby-version @@ -0,0 +1 @@ +ruby-3.0.5 diff --git a/week_4/activity-tracker/.tool-versions b/week_4/activity-tracker/.tool-versions new file mode 100644 index 00000000..4f7cf395 --- /dev/null +++ b/week_4/activity-tracker/.tool-versions @@ -0,0 +1,2 @@ +nodejs lts +ruby 3.0.5 diff --git a/week_4/activity-tracker/Gemfile b/week_4/activity-tracker/Gemfile new file mode 100644 index 00000000..413b15ae --- /dev/null +++ b/week_4/activity-tracker/Gemfile @@ -0,0 +1,74 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "3.0.5" + +# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" +gem "rails", "~> 7.0.4" + +# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] +gem "sprockets-rails" + +# Use sqlite3 as the database for Active Record +gem "sqlite3", "~> 1.4" + +# Use the Puma web server [https://github.com/puma/puma] +gem "puma", "~> 5.0" + +# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] +gem "importmap-rails" + +# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] +gem "turbo-rails" + +# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] +gem "stimulus-rails" + +# Build JSON APIs with ease [https://github.com/rails/jbuilder] +gem "jbuilder" + +# Use Redis adapter to run Action Cable in production +# gem "redis", "~> 4.0" + +# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] +# gem "kredis" + +# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] +# gem "bcrypt", "~> 3.1.7" + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] + +# Reduces boot times through caching; required in config/boot.rb +gem "bootsnap", require: false + +# Use Sass to process CSS +# gem "sassc-rails" + +# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] +# gem "image_processing", "~> 1.2" + +group :development, :test do + # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # Use console on exceptions pages [https://github.com/rails/web-console] + gem "web-console" + + # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] + # gem "rack-mini-profiler" + + # Speed up commands on slow machines / big apps [https://github.com/rails/spring] + # gem "spring" +end + +group :test do + # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] + gem "capybara" + gem "selenium-webdriver" + gem "webdrivers" +end + +gem "rails-controller-testing" diff --git a/week_4/activity-tracker/Gemfile.lock b/week_4/activity-tracker/Gemfile.lock new file mode 100644 index 00000000..e8909a06 --- /dev/null +++ b/week_4/activity-tracker/Gemfile.lock @@ -0,0 +1,237 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.4) + actionpack (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activesupport (= 7.0.4) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.4) + actionview (= 7.0.4) + activesupport (= 7.0.4) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.4) + actionpack (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.4) + activesupport (= 7.0.4) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.3.6) + activemodel (7.0.4) + activesupport (= 7.0.4) + activerecord (7.0.4) + activemodel (= 7.0.4) + activesupport (= 7.0.4) + activestorage (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activesupport (= 7.0.4) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + bindex (0.8.1) + bootsnap (1.15.0) + msgpack (~> 1.2) + builder (3.2.4) + capybara (3.38.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + concurrent-ruby (1.1.10) + crass (1.0.6) + date (3.3.3) + debug (1.7.1) + irb (>= 1.5.0) + reline (>= 0.3.1) + erubi (1.12.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + importmap-rails (1.1.5) + actionpack (>= 6.0.0) + railties (>= 6.0.0) + io-console (0.6.0) + irb (1.6.2) + reline (>= 0.3.0) + jbuilder (2.11.5) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + loofah (2.19.1) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.8.0.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) + matrix (0.4.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.17.0) + msgpack (1.6.0) + net-imap (0.3.4) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.1) + timeout + net-smtp (0.3.3) + net-protocol + nio4r (2.5.8) + nokogiri (1.14.0-x86_64-linux) + racc (~> 1.4) + public_suffix (5.0.1) + puma (5.6.5) + nio4r (~> 2.0) + racc (1.6.2) + rack (2.2.5) + rack-test (2.0.2) + rack (>= 1.3) + rails (7.0.4) + actioncable (= 7.0.4) + actionmailbox (= 7.0.4) + actionmailer (= 7.0.4) + actionpack (= 7.0.4) + actiontext (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activemodel (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + bundler (>= 1.15.0) + railties (= 7.0.4) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.4) + loofah (~> 2.19, >= 2.19.1) + railties (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + regexp_parser (2.6.1) + reline (0.3.2) + io-console (~> 0.5) + rexml (3.2.5) + rubyzip (2.3.2) + selenium-webdriver (4.7.1) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + sprockets (4.2.0) + concurrent-ruby (~> 1.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + sqlite3 (1.5.4-x86_64-linux) + stimulus-rails (1.2.1) + railties (>= 6.0.0) + thor (1.2.1) + timeout (0.3.1) + turbo-rails (1.3.2) + actionpack (>= 6.0.0) + activejob (>= 6.0.0) + railties (>= 6.0.0) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + webdrivers (5.2.0) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0) + websocket (1.2.9) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.6.6) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + capybara + debug + importmap-rails + jbuilder + puma (~> 5.0) + rails (~> 7.0.4) + rails-controller-testing + selenium-webdriver + sprockets-rails + sqlite3 (~> 1.4) + stimulus-rails + turbo-rails + tzinfo-data + web-console + webdrivers + +RUBY VERSION + ruby 3.0.5p211 + +BUNDLED WITH + 2.2.33 diff --git a/week_4/activity-tracker/README.md b/week_4/activity-tracker/README.md new file mode 100644 index 00000000..c3248fd1 --- /dev/null +++ b/week_4/activity-tracker/README.md @@ -0,0 +1,151 @@ +# Controllers | Activity Tracker + +Alright! We have our model (which we will use to represent our data) ready to go. Now what we need to do is somehow be able to use this data to display content on our web app. + +Before we go into what controllers are, lets briefly look into what happens when a request is made to a Rails application. + +## Request Response Cycle +_(This is an oversimplification of the processes that happen under the hood. To know more details about what happens, you can refer to any resource about request-response cycle online.)_ + +The first thing that you would do is open up your browser, and enter a URL. Then some magic happens, and you can see the output webpage. Right? + +What happens internally is, every URL is mapped to a particular controller action. It is the controller's function to take over control, and fetch any necessary data it needs from database (via models that you made during the last week. Nice!). +This data is then packaged in appropriate formats - for example, if you are making an API server, your response would probably be in the JSON format. + +For a regular Rails app, the data from the controller is passed on the the special HTML pages, called _views_. In the views, you define how your data should be presented to the user. + +## Steps + +So lets recap. For making the web application work, we need: +- URLs. Each one of these are mapped to particular controller actions. +- Controllers. They aggregate all information needed for display, and pass it to the views. +- Views. They are what you see as the response. + +Quite a lot of steps right? Well, you're lucky you're learning Rails. + +## Scaffolding +There is a lot of "magic" that Rails does to make the developer's life much easier. One of the greatest ways, and very powerful tool that you'll be using often, is **scaffolds**. + +A scaffold basically does what it says - creates a lot of boilerplate code, so that you don't have to manually type it out. What is this boilerplate you ask? + +The scaffold operation creates the model, controller, views, routes and associated test files for the object that you specify. The URLs and controller actions that are made are the ones commonly used for CRUD operations - creating, removing, updating and deleting records. + +If it seems a little overwhelming to you right now, fear not! All shall be revealed soon. + +## Requirement +As a small recap, this is the data that we need in our application. + +- Title: `string` +- ActivityType: `string` +- Start: `datetime` +- Duration: `decimal` +- Calories: `integer` + +In the previous week, you might have generated the model for this using `rails generate model`. This time, we'll create a scaffold for this. + +```shell +rails generate scaffold Activity title:string activity_type:string start:datetime duration:decimal calories:integer +``` + +Make sure you keep in mind the Rails naming conventions! They apply here also. + +When you run this command, a ton of files would have been generated on your system. Lets take an overview of the files generated. + +- `create db/migrate/20230127173852_create_activities.rb`: Creating the migration file, to be applied to the database. +- `create app/models/activity.rb0`: The model file for our model. +- `create test/models/activity_test.rb`: Test file, for writing tests. +- `route resources :activities`: Routes (URLs). Add the basic CRUD URLs automatically. +- `create app/controllers/activities_controller.rb`: Controller. This is where you write controller actions. +- `create app/views/activities/*`: A bunch of files in this directory. These correspond to the views that will be rendered. +- `create test/controllers/activities_controller_test.rb`: Test suite for the controller. +- `create app/helpers/activities_helper.rb`: Helper for our resource. + +Ensure that you have created the database using `rails db:create`. You can now apply migrations created by using `rails db:migrate`. + +Run the server using `rails server`. If you now go to `localhost:3000/activities` on your browser, you can see a basic app in function! + +## The Controller +Now, lets open the controller and see what is happening. We'll take an example of a simple function, and try to understand what is happening. + +```ruby + def index + @activities = Activity.all + end +``` + +This is the `index` function. As the name suggests, this is the controller action that is called when you go to the home page. It displays a list of all the available entries for you to view (i.e. it provides an "index" of all data.) + +`Activity` refers to our model. The all function allows us to pick up all the entries that are stored as part of the `Activity` model, that is, all rows in the activities table. We save that in a variable called `@activities`. + +If you notice, the variable starts with `@`. This is a special type of variable in Rails, known as **instance variables**. These are variables that are accessible in both the controller and the views. + +At the end, we do not tell Rails to render any particular template (in opposition to some other frameworks, for instance Django). This is because of how Rails works - convention over configuration. Rails will automatically look for a file with the name `index.html` or `index.html.erb` (you'll learn about the `.erb` format when you learn about views), and directly render that file. +Pretty convenient, right? + +## `rails generate controller` +Scaffolding is an extremely easy and powerful way to bring up your resources. However, this is not the only way you can create controllers. +They can also be generated normally by + +```shell +rails generate controller NAME [action action] [options] +``` + +Using this, you can create your own controllers as well. They do not have to be always bound to a particular model +and can exist independently as well. + +## Routing +Now, we have all the CRUD URLs by default for us, thanks to scaffold. Let's dig a bit deeper into how routes works. +Open up `config/routes.rb`. Your file will look something like this: + +```ruby +Rails.application.routes.draw do + resources :activities + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + # Defines the root path route ("/") + # root "articles#index" +end + +``` + +This is the file where all routes for the application are defined. Whenever the server receives a request, it searches among this list of routes and controller action mappings to find what to do with the request. +Note the second line: + +```ruby +resources :activities +``` + +This is what generates all the CRUD operations on that model. In general, if you have a model, you can add all the CRUD operations by using `resources :NAME` without having to individually define routes. + +However, sometimes we need other routes too, and not just these basic ones. An example is the following: + +```ruby + get 'about', to: "pages#about" +``` + +This tells Rails to dispatch a GET request to `/about` to the `about` action of the `Pages` controller. The generic format is `GET/POST/etc 'route', to: 'controller#action'` + +But what if you wanted an additional route on your resource? Lets say you wanted the following routes: +- `/activity/load`: to load some activity data from another file. +- `/activity/:id/share`: to share your activity with friends. + +You could write these routes similar to the previous way; where you explicitly define the entire route. However, for URLs that add to resources, there is a better way. + +```ruby +resources :activities do + member do + get 'share' # GET /activity/:id/share + end + collection do + get 'load' # GET /activities/load + end +end +``` + +`member` adds the route to every individual record of that item, making routes that contain the ID of the item. `collection` adds the route to the entire collection, and so there are no IDs to the URL. +Not providing `to:` will tell Rails to look for a action with the same name as the URL, in the controller for that model. + +## References +- [Rails Routing from the Outside In](https://guides.rubyonrails.org/routing.html) +- [Action Controllers](https://guides.rubyonrails.org/action_controller_overview.html) +- [Layouts and Rendering in Rails (Views)](https://guides.rubyonrails.org/layouts_and_rendering.html) \ No newline at end of file diff --git a/week_4/activity-tracker/Rakefile b/week_4/activity-tracker/Rakefile new file mode 100644 index 00000000..9a5ea738 --- /dev/null +++ b/week_4/activity-tracker/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative "config/application" + +Rails.application.load_tasks diff --git a/week_4/activity-tracker/app/assets/config/manifest.js b/week_4/activity-tracker/app/assets/config/manifest.js new file mode 100644 index 00000000..ddd546a0 --- /dev/null +++ b/week_4/activity-tracker/app/assets/config/manifest.js @@ -0,0 +1,4 @@ +//= link_tree ../images +//= link_directory ../stylesheets .css +//= link_tree ../../javascript .js +//= link_tree ../../../vendor/javascript .js diff --git a/week_4/activity-tracker/app/assets/images/.keep b/week_4/activity-tracker/app/assets/images/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/app/assets/stylesheets/application.css b/week_4/activity-tracker/app/assets/stylesheets/application.css new file mode 100644 index 00000000..288b9ab7 --- /dev/null +++ b/week_4/activity-tracker/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/week_4/activity-tracker/app/channels/application_cable/channel.rb b/week_4/activity-tracker/app/channels/application_cable/channel.rb new file mode 100644 index 00000000..d6726972 --- /dev/null +++ b/week_4/activity-tracker/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/week_4/activity-tracker/app/channels/application_cable/connection.rb b/week_4/activity-tracker/app/channels/application_cable/connection.rb new file mode 100644 index 00000000..0ff5442f --- /dev/null +++ b/week_4/activity-tracker/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/week_4/activity-tracker/app/controllers/activities_controller.rb b/week_4/activity-tracker/app/controllers/activities_controller.rb new file mode 100644 index 00000000..a1dc90c1 --- /dev/null +++ b/week_4/activity-tracker/app/controllers/activities_controller.rb @@ -0,0 +1,70 @@ +class ActivitiesController < ApplicationController + before_action :set_activity, only: %i[ show edit update destroy ] + + # GET /activities or /activities.json + def index + @activities = Activity.all + end + + # GET /activities/1 or /activities/1.json + def show + end + + # GET /activities/new + def new + @activity = Activity.new + end + + # GET /activities/1/edit + def edit + end + + # POST /activities or /activities.json + def create + @activity = Activity.new(activity_params) + + respond_to do |format| + if @activity.save + format.html { redirect_to activity_url(@activity), notice: "Activity was successfully created." } + format.json { render :show, status: :created, location: @activity } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @activity.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /activities/1 or /activities/1.json + def update + respond_to do |format| + if @activity.update(activity_params) + format.html { redirect_to activity_url(@activity), notice: "Activity was successfully updated." } + format.json { render :show, status: :ok, location: @activity } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @activity.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /activities/1 or /activities/1.json + def destroy + @activity.destroy + + respond_to do |format| + format.html { redirect_to activities_url, notice: "Activity was successfully destroyed." } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_activity + @activity = Activity.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def activity_params + params.require(:activity).permit(:title, :activity_type, :start, :duration, :calories) + end +end diff --git a/week_4/activity-tracker/app/controllers/application_controller.rb b/week_4/activity-tracker/app/controllers/application_controller.rb new file mode 100644 index 00000000..09705d12 --- /dev/null +++ b/week_4/activity-tracker/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/week_4/activity-tracker/app/controllers/concerns/.keep b/week_4/activity-tracker/app/controllers/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/app/helpers/activities_helper.rb b/week_4/activity-tracker/app/helpers/activities_helper.rb new file mode 100644 index 00000000..4e9784cc --- /dev/null +++ b/week_4/activity-tracker/app/helpers/activities_helper.rb @@ -0,0 +1,2 @@ +module ActivitiesHelper +end diff --git a/week_4/activity-tracker/app/helpers/application_helper.rb b/week_4/activity-tracker/app/helpers/application_helper.rb new file mode 100644 index 00000000..de6be794 --- /dev/null +++ b/week_4/activity-tracker/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/week_4/activity-tracker/app/javascript/application.js b/week_4/activity-tracker/app/javascript/application.js new file mode 100644 index 00000000..0d7b4940 --- /dev/null +++ b/week_4/activity-tracker/app/javascript/application.js @@ -0,0 +1,3 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +import "@hotwired/turbo-rails" +import "controllers" diff --git a/week_4/activity-tracker/app/javascript/controllers/application.js b/week_4/activity-tracker/app/javascript/controllers/application.js new file mode 100644 index 00000000..1213e85c --- /dev/null +++ b/week_4/activity-tracker/app/javascript/controllers/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +// Configure Stimulus development experience +application.debug = false +window.Stimulus = application + +export { application } diff --git a/week_4/activity-tracker/app/javascript/controllers/hello_controller.js b/week_4/activity-tracker/app/javascript/controllers/hello_controller.js new file mode 100644 index 00000000..5975c078 --- /dev/null +++ b/week_4/activity-tracker/app/javascript/controllers/hello_controller.js @@ -0,0 +1,7 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + this.element.textContent = "Hello World!" + } +} diff --git a/week_4/activity-tracker/app/javascript/controllers/index.js b/week_4/activity-tracker/app/javascript/controllers/index.js new file mode 100644 index 00000000..54ad4cad --- /dev/null +++ b/week_4/activity-tracker/app/javascript/controllers/index.js @@ -0,0 +1,11 @@ +// Import and register all your controllers from the importmap under controllers/* + +import { application } from "controllers/application" + +// Eager load all controllers defined in the import map under controllers/**/*_controller +import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +eagerLoadControllersFrom("controllers", application) + +// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!) +// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading" +// lazyLoadControllersFrom("controllers", application) diff --git a/week_4/activity-tracker/app/jobs/application_job.rb b/week_4/activity-tracker/app/jobs/application_job.rb new file mode 100644 index 00000000..d394c3d1 --- /dev/null +++ b/week_4/activity-tracker/app/jobs/application_job.rb @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/week_4/activity-tracker/app/mailers/application_mailer.rb b/week_4/activity-tracker/app/mailers/application_mailer.rb new file mode 100644 index 00000000..3c34c814 --- /dev/null +++ b/week_4/activity-tracker/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/week_4/activity-tracker/app/models/activity.rb b/week_4/activity-tracker/app/models/activity.rb new file mode 100644 index 00000000..a99f990d --- /dev/null +++ b/week_4/activity-tracker/app/models/activity.rb @@ -0,0 +1,2 @@ +class Activity < ApplicationRecord +end diff --git a/week_4/activity-tracker/app/models/application_record.rb b/week_4/activity-tracker/app/models/application_record.rb new file mode 100644 index 00000000..b63caeb8 --- /dev/null +++ b/week_4/activity-tracker/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/week_4/activity-tracker/app/models/concerns/.keep b/week_4/activity-tracker/app/models/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/app/views/activities/_activity.html.erb b/week_4/activity-tracker/app/views/activities/_activity.html.erb new file mode 100644 index 00000000..aab462e3 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/_activity.html.erb @@ -0,0 +1,27 @@ +
+

+ Title: + <%= activity.title %> +

+ +

+ Activity type: + <%= activity.activity_type %> +

+ +

+ Start: + <%= activity.start %> +

+ +

+ Duration: + <%= activity.duration %> +

+ +

+ Calories: + <%= activity.calories %> +

+ +
diff --git a/week_4/activity-tracker/app/views/activities/_activity.json.jbuilder b/week_4/activity-tracker/app/views/activities/_activity.json.jbuilder new file mode 100644 index 00000000..8efbd331 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/_activity.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! activity, :id, :title, :activity_type, :start, :duration, :calories, :created_at, :updated_at +json.url activity_url(activity, format: :json) diff --git a/week_4/activity-tracker/app/views/activities/_form.html.erb b/week_4/activity-tracker/app/views/activities/_form.html.erb new file mode 100644 index 00000000..6d4079c4 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/_form.html.erb @@ -0,0 +1,42 @@ +<%= form_with(model: activity) do |form| %> + <% if activity.errors.any? %> +
+

<%= pluralize(activity.errors.count, "error") %> prohibited this activity from being saved:

+ +
    + <% activity.errors.each do |error| %> +
  • <%= error.full_message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= form.label :title, style: "display: block" %> + <%= form.text_field :title %> +
+ +
+ <%= form.label :activity_type, style: "display: block" %> + <%= form.text_field :activity_type %> +
+ +
+ <%= form.label :start, style: "display: block" %> + <%= form.datetime_field :start %> +
+ +
+ <%= form.label :duration, style: "display: block" %> + <%= form.text_field :duration %> +
+ +
+ <%= form.label :calories, style: "display: block" %> + <%= form.number_field :calories %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/week_4/activity-tracker/app/views/activities/edit.html.erb b/week_4/activity-tracker/app/views/activities/edit.html.erb new file mode 100644 index 00000000..4774a05e --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/edit.html.erb @@ -0,0 +1,10 @@ +

Editing activity

+ +<%= render "form", activity: @activity %> + +
+ +
+ <%= link_to "Show this activity", @activity %> | + <%= link_to "Back to activities", activities_path %> +
diff --git a/week_4/activity-tracker/app/views/activities/index.html.erb b/week_4/activity-tracker/app/views/activities/index.html.erb new file mode 100644 index 00000000..776f9042 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/index.html.erb @@ -0,0 +1,14 @@ +

<%= notice %>

+ +

Activities

+ +
+ <% @activities.each do |activity| %> + <%= render activity %> +

+ <%= link_to "Show this activity", activity %> +

+ <% end %> +
+ +<%= link_to "New activity", new_activity_path %> diff --git a/week_4/activity-tracker/app/views/activities/index.json.jbuilder b/week_4/activity-tracker/app/views/activities/index.json.jbuilder new file mode 100644 index 00000000..865f89ee --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @activities, partial: "activities/activity", as: :activity diff --git a/week_4/activity-tracker/app/views/activities/new.html.erb b/week_4/activity-tracker/app/views/activities/new.html.erb new file mode 100644 index 00000000..855a5899 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/new.html.erb @@ -0,0 +1,9 @@ +

New activity

+ +<%= render "form", activity: @activity %> + +
+ +
+ <%= link_to "Back to activities", activities_path %> +
diff --git a/week_4/activity-tracker/app/views/activities/show.html.erb b/week_4/activity-tracker/app/views/activities/show.html.erb new file mode 100644 index 00000000..73be1e19 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/show.html.erb @@ -0,0 +1,10 @@ +

<%= notice %>

+ +<%= render @activity %> + +
+ <%= link_to "Edit this activity", edit_activity_path(@activity) %> | + <%= link_to "Back to activities", activities_path %> + + <%= button_to "Destroy this activity", @activity, method: :delete %> +
diff --git a/week_4/activity-tracker/app/views/activities/show.json.jbuilder b/week_4/activity-tracker/app/views/activities/show.json.jbuilder new file mode 100644 index 00000000..a145d0a8 --- /dev/null +++ b/week_4/activity-tracker/app/views/activities/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "activities/activity", activity: @activity diff --git a/week_4/activity-tracker/app/views/activities/stats.html.erb b/week_4/activity-tracker/app/views/activities/stats.html.erb new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/app/views/layouts/application.html.erb b/week_4/activity-tracker/app/views/layouts/application.html.erb new file mode 100644 index 00000000..5f65d83d --- /dev/null +++ b/week_4/activity-tracker/app/views/layouts/application.html.erb @@ -0,0 +1,16 @@ + + + + ActivityTracker + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> + <%= javascript_importmap_tags %> + + + + <%= yield %> + + diff --git a/week_4/activity-tracker/app/views/layouts/mailer.html.erb b/week_4/activity-tracker/app/views/layouts/mailer.html.erb new file mode 100644 index 00000000..cbd34d2e --- /dev/null +++ b/week_4/activity-tracker/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/week_4/activity-tracker/app/views/layouts/mailer.text.erb b/week_4/activity-tracker/app/views/layouts/mailer.text.erb new file mode 100644 index 00000000..37f0bddb --- /dev/null +++ b/week_4/activity-tracker/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/week_4/activity-tracker/authentication.md b/week_4/activity-tracker/authentication.md new file mode 100644 index 00000000..9621e41a --- /dev/null +++ b/week_4/activity-tracker/authentication.md @@ -0,0 +1,31 @@ +# Authentication | Activity Tracker + +Now that we have a good, functioning app ready, we need to secure it. Right now, anyone can access the data that we are entering. This is particularly concerning, since a lot of this might actually be sensitive information (especially in the case of a fitness tracker app), and needs to be secured properly. + +One way to do this is to allow only authorised users to be able to view the information stored. This is known as **authentication**. You provide basic information to prove that it is indeed you who are making the request, so that the application can trust you. + +In Rails, there is no in-built authentication system. However, there are great gems that are available for this very purpose. We will look at one of the most common ones, which is also in use at IRIS, called **Devise**. + +## Devise +`Devise` is an gem that provides authorisation capabilities to your Rails app, with very little difficulty. It is nearly completely customisable, and can be modified to fit all your individual needs. You can read a bit more about the project from the link in the references. + +We'll look at their README file, and quickly follow along to get it up and running. + +First, we need to get the gem. Add this to your `Gemfile` + +```ruby +gem 'devise' +``` + +Then we need to generate the files that Devise needs. This is done easily by the generater that the kind folks at Devise have made for us. + +```shell +$ rails generate devise:install +``` + +A few instructions would be printed onto your console. Make sure you follow them to properly set it up. + +Great job! Now you have Devise installed, you can set it up to protect your application. + +## References +- [Devise Repository](https://github.com/heartcombo/devise) \ No newline at end of file diff --git a/week_4/activity-tracker/bin/bundle b/week_4/activity-tracker/bin/bundle new file mode 100755 index 00000000..374a0a1f --- /dev/null +++ b/week_4/activity-tracker/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/week_4/activity-tracker/bin/importmap b/week_4/activity-tracker/bin/importmap new file mode 100755 index 00000000..36502ab1 --- /dev/null +++ b/week_4/activity-tracker/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/week_4/activity-tracker/bin/rails b/week_4/activity-tracker/bin/rails new file mode 100755 index 00000000..efc03774 --- /dev/null +++ b/week_4/activity-tracker/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/week_4/activity-tracker/bin/rake b/week_4/activity-tracker/bin/rake new file mode 100755 index 00000000..4fbf10b9 --- /dev/null +++ b/week_4/activity-tracker/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/week_4/activity-tracker/bin/setup b/week_4/activity-tracker/bin/setup new file mode 100755 index 00000000..ec47b79b --- /dev/null +++ b/week_4/activity-tracker/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/week_4/activity-tracker/config.ru b/week_4/activity-tracker/config.ru new file mode 100644 index 00000000..4a3c09a6 --- /dev/null +++ b/week_4/activity-tracker/config.ru @@ -0,0 +1,6 @@ +# This file is used by Rack-based servers to start the application. + +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/week_4/activity-tracker/config/application.rb b/week_4/activity-tracker/config/application.rb new file mode 100644 index 00000000..eaab4107 --- /dev/null +++ b/week_4/activity-tracker/config/application.rb @@ -0,0 +1,22 @@ +require_relative "boot" + +require "rails/all" + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module ActivityTracker + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 7.0 + + # Configuration for the application, engines, and railties goes here. + # + # These settings can be overridden in specific environments using the files + # in config/environments, which are processed later. + # + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + end +end diff --git a/week_4/activity-tracker/config/boot.rb b/week_4/activity-tracker/config/boot.rb new file mode 100644 index 00000000..988a5ddc --- /dev/null +++ b/week_4/activity-tracker/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" # Set up gems listed in the Gemfile. +require "bootsnap/setup" # Speed up boot time by caching expensive operations. diff --git a/week_4/activity-tracker/config/cable.yml b/week_4/activity-tracker/config/cable.yml new file mode 100644 index 00000000..fc223da2 --- /dev/null +++ b/week_4/activity-tracker/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: activity_tracker_production diff --git a/week_4/activity-tracker/config/credentials.yml.enc b/week_4/activity-tracker/config/credentials.yml.enc new file mode 100644 index 00000000..4410c9ad --- /dev/null +++ b/week_4/activity-tracker/config/credentials.yml.enc @@ -0,0 +1 @@ +vy9Yyajw1b8PCBzOL90ahf4dlXAdev9jaGcu43MsIEltJ9tLudTQHZhztOYwXgig6D1/W6vai5IQKKPbfBCioSi0cdsXraMUQpVx6wPgHjU4CRMYm5gbMJ8MoGpTTRO3546ceKYioiXoAtBnnM6jyHlqdqPm/xIND5SfytLSBOJrUxg8v06TISxfhIbRlGneBeEV7I8HcrBC2ulCNToXou0oojijWGkCUYjFV/0452pmrHDX+HC4Psc252O0H7emGpqjh6puxAV6aYmiNU3cvqNjUQXxHmaH7N1jgAnR/5xB1bwZHKUB7ngTufyFzt+3ZQg5UCbuuJ+4f8lSGbrJUKNJjpVVwW5jNrRCrDm8ZMbvHCus2ApGtHu/vVjxw5bo3hWda83vQhVcBI74bNo5JnbzuKNhmQi8VEHm--ByL641PQMhBRCAI2--Mnwv25FxL4SSK6RIuW8L1Q== \ No newline at end of file diff --git a/week_4/activity-tracker/config/database.yml b/week_4/activity-tracker/config/database.yml new file mode 100644 index 00000000..fcba57f1 --- /dev/null +++ b/week_4/activity-tracker/config/database.yml @@ -0,0 +1,25 @@ +# SQLite. Versions 3.8.0 and up are supported. +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem "sqlite3" +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/week_4/activity-tracker/config/environment.rb b/week_4/activity-tracker/config/environment.rb new file mode 100644 index 00000000..cac53157 --- /dev/null +++ b/week_4/activity-tracker/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative "application" + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/week_4/activity-tracker/config/environments/development.rb b/week_4/activity-tracker/config/environments/development.rb new file mode 100644 index 00000000..f2a3adc8 --- /dev/null +++ b/week_4/activity-tracker/config/environments/development.rb @@ -0,0 +1,72 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable server timing + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + config.hosts << "mittal-parth-animated-cod-gpxgvr5gwp62v4v5-3000.preview.app.github.dev" + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true +end diff --git a/week_4/activity-tracker/config/environments/production.rb b/week_4/activity-tracker/config/environments/production.rb new file mode 100644 index 00000000..86a19e32 --- /dev/null +++ b/week_4/activity-tracker/config/environments/production.rb @@ -0,0 +1,93 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "activity_tracker_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/week_4/activity-tracker/config/environments/test.rb b/week_4/activity-tracker/config/environments/test.rb new file mode 100644 index 00000000..6ea4d1e7 --- /dev/null +++ b/week_4/activity-tracker/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/week_4/activity-tracker/config/importmap.rb b/week_4/activity-tracker/config/importmap.rb new file mode 100644 index 00000000..8dce42d4 --- /dev/null +++ b/week_4/activity-tracker/config/importmap.rb @@ -0,0 +1,7 @@ +# Pin npm packages by running ./bin/importmap + +pin "application", preload: true +pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true +pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true +pin_all_from "app/javascript/controllers", under: "controllers" diff --git a/week_4/activity-tracker/config/initializers/assets.rb b/week_4/activity-tracker/config/initializers/assets.rb new file mode 100644 index 00000000..2eeef966 --- /dev/null +++ b/week_4/activity-tracker/config/initializers/assets.rb @@ -0,0 +1,12 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = "1.0" + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/week_4/activity-tracker/config/initializers/content_security_policy.rb b/week_4/activity-tracker/config/initializers/content_security_policy.rb new file mode 100644 index 00000000..54f47cf1 --- /dev/null +++ b/week_4/activity-tracker/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header + +# Rails.application.configure do +# config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end +# +# # Generate session nonces for permitted importmap and inline scripts +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true +# end diff --git a/week_4/activity-tracker/config/initializers/filter_parameter_logging.rb b/week_4/activity-tracker/config/initializers/filter_parameter_logging.rb new file mode 100644 index 00000000..adc6568c --- /dev/null +++ b/week_4/activity-tracker/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/week_4/activity-tracker/config/initializers/inflections.rb b/week_4/activity-tracker/config/initializers/inflections.rb new file mode 100644 index 00000000..3860f659 --- /dev/null +++ b/week_4/activity-tracker/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/week_4/activity-tracker/config/initializers/permissions_policy.rb b/week_4/activity-tracker/config/initializers/permissions_policy.rb new file mode 100644 index 00000000..00f64d71 --- /dev/null +++ b/week_4/activity-tracker/config/initializers/permissions_policy.rb @@ -0,0 +1,11 @@ +# Define an application-wide HTTP permissions policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.permissions_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/week_4/activity-tracker/config/locales/en.yml b/week_4/activity-tracker/config/locales/en.yml new file mode 100644 index 00000000..8ca56fc7 --- /dev/null +++ b/week_4/activity-tracker/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/week_4/activity-tracker/config/master.key b/week_4/activity-tracker/config/master.key new file mode 100644 index 00000000..3e69d63e --- /dev/null +++ b/week_4/activity-tracker/config/master.key @@ -0,0 +1 @@ +7ffae4e43de01027f283f3630db4227c \ No newline at end of file diff --git a/week_4/activity-tracker/config/puma.rb b/week_4/activity-tracker/config/puma.rb new file mode 100644 index 00000000..daaf0369 --- /dev/null +++ b/week_4/activity-tracker/config/puma.rb @@ -0,0 +1,43 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +# Specifies the `worker_timeout` threshold that Puma will use to wait before +# terminating a worker in development environments. +# +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked web server processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart diff --git a/week_4/activity-tracker/config/routes.rb b/week_4/activity-tracker/config/routes.rb new file mode 100644 index 00000000..9ee203b2 --- /dev/null +++ b/week_4/activity-tracker/config/routes.rb @@ -0,0 +1,8 @@ +Rails.application.routes.draw do + resources :activities + + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + # Defines the root path route ("/") + # root "articles#index" +end diff --git a/week_4/activity-tracker/config/storage.yml b/week_4/activity-tracker/config/storage.yml new file mode 100644 index 00000000..4942ab66 --- /dev/null +++ b/week_4/activity-tracker/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb b/week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb new file mode 100644 index 00000000..d0fe3b06 --- /dev/null +++ b/week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb @@ -0,0 +1,13 @@ +class CreateActivities < ActiveRecord::Migration[7.0] + def change + create_table :activities do |t| + t.string :title + t.string :activity_type + t.datetime :start + t.decimal :duration + t.integer :calories + + t.timestamps + end + end +end diff --git a/week_4/activity-tracker/db/schema.rb b/week_4/activity-tracker/db/schema.rb new file mode 100644 index 00000000..8543cda3 --- /dev/null +++ b/week_4/activity-tracker/db/schema.rb @@ -0,0 +1,24 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2023_01_27_184553) do + create_table "activities", force: :cascade do |t| + t.string "title" + t.string "activity_type" + t.datetime "start" + t.decimal "duration" + t.integer "calories" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/week_4/activity-tracker/db/seeds.rb b/week_4/activity-tracker/db/seeds.rb new file mode 100644 index 00000000..bc25fce3 --- /dev/null +++ b/week_4/activity-tracker/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). +# +# Examples: +# +# movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) +# Character.create(name: "Luke", movie: movies.first) diff --git a/week_4/activity-tracker/lib/assets/.keep b/week_4/activity-tracker/lib/assets/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/lib/tasks/.keep b/week_4/activity-tracker/lib/tasks/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/public/404.html b/week_4/activity-tracker/public/404.html new file mode 100644 index 00000000..2be3af26 --- /dev/null +++ b/week_4/activity-tracker/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
+
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_4/activity-tracker/public/422.html b/week_4/activity-tracker/public/422.html new file mode 100644 index 00000000..c08eac0d --- /dev/null +++ b/week_4/activity-tracker/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
+
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_4/activity-tracker/public/500.html b/week_4/activity-tracker/public/500.html new file mode 100644 index 00000000..78a030af --- /dev/null +++ b/week_4/activity-tracker/public/500.html @@ -0,0 +1,66 @@ + + + + We're sorry, but something went wrong (500) + + + + + + +
+
+

We're sorry, but something went wrong.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/week_4/activity-tracker/public/apple-touch-icon-precomposed.png b/week_4/activity-tracker/public/apple-touch-icon-precomposed.png new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/public/apple-touch-icon.png b/week_4/activity-tracker/public/apple-touch-icon.png new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/public/favicon.ico b/week_4/activity-tracker/public/favicon.ico new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/public/robots.txt b/week_4/activity-tracker/public/robots.txt new file mode 100644 index 00000000..c19f78ab --- /dev/null +++ b/week_4/activity-tracker/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/week_4/activity-tracker/storage/.keep b/week_4/activity-tracker/storage/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/application_system_test_case.rb b/week_4/activity-tracker/test/application_system_test_case.rb new file mode 100644 index 00000000..d19212ab --- /dev/null +++ b/week_4/activity-tracker/test/application_system_test_case.rb @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/week_4/activity-tracker/test/channels/application_cable/connection_test.rb b/week_4/activity-tracker/test/channels/application_cable/connection_test.rb new file mode 100644 index 00000000..800405f1 --- /dev/null +++ b/week_4/activity-tracker/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/week_4/activity-tracker/test/controllers/.keep b/week_4/activity-tracker/test/controllers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/controllers/activities_controller_test.rb b/week_4/activity-tracker/test/controllers/activities_controller_test.rb new file mode 100644 index 00000000..f1d89c50 --- /dev/null +++ b/week_4/activity-tracker/test/controllers/activities_controller_test.rb @@ -0,0 +1,59 @@ +require "test_helper" + +class ActivitiesControllerTest < ActionDispatch::IntegrationTest + setup do + @activity = activities(:one) + end + + test "should get index" do + get activities_url + assert_response :success + end + + test "should get new" do + get new_activity_url + assert_response :success + end + + test "should create activity" do + assert_difference("Activity.count") do + post activities_url, params: { activity: { activity_type: @activity.activity_type, calories: @activity.calories, duration: @activity.duration, start: @activity.start, title: @activity.title } } + end + + assert_redirected_to activity_url(Activity.last) + end + + test "should show activity" do + get activity_url(@activity) + assert_response :success + end + + test "should get edit" do + get edit_activity_url(@activity) + assert_response :success + end + + test "should update activity" do + patch activity_url(@activity), params: { activity: { activity_type: @activity.activity_type, calories: @activity.calories, duration: @activity.duration, start: @activity.start, title: @activity.title } } + assert_redirected_to activity_url(@activity) + end + + test "should destroy activity" do + assert_difference("Activity.count", -1) do + delete activity_url(@activity) + end + + assert_redirected_to activities_url + end + + test "should get stats" do + get stats_activities_url + assert_response :success + expected_calories = Activity.sum(&:calories) + expected_duration = Activity.sum(&:duration) + cal = assigns(:total_calories) + dur = assigns(:total_duration) + assert_equal(expected_calories, cal) + assert_equal(expected_duration, dur) + end +end diff --git a/week_4/activity-tracker/test/fixtures/activities.yml b/week_4/activity-tracker/test/fixtures/activities.yml new file mode 100644 index 00000000..aff553eb --- /dev/null +++ b/week_4/activity-tracker/test/fixtures/activities.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + title: MyString + activity_type: MyString + start: 2023-01-28 00:15:53 + duration: 9.99 + calories: 1 + +two: + title: MyString + activity_type: MyString + start: 2023-01-28 00:15:53 + duration: 9.99 + calories: 1 diff --git a/week_4/activity-tracker/test/fixtures/files/.keep b/week_4/activity-tracker/test/fixtures/files/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/helpers/.keep b/week_4/activity-tracker/test/helpers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/integration/.keep b/week_4/activity-tracker/test/integration/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/mailers/.keep b/week_4/activity-tracker/test/mailers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/models/.keep b/week_4/activity-tracker/test/models/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/models/activity_model_test.rb b/week_4/activity-tracker/test/models/activity_model_test.rb new file mode 100644 index 00000000..3097c757 --- /dev/null +++ b/week_4/activity-tracker/test/models/activity_model_test.rb @@ -0,0 +1,23 @@ +require "test_helper" + +class ActivityTest < ActiveSupport::TestCase + test 'has a string column title' do + assert_equal :string, Activity.type_for_attribute('title').type + end + + test 'has a string column type' do + assert_equal :string, Activity.type_for_attribute('activity_type').type + end + + test 'has a datetime column start' do + assert_equal :datetime, Activity.type_for_attribute('start').type + end + + test 'has a decimal column duration' do + assert_equal :decimal, Activity.type_for_attribute('duration').type + end + + test 'has an integer column calories' do + assert_equal :integer, Activity.type_for_attribute('calories').type + end +end \ No newline at end of file diff --git a/week_4/activity-tracker/test/models/activity_test.rb b/week_4/activity-tracker/test/models/activity_test.rb new file mode 100644 index 00000000..c07a8b91 --- /dev/null +++ b/week_4/activity-tracker/test/models/activity_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ActivityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/week_4/activity-tracker/test/system/.keep b/week_4/activity-tracker/test/system/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/test/system/activities_test.rb b/week_4/activity-tracker/test/system/activities_test.rb new file mode 100644 index 00000000..15feb5a2 --- /dev/null +++ b/week_4/activity-tracker/test/system/activities_test.rb @@ -0,0 +1,49 @@ +require "application_system_test_case" + +class ActivitiesTest < ApplicationSystemTestCase + setup do + @activity = activities(:one) + end + + test "visiting the index" do + visit activities_url + assert_selector "h1", text: "Activities" + end + + test "should create activity" do + visit activities_url + click_on "New activity" + + fill_in "Activity type", with: @activity.activity_type + fill_in "Calories", with: @activity.calories + fill_in "Duration", with: @activity.duration + fill_in "Start", with: @activity.start + fill_in "Title", with: @activity.title + click_on "Create Activity" + + assert_text "Activity was successfully created" + click_on "Back" + end + + test "should update Activity" do + visit activity_url(@activity) + click_on "Edit this activity", match: :first + + fill_in "Activity type", with: @activity.activity_type + fill_in "Calories", with: @activity.calories + fill_in "Duration", with: @activity.duration + fill_in "Start", with: @activity.start + fill_in "Title", with: @activity.title + click_on "Update Activity" + + assert_text "Activity was successfully updated" + click_on "Back" + end + + test "should destroy Activity" do + visit activity_url(@activity) + click_on "Destroy this activity", match: :first + + assert_text "Activity was successfully destroyed" + end +end diff --git a/week_4/activity-tracker/test/test_helper.rb b/week_4/activity-tracker/test/test_helper.rb new file mode 100644 index 00000000..d713e377 --- /dev/null +++ b/week_4/activity-tracker/test/test_helper.rb @@ -0,0 +1,13 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + # Run tests in parallel with specified workers + parallelize(workers: :number_of_processors) + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + fixtures :all + + # Add more helper methods to be used by all tests here... +end diff --git a/week_4/activity-tracker/vendor/.keep b/week_4/activity-tracker/vendor/.keep new file mode 100644 index 00000000..e69de29b diff --git a/week_4/activity-tracker/vendor/javascript/.keep b/week_4/activity-tracker/vendor/javascript/.keep new file mode 100644 index 00000000..e69de29b From ef8052b74e95947b87147e9b409466a00c886777 Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Mon, 30 Jan 2023 03:54:23 +0000 Subject: [PATCH 32/34] remove already scaffolded code --- .../app/controllers/activities_controller.rb | 70 ------------------- .../app/helpers/activities_helper.rb | 2 - .../activity-tracker/app/models/activity.rb | 2 - .../app/views/activities/_activity.html.erb | 27 ------- .../views/activities/_activity.json.jbuilder | 2 - .../app/views/activities/_form.html.erb | 42 ----------- .../app/views/activities/edit.html.erb | 10 --- .../app/views/activities/index.html.erb | 14 ---- .../app/views/activities/index.json.jbuilder | 1 - .../app/views/activities/new.html.erb | 9 --- .../app/views/activities/show.html.erb | 10 --- .../app/views/activities/show.json.jbuilder | 1 - .../app/views/activities/stats.html.erb | 0 week_4/activity-tracker/config/routes.rb | 1 - .../20230127184553_create_activities.rb | 13 ---- week_4/activity-tracker/db/schema.rb | 12 +--- .../test/fixtures/activities.yml | 15 ---- .../test/models/activity_test.rb | 7 -- .../test/system/activities_test.rb | 49 ------------- 19 files changed, 1 insertion(+), 286 deletions(-) delete mode 100644 week_4/activity-tracker/app/controllers/activities_controller.rb delete mode 100644 week_4/activity-tracker/app/helpers/activities_helper.rb delete mode 100644 week_4/activity-tracker/app/models/activity.rb delete mode 100644 week_4/activity-tracker/app/views/activities/_activity.html.erb delete mode 100644 week_4/activity-tracker/app/views/activities/_activity.json.jbuilder delete mode 100644 week_4/activity-tracker/app/views/activities/_form.html.erb delete mode 100644 week_4/activity-tracker/app/views/activities/edit.html.erb delete mode 100644 week_4/activity-tracker/app/views/activities/index.html.erb delete mode 100644 week_4/activity-tracker/app/views/activities/index.json.jbuilder delete mode 100644 week_4/activity-tracker/app/views/activities/new.html.erb delete mode 100644 week_4/activity-tracker/app/views/activities/show.html.erb delete mode 100644 week_4/activity-tracker/app/views/activities/show.json.jbuilder delete mode 100644 week_4/activity-tracker/app/views/activities/stats.html.erb delete mode 100644 week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb delete mode 100644 week_4/activity-tracker/test/fixtures/activities.yml delete mode 100644 week_4/activity-tracker/test/models/activity_test.rb delete mode 100644 week_4/activity-tracker/test/system/activities_test.rb diff --git a/week_4/activity-tracker/app/controllers/activities_controller.rb b/week_4/activity-tracker/app/controllers/activities_controller.rb deleted file mode 100644 index a1dc90c1..00000000 --- a/week_4/activity-tracker/app/controllers/activities_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -class ActivitiesController < ApplicationController - before_action :set_activity, only: %i[ show edit update destroy ] - - # GET /activities or /activities.json - def index - @activities = Activity.all - end - - # GET /activities/1 or /activities/1.json - def show - end - - # GET /activities/new - def new - @activity = Activity.new - end - - # GET /activities/1/edit - def edit - end - - # POST /activities or /activities.json - def create - @activity = Activity.new(activity_params) - - respond_to do |format| - if @activity.save - format.html { redirect_to activity_url(@activity), notice: "Activity was successfully created." } - format.json { render :show, status: :created, location: @activity } - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @activity.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /activities/1 or /activities/1.json - def update - respond_to do |format| - if @activity.update(activity_params) - format.html { redirect_to activity_url(@activity), notice: "Activity was successfully updated." } - format.json { render :show, status: :ok, location: @activity } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @activity.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /activities/1 or /activities/1.json - def destroy - @activity.destroy - - respond_to do |format| - format.html { redirect_to activities_url, notice: "Activity was successfully destroyed." } - format.json { head :no_content } - end - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_activity - @activity = Activity.find(params[:id]) - end - - # Only allow a list of trusted parameters through. - def activity_params - params.require(:activity).permit(:title, :activity_type, :start, :duration, :calories) - end -end diff --git a/week_4/activity-tracker/app/helpers/activities_helper.rb b/week_4/activity-tracker/app/helpers/activities_helper.rb deleted file mode 100644 index 4e9784cc..00000000 --- a/week_4/activity-tracker/app/helpers/activities_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ActivitiesHelper -end diff --git a/week_4/activity-tracker/app/models/activity.rb b/week_4/activity-tracker/app/models/activity.rb deleted file mode 100644 index a99f990d..00000000 --- a/week_4/activity-tracker/app/models/activity.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Activity < ApplicationRecord -end diff --git a/week_4/activity-tracker/app/views/activities/_activity.html.erb b/week_4/activity-tracker/app/views/activities/_activity.html.erb deleted file mode 100644 index aab462e3..00000000 --- a/week_4/activity-tracker/app/views/activities/_activity.html.erb +++ /dev/null @@ -1,27 +0,0 @@ -
-

- Title: - <%= activity.title %> -

- -

- Activity type: - <%= activity.activity_type %> -

- -

- Start: - <%= activity.start %> -

- -

- Duration: - <%= activity.duration %> -

- -

- Calories: - <%= activity.calories %> -

- -
diff --git a/week_4/activity-tracker/app/views/activities/_activity.json.jbuilder b/week_4/activity-tracker/app/views/activities/_activity.json.jbuilder deleted file mode 100644 index 8efbd331..00000000 --- a/week_4/activity-tracker/app/views/activities/_activity.json.jbuilder +++ /dev/null @@ -1,2 +0,0 @@ -json.extract! activity, :id, :title, :activity_type, :start, :duration, :calories, :created_at, :updated_at -json.url activity_url(activity, format: :json) diff --git a/week_4/activity-tracker/app/views/activities/_form.html.erb b/week_4/activity-tracker/app/views/activities/_form.html.erb deleted file mode 100644 index 6d4079c4..00000000 --- a/week_4/activity-tracker/app/views/activities/_form.html.erb +++ /dev/null @@ -1,42 +0,0 @@ -<%= form_with(model: activity) do |form| %> - <% if activity.errors.any? %> -
-

<%= pluralize(activity.errors.count, "error") %> prohibited this activity from being saved:

- -
    - <% activity.errors.each do |error| %> -
  • <%= error.full_message %>
  • - <% end %> -
-
- <% end %> - -
- <%= form.label :title, style: "display: block" %> - <%= form.text_field :title %> -
- -
- <%= form.label :activity_type, style: "display: block" %> - <%= form.text_field :activity_type %> -
- -
- <%= form.label :start, style: "display: block" %> - <%= form.datetime_field :start %> -
- -
- <%= form.label :duration, style: "display: block" %> - <%= form.text_field :duration %> -
- -
- <%= form.label :calories, style: "display: block" %> - <%= form.number_field :calories %> -
- -
- <%= form.submit %> -
-<% end %> diff --git a/week_4/activity-tracker/app/views/activities/edit.html.erb b/week_4/activity-tracker/app/views/activities/edit.html.erb deleted file mode 100644 index 4774a05e..00000000 --- a/week_4/activity-tracker/app/views/activities/edit.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

Editing activity

- -<%= render "form", activity: @activity %> - -
- -
- <%= link_to "Show this activity", @activity %> | - <%= link_to "Back to activities", activities_path %> -
diff --git a/week_4/activity-tracker/app/views/activities/index.html.erb b/week_4/activity-tracker/app/views/activities/index.html.erb deleted file mode 100644 index 776f9042..00000000 --- a/week_4/activity-tracker/app/views/activities/index.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -

<%= notice %>

- -

Activities

- -
- <% @activities.each do |activity| %> - <%= render activity %> -

- <%= link_to "Show this activity", activity %> -

- <% end %> -
- -<%= link_to "New activity", new_activity_path %> diff --git a/week_4/activity-tracker/app/views/activities/index.json.jbuilder b/week_4/activity-tracker/app/views/activities/index.json.jbuilder deleted file mode 100644 index 865f89ee..00000000 --- a/week_4/activity-tracker/app/views/activities/index.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.array! @activities, partial: "activities/activity", as: :activity diff --git a/week_4/activity-tracker/app/views/activities/new.html.erb b/week_4/activity-tracker/app/views/activities/new.html.erb deleted file mode 100644 index 855a5899..00000000 --- a/week_4/activity-tracker/app/views/activities/new.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -

New activity

- -<%= render "form", activity: @activity %> - -
- -
- <%= link_to "Back to activities", activities_path %> -
diff --git a/week_4/activity-tracker/app/views/activities/show.html.erb b/week_4/activity-tracker/app/views/activities/show.html.erb deleted file mode 100644 index 73be1e19..00000000 --- a/week_4/activity-tracker/app/views/activities/show.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

<%= notice %>

- -<%= render @activity %> - -
- <%= link_to "Edit this activity", edit_activity_path(@activity) %> | - <%= link_to "Back to activities", activities_path %> - - <%= button_to "Destroy this activity", @activity, method: :delete %> -
diff --git a/week_4/activity-tracker/app/views/activities/show.json.jbuilder b/week_4/activity-tracker/app/views/activities/show.json.jbuilder deleted file mode 100644 index a145d0a8..00000000 --- a/week_4/activity-tracker/app/views/activities/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! "activities/activity", activity: @activity diff --git a/week_4/activity-tracker/app/views/activities/stats.html.erb b/week_4/activity-tracker/app/views/activities/stats.html.erb deleted file mode 100644 index e69de29b..00000000 diff --git a/week_4/activity-tracker/config/routes.rb b/week_4/activity-tracker/config/routes.rb index 9ee203b2..7ff20da4 100644 --- a/week_4/activity-tracker/config/routes.rb +++ b/week_4/activity-tracker/config/routes.rb @@ -1,5 +1,4 @@ Rails.application.routes.draw do - resources :activities # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html diff --git a/week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb b/week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb deleted file mode 100644 index d0fe3b06..00000000 --- a/week_4/activity-tracker/db/migrate/20230127184553_create_activities.rb +++ /dev/null @@ -1,13 +0,0 @@ -class CreateActivities < ActiveRecord::Migration[7.0] - def change - create_table :activities do |t| - t.string :title - t.string :activity_type - t.datetime :start - t.decimal :duration - t.integer :calories - - t.timestamps - end - end -end diff --git a/week_4/activity-tracker/db/schema.rb b/week_4/activity-tracker/db/schema.rb index 8543cda3..a3b04951 100644 --- a/week_4/activity-tracker/db/schema.rb +++ b/week_4/activity-tracker/db/schema.rb @@ -10,15 +10,5 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_01_27_184553) do - create_table "activities", force: :cascade do |t| - t.string "title" - t.string "activity_type" - t.datetime "start" - t.decimal "duration" - t.integer "calories" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - +ActiveRecord::Schema[7.0].define(version: 0) do end diff --git a/week_4/activity-tracker/test/fixtures/activities.yml b/week_4/activity-tracker/test/fixtures/activities.yml deleted file mode 100644 index aff553eb..00000000 --- a/week_4/activity-tracker/test/fixtures/activities.yml +++ /dev/null @@ -1,15 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - title: MyString - activity_type: MyString - start: 2023-01-28 00:15:53 - duration: 9.99 - calories: 1 - -two: - title: MyString - activity_type: MyString - start: 2023-01-28 00:15:53 - duration: 9.99 - calories: 1 diff --git a/week_4/activity-tracker/test/models/activity_test.rb b/week_4/activity-tracker/test/models/activity_test.rb deleted file mode 100644 index c07a8b91..00000000 --- a/week_4/activity-tracker/test/models/activity_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class ActivityTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/week_4/activity-tracker/test/system/activities_test.rb b/week_4/activity-tracker/test/system/activities_test.rb deleted file mode 100644 index 15feb5a2..00000000 --- a/week_4/activity-tracker/test/system/activities_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -require "application_system_test_case" - -class ActivitiesTest < ApplicationSystemTestCase - setup do - @activity = activities(:one) - end - - test "visiting the index" do - visit activities_url - assert_selector "h1", text: "Activities" - end - - test "should create activity" do - visit activities_url - click_on "New activity" - - fill_in "Activity type", with: @activity.activity_type - fill_in "Calories", with: @activity.calories - fill_in "Duration", with: @activity.duration - fill_in "Start", with: @activity.start - fill_in "Title", with: @activity.title - click_on "Create Activity" - - assert_text "Activity was successfully created" - click_on "Back" - end - - test "should update Activity" do - visit activity_url(@activity) - click_on "Edit this activity", match: :first - - fill_in "Activity type", with: @activity.activity_type - fill_in "Calories", with: @activity.calories - fill_in "Duration", with: @activity.duration - fill_in "Start", with: @activity.start - fill_in "Title", with: @activity.title - click_on "Update Activity" - - assert_text "Activity was successfully updated" - click_on "Back" - end - - test "should destroy Activity" do - visit activity_url(@activity) - click_on "Destroy this activity", match: :first - - assert_text "Activity was successfully destroyed" - end -end From 4d5fba37c18aadeaa931da35f4ced30aed775a59 Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Mon, 30 Jan 2023 11:23:50 +0530 Subject: [PATCH 33/34] Week-4: Add logs, more controller info and screenshots --- week_4/activity-tracker/README.md | 113 +++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/week_4/activity-tracker/README.md b/week_4/activity-tracker/README.md index c3248fd1..d97ac306 100644 --- a/week_4/activity-tracker/README.md +++ b/week_4/activity-tracker/README.md @@ -64,6 +64,23 @@ Ensure that you have created the database using `rails db:create`. You can now a Run the server using `rails server`. If you now go to `localhost:3000/activities` on your browser, you can see a basic app in function! +image + +Feel free to play around with the app now. Here are some screenshots of what you should be able to see: + +image + +_New Activity_ + +image + +_Show activity_ + +image + +_Editing an activity_ + + ## The Controller Now, lets open the controller and see what is happening. We'll take an example of a simple function, and try to understand what is happening. @@ -82,6 +99,100 @@ If you notice, the variable starts with `@`. This is a special type of variable At the end, we do not tell Rails to render any particular template (in opposition to some other frameworks, for instance Django). This is because of how Rails works - convention over configuration. Rails will automatically look for a file with the name `index.html` or `index.html.erb` (you'll learn about the `.erb` format when you learn about views), and directly render that file. Pretty convenient, right? +### Other important actions + +- `before_action`: A callback that sets the @activity instance variable with the Activity model instance, based on the id passed in the URL, before executing show, edit, update, and destroy actions. + +- `show` action: Displays the information of a single Activity instance, stored in the @activity instance variable. (GET Request) + +- `new` action: Creates a new instance of the Activity model, stored in the @activity instance variable. (GET Request) + +- `edit` action: Edits an existing Activity instance, stored in the @activity instance variable. (GET Request) + +- `create` action: Creates a new Activity instance with the parameters passed from the form, stored in the @activity instance variable. If the save is successful, it redirects to the show view with a success message, otherwise it renders the new view with an error message. (POST Request) + +```ruby + + def create + @activity = Activity.new(activity_params) + + respond_to do |format| + if @activity.save + format.html { redirect_to activity_url(@activity), notice: "Activity was successfully created." } + format.json { render :show, status: :created, location: @activity } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @activity.errors, status: :unprocessable_entity } + end + end + end + +``` + +- `update` action: Updates an existing Activity instance with the parameters passed from the form, stored in the @activity instance variable. If the update is successful, it redirects to the show view with a success message, otherwise it renders the edit view with an error message. (PUT/PATCH Request) + +```ruby + + def update + respond_to do |format| + if @activity.update(activity_params) + format.html { redirect_to activity_url(@activity), notice: "Activity was successfully updated." } + format.json { render :show, status: :ok, location: @activity } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @activity.errors, status: :unprocessable_entity } + end + end + end + +``` + +- `destroy` action: Destroys an existing Activity instance, stored in the @activity instance variable. It then redirects to the index view with a success message. (DELETE Request) + +```ruby + + def destroy + @activity.destroy + + respond_to do |format| + format.html { redirect_to activities_url, notice: "Activity was successfully destroyed." } + format.json { head :no_content } + end + end + +``` + +- `set_activity` private method: Sets the @activity instance variable based on the id passed in the URL. + +- `activity_params` private method: Strong parameters method, allows only the title, activity_type, start, duration, and calories attributes to be passed as parameters to the Activity model. + +image + + +## Looking at the logs + +Logs are useful to debug the application and display information about what is happening (as they 'log' everything). They can be viewed in the terminal where you ran `rails server`. + +Lets understand one such log. Others follow a similar pattern and can be explored on your own. + +image + +This is generated when you try to edit an activity. + +- The first line indicates that it has started the "PATCH" method for the _route_ `/activites/1`. + +- Processing by `ActivitiesController#update` indicates that the request is being processed by the `ActivitiesController`'s `update` action. + +- The next line indicates all the paramters being passed. This is the body of an HTTP Request. It contains all the information of our activity. + +- `set_activity` is run as a before action to find the mathing activity. + +- `UPDATE "activities" SET "calories" = ?....` indicates that an SQL `UPDATE` query is run to update our activity in the database. + +- `Redirected to https://mittal-parth-zany-space-engine-6pvjx5rjx743pwp-3000.preview.app.github.dev/activities/1` indicates that after successful updation of the record, the user has been redirected to `/activities/1` (showing the activity) + +- `Completed 302` indicates the status code of the response. 302 as you'd recall stands for redirect. + ## `rails generate controller` Scaffolding is an extremely easy and powerful way to bring up your resources. However, this is not the only way you can create controllers. They can also be generated normally by @@ -148,4 +259,4 @@ Not providing `to:` will tell Rails to look for a action with the same name as t ## References - [Rails Routing from the Outside In](https://guides.rubyonrails.org/routing.html) - [Action Controllers](https://guides.rubyonrails.org/action_controller_overview.html) -- [Layouts and Rendering in Rails (Views)](https://guides.rubyonrails.org/layouts_and_rendering.html) \ No newline at end of file +- [Layouts and Rendering in Rails (Views)](https://guides.rubyonrails.org/layouts_and_rendering.html) From d6997b7ae3085b45edf8ab464e246fdaa9fff2dc Mon Sep 17 00:00:00 2001 From: Parth Mittal <76661350+mittal-parth@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:33:40 +0530 Subject: [PATCH 34/34] Add week 4 link --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index aa3fc22b..ecc06009 100644 --- a/README.md +++ b/README.md @@ -24,5 +24,9 @@ create a new Rails project and build a simple website. Later we will take a closer look at Model of the MVC Architecture and talk about databases and working with records. +## [Week 4 - Controllers and Authentication](/week_4) + +This week, we will look into controllers, routing and authentication. + ## Contact In case of doubts related to the Bootcamp, feel free to reach out to the mentors on the [**#doubts**](https://discord.com/channels/1052463702558908416/1052467811143913552) channel on [Discord](https://discord.gg/HQKpB6XH).