├── g ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico ├── database.db ├── templates │ ├── index.html │ ├── login.html │ ├── signup.html │ ├── base.html │ └── _render_elements.html └── app.py ├── FINAL ├── uploads │ └── all_files_here ├── static │ ├── imgs │ │ ├── carita.png │ │ └── favicon.ico │ ├── js │ │ ├── main.js │ │ └── popper.min.js │ └── css │ │ ├── style.css │ │ └── bootstrap │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-reboot.min.css.map │ │ └── bootstrap-grid.css ├── requirements.txt ├── templates │ ├── 404_page_not_found.html │ ├── my_files.html │ ├── edit_profile.html │ ├── home.html │ ├── files.html │ ├── login.html │ ├── signup.html │ ├── _render_elements.html │ ├── about.html │ ├── index.html │ ├── profile.html │ └── base.html ├── config.py └── app.py ├── database ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico ├── database.db ├── templates │ ├── index.html │ └── base.html └── app.py ├── estaticos ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico └── app.py ├── jinja2 ├── static │ ├── css │ │ └── style.css │ ├── js │ │ └── main.js │ └── imgs │ │ └── favicon.ico ├── templates │ ├── index.html │ └── base.html └── app.py ├── macros ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico ├── database.db ├── templates │ ├── index.html │ ├── login.html │ ├── signup.html │ ├── base.html │ └── _render_elements.html └── app.py ├── sessions ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico ├── database.db ├── templates │ ├── index.html │ ├── base.html │ ├── login.html │ └── signup.html └── app.py ├── vistas ├── static │ ├── css │ │ └── style.css │ ├── js │ │ └── main.js │ └── imgs │ │ └── favicon.ico ├── app.py └── templates │ └── index.html ├── forms ├── complete │ ├── static │ │ ├── js │ │ │ └── main.js │ │ ├── css │ │ │ └── style.css │ │ └── imgs │ │ │ └── favicon.ico │ ├── database.db │ ├── templates │ │ ├── index.html │ │ ├── base.html │ │ ├── login.html │ │ └── signup.html │ └── app.py └── initial │ ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico │ ├── templates │ ├── .login.html.swp │ ├── index.html │ ├── base.html │ └── signup.html │ └── app.py ├── message-flashing ├── static │ ├── js │ │ └── main.js │ ├── css │ │ └── style.css │ └── imgs │ │ └── favicon.ico ├── database.db ├── templates │ ├── index.html │ ├── login.html │ ├── signup.html │ └── base.html └── app.py ├── configs ├── complete │ ├── app │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ └── post.py │ │ ├── __init__.py │ │ ├── templates │ │ │ ├── document.html │ │ │ └── add_document.html │ │ └── routes │ │ │ └── __init__.py │ ├── run.py │ └── config.py └── initial │ ├── database.db │ ├── templates │ ├── document.html │ └── add_document.html │ └── app.py ├── hw └── app.py ├── run └── app.py ├── cookies ├── templates │ └── index.html └── app.py ├── whitespacing ├── templates │ ├── index.html │ └── base.html └── app.py ├── handle-errors ├── templates │ ├── page_not_found.html │ └── forbidden.html └── app.py ├── requests ├── templates │ └── video.html └── app.py ├── urlfor-redirect └── app.py ├── json └── app.py ├── routes └── app.py ├── request-decorators └── app.py ├── upload-files └── app.py ├── .gitignore └── README.md /g/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /FINAL/uploads/all_files_here: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /database/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /estaticos/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jinja2/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jinja2/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /macros/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sessions/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vistas/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vistas/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /database/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /estaticos/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /forms/complete/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /forms/initial/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sessions/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /forms/complete/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /forms/initial/static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /message-flashing/static/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /configs/complete/app/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /message-flashing/static/css/style.css: -------------------------------------------------------------------------------- 1 | .success { 2 | color: green; 3 | } 4 | -------------------------------------------------------------------------------- /g/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/g/database.db -------------------------------------------------------------------------------- /macros/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/macros/database.db -------------------------------------------------------------------------------- /database/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/database/database.db -------------------------------------------------------------------------------- /g/static/css/style.css: -------------------------------------------------------------------------------- 1 | .success { 2 | color: green; 3 | } 4 | 5 | .error { 6 | color: red; 7 | } 8 | -------------------------------------------------------------------------------- /sessions/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/sessions/database.db -------------------------------------------------------------------------------- /macros/static/css/style.css: -------------------------------------------------------------------------------- 1 | .success { 2 | color: green; 3 | } 4 | 5 | .error { 6 | color: red; 7 | } 8 | -------------------------------------------------------------------------------- /forms/complete/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/forms/complete/database.db -------------------------------------------------------------------------------- /g/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/g/static/imgs/favicon.ico -------------------------------------------------------------------------------- /FINAL/static/imgs/carita.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/FINAL/static/imgs/carita.png -------------------------------------------------------------------------------- /configs/initial/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/configs/initial/database.db -------------------------------------------------------------------------------- /message-flashing/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/message-flashing/database.db -------------------------------------------------------------------------------- /FINAL/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/FINAL/static/imgs/favicon.ico -------------------------------------------------------------------------------- /jinja2/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/jinja2/static/imgs/favicon.ico -------------------------------------------------------------------------------- /macros/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/macros/static/imgs/favicon.ico -------------------------------------------------------------------------------- /vistas/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/vistas/static/imgs/favicon.ico -------------------------------------------------------------------------------- /configs/complete/run.py: -------------------------------------------------------------------------------- 1 | from app import app, db 2 | 3 | if __name__ == "__main__": 4 | db.create_all() 5 | app.run() -------------------------------------------------------------------------------- /database/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/database/static/imgs/favicon.ico -------------------------------------------------------------------------------- /estaticos/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/estaticos/static/imgs/favicon.ico -------------------------------------------------------------------------------- /sessions/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/sessions/static/imgs/favicon.ico -------------------------------------------------------------------------------- /forms/complete/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/forms/complete/static/imgs/favicon.ico -------------------------------------------------------------------------------- /forms/initial/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/forms/initial/static/imgs/favicon.ico -------------------------------------------------------------------------------- /forms/initial/templates/.login.html.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/forms/initial/templates/.login.html.swp -------------------------------------------------------------------------------- /message-flashing/static/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codenoschool/flask-course/HEAD/message-flashing/static/imgs/favicon.ico -------------------------------------------------------------------------------- /jinja2/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Index 4 | {% endblock %} 5 | {% block content %} 6 |

{{ titulo }}

7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /database/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Index 4 | {% endblock %} 5 | {% block content %} 6 |

{{ titulo }}

7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /configs/complete/app/schemas/post.py: -------------------------------------------------------------------------------- 1 | from app import db 2 | 3 | class Post(db.Model): 4 | id = db.Column(db.Integer, primary_key=True) 5 | document = db.Column(db.Text(length=None), nullable=False) -------------------------------------------------------------------------------- /hw/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | return "Hello World!" 8 | 9 | if __name__ == "__main__": 10 | app.run() 11 | -------------------------------------------------------------------------------- /run/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | return "Hello World!" 8 | 9 | if __name__ == "__main__": 10 | app.run(debug=True) 11 | -------------------------------------------------------------------------------- /FINAL/requirements.txt: -------------------------------------------------------------------------------- 1 | click==6.7 2 | Flask==0.12.2 3 | Flask-SQLAlchemy==2.3.2 4 | itsdangerous==0.24 5 | Jinja2==2.10 6 | MarkupSafe==1.0 7 | pkg-resources==0.0.0 8 | SQLAlchemy==1.2.0 9 | Werkzeug==0.13 10 | -------------------------------------------------------------------------------- /estaticos/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | return "Hello World!" 8 | 9 | if __name__ == "__main__": 10 | app.run(debug=True) 11 | -------------------------------------------------------------------------------- /cookies/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Home 6 | 7 | 8 |

The cookie has been created.

9 | 10 | 11 | -------------------------------------------------------------------------------- /configs/complete/app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask_sqlalchemy import SQLAlchemy 3 | 4 | app = Flask(__name__) 5 | app.config.from_object("config.DevelopmentConfig") 6 | 7 | db = SQLAlchemy(app) 8 | 9 | from app.routes import * -------------------------------------------------------------------------------- /vistas/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | return render_template("index.html") 8 | 9 | if __name__ == "__main__": 10 | app.run(debug=True) 11 | -------------------------------------------------------------------------------- /whitespacing/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title -%} 3 | Home 4 | {%- endblock %} 5 | {% block content -%} 6 |

Welcome to my website!

7 |

Jinja2 whitespacing.

8 |

lkjdlaskdjas

9 | {%- endblock %} 10 | -------------------------------------------------------------------------------- /whitespacing/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | {% block content %} 9 | {% endblock %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /vistas/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Home 6 | 7 | 8 | 9 |

Welcome!

10 | 11 | 12 | -------------------------------------------------------------------------------- /handle-errors/templates/page_not_found.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found! 6 | 7 | 8 |

Page Not Found!

9 |

We're so sorry (Error: 404)

10 | 11 | 12 | -------------------------------------------------------------------------------- /whitespacing/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | #app.jinja_env.trim_blocks = True 5 | 6 | @app.route("/") 7 | def index(): 8 | 9 | return render_template("index.html") 10 | 11 | if __name__ == "__main__": 12 | app.run(debug=True) 13 | -------------------------------------------------------------------------------- /FINAL/templates/404_page_not_found.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Page not found 4 | {% endblock %} 5 | {% block content %} 6 |

Page Not Found (Error 404)!

7 |

We're so sorry :(

8 |

Return to Home Page.

9 | {% endblock %} -------------------------------------------------------------------------------- /handle-errors/templates/forbidden.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Forbidden Access! 6 | 7 | 8 |

Forbidden Access!

9 |

You have no permission to access this page.

10 | 11 | 12 | -------------------------------------------------------------------------------- /requests/templates/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Videos 5 | 6 | 7 |

Video

8 | {% if videos %} 9 |

{{ videos["videos"]["cns"][0]["title"] }}

10 | {% else %} 11 |

There are no videos

12 | {% endif %} 13 | 14 | 15 | -------------------------------------------------------------------------------- /g/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Welcome!

7 |
8 |

9 | 10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /macros/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Welcome!

7 |
8 |

9 | 10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /sessions/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Welcome!

7 |
8 |

9 | 10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /forms/complete/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Welcome!

7 |
8 |

9 | 10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /forms/initial/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Welcome!

7 |
8 |

9 | 10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /jinja2/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | titulo = "Home!" 8 | lista = ["footer", "header", "info"] 9 | return render_template("index.html", titulo=titulo, lista=lista) 10 | 11 | if __name__ == "__main__": 12 | app.run(debug=True) 13 | -------------------------------------------------------------------------------- /message-flashing/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Welcome!

7 |
8 |

9 | 10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /jinja2/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | {% block content %} 10 | {% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /database/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | {% block content %} 10 | {% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /sessions/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | {% block content %} 10 | {% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /forms/complete/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | {% block content %} 10 | {% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /forms/initial/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | {% block content %} 10 | {% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /g/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Log In 4 | {% endblock %} 5 | {% block content %} 6 |

Log In

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /macros/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Log In 4 | {% endblock %} 5 | {% block content %} 6 |

Log In

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /sessions/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Log In 4 | {% endblock %} 5 | {% block content %} 6 |

Log In

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /sessions/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Sign Up 4 | {% endblock %} 5 | {% block content %} 6 |

Sign Up

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /forms/complete/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Log In 4 | {% endblock %} 5 | {% block content %} 6 |

Log In

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /forms/initial/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Sign Up 4 | {% endblock %} 5 | {% block content %} 6 |

Sign Up

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /message-flashing/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Log In 4 | {% endblock %} 5 | {% block content %} 6 |

Log In

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /forms/complete/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Sign Up 4 | {% endblock %} 5 | {% block content %} 6 |

Sign Up

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /message-flashing/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Sign Up 4 | {% endblock %} 5 | {% block content %} 6 |

Sign Up

7 |
8 |

9 |

10 | 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /configs/initial/templates/document.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document {{ post.id }} 8 | 9 | 10 |

Document {{ post.id }}

11 |

12 | {{ body|safe }} 13 |

14 | 15 | -------------------------------------------------------------------------------- /configs/complete/app/templates/document.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document {{ post.id }} 8 | 9 | 10 |

Document {{ post.id }}

11 |

12 | {{ body|safe }} 13 |

14 | 15 | -------------------------------------------------------------------------------- /FINAL/static/js/main.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | console.log('I am ready.'); 3 | // get current URL path and assign 'active' class 4 | var pathname = window.location.pathname; 5 | $('.navbar-nav > li > a[href="'+pathname+'"]').parent().addClass('active'); 6 | 7 | setTimeout( 8 | function(){ 9 | $(".alert-success").alert('close'); 10 | }, 2500 11 | ); 12 | //$(".alert").alert('close'); 13 | }); -------------------------------------------------------------------------------- /forms/initial/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | from flask_sqlalchemy import SQLAlchemy 3 | 4 | import os 5 | 6 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 7 | 8 | app = Flask(__name__) 9 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 10 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 11 | db = SQLAlchemy(app) 12 | 13 | if __name__ == "__main__": 14 | db.create_all() 15 | app.run(debug=True) 16 | -------------------------------------------------------------------------------- /g/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_render_elements.html" import render_input %} 3 | {% block title %} 4 | Sign Up 5 | {% endblock %} 6 | {% block content %} 7 |

Sign Up

8 |
9 | {{ render_input("username", "Username") }} 10 | {{ render_input("password", "Password", type="password") }} 11 | 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /macros/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_render_elements.html" import render_input %} 3 | {% block title %} 4 | Sign Up 5 | {% endblock %} 6 | {% block content %} 7 |

Sign Up

8 |
9 | {{ render_input("username", "Username") }} 10 | {{ render_input("password", "Password", type="password") }} 11 | 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /requests/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | from requests import get 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route("/") 8 | def index(): 9 | 10 | return "Hello World!" 11 | 12 | @app.route("/video") 13 | def show_video(): 14 | 15 | videos = get("http://127.0.0.1:5000/api/v1/videos/").json() 16 | 17 | return render_template("video.html", videos=videos) 18 | 19 | if __name__ == "__main__": 20 | app.run(debug=True, port=3000) 21 | -------------------------------------------------------------------------------- /FINAL/templates/my_files.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | My Files 4 | {% endblock %} 5 | {% block content %} 6 |

My Files

7 | {% if files %} 8 | 13 | {% else %} 14 |

There are no files yet :(

15 |

Let's upload one! ^^

16 | {% endif %} 17 | {% endblock %} -------------------------------------------------------------------------------- /configs/complete/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | class Config(object): 4 | DEBUG = False 5 | SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' 6 | SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:" 7 | SQLALCHEMY_TRACK_MODIFICATIONS = False 8 | 9 | class ProductionConfig(Config): 10 | SECRET_KEY = os.environ["SECRET_KEY"] 11 | SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.abspath(os.getcwd()) + "\\database.db" 12 | 13 | class DevelopmentConfig(Config): 14 | DEBUG = True -------------------------------------------------------------------------------- /g/templates/base.html: -------------------------------------------------------------------------------- 1 | {% from "_render_elements.html" import render_messages %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | {{ render_messages(messages) }} 12 | {% block content %} 13 | {% endblock %} 14 | 15 | 16 | -------------------------------------------------------------------------------- /macros/templates/base.html: -------------------------------------------------------------------------------- 1 | {% from "_render_elements.html" import render_messages %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | {{ render_messages(messages) }} 12 | {% block content %} 13 | {% endblock %} 14 | 15 | 16 | -------------------------------------------------------------------------------- /FINAL/templates/edit_profile.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Edit Profile 4 | {% endblock %} 5 | {% block content %} 6 |

Settings

7 |
Edit Profile
8 |
9 |
10 | 11 | 12 |
13 | 14 |
15 | {% endblock %} -------------------------------------------------------------------------------- /configs/initial/templates/add_document.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Add Document 8 | 9 | 10 |

New Document

11 |
12 |

13 |

14 | 15 |
16 | 17 | -------------------------------------------------------------------------------- /configs/complete/app/templates/add_document.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Add Document 8 | 9 | 10 |

New Document

11 |
12 |

13 |

14 | 15 |
16 | 17 | -------------------------------------------------------------------------------- /FINAL/static/css/style.css: -------------------------------------------------------------------------------- 1 | .success { 2 | color: green; 3 | } 4 | 5 | .error { 6 | color: red; 7 | } 8 | 9 | /* Sticky footer styles 10 | -------------------------------------------------- */ 11 | html { 12 | position: relative; 13 | min-height: 100%; 14 | } 15 | body { 16 | margin-bottom: 60px; /* Margin bottom by footer height */ 17 | } 18 | .footer { 19 | position: absolute; 20 | bottom: 0; 21 | width: 100%; 22 | height: 60px; /* Set the fixed height of the footer here */ 23 | line-height: 60px; /* Vertically center the text there */ 24 | background-color: #f5f5f5; 25 | } 26 | -------------------------------------------------------------------------------- /FINAL/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |
7 |
8 |

Welcome!

9 |

Select your file to upload.*

10 |
11 |

12 |

13 |
14 |
15 |

16 | * All the files are public so be careful with your uploads. 17 |

18 |
19 |
20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /FINAL/templates/files.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Files 4 | {% endblock %} 5 | {% block content %} 6 |

Files

7 | {% if files %} 8 |
9 | {% for file in files[::-1] %} 10 |
Title: {{ file.filename }}
11 |
- Author: {{ file.owner_username|lower }}
12 | {% endfor %} 13 |
14 | {% else %} 15 |

There are no files yet :(

16 |

Let's upload one! ^^

17 | {% endif %} 18 | {% endblock %} -------------------------------------------------------------------------------- /FINAL/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | UPLOAD_FOLDER = os.path.abspath("./uploads/") 4 | DB_URI = "TBD" 5 | 6 | class Config(object): 7 | DEBUG = False 8 | SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' 9 | SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:" 10 | SQLALCHEMY_TRACK_MODIFICATIONS = False 11 | UPLOAD_FOLDER = UPLOAD_FOLDER 12 | 13 | class ProductionConfig(Config): 14 | SECRET_KEY = os.environ["SECRET_KEY"] 15 | SQLALCHEMY_DATABASE_URI = DB_URI 16 | 17 | class DevelopmentConfig(Config): 18 | DEBUG = True 19 | SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.abspath("./database.db") -------------------------------------------------------------------------------- /FINAL/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_render_elements.html" import render_input %} 3 | {% block title %} 4 | Log In 5 | {% endblock %} 6 | {% block content %} 7 |
8 |
9 |

Log In

10 |
11 | {{ render_input("username", "Username") }} 12 | {{ render_input("password", "Password", type="password") }} 13 | 14 |
15 |

Haven't an account yet? Sign up for FREE!

16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /handle-errors/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, abort 2 | 3 | app = Flask(__name__) 4 | 5 | admin_user = "" 6 | 7 | @app.route("/") 8 | def index(): 9 | 10 | return "Hello World!" 11 | 12 | @app.route("/admin") 13 | def admin(): 14 | if not admin_user: 15 | abort(403) 16 | 17 | return "Welcome {}!".format(admin_user) 18 | 19 | @app.errorhandler(404) 20 | def page_not_found(err): 21 | 22 | return render_template("page_not_found.html"), 404 23 | 24 | @app.errorhandler(403) 25 | def forbidden(err): 26 | 27 | return render_template("forbidden.html"), 403 28 | 29 | if __name__ == "__main__": 30 | app.run(debug=True) 31 | -------------------------------------------------------------------------------- /cookies/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, make_response 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | 8 | return "Hello World!" 9 | 10 | @app.route("/cookie/set") 11 | def set_cookie(): 12 | resp = make_response(render_template("index.html")) 13 | resp.set_cookie("username", "CodeNoSchool") 14 | 15 | return resp 16 | 17 | @app.route("/cookie/read") 18 | def read_cookie(): 19 | username = request.cookies.get("username", None) 20 | 21 | if username == None: 22 | return "The cookie doesn't exist." 23 | 24 | return username 25 | 26 | if __name__ == "__main__": 27 | app.run(debug=True) 28 | -------------------------------------------------------------------------------- /urlfor-redirect/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, redirect, url_for 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | 8 | return "Hello World!" 9 | 10 | @app.route("/start") 11 | def start(): 12 | 13 | return url_for("start", next="login") 14 | 15 | @app.route("/google") 16 | def go_to_google(): 17 | 18 | return redirect("https://www.google.com") 19 | 20 | @app.route("/post/") 21 | def post(id): 22 | 23 | return "Showing post: {}".format(id) 24 | 25 | @app.route("/today") 26 | def today(): 27 | 28 | return redirect(url_for("post", id=50, next="edit")) 29 | 30 | if __name__ == "__main__": 31 | app.run(debug=True) 32 | -------------------------------------------------------------------------------- /FINAL/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_render_elements.html" import render_input %} 3 | {% block title %} 4 | Sign Up 5 | {% endblock %} 6 | {% block content %} 7 |
8 |
9 |

Sign Up

10 |
11 | {{ render_input("username", "Username") }} 12 | {{ render_input("email", "Email") }} 13 | {{ render_input("password", "Password", type="password") }} 14 | 15 |
16 |

Have an account already? Log In

17 |
18 |
19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /message-flashing/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | 10 | {% with messages = get_flashed_messages(category_filter=["success"]) %} 11 | {% if messages %} 12 | 17 | {% endif %} 18 | {% endwith %} 19 | {% block content %} 20 | {% endblock %} 21 | 22 | 23 | -------------------------------------------------------------------------------- /g/templates/_render_elements.html: -------------------------------------------------------------------------------- 1 | {% macro render_input(name, placeholder, type="text") %} 2 |

3 | {% endmacro %} 4 | 5 | {% macro render_messages(messages) %} 6 | {% with messages = get_flashed_messages(category_filter=["success"]) %} 7 | {% if messages %} 8 | 13 | {% endif %} 14 | {% endwith %} 15 | {% with messages = get_flashed_messages(category_filter=["error"]) %} 16 | {% if messages %} 17 | 22 | {% endif %} 23 | {% endwith %} 24 | {% endmacro %} 25 | -------------------------------------------------------------------------------- /macros/templates/_render_elements.html: -------------------------------------------------------------------------------- 1 | {% macro render_input(name, placeholder, type="text") %} 2 |

3 | {% endmacro %} 4 | 5 | {% macro render_messages(messages) %} 6 | {% with messages = get_flashed_messages(category_filter=["success"]) %} 7 | {% if messages %} 8 | 13 | {% endif %} 14 | {% endwith %} 15 | {% with messages = get_flashed_messages(category_filter=["error"]) %} 16 | {% if messages %} 17 | 22 | {% endif %} 23 | {% endwith %} 24 | {% endmacro %} 25 | -------------------------------------------------------------------------------- /FINAL/templates/_render_elements.html: -------------------------------------------------------------------------------- 1 | {% macro render_input(name, placeholder, type="text") %} 2 |
3 | 4 | 5 |
6 | {% endmacro %} 7 | 8 | {% macro render_messages(messages) %} 9 | {% with messages = get_flashed_messages(with_categories=true) %} 10 | {% if messages %} 11 | {% for category, message in messages %} 12 | 18 | {% endfor %} 19 | {% endif %} 20 | {% endwith %} 21 | {% endmacro %} 22 | -------------------------------------------------------------------------------- /configs/complete/app/routes/__init__.py: -------------------------------------------------------------------------------- 1 | from app import app, db 2 | from app.schemas.post import Post 3 | from flask import render_template, request, redirect, url_for 4 | 5 | @app.route("/") 6 | def index(): 7 | 8 | return "Hello World!" 9 | 10 | @app.route("/add/document", methods=["GET", "POST"]) 11 | def document(): 12 | if request.method == "POST": 13 | new_post = Post(document=request.form["document"]) 14 | db.session.add(new_post) 15 | db.session.commit() 16 | 17 | return redirect(url_for("get_document", id=new_post.id)) 18 | 19 | return render_template("add_document.html") 20 | 21 | @app.route("/document/") 22 | def get_document(id): 23 | 24 | post = Post.query.get(id) 25 | bodytoHTML = post.document.replace("\n", "
") 26 | 27 | return render_template("document.html", post=post, body=bodytoHTML) -------------------------------------------------------------------------------- /json/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | app = Flask(__name__) 4 | 5 | cns = [ 6 | { 7 | "id": 1, 8 | "title": "1.- Hello World - Curso Flask" 9 | }, 10 | { 11 | "id": 2, 12 | "title": "2.- Metodo Run - Curso Flask" 13 | } 14 | ] 15 | 16 | isc = [ 17 | { 18 | "id": 1, 19 | "title": "1.- Hello World - Curso Flask" 20 | }, 21 | { 22 | "id": 2, 23 | "title": "2.- Metodo Run - Curso Flask" 24 | } 25 | ] 26 | 27 | @app.route("/") 28 | def index(): 29 | 30 | return "Hello World!" 31 | 32 | @app.route("/api/v1/videos/") 33 | def get_all_videos(): 34 | 35 | return jsonify({"videos": {"cns": cns, "isc": isc}}) 36 | 37 | if __name__ == "__main__": 38 | app.run(debug=True) 39 | -------------------------------------------------------------------------------- /routes/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route("/") 6 | def index(): 7 | return "Hello World!" 8 | 9 | @app.route("/hola") 10 | def hola(): 11 | return "Hola." 12 | 13 | @app.route("/user/") 14 | def user(user): 15 | return "Hola " + user 16 | 17 | @app.route("/numero/") 18 | def numero(n): 19 | return "Numero: {}".format(n) 20 | 21 | @app.route("/user//") 22 | def username(id, username): 23 | return "ID: {}, Nombre de ususario: {}".format(id, username) 24 | 25 | @app.route("/suma//") 26 | def suma(n1, n2): 27 | return "El resultado es: {}".format(n1 + n2) 28 | 29 | @app.route("/default/") 30 | @app.route("/default/") 31 | def dft(dft="xD"): 32 | return "El valor de dft es: " + dft 33 | 34 | if __name__ == "__main__": 35 | app.run(debug=True) 36 | -------------------------------------------------------------------------------- /request-decorators/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | 6 | request_status = "" 7 | 8 | @app.before_request 9 | def before_request(): 10 | global request_status 11 | 12 | request_status += "Before request" 13 | print("Before request.") 14 | 15 | @app.after_request 16 | def after_request(response): 17 | global request_status 18 | 19 | request_status = request_status + " After request" 20 | print("After request") 21 | 22 | return response 23 | 24 | @app.teardown_request 25 | def teardown_request(response): 26 | global request_status 27 | 28 | request_status = request_status + " Teardown request" 29 | print("Teardown request.") 30 | 31 | return response 32 | 33 | @app.route("/") 34 | def index(): 35 | 36 | return "Request status: " + request_status 37 | 38 | if __name__ == "__main__": 39 | app.run(debug=True) 40 | -------------------------------------------------------------------------------- /database/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | from flask_sqlalchemy import SQLAlchemy 3 | 4 | import os 5 | 6 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 7 | 8 | app = Flask(__name__) 9 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 10 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 11 | db = SQLAlchemy(app) 12 | 13 | class Posts(db.Model): 14 | id = db.Column(db.Integer, primary_key=True) 15 | title = db.Column(db.String(50)) 16 | 17 | @app.route("/") 18 | def index(): 19 | titulo = "Home!" 20 | lista = ["footer", "header", "info"] 21 | return render_template("index.html", titulo=titulo, lista=lista) 22 | 23 | @app.route("/insert/default") 24 | def insert_default(): 25 | new_post = Posts(title="Default Title") 26 | db.session.add(new_post) 27 | db.session.commit() 28 | 29 | return "The default post was created." 30 | 31 | @app.route("/select/default") 32 | def select_default(): 33 | post = Posts.query.filter_by(id=1).first() 34 | 35 | print(post.title) 36 | 37 | return "Query done." 38 | 39 | if __name__ == "__main__": 40 | db.create_all() 41 | app.run(debug=True) 42 | -------------------------------------------------------------------------------- /FINAL/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | About 4 | {% endblock %} 5 | {% block content %} 6 |

About

7 |

Learn more about this web application.

8 |

9 | This web application is the final result of 10 | The Free Flask Course. 11 |

12 |

13 | You can follow the course right here! 14 |
15 | Repository of the course (GitHub): 16 | Available here! 17 |

18 |

19 | CodeNoSchool 20 |

27 |

28 |

29 | ISC School 30 |

35 |

36 | {% endblock %} -------------------------------------------------------------------------------- /configs/initial/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, render_template, redirect, url_for 2 | from flask_sqlalchemy import SQLAlchemy 3 | 4 | import os 5 | 6 | DBURI = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 7 | app = Flask(__name__) 8 | app.config["SQLALCHEMY_DATABASE_URI"] = DBURI 9 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 10 | 11 | db = SQLAlchemy(app) 12 | 13 | class Post(db.Model): 14 | id = db.Column(db.Integer, primary_key=True) 15 | document = db.Column(db.Text(length=None), nullable=False) 16 | 17 | @app.route("/") 18 | def index(): 19 | 20 | return "Hello World!" 21 | 22 | @app.route("/add/document", methods=["GET", "POST"]) 23 | def document(): 24 | if request.method == "POST": 25 | new_post = Post(document=request.form["document"]) 26 | db.session.add(new_post) 27 | db.session.commit() 28 | 29 | return redirect(url_for("get_document", id=new_post.id)) 30 | 31 | return render_template("add_document.html") 32 | 33 | @app.route("/document/") 34 | def get_document(id): 35 | 36 | post = Post.query.get(id) 37 | bodytoHTML = post.document.replace("\n", "
") 38 | 39 | return render_template("document.html", post=post, body=bodytoHTML) 40 | 41 | if __name__ == "__main__": 42 | db.create_all() 43 | app.run(debug=True) -------------------------------------------------------------------------------- /FINAL/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | Welcome 4 | {% endblock %} 5 | {% block content %} 6 |
7 |
8 |

ISC & CodeNoSchool!

9 |

Always providing you new learnings.

10 |
11 |
12 |
13 |
14 |
15 |
16 |

Help

17 |

Do you need more information about this project?

18 | Check it out! 19 |
20 |
21 |
22 |
23 |
24 |
25 |

Welcome!

26 |

What are you waiting for? Start now to upload your files!

27 | Go! 28 |
29 |
30 |
31 |
32 |
33 |
34 |

Account

35 |

All that you need is an account to share your files! It's free!

36 | Sign Up 37 | Log In 38 |
39 |
40 |
41 |
42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /FINAL/templates/profile.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %} 3 | {{ user.username|upper }} Profile 4 | {% endblock %} 5 | {% block content %} 6 |
7 |
8 |
9 | Card image cap 10 |
11 |

{{ user.username|upper }}

12 |

About me

13 | {% if user.about_me %} 14 |

{{ user.about_me|capitalize }}

15 | {% else %} 16 |

Nothing to show us :( 17 | {% if user.username == g.user %} 18 |
Edit Profile 19 | {% endif %} 20 |

21 | {% endif %} 22 |
23 |
24 |
25 |
26 |

Files (10)

27 | {% if files %} 28 |
29 | {% for file in files[::-1] %} 30 | 31 | {{ file.filename}} 32 | 33 | {% endfor %} 34 |
35 | {% else %} 36 |

There are no files yet.

37 | {% endif %} 38 |
39 |
40 | {% endblock %} -------------------------------------------------------------------------------- /upload-files/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, redirect, url_for, send_from_directory 2 | from werkzeug.utils import secure_filename 3 | 4 | import os 5 | 6 | UPLOAD_FOLDER = os.path.abspath("./uploads/") 7 | ALLOWED_EXTENSIONS = set(["png", "jpg", "jpge"]) 8 | 9 | def allowed_file(filename): 10 | 11 | return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS 12 | 13 | app = Flask(__name__) 14 | app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER 15 | 16 | @app.route("/") 17 | def index(): 18 | 19 | return "Hello World!" 20 | 21 | @app.route("/upload", methods=["GET", "POST"]) 22 | def upload_file(): 23 | if request.method == "POST": 24 | if not "file" in request.files: 25 | return "No file part in the form." 26 | f = request.files["file"] 27 | if f.filename == "": 28 | return "No file selected." 29 | if f and allowed_file(f.filename): 30 | filename = secure_filename(f.filename) 31 | f.save(os.path.join(app.config["UPLOAD_FOLDER"], filename)) 32 | return redirect(url_for("get_file", filename=filename)) 33 | return "File not allowed." 34 | 35 | return """ 36 | 37 | 38 | 39 | Upload File 40 | 41 | 42 |

Upload File

43 |
44 | 45 | 46 |
47 | 48 | """ 49 | 50 | @app.route("/uploads/") 51 | def get_file(filename): 52 | 53 | return send_from_directory(app.config["UPLOAD_FOLDER"], filename) 54 | 55 | if __name__ == "__main__": 56 | app.run(debug=True) 57 | -------------------------------------------------------------------------------- /forms/complete/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | from flask_sqlalchemy import SQLAlchemy 3 | from werkzeug.security import generate_password_hash, check_password_hash 4 | 5 | import os 6 | 7 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 8 | 9 | app = Flask(__name__) 10 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 11 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 12 | db = SQLAlchemy(app) 13 | 14 | class Users(db.Model): 15 | id = db.Column(db.Integer, primary_key=True) 16 | username = db.Column(db.String(50), unique=True, nullable=False) 17 | password = db.Column(db.String(80), nullable=False) 18 | 19 | @app.route("/") 20 | def index(): 21 | return render_template("index.html") 22 | 23 | @app.route("/search") 24 | def search(): 25 | nickname = request.args.get("nickname") 26 | 27 | user = Users.query.filter_by(username=nickname).first() 28 | 29 | if user: 30 | return user.username 31 | 32 | return "The user doesn't exist." 33 | 34 | @app.route("/signup", methods=["GET", "POST"]) 35 | def signup(): 36 | if request.method == "POST": 37 | hashed_pw = generate_password_hash(request.form["password"], method="sha256") 38 | new_user = Users(username=request.form["username"], password=hashed_pw) 39 | db.session.add(new_user) 40 | db.session.commit() 41 | 42 | return "You've registered successfully." 43 | 44 | return render_template("signup.html") 45 | 46 | @app.route("/login", methods=["GET", "POST"]) 47 | def login(): 48 | if request.method == "POST": 49 | user = Users.query.filter_by(username=request.form["username"]).first() 50 | 51 | if user and check_password_hash(user.password, request.form["password"]): 52 | return "You are logged in" 53 | return "Your credentials are invalid, check and try again." 54 | 55 | return render_template("login.html") 56 | 57 | if __name__ == "__main__": 58 | db.create_all() 59 | app.run(debug=True) 60 | -------------------------------------------------------------------------------- /sessions/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, session, escape 2 | from flask_sqlalchemy import SQLAlchemy 3 | from werkzeug.security import generate_password_hash, check_password_hash 4 | 5 | import os 6 | 7 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 8 | 9 | app = Flask(__name__) 10 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 11 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 12 | db = SQLAlchemy(app) 13 | 14 | class Users(db.Model): 15 | id = db.Column(db.Integer, primary_key=True) 16 | username = db.Column(db.String(50), unique=True, nullable=False) 17 | password = db.Column(db.String(80), nullable=False) 18 | 19 | @app.route("/") 20 | def index(): 21 | return render_template("index.html") 22 | 23 | @app.route("/search") 24 | def search(): 25 | nickname = request.args.get("nickname") 26 | 27 | user = Users.query.filter_by(username=nickname).first() 28 | 29 | if user: 30 | return user.username 31 | 32 | return "The user doesn't exist." 33 | 34 | @app.route("/signup", methods=["GET", "POST"]) 35 | def signup(): 36 | if request.method == "POST": 37 | hashed_pw = generate_password_hash(request.form["password"], method="sha256") 38 | new_user = Users(username=request.form["username"], password=hashed_pw) 39 | db.session.add(new_user) 40 | db.session.commit() 41 | 42 | return "You've registered successfully." 43 | 44 | return render_template("signup.html") 45 | 46 | @app.route("/login", methods=["GET", "POST"]) 47 | def login(): 48 | if request.method == "POST": 49 | user = Users.query.filter_by(username=request.form["username"]).first() 50 | 51 | if user and check_password_hash(user.password, request.form["password"]): 52 | session["username"] = user.username 53 | return "You are logged in" 54 | return "Your credentials are invalid, check and try again." 55 | 56 | return render_template("login.html") 57 | 58 | @app.route("/home") 59 | def home(): 60 | if "username" in session: 61 | return "You are %s" % escape(session["username"]) 62 | 63 | return "You must log in first." 64 | 65 | @app.route("/logout") 66 | def logout(): 67 | session.pop("username", None) 68 | 69 | return "You are logged out." 70 | 71 | app.secret_key = "12345" 72 | 73 | 74 | if __name__ == "__main__": 75 | db.create_all() 76 | app.run(debug=True) 77 | -------------------------------------------------------------------------------- /macros/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, session, escape, redirect, url_for, flash 2 | from flask_sqlalchemy import SQLAlchemy 3 | from werkzeug.security import generate_password_hash, check_password_hash 4 | 5 | import os 6 | 7 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 8 | 9 | app = Flask(__name__) 10 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 11 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 12 | db = SQLAlchemy(app) 13 | 14 | class Users(db.Model): 15 | id = db.Column(db.Integer, primary_key=True) 16 | username = db.Column(db.String(50), unique=True, nullable=False) 17 | password = db.Column(db.String(80), nullable=False) 18 | 19 | @app.route("/") 20 | def index(): 21 | return render_template("index.html") 22 | 23 | @app.route("/search") 24 | def search(): 25 | nickname = request.args.get("nickname") 26 | 27 | user = Users.query.filter_by(username=nickname).first() 28 | 29 | if user: 30 | return user.username 31 | 32 | return "The user doesn't exist." 33 | 34 | @app.route("/signup", methods=["GET", "POST"]) 35 | def signup(): 36 | if request.method == "POST": 37 | hashed_pw = generate_password_hash(request.form["password"], method="sha256") 38 | new_user = Users(username=request.form["username"], password=hashed_pw) 39 | db.session.add(new_user) 40 | db.session.commit() 41 | 42 | flash("You've registered successfully.", "success") 43 | 44 | return redirect(url_for("login")) 45 | 46 | return render_template("signup.html") 47 | 48 | @app.route("/login", methods=["GET", "POST"]) 49 | def login(): 50 | if request.method == "POST": 51 | user = Users.query.filter_by(username=request.form["username"]).first() 52 | 53 | if user and check_password_hash(user.password, request.form["password"]): 54 | session["username"] = user.username 55 | return "You are logged in" 56 | flash("Your credentials are invalid, check and try again.", "error") 57 | 58 | return render_template("login.html") 59 | 60 | @app.route("/home") 61 | def home(): 62 | if "username" in session: 63 | return "You are %s" % escape(session["username"]) 64 | 65 | return "You must log in first." 66 | 67 | @app.route("/logout") 68 | def logout(): 69 | session.pop("username", None) 70 | 71 | return "You are logged out." 72 | 73 | app.secret_key = "12345" 74 | 75 | 76 | if __name__ == "__main__": 77 | db.create_all() 78 | app.run(debug=True) 79 | -------------------------------------------------------------------------------- /message-flashing/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, session, escape, redirect, url_for, flash 2 | from flask_sqlalchemy import SQLAlchemy 3 | from werkzeug.security import generate_password_hash, check_password_hash 4 | 5 | import os 6 | 7 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 8 | 9 | app = Flask(__name__) 10 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 11 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 12 | db = SQLAlchemy(app) 13 | 14 | class Users(db.Model): 15 | id = db.Column(db.Integer, primary_key=True) 16 | username = db.Column(db.String(50), unique=True, nullable=False) 17 | password = db.Column(db.String(80), nullable=False) 18 | 19 | @app.route("/") 20 | def index(): 21 | return render_template("index.html") 22 | 23 | @app.route("/search") 24 | def search(): 25 | nickname = request.args.get("nickname") 26 | 27 | user = Users.query.filter_by(username=nickname).first() 28 | 29 | if user: 30 | return user.username 31 | 32 | return "The user doesn't exist." 33 | 34 | @app.route("/signup", methods=["GET", "POST"]) 35 | def signup(): 36 | if request.method == "POST": 37 | hashed_pw = generate_password_hash(request.form["password"], method="sha256") 38 | new_user = Users(username=request.form["username"], password=hashed_pw) 39 | db.session.add(new_user) 40 | db.session.commit() 41 | 42 | flash("You've registered successfully.", "success") 43 | 44 | return redirect(url_for("login")) 45 | 46 | return render_template("signup.html") 47 | 48 | @app.route("/login", methods=["GET", "POST"]) 49 | def login(): 50 | if request.method == "POST": 51 | user = Users.query.filter_by(username=request.form["username"]).first() 52 | 53 | if user and check_password_hash(user.password, request.form["password"]): 54 | session["username"] = user.username 55 | return "You are logged in" 56 | flash("Your credentials are invalid, check and try again.", "success") 57 | 58 | return render_template("login.html") 59 | 60 | @app.route("/home") 61 | def home(): 62 | if "username" in session: 63 | return "You are %s" % escape(session["username"]) 64 | 65 | return "You must log in first." 66 | 67 | @app.route("/logout") 68 | def logout(): 69 | session.pop("username", None) 70 | 71 | return "You are logged out." 72 | 73 | app.secret_key = "12345" 74 | 75 | 76 | if __name__ == "__main__": 77 | db.create_all() 78 | app.run(debug=True) 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/linux,python,windows 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### Python ### 20 | # Byte-compiled / optimized / DLL files 21 | __pycache__/ 22 | *.py[cod] 23 | *$py.class 24 | 25 | # C extensions 26 | *.so 27 | 28 | # Distribution / packaging 29 | .Python 30 | build/ 31 | develop-eggs/ 32 | dist/ 33 | downloads/ 34 | eggs/ 35 | .eggs/ 36 | lib/ 37 | lib64/ 38 | parts/ 39 | sdist/ 40 | var/ 41 | wheels/ 42 | *.egg-info/ 43 | .installed.cfg 44 | *.egg 45 | 46 | # PyInstaller 47 | # Usually these files are written by a python script from a template 48 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 49 | *.manifest 50 | *.spec 51 | 52 | # Installer logs 53 | pip-log.txt 54 | pip-delete-this-directory.txt 55 | 56 | # Unit test / coverage reports 57 | htmlcov/ 58 | .tox/ 59 | .coverage 60 | .coverage.* 61 | .cache 62 | nosetests.xml 63 | coverage.xml 64 | *.cover 65 | .hypothesis/ 66 | 67 | # Translations 68 | *.mo 69 | *.pot 70 | 71 | # Django stuff: 72 | *.log 73 | local_settings.py 74 | 75 | # Flask stuff: 76 | instance/ 77 | .webassets-cache 78 | 79 | # Scrapy stuff: 80 | .scrapy 81 | 82 | # Sphinx documentation 83 | docs/_build/ 84 | 85 | # PyBuilder 86 | target/ 87 | 88 | # Jupyter Notebook 89 | .ipynb_checkpoints 90 | 91 | # pyenv 92 | .python-version 93 | 94 | # celery beat schedule file 95 | celerybeat-schedule 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | 122 | ### Windows ### 123 | # Windows thumbnail cache files 124 | Thumbs.db 125 | ehthumbs.db 126 | ehthumbs_vista.db 127 | 128 | # Folder config file 129 | Desktop.ini 130 | 131 | # Recycle Bin used on file shares 132 | $RECYCLE.BIN/ 133 | 134 | # Windows Installer files 135 | *.cab 136 | *.msi 137 | *.msm 138 | *.msp 139 | 140 | # Windows shortcuts 141 | *.lnk 142 | 143 | # End of https://www.gitignore.io/api/linux,python,windows 144 | -------------------------------------------------------------------------------- /g/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, session, escape, redirect, url_for, flash, g 2 | from flask_sqlalchemy import SQLAlchemy 3 | from werkzeug.security import generate_password_hash, check_password_hash 4 | 5 | import os 6 | 7 | dbdir = "sqlite:///" + os.path.abspath(os.getcwd()) + "/database.db" 8 | 9 | app = Flask(__name__) 10 | app.config["SQLALCHEMY_DATABASE_URI"] = dbdir 11 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 12 | db = SQLAlchemy(app) 13 | 14 | class Users(db.Model): 15 | id = db.Column(db.Integer, primary_key=True) 16 | username = db.Column(db.String(50), unique=True, nullable=False) 17 | password = db.Column(db.String(80), nullable=False) 18 | 19 | @app.before_request 20 | def before_request(): 21 | if "username" in session: 22 | g.user = session["username"] 23 | else: 24 | g.user = None 25 | 26 | @app.route("/") 27 | def index(): 28 | return render_template("index.html") 29 | 30 | @app.route("/search") 31 | def search(): 32 | nickname = request.args.get("nickname") 33 | 34 | user = Users.query.filter_by(username=nickname).first() 35 | 36 | if user: 37 | return user.username 38 | 39 | return "The user doesn't exist." 40 | 41 | @app.route("/signup", methods=["GET", "POST"]) 42 | def signup(): 43 | if request.method == "POST": 44 | hashed_pw = generate_password_hash(request.form["password"], method="sha256") 45 | new_user = Users(username=request.form["username"], password=hashed_pw) 46 | db.session.add(new_user) 47 | db.session.commit() 48 | 49 | flash("You've registered successfully.", "success") 50 | 51 | return redirect(url_for("login")) 52 | 53 | return render_template("signup.html") 54 | 55 | @app.route("/login", methods=["GET", "POST"]) 56 | def login(): 57 | if request.method == "POST": 58 | user = Users.query.filter_by(username=request.form["username"]).first() 59 | 60 | if user and check_password_hash(user.password, request.form["password"]): 61 | session["username"] = user.username 62 | return "You are logged in" 63 | flash("Your credentials are invalid, check and try again.", "error") 64 | 65 | return render_template("login.html") 66 | 67 | @app.route("/home") 68 | def home(): 69 | if g.user: 70 | return "You are %s" % g.user 71 | 72 | return "You must log in first." 73 | 74 | @app.route("/logout") 75 | def logout(): 76 | session.pop("username", None) 77 | 78 | return "You are logged out." 79 | 80 | app.secret_key = "12345" 81 | 82 | 83 | if __name__ == "__main__": 84 | db.create_all() 85 | app.run(debug=True) 86 | -------------------------------------------------------------------------------- /FINAL/static/css/bootstrap/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /FINAL/templates/base.html: -------------------------------------------------------------------------------- 1 | {% from "_render_elements.html" import render_messages %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% block title %}{% endblock %} 9 | {% block styles %} 10 | 11 | 12 | 13 | {% endblock %} 14 | 15 | 16 | 66 | 67 | {{ render_messages(messages) }} 68 | 69 |
70 | {% block content %} 71 | {% endblock %} 72 |
73 | 74 |
75 |
76 | © 2017 ISC 77 | & CodeNoSchool. All rigths reserved. 78 |
79 |
80 | 81 | {% block scripts %} 82 | 83 | 84 | 85 | 86 | {% endblock %} 87 | 88 | 89 | -------------------------------------------------------------------------------- /FINAL/static/css/bootstrap/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -ms-text-size-adjust: 100%; 19 | -ms-overflow-style: scrollbar; 20 | -webkit-tap-highlight-color: transparent; 21 | } 22 | 23 | @-ms-viewport { 24 | width: device-width; 25 | } 26 | 27 | article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { 28 | display: block; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 34 | font-size: 1rem; 35 | font-weight: 400; 36 | line-height: 1.5; 37 | color: #212529; 38 | text-align: left; 39 | background-color: #fff; 40 | } 41 | 42 | [tabindex="-1"]:focus { 43 | outline: none !important; 44 | } 45 | 46 | hr { 47 | box-sizing: content-box; 48 | height: 0; 49 | overflow: visible; 50 | } 51 | 52 | h1, h2, h3, h4, h5, h6 { 53 | margin-top: 0; 54 | margin-bottom: 0.5rem; 55 | } 56 | 57 | p { 58 | margin-top: 0; 59 | margin-bottom: 1rem; 60 | } 61 | 62 | abbr[title], 63 | abbr[data-original-title] { 64 | text-decoration: underline; 65 | -webkit-text-decoration: underline dotted; 66 | text-decoration: underline dotted; 67 | cursor: help; 68 | border-bottom: 0; 69 | } 70 | 71 | address { 72 | margin-bottom: 1rem; 73 | font-style: normal; 74 | line-height: inherit; 75 | } 76 | 77 | ol, 78 | ul, 79 | dl { 80 | margin-top: 0; 81 | margin-bottom: 1rem; 82 | } 83 | 84 | ol ol, 85 | ul ul, 86 | ol ul, 87 | ul ol { 88 | margin-bottom: 0; 89 | } 90 | 91 | dt { 92 | font-weight: 700; 93 | } 94 | 95 | dd { 96 | margin-bottom: .5rem; 97 | margin-left: 0; 98 | } 99 | 100 | blockquote { 101 | margin: 0 0 1rem; 102 | } 103 | 104 | dfn { 105 | font-style: italic; 106 | } 107 | 108 | b, 109 | strong { 110 | font-weight: bolder; 111 | } 112 | 113 | small { 114 | font-size: 80%; 115 | } 116 | 117 | sub, 118 | sup { 119 | position: relative; 120 | font-size: 75%; 121 | line-height: 0; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -.25em; 127 | } 128 | 129 | sup { 130 | top: -.5em; 131 | } 132 | 133 | a { 134 | color: #007bff; 135 | text-decoration: none; 136 | background-color: transparent; 137 | -webkit-text-decoration-skip: objects; 138 | } 139 | 140 | a:hover { 141 | color: #0056b3; 142 | text-decoration: underline; 143 | } 144 | 145 | a:not([href]):not([tabindex]) { 146 | color: inherit; 147 | text-decoration: none; 148 | } 149 | 150 | a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover { 151 | color: inherit; 152 | text-decoration: none; 153 | } 154 | 155 | a:not([href]):not([tabindex]):focus { 156 | outline: 0; 157 | } 158 | 159 | pre, 160 | code, 161 | kbd, 162 | samp { 163 | font-family: monospace, monospace; 164 | font-size: 1em; 165 | } 166 | 167 | pre { 168 | margin-top: 0; 169 | margin-bottom: 1rem; 170 | overflow: auto; 171 | -ms-overflow-style: scrollbar; 172 | } 173 | 174 | figure { 175 | margin: 0 0 1rem; 176 | } 177 | 178 | img { 179 | vertical-align: middle; 180 | border-style: none; 181 | } 182 | 183 | svg:not(:root) { 184 | overflow: hidden; 185 | } 186 | 187 | a, 188 | area, 189 | button, 190 | [role="button"], 191 | input:not([type="range"]), 192 | label, 193 | select, 194 | summary, 195 | textarea { 196 | -ms-touch-action: manipulation; 197 | touch-action: manipulation; 198 | } 199 | 200 | table { 201 | border-collapse: collapse; 202 | } 203 | 204 | caption { 205 | padding-top: 0.75rem; 206 | padding-bottom: 0.75rem; 207 | color: #868e96; 208 | text-align: left; 209 | caption-side: bottom; 210 | } 211 | 212 | th { 213 | text-align: inherit; 214 | } 215 | 216 | label { 217 | display: inline-block; 218 | margin-bottom: .5rem; 219 | } 220 | 221 | button { 222 | border-radius: 0; 223 | } 224 | 225 | button:focus { 226 | outline: 1px dotted; 227 | outline: 5px auto -webkit-focus-ring-color; 228 | } 229 | 230 | input, 231 | button, 232 | select, 233 | optgroup, 234 | textarea { 235 | margin: 0; 236 | font-family: inherit; 237 | font-size: inherit; 238 | line-height: inherit; 239 | } 240 | 241 | button, 242 | input { 243 | overflow: visible; 244 | } 245 | 246 | button, 247 | select { 248 | text-transform: none; 249 | } 250 | 251 | button, 252 | html [type="button"], 253 | [type="reset"], 254 | [type="submit"] { 255 | -webkit-appearance: button; 256 | } 257 | 258 | button::-moz-focus-inner, 259 | [type="button"]::-moz-focus-inner, 260 | [type="reset"]::-moz-focus-inner, 261 | [type="submit"]::-moz-focus-inner { 262 | padding: 0; 263 | border-style: none; 264 | } 265 | 266 | input[type="radio"], 267 | input[type="checkbox"] { 268 | box-sizing: border-box; 269 | padding: 0; 270 | } 271 | 272 | input[type="date"], 273 | input[type="time"], 274 | input[type="datetime-local"], 275 | input[type="month"] { 276 | -webkit-appearance: listbox; 277 | } 278 | 279 | textarea { 280 | overflow: auto; 281 | resize: vertical; 282 | } 283 | 284 | fieldset { 285 | min-width: 0; 286 | padding: 0; 287 | margin: 0; 288 | border: 0; 289 | } 290 | 291 | legend { 292 | display: block; 293 | width: 100%; 294 | max-width: 100%; 295 | padding: 0; 296 | margin-bottom: .5rem; 297 | font-size: 1.5rem; 298 | line-height: inherit; 299 | color: inherit; 300 | white-space: normal; 301 | } 302 | 303 | progress { 304 | vertical-align: baseline; 305 | } 306 | 307 | [type="number"]::-webkit-inner-spin-button, 308 | [type="number"]::-webkit-outer-spin-button { 309 | height: auto; 310 | } 311 | 312 | [type="search"] { 313 | outline-offset: -2px; 314 | -webkit-appearance: none; 315 | } 316 | 317 | [type="search"]::-webkit-search-cancel-button, 318 | [type="search"]::-webkit-search-decoration { 319 | -webkit-appearance: none; 320 | } 321 | 322 | ::-webkit-file-upload-button { 323 | font: inherit; 324 | -webkit-appearance: button; 325 | } 326 | 327 | output { 328 | display: inline-block; 329 | } 330 | 331 | summary { 332 | display: list-item; 333 | } 334 | 335 | template { 336 | display: none; 337 | } 338 | 339 | [hidden] { 340 | display: none !important; 341 | } 342 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /FINAL/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, session, escape,\ 2 | redirect, url_for, flash, g, send_from_directory, abort 3 | from flask_sqlalchemy import SQLAlchemy 4 | from werkzeug.security import generate_password_hash, check_password_hash 5 | from werkzeug.utils import secure_filename 6 | 7 | import os 8 | import urllib.parse, hashlib 9 | 10 | ALLOWED_EXTENSIONS = set(["png", "jpg", "jpge", "gif", "pdf"]) 11 | 12 | app = Flask(__name__) 13 | app.config.from_object("config.DevelopmentConfig") 14 | db = SQLAlchemy(app) 15 | 16 | def allowed_file(filename): 17 | 18 | return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS 19 | 20 | def get_profile_picture(email): 21 | default = "https://lh5.googleusercontent.com/fhcUNRdmwXqNpwf4kMHMPbn3y6eOOQnx4UfI3l0OfA308R-tI3e0cg3pFeEhxshDKyXRuZj9s8aHBqrFrmbR=w1366-h635" 22 | size = 512 23 | 24 | gravatar_url = "https://www.gravatar.com/avatar/" + \ 25 | hashlib.md5(email.encode("utf-8").lower()).hexdigest() + "?" 26 | gravatar_url += urllib.parse.urlencode({"d":default, "s":str(size)}) 27 | 28 | return gravatar_url 29 | 30 | class Base(db.Model): 31 | __abstract__ = True 32 | 33 | id = db.Column(db.Integer, primary_key=True) 34 | date_created = db.Column(db.DateTime, default=db.func.current_timestamp()) 35 | date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(),\ 36 | onupdate=db.func.current_timestamp()) 37 | 38 | class Users(Base): 39 | username = db.Column(db.String(50), unique=True, nullable=False) 40 | email = db.Column(db.String(50), unique=True, nullable=False) 41 | password = db.Column(db.String(80), nullable=False) 42 | about_me = db.Column(db.String(280), default="") 43 | images = db.relationship("Image", backref="owner", lazy="dynamic") 44 | 45 | class Image(Base): 46 | filename = db.Column(db.String(80), nullable=False) 47 | user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False) 48 | owner_username = db.Column(db.String(50), nullable=False) 49 | 50 | @app.before_request 51 | def before_request(): 52 | if "username" in session: 53 | g.user = session["username"] 54 | else: 55 | g.user = None 56 | 57 | @app.route("/") 58 | def index(): 59 | 60 | return render_template("index.html") 61 | 62 | @app.route("/search") 63 | def search(): 64 | username = request.args.get("username") 65 | 66 | return redirect(url_for("profile", username=username)) 67 | 68 | @app.route("/signup", methods=["GET", "POST"]) 69 | def signup(): 70 | if not g.user: 71 | if request.method == "POST": 72 | username = Users.query.filter_by(username=request.form["username"]\ 73 | .lower()).first() 74 | email = Users.query.filter_by(email=request.form["email"].lower()).first() 75 | 76 | if username or email: 77 | flash("Usernames and emails must be unique.", "alert-warning") 78 | 79 | return redirect(request.url) 80 | hashed_pw = generate_password_hash(request.form["password"], method="sha256") 81 | new_user = Users(username=request.form["username"].lower(), \ 82 | email=request.form["email"].lower(), password=hashed_pw) 83 | db.session.add(new_user) 84 | db.session.commit() 85 | 86 | flash("You've registered successfully.", "alert-success") 87 | 88 | return redirect(url_for("login")) 89 | 90 | return render_template("signup.html") 91 | flash("You're already logged in.", "alert-primary") 92 | 93 | return redirect(url_for("home")) 94 | 95 | @app.route("/login", methods=["GET", "POST"]) 96 | def login(): 97 | if not g.user: 98 | if request.method == "POST": 99 | user = Users.query.filter_by(username=request.form["username"]\ 100 | .lower()).first() 101 | 102 | if user and check_password_hash(user.password, request.form["password"]): 103 | session["username"] = user.username 104 | flash("Now you're logged in.", "alert-success") 105 | return redirect("home") 106 | flash("Your credentials are invalid, check and try again.", "alert-warning") 107 | 108 | return render_template("login.html") 109 | flash("You are already logged in.", "alert-primary") 110 | 111 | return redirect(url_for("home")) 112 | 113 | @app.route("/profile/") 114 | def profile(username): 115 | user = Users.query.filter_by(username=username).first() 116 | 117 | if user: 118 | files = user.images.order_by(Image.date_modified).limit(10).all() 119 | picture = get_profile_picture(user.email) 120 | 121 | return render_template("profile.html", user=user, files=files, picture=picture) 122 | 123 | abort(404) 124 | 125 | @app.route("/profile/edit", methods=["GET", "POST"]) 126 | def edit_profile(): 127 | user = Users.query.filter_by(username=g.user).first() 128 | 129 | if request.method == "POST": 130 | user.about_me = request.form["about"] 131 | db.session.commit() 132 | 133 | flash("Changes has been saved successfully!", "alert-success") 134 | return redirect(url_for("profile", username=g.user)) 135 | 136 | return render_template("edit_profile.html", user=user) 137 | 138 | @app.route("/home", methods=["GET", "POST"]) 139 | def home(): 140 | if g.user: 141 | if request.method == "POST": 142 | if "file" not in request.files: 143 | flash("No file part.", "alert-danger") 144 | return redirect(request.url) 145 | file = request.files["file"] 146 | if file.filename == "": 147 | flash("No selected file.", "alert-warning") 148 | return redirect(request.url) 149 | if file and allowed_file(file.filename): 150 | filename = secure_filename(file.filename) 151 | user = Users.query.filter_by(username=g.user).first() 152 | file_to_db = Image(filename=filename, owner=user, \ 153 | owner_username=user.username) 154 | db.session.add(file_to_db) 155 | db.session.commit() 156 | file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename)) 157 | return redirect(url_for("get_files")) 158 | return render_template("home.html") 159 | flash("You must be logged in.", "alert-warning") 160 | 161 | return redirect(url_for("login")) 162 | 163 | @app.route("/files") 164 | def get_all_files(): 165 | files = Image.query.order_by(Image.date_modified).limit(200).all() 166 | 167 | return render_template("files.html", files=files) 168 | 169 | 170 | @app.route("/myfiles") 171 | def get_files(): 172 | if g.user: 173 | user = Users.query.filter_by(username=g.user).first() 174 | 175 | if user.images.all(): 176 | files = user.images.order_by(Image.date_modified).all() 177 | return render_template("my_files.html", files=files) 178 | 179 | files = [] 180 | return render_template("my_files.html", files=files) 181 | 182 | flash("You must be logged in.", "alert-warning") 183 | 184 | return redirect(url_for("login")) 185 | 186 | @app.route('/uploads/') 187 | def uploaded_file(filename): 188 | 189 | return send_from_directory(app.config['UPLOAD_FOLDER'], filename) 190 | 191 | @app.route("/logout") 192 | def logout(): 193 | session.pop("username", None) 194 | flash("You're logged out.", "alert-secondary") 195 | 196 | return redirect(url_for("index")) 197 | 198 | @app.route("/about") 199 | def about(): 200 | 201 | return render_template("about.html") 202 | 203 | @app.errorhandler(404) 204 | def page_not_found(error): 205 | 206 | return render_template("404_page_not_found.html"), 404 207 | 208 | if __name__ == "__main__": 209 | db.create_all() 210 | app.run() 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Curso Básico de Flask 2 | ## Introducción 3 | 4 | En este curso aprenderemos a utilizar Flask, el cual es un marco de desarrollo web basado en Python. 5 | 6 | Flask es un framework minimalista con el cual es muy fácil hacer aplicaciones web. Incluso siendo minimalista, Flask puede escalar junto con tus proyectos tanto como lo necesites, claro que necesitaras un poco más de conocimiento pero la posibilidad existe. Afortunadamente es un framework que cuenta con bastantes funcionalidades para cumplir las tareas mas comunes y en que caso de que necesites algo más puedes hacer uso de las librerías que otros usuarios han creado para hacer que tu aplicación pueda hacer justo lo que necesitas, eso vuelve todo el proceso más sencillo, así que no hay nada de que preocuparse. 7 | 8 | ### Hola Mundo con Flask (Ejemplo; App) 9 | ```python 10 | from flask import Flask 11 | 12 | app = Flask(__name__) 13 | 14 | @app.route("/") 15 | def index(): 16 | return "Hello World!" 17 | 18 | if __name__ == "__main__": 19 | app.run() 20 | ``` 21 | 22 | **Sencillo, ¿no es así? Pues vamos a comenzar entonces, ¡suerte!** 23 | 24 | ## Resumen general 25 | 26 | Bienvenido al resumen general de curso, aquí puedes darte una idea del contenido de cada vídeo y si estás buscando algo en específico pues a por ello. Aún así te recomendamos que mires cada vídeo para que te puedas beneficiar de toda la información. 27 | 28 | #### Aplicación base, servidor y servir aplicación localmente. 29 | ##### Tutoriales: 1, y 2. 30 | Crear una aplicación de Flask es algo muy sencillo, y comenzar a utilizarla también, para hacerlo solamente necesitamos servirla mediante un servidor local que nosotros establecemos. En esto último nosotros podemos elegir en que puerto y host se ejecutará nuestra aplicación, entre otras cosas. 31 | 32 | #### Rutas, Url's, estáticas y dinamicas 33 | ##### Tutorial: 3 34 | Una de las actividades mas comúnes consiste en crear rutas mediante las cuales realizamos diferentes acciones. Ya sean rutas dinamicas o estáticas nosotros aprendimos a crearlas, y analizamos diferentes características de estas, e incluso mencionamos algunos consejos para crearlas de manera correcta. 35 | 36 | #### Archivos estáticos 37 | ##### Tutorial: 4 38 | Un tema que no es complejo del todo y del que además no hablamos mucho son los archivos estáticos (CSS, JS, Favicon) pues no corresponden como tal de manera literal al curso, sin embargo, aún así explicamos qué son y como utilizarlos en conjunto con nuestra aplicación. 39 | 40 | #### Vistas (Plantillas HTML) 41 | ##### Tutorial: 5 42 | Podemos crear aplicaciones web mediante Flask utilizando diferentes bases referentes a desarrollo web, sin embargo, muchas de las aplicaciones creadas hoy en día son para que las utilicé cualquier usuario común directamente y para hacer que esto se cumpla nosotros les fácilitamos el uso del sitio web mostrando la información necesaria mediante plantillas HTML en las cuales nosotros podemos presentar diferentes elementos visuales al usuario para que pueda hacer uso de cada una de las funciones que nuestro sitio web ofrezca. Lograr todo esto es bastante sencillo, preparamos un directorio y allí guardamos nuestras plantillas, después a cada ruta le asignamos una plantilla que distribuir, y listo! 43 | 44 | #### Jinja (Motor de vistas) 45 | ##### Tutorial: 6 46 | La mayoría de plantillas HTML muestran datos estáticos, es decir, no cambian, sin embargo nosotros estamos creando un sitio web dinamico donde mucha de la información cambia en base a los datos que se esten manejando en el área del servidor (backend) y que de hecho es la parte que estamos administrando mediante Flask, es por ello que contamos con un motor de vistas por defecto y ese es Jinja el cual se encarga de crear un vinculo entre nuestras plantillas HTML y nuestra aplicación para darle vida a esa información, y no solo eso sino que con Jinja también podemos "programar" en dichas plantillas. Un motor de vistas bastante potente y del cuál hay muchas cosas de que hablar, aquí te damos los básicos para que aprendas el uso que le puedas dar (más adelante hay mas tutoriales referentes a Jinja). 47 | 48 | #### Bases de Datos (Conexión, esquemas y operaciones) 49 | ##### Tutorial: 7 50 | En este tipo de aplicaciones requerimos hacer eso de un montón de datos y muchos de ellos se necesitan almacenar, para después recuperarlos y realizar diferentes operaciones con ellos para en la mayoría de ocasiones mostrarlos como información a un usuario. En pocas palabras, necesitamos persistencia de datos y para ello existen las bases de datos, esta ocasión te mostramos como ligar a tu aplicación una base de datos MySQL pero utilizando lenguaje No-SQL para administrarla, así que ni siquiera necesitas saber SQL. (En tutoriales posteriores se muestra más información acerca de bases de datos). 51 | 52 | #### Formularios (GET, POST, DB, Cifrar Datos) 53 | ##### Tutorial: 8 54 | A través de los formularios HTML podemos recuperar datos, y hacer algo con esos datos en el área del servidor, por ejemplo, almacenarlos en una base de datos. Algo muy común en un sitio web es pedir a los usuarios registrarse para poder ofrecerles una mejor experiencia durante su visita, es precisamente este ejercicio el que tomamos: Sistema de gestión de usuarios, para explicar todos los elementos y aprender a cómo utilizar formularios por diferentes métodos, rutas; incluso cifrar sus datos, realizar validaciones, etc. Un vídeo bastante importante pues a partir de aquí en adelante se hacen muchas referencias a este ejercicio. 55 | 56 | #### Cookies (Crear, leer, e información general) 57 | ##### Tutorial: 9 58 | Hacer o no uso de cookies en un sitio web es algo sobre lo que se discute muy amenudo por diferentes cuestiones como seguridad, rendimiento y la privacidad del usuario. En esta ocasión no estaremos tocando el tema por ese lado sino solamente aprenderas a crearlas, leerlas, en fin, a utilizarlas de manera general, y sino sabes qué son te damos algunas ideas para que formes la tuya propia y les des un uso. _(Te recomedamos ver el último vídeo del curso pues hay información importante relacionada a este tema)_. 59 | 60 | #### Sesiones (Crear, editar y eliminar; Cookies) 61 | ##### Tutorial: 10 62 | Las sesiones están relacionadas a las cookies pues la sesión en sí misma es una cookie, pero que estas son más fáciles de utilizar pues tienen algunos valores por defecto. En ellas podemos almacenar diferente información, por ejemplo, guardar los datos de un usuario ya registrado que ha accedido con sus datos a nuestro sitio web y entonces por ejemplo, comprobar si el usuario esta navegando por nuestro sitio web a través de su cuenta o no, entre otras cosas. 63 | 64 | #### Redirect & Url_for (Rutas; URL's) 65 | ##### Tutorial: 11 66 | Como ya habíamos mencionado, trabajar con rutas es algo de lo más común en aplicaciones web, y dos de las acciones más requeridas son: redireccionar y aputar a diferentes rutas. Podemos lograr esto de manera sencilla utilizando las funciones redirect y url_for, incluso podemos utilizarlas en conjunto, y lograr sacar provecho de otras caracteristicas interesantes que poseen. 67 | 68 | #### Message Flashing (Mensajes Flash [info, error, éxito, etc]) 69 | ##### Tutorial: 12 70 | Cuando un usuario utilice nuestro sitio web lo más probable es que se necesiten llevar a cabo diferentes acciones en el área del servidor que posteriormente arrojen un resultado, y una manera de informar estos resultados de manera amigable al usuario es hacer uso de los mensajes flash. De hecho me atrevería a decir que es la manera más "amigable" de hacerlo, pues estos mensajes normalmente son llamativos y no le resultan molestos al usuario pues se muestran de manera espontanea en la ruta donde se encuentra. 71 | 72 | #### Macros (Jinja; Don't repeat yourself) 73 | ##### Tutorial: 13 74 | Cuando estamos programando y notamos que hacemos acciones de manera bastante repetitiva creamos funciones, y así evitamos repetir código, lo que se traduce en un código mejor estructurado a la par de que desarrollamos más rápido nustro proyecto pues perdemos menos tiempo escribiendo código innecesario. Esta situación se puede aplicar a la macros que si bien no son lo mismo que una función, pues las ventajas que nos ofrecen son parecidas, en este caso en particular nosotros creamos macros a través de nuestro motor de vistas Jinja para crear plantillas HTML mejor organizadas, más eficientes, fáciles de actualizar y todo ello en menos tiempo. 75 | 76 | #### WhiteSpacing (Jinja; remover espacios blancos) 77 | ##### Tutorial: 14 78 | Un tutorial bastante corto donde aprendemos a evitar los espacios blancos que deja nuestro motor de vistas Jinja a la hora de ver/analizar las plantillas HTML en un navegador web. Un tema de no tanta relevancia pero que puede ser útil para tareas como depurar plantillas, y mejorar la semantica de las mismas. 79 | 80 | #### Decoradores de petición (Before, after y teardown requests) 81 | ##### Tutorial: 15 82 | En muchas ocasiones necesitamos realizar diferentes acciones antes, o después de una petición bajo diferentes circunstancias. Es en esta parte que hacemos uso de estos decoradores, existen varios de ellos pero aquí te mostramos tres de los que más se utilizan comúnmente. 83 | 84 | #### Objecto Global (flask.g) 85 | ##### Tutorial: 16 86 | A veces es necesario mover información a través de diferentes contextos en nuestra aplicación, una manera sencilla de hacerlo es hacer uso del objeto global que nos proporciona Flask al cual podemos agregarle diferentes métodos y almacenar allí información, por ejemplo: guardar conexiones/operaciones de una base de datos, la información de un usuario, etc. Algo interesante acerca de este objeto es que incluso podemos hacer uso de el a través de nuestro motor de vistas Jinja y ejecutar diferentes acciones en nuestras plantillas HTML, sin siquiera tener que importarlo pues esto se hace por defecto. 87 | 88 | #### JSON (Jsonify) 89 | ##### Tutorial: 17 90 | Hasta el momento hemos hablado de sitios web creados para ser utilizados por usuarios comunes, pero existen otras bases de desarrollo web que son utilizadas para crear aplicaciones, una de la bases más populares se le conoce como "RESTful API" y en muchas ocasiones estas aplicaciones utilizan las estructuras JSON para intercambiar datos y llevar a cabo diferentes tareas. Pues aquí te damos una breve introducción a ello, explicando que son las estructuras JSON y como puedes administrarlas a través de tu aplicación de Flask. _Habrá un curso exclusivo para crear este tipo de aplicaciones_. 91 | 92 | #### Requests (GET, API to API) 93 | ##### Tutorial: 18 94 | Haciendo uso de la librebría requests en conjunto con tu aplicación de Flask puedes comunicarte con otras aplicaciones, a través del protocolo HTTP y bajo el contexto de RESTful API. _Recordemos que habrá un curso exclusivo para este tipo de aplicaciones_ pero aún así te dejamos un sencillo ejemplo para solicitar recursos servidos por otra API. 95 | 96 | #### Subir Archivos (y validaciones) 97 | ##### Tutorial: 19 98 | Aprender a subir archivos mediante tu aplicación de Flask utilizando formularios HTML, algo importante en este tema es cuidar el tipo de archivos que se suben y para ello podemos realizar diferentes validaciones de seguridad, pues aquí cubrimos todo eso e incluso te mostramos como recuperar esos archivos una vez que hayan sido subidos y mostrarlos a través de una ruta de tu aplicación. 99 | 100 | #### Manejar errores (Rutas; URL's, Códigos de estado [peticiones]) 101 | ##### Tutorial: 20 102 | Nuevamente, una de las cosas más comunes en aplicaciones web es hacer uso de diferentes rutas, y es aquí donde nos topamos con algunos errores más comúnes, como acceder a una ruta que no existe o entrar a una ruta no autorizada. Aunque se devuelven respuestas por defecto, nosotros podemos tomar tales errores y devolver respuestas personalizadas, como una plantilla personalizada para cubrir el famoso error 404 (recurso no encontrado), o incluso un JSON con un objecto que contenga el error, eso ya dependerá del concepto de nuestra aplicación. 103 | 104 | #### Organización y configuración (básica-intermedia) 105 | ##### Tutorial: 21 106 | Nuestra aplicación comienza a crecer después de un tiempo y es por ello que debemos tomarnos el tiempo de organizar el árbol de nuestra aplicación de alguna manera en que podamos mantener todo bajo control de una manera más sencilla. Existen varias maneras de organizar una aplicación de Flask, en esta ocasión te mostramos como hacerlo mediante el concepto paquete-modúlo-importación. Otra cosa muy importante son los párametros de configuración que necesita nuestra aplicación para funcionar, de igual manera hay diferentes prácticas para lograrlo, aquí se muestra como asignar diferentes configuraciones en base a clases (desarrollo-producción) y como recuperar los valores de configuración de diferentes maneras (variables, archivos, objetos, variables de entorno). 107 | 108 | #### Aplicación final (Resumen de curso) 109 | ##### Tutorial: 22 110 | Durante el curso se mostro bastante información y se abordo en muchas ocasiones de diferente manera, aunque esto no me parece que haya sido un problema pues siempre estuvo disponible el repositorio del curso en GitHub de donde podías tomar cada uno de los proyectos que se fuesen generando a lo largo del curso. De cualquiera manera en esta ocasión se dará un breve resumen del curso de manera interactiva mostrando una aplicación de Flask que ha sido creada utilizando la mayoría de información que se mosotró durante todo el curso. De hecho, es en este tutorial donde se te invitará a leer este mismo resumen que estás leyendo para que no te olvides de incluir nada que se haya enseñado en el curso en tu propio proyecto. 111 | 112 | #### Aplicación en producción (App Deployment; App in Cloud) 113 | ##### Tutorial: 23 114 | Llegó la hora de subir una aplicación de Flask a la nube para que los usuarios puedan hacer uso de ella desde sus respectivos dispositivos conectados a Internet, después de todo es una aplicación web. Para hacer disponible nuestra aplicación de Flask al público existen diferentes maneras de hacerlo, una de ellas es hacer uso de algún servicio de terceros. En esta ocasión lo haremos a través de PythonAnyWhere, un host gratuito y fácil de usar. 115 | 116 | #### Base de datos remota; MySQL (App Deploymente; parte 2) 117 | ##### Tutorial: 24 118 | Si bien cuando desarrollamos, SQLite3 es una buena herramienta para manejar nuestras bases de datos, lo cierto es que a la hora colocar nuestra aplicación en producción SQLite3 se nos comienza a quedar corto, por ello se hacen uso de otros servicios como MySQL, PostreSQL, MongoDB, entre otros. En el tutorial pasado hicimos uso de PythonAnyWhere para distribuir nuestra aplicación, pues en este mismo Host podemos configurar nuestro servicio de MySQL de manera gratuita, y entonces integrar ese servicio con nuestra aplicación de Flask sin ningún problema. 119 | 120 | #### Final; Información importante 121 | ##### Tutorial: 25 122 | Llegamos a nuestro final de curso, y aún quedan bastantes cosas que aprender sobre Flask, pero lo básico ya está y nos será bastante útil para seguir los siguientes tutoriales y cursos sobre el mismo, así que esten pendientes a ellos. Claro que antes de dar por finalizado el curso debemos analizar algunas cuestiones importantes sobre las aplicaciones que podemos generar con todo el conocimiento que adquirimos durante el curso. 123 | 124 | **Dudas importantes**: 125 | * ¿Qué más se puede hacer con Flask? 126 | * ¿Ya está lista mi aplicación de Flask para ser puesta en producción? 127 | * ¿Cómo hacer uso de HTTPS? 128 | * ¿Qué hay del uso de Cookies y Sesiones? 129 | * ¿Cómo protegerse contra los ataques maliciosos más comúnes? 130 | * ¿Cómo mantener la configuración de mi app más segura? 131 | * ¿Cómo crear aplicaciones de Flask grandes de manera correcta? 132 | * ¿Cómo puedo crear mejores aplicaciones? 133 | * En general, ¿y ahora qué? o.o! -------------------------------------------------------------------------------- /FINAL/static/js/popper.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) Federico Zivolo 2017 3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). 4 | */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=window.getComputedStyle(e,null);return t?o[t]:o}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e||-1!==['HTML','BODY','#document'].indexOf(e.nodeName))return window.document.body;var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll)/.test(r+s+p)?e:n(o(e))}function r(e){var o=e&&e.offsetParent,i=o&&o.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TD','TABLE'].indexOf(o.nodeName)&&'static'===t(o,'position')?r(o):o:window.document.documentElement}function p(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||r(e.firstElementChild)===e)}function s(e){return null===e.parentNode?e:s(e.parentNode)}function d(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return window.document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,i=o?e:t,n=o?t:e,a=document.createRange();a.setStart(i,0),a.setEnd(n,0);var l=a.commonAncestorContainer;if(e!==l&&t!==l||i.contains(n))return p(l)?l:r(l);var f=s(e);return f.host?d(f.host,t):d(e,s(t).host)}function a(e){var t=1=o.clientWidth&&i>=o.clientHeight}),l=0i[e]&&!t.escapeWithReference&&(n=V(p[o],i[e]-('right'===e?p.width:p.height))),se({},o,n)}};return n.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';p=de({},p,s[t](e))}),e.offsets.popper=p,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,i=t.reference,n=e.placement.split('-')[0],r=_,p=-1!==['top','bottom'].indexOf(n),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(i[s])&&(e.offsets.popper[d]=r(i[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){if(!F(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var n=e.placement.split('-')[0],r=e.offsets,p=r.popper,s=r.reference,d=-1!==['left','right'].indexOf(n),a=d?'height':'width',l=d?'Top':'Left',f=l.toLowerCase(),m=d?'left':'top',c=d?'bottom':'right',g=O(i)[a];s[c]-gp[c]&&(e.offsets.popper[f]+=s[f]+g-p[c]);var u=s[f]+s[a]/2-g/2,b=t(e.instance.popper,'margin'+l).replace('px',''),y=u-h(e.offsets.popper)[f]-b;return y=X(V(p[a]-g,y),0),e.arrowElement=i,e.offsets.arrow={},e.offsets.arrow[f]=Math.round(y),e.offsets.arrow[m]='',e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=w(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement),i=e.placement.split('-')[0],n=L(i),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case fe.FLIP:p=[i,n];break;case fe.CLOCKWISE:p=K(i);break;case fe.COUNTERCLOCKWISE:p=K(i,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(i!==s||p.length===d+1)return e;i=e.placement.split('-')[0],n=L(i);var a=e.offsets.popper,l=e.offsets.reference,f=_,m='left'===i&&f(a.right)>f(l.left)||'right'===i&&f(a.left)f(l.top)||'bottom'===i&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===i&&c||'right'===i&&h||'top'===i&&g||'bottom'===i&&u,y=-1!==['top','bottom'].indexOf(i),w=!!t.flipVariations&&(y&&'start'===r&&c||y&&'end'===r&&h||!y&&'start'===r&&g||!y&&'end'===r&&u);(m||b||w)&&(e.flipped=!0,(m||b)&&(i=p[d+1]),w&&(r=j(r)),e.placement=i+(r?'-'+r:''),e.offsets.popper=de({},e.offsets.popper,S(e.instance.popper,e.offsets.reference,e.placement)),e=N(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],i=e.offsets,n=i.popper,r=i.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return n[p?'left':'top']=r[o]-(s?n[p?'width':'height']:0),e.placement=L(t),e.offsets.popper=h(n),e}},hide:{order:800,enabled:!0,fn:function(e){if(!F(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=T(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}} 7 | /*# sourceMappingURL=bootstrap-grid.min.css.map */ -------------------------------------------------------------------------------- /FINAL/static/css/bootstrap/bootstrap-reboot.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../scss/bootstrap-reboot.scss","../../scss/_reboot.scss","dist/css/bootstrap-reboot.css","bootstrap-reboot.css","../../scss/mixins/_hover.scss"],"names":[],"mappings":"AAAA;;;;;;ACoBA,ECXA,QADA,SDeE,WAAA,WAGF,KACE,YAAA,WACA,YAAA,KACA,yBAAA,KACA,qBAAA,KACA,mBAAA,UACA,4BAAA,YAKA,cACE,MAAA,aAMJ,QAAA,MAAA,OAAA,WAAA,OAAA,OAAA,OAAA,OAAA,KAAA,IAAA,QACE,QAAA,MAWF,KACE,OAAA,EACA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,kBACA,UAAA,KACA,YAAA,IACA,YAAA,IACA,MAAA,QACA,WAAA,KACA,iBAAA,KEvBF,sBFgCE,QAAA,YASF,GACE,WAAA,YACA,OAAA,EACA,SAAA,QAaF,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAQF,EACE,WAAA,EACA,cAAA,KChDF,0BD0DA,YAEE,gBAAA,UACA,wBAAA,UAAA,OAAA,gBAAA,UAAA,OACA,OAAA,KACA,cAAA,EAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QCrDF,GDwDA,GCzDA,GD4DE,WAAA,EACA,cAAA,KAGF,MCxDA,MACA,MAFA,MD6DE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAGF,IACE,WAAA,OAIF,EC1DA,OD4DE,YAAA,OAIF,MACE,UAAA,IAQF,IChEA,IDkEE,SAAA,SACA,UAAA,IACA,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAON,EACE,MAAA,QACA,gBAAA,KACA,iBAAA,YACA,6BAAA,QG9LE,QHiMA,MAAA,QACA,gBAAA,UAUJ,8BACE,MAAA,QACA,gBAAA,KGlME,oCAAA,oCHqMA,MAAA,QACA,gBAAA,KANJ,oCAUI,QAAA,EClEJ,KACA,ID2EA,IC1EA,KD8EE,YAAA,SAAA,CAAA,UACA,UAAA,IAIF,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAGA,mBAAA,UAQF,OAEE,OAAA,EAAA,EAAA,KAQF,IACE,eAAA,OACA,aAAA,KAGF,eACE,SAAA,OCxFF,cDsGA,ECxGA,KACA,OAEA,wBACA,MACA,OACA,QACA,SD0GE,iBAAA,aAAA,aAAA,aAQF,MACE,gBAAA,SAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAGF,GAGE,WAAA,QAQF,MAEE,QAAA,aACA,cAAA,MAMF,OACE,cAAA,EAOF,aACE,QAAA,IAAA,OACA,QAAA,IAAA,KAAA,yBCxHF,OD2HA,MCzHA,SADA,OAEA,SD6HE,OAAA,EACA,YAAA,QACA,UAAA,QACA,YAAA,QAGF,OC3HA,MD6HE,SAAA,QAGF,OC3HA,OD6HE,eAAA,KCvHF,aACA,cD4HA,OC9HA,mBDkIE,mBAAA,OC3HF,gCACA,+BACA,gCD6HA,yBAIE,QAAA,EACA,aAAA,KC5HF,qBD+HA,kBAEE,WAAA,WACA,QAAA,EAIF,iBC/HA,2BACA,kBAFA,iBDyIE,mBAAA,QAGF,SACE,SAAA,KAEA,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAKF,OACE,QAAA,MACA,MAAA,KACA,UAAA,KACA,QAAA,EACA,cAAA,MACA,UAAA,OACA,YAAA,QACA,MAAA,QACA,YAAA,OAGF,SACE,eAAA,SE9IF,yCDGA,yCDiJE,OAAA,KE/IF,cFuJE,eAAA,KACA,mBAAA,KEnJF,4CDGA,yCDyJE,mBAAA,KAQF,6BACE,KAAA,QACA,mBAAA,OAOF,OACE,QAAA,aAGF,QACE,QAAA,UAGF,SACE,QAAA,KEhKF,SFsKE,QAAA","sourcesContent":["/*!\n * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"reboot\";\n","// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so\n// we force a non-overlapping, non-auto-hiding scrollbar to counteract.\n// 6. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n}\n\nhtml {\n font-family: sans-serif; // 2\n line-height: 1.15; // 3\n -webkit-text-size-adjust: 100%; // 4\n -ms-text-size-adjust: 100%; // 4\n -ms-overflow-style: scrollbar; // 5\n -webkit-tap-highlight-color: rgba(0,0,0,0); // 6\n}\n\n// IE10+ doesn't honor `` in some cases.\n@at-root {\n @-ms-viewport {\n width: device-width;\n }\n}\n\n// stylelint-disable selector-list-comma-newline-after\n// Shim for \"new\" HTML5 structural elements to display correctly (IE10, older browsers)\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n// stylelint-enable selector-list-comma-newline-after\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Set an explicit initial text-align value so that we can later use the\n// the `inherit` value on things like `` elements.\n\nbody {\n margin: 0; // 1\n font-family: $font-family-base;\n font-size: $font-size-base;\n font-weight: $font-weight-base;\n line-height: $line-height-base;\n color: $body-color;\n text-align: left; // 3\n background-color: $body-bg; // 2\n}\n\n// Suppress the focus outline on elements that cannot be accessed via keyboard.\n// This prevents an unwanted focus outline from appearing around elements that\n// might still respond to pointer events.\n//\n// Credit: https://github.com/suitcss/base\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\n\n// Content grouping\n//\n// 1. Add the correct box sizing in Firefox.\n// 2. Show the overflow in Edge and IE.\n\nhr {\n box-sizing: content-box; // 1\n height: 0; // 1\n overflow: visible; // 2\n}\n\n\n//\n// Typography\n//\n\n// Remove top margins from headings\n//\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n// stylelint-disable selector-list-comma-newline-after\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: $headings-margin-bottom;\n}\n// stylelint-enable selector-list-comma-newline-after\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n// Abbreviations\n//\n// 1. Remove the bottom border in Firefox 39-.\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Duplicate behavior to the data-* attribute for our tooltip plugin\n\nabbr[title],\nabbr[data-original-title] { // 4\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n border-bottom: 0; // 1\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // Undo browser default\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic; // Add the correct font style in Android 4.3-\n}\n\n// stylelint-disable font-weight-notation\nb,\nstrong {\n font-weight: bolder; // Add the correct font weight in Chrome, Edge, and Safari\n}\n// stylelint-enable font-weight-notation\n\nsmall {\n font-size: 80%; // Add the correct font size in all browsers\n}\n\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n//\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n//\n// Links\n//\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n background-color: transparent; // Remove the gray background on active links in IE 10.\n -webkit-text-decoration-skip: objects; // Remove gaps in links underline in iOS 8+ and Safari 8+.\n\n @include hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href)\n// which have not been made explicitly keyboard-focusable (without tabindex).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n\n @include hover-focus {\n color: inherit;\n text-decoration: none;\n }\n\n &:focus {\n outline: 0;\n }\n}\n\n\n//\n// Code\n//\n\n// stylelint-disable font-family-no-duplicate-names\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; // Correct the inheritance and scaling of font size in all browsers.\n font-size: 1em; // Correct the odd `em` font sizing in all browsers.\n}\n// stylelint-enable font-family-no-duplicate-names\n\npre {\n // Remove browser default top margin\n margin-top: 0;\n // Reset browser default of `1em` to use `rem`s\n margin-bottom: 1rem;\n // Don't allow content to break outside\n overflow: auto;\n // We have @viewport set which causes scrollbars to overlap content in IE11 and Edge, so\n // we force a non-overlapping, non-auto-hiding scrollbar to counteract.\n -ms-overflow-style: scrollbar;\n}\n\n\n//\n// Figures\n//\n\nfigure {\n // Apply a consistent margin strategy (matches our type styles).\n margin: 0 0 1rem;\n}\n\n\n//\n// Images and content\n//\n\nimg {\n vertical-align: middle;\n border-style: none; // Remove the border on images inside links in IE 10-.\n}\n\nsvg:not(:root) {\n overflow: hidden; // Hide the overflow in IE\n}\n\n\n// Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.\n//\n// In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11\n// DON'T remove the click delay when `` is present.\n// However, they DO support removing the click delay via `touch-action: manipulation`.\n// See:\n// * https://getbootstrap.com/docs/4.0/content/reboot/#click-delay-optimization-for-touch\n// * https://caniuse.com/#feat=css-touch-action\n// * https://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput:not([type=\"range\"]),\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\n\n\n//\n// Tables\n//\n\ntable {\n border-collapse: collapse; // Prevent double borders\n}\n\ncaption {\n padding-top: $table-cell-padding;\n padding-bottom: $table-cell-padding;\n color: $text-muted;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n // Matches default `` alignment by inheriting from the ``, or the\n // closest parent with a set `text-align`.\n text-align: inherit;\n}\n\n\n//\n// Forms\n//\n\nlabel {\n // Allow labels to use `margin` for spacing.\n display: inline-block;\n margin-bottom: .5rem;\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n//\n// Details at https://github.com/twbs/bootstrap/issues/24093\nbutton {\n border-radius: 0;\n}\n\n// Work around a Firefox/IE bug where the transparent `button` background\n// results in a loss of the default `button` focus styles.\n//\n// Credit: https://github.com/suitcss/base/\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // Remove the margin in Firefox and Safari\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible; // Show the overflow in Edge\n}\n\nbutton,\nselect {\n text-transform: none; // Remove the inheritance of text transform in Firefox\n}\n\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`\n// controls in Android 4.\n// 2. Correct the inability to style clickable types in iOS and Safari.\nbutton,\nhtml [type=\"button\"], // 1\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button; // 2\n}\n\n// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box; // 1. Add the correct box sizing in IE 10-\n padding: 0; // 2. Remove the padding in IE 10-\n}\n\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n // Remove the default appearance of temporal inputs to avoid a Mobile Safari\n // bug where setting a custom line-height prevents text from being vertically\n // centered within the input.\n // See https://bugs.webkit.org/show_bug.cgi?id=139848\n // and https://github.com/twbs/bootstrap/issues/11266\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto; // Remove the default vertical scrollbar in IE.\n // Textareas should really only resize vertically so they don't break their (horizontal) containers.\n resize: vertical;\n}\n\nfieldset {\n // Browsers set a default `min-width: min-content;` on fieldsets,\n // unlike e.g. `

`s, which have `min-width: 0;` by default.\n // So we reset that to ensure fieldsets behave more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359\n // and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements\n min-width: 0;\n // Reset the default outline behavior of fieldsets so they don't affect page layout.\n padding: 0;\n margin: 0;\n border: 0;\n}\n\n// 1. Correct the text wrapping in Edge and IE.\n// 2. Correct the color inheritance from `fieldset` elements in IE.\nlegend {\n display: block;\n width: 100%;\n max-width: 100%; // 1\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit; // 2\n white-space: normal; // 1\n}\n\nprogress {\n vertical-align: baseline; // Add the correct vertical alignment in Chrome, Firefox, and Opera.\n}\n\n// Correct the cursor style of increment and decrement buttons in Chrome.\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n // This overrides the extra rounded corners on search inputs in iOS so that our\n // `.form-control` class can properly style them. Note that this cannot simply\n // be added to `.form-control` as it's not specific enough. For details, see\n // https://github.com/twbs/bootstrap/issues/11586.\n outline-offset: -2px; // 2. Correct the outline style in Safari.\n -webkit-appearance: none;\n}\n\n//\n// Remove the inner padding and cancel buttons in Chrome and Safari on macOS.\n//\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// 1. Correct the inability to style clickable types in iOS and Safari.\n// 2. Change font properties to `inherit` in Safari.\n//\n\n::-webkit-file-upload-button {\n font: inherit; // 2\n -webkit-appearance: button; // 1\n}\n\n//\n// Correct element displays\n//\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item; // Add the correct display in all browsers\n}\n\ntemplate {\n display: none; // Add the correct display in IE\n}\n\n// Always hide an element with the `hidden` HTML attribute (from PureCSS).\n// Needed for proper display in IE 10-.\n[hidden] {\n display: none !important;\n}\n","/*!\n * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: transparent;\n}\n\n@-ms-viewport {\n width: device-width;\n}\n\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n text-align: left;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n -webkit-text-decoration-skip: objects;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n -ms-overflow-style: scrollbar;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput:not([type=\"range\"]),\nlabel,\nselect,\nsummary,\ntextarea {\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #868e96;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: inherit;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: .5rem;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml [type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n/*# sourceMappingURL=bootstrap-reboot.css.map */","/*!\n * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: transparent;\n}\n\n@-ms-viewport {\n width: device-width;\n}\n\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n text-align: left;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n -webkit-text-decoration-skip: objects;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n -ms-overflow-style: scrollbar;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput:not([type=\"range\"]),\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #868e96;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: inherit;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: .5rem;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml [type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\n/*# sourceMappingURL=bootstrap-reboot.css.map */","// stylelint-disable indentation\n@mixin hover {\n // TODO: re-enable along with mq4-hover-shim\n// @if $enable-hover-media-query {\n// // See Media Queries Level 4: https://drafts.csswg.org/mediaqueries/#hover\n// // Currently shimmed by https://github.com/twbs/mq4-hover-shim\n// @media (hover: hover) {\n// &:hover { @content }\n// }\n// }\n// @else {\n &:hover { @content; }\n// }\n}\n\n\n@mixin hover-focus {\n @if $enable-hover-media-query {\n &:focus {\n @content;\n }\n @include hover { @content; }\n } @else {\n &:focus,\n &:hover {\n @content;\n }\n }\n}\n\n@mixin plain-hover-focus {\n @if $enable-hover-media-query {\n &,\n &:focus {\n @content;\n }\n @include hover { @content; }\n } @else {\n &,\n &:focus,\n &:hover {\n @content;\n }\n }\n}\n\n@mixin hover-focus-active {\n @if $enable-hover-media-query {\n &:focus,\n &:active {\n @content;\n }\n @include hover { @content; }\n } @else {\n &:focus,\n &:active,\n &:hover {\n @content;\n }\n }\n}\n"]} -------------------------------------------------------------------------------- /FINAL/static/css/bootstrap/bootstrap-grid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Grid v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | */ 7 | @-ms-viewport { 8 | width: device-width; 9 | } 10 | 11 | html { 12 | box-sizing: border-box; 13 | -ms-overflow-style: scrollbar; 14 | } 15 | 16 | *, 17 | *::before, 18 | *::after { 19 | box-sizing: inherit; 20 | } 21 | 22 | .container { 23 | width: 100%; 24 | padding-right: 15px; 25 | padding-left: 15px; 26 | margin-right: auto; 27 | margin-left: auto; 28 | } 29 | 30 | @media (min-width: 576px) { 31 | .container { 32 | max-width: 540px; 33 | } 34 | } 35 | 36 | @media (min-width: 768px) { 37 | .container { 38 | max-width: 720px; 39 | } 40 | } 41 | 42 | @media (min-width: 992px) { 43 | .container { 44 | max-width: 960px; 45 | } 46 | } 47 | 48 | @media (min-width: 1200px) { 49 | .container { 50 | max-width: 1140px; 51 | } 52 | } 53 | 54 | .container-fluid { 55 | width: 100%; 56 | padding-right: 15px; 57 | padding-left: 15px; 58 | margin-right: auto; 59 | margin-left: auto; 60 | } 61 | 62 | .row { 63 | display: -ms-flexbox; 64 | display: flex; 65 | -ms-flex-wrap: wrap; 66 | flex-wrap: wrap; 67 | margin-right: -15px; 68 | margin-left: -15px; 69 | } 70 | 71 | .no-gutters { 72 | margin-right: 0; 73 | margin-left: 0; 74 | } 75 | 76 | .no-gutters > .col, 77 | .no-gutters > [class*="col-"] { 78 | padding-right: 0; 79 | padding-left: 0; 80 | } 81 | 82 | .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, 83 | .col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, 84 | .col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, 85 | .col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, 86 | .col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, 87 | .col-xl-auto { 88 | position: relative; 89 | width: 100%; 90 | min-height: 1px; 91 | padding-right: 15px; 92 | padding-left: 15px; 93 | } 94 | 95 | .col { 96 | -ms-flex-preferred-size: 0; 97 | flex-basis: 0; 98 | -ms-flex-positive: 1; 99 | flex-grow: 1; 100 | max-width: 100%; 101 | } 102 | 103 | .col-auto { 104 | -ms-flex: 0 0 auto; 105 | flex: 0 0 auto; 106 | width: auto; 107 | max-width: none; 108 | } 109 | 110 | .col-1 { 111 | -ms-flex: 0 0 8.333333%; 112 | flex: 0 0 8.333333%; 113 | max-width: 8.333333%; 114 | } 115 | 116 | .col-2 { 117 | -ms-flex: 0 0 16.666667%; 118 | flex: 0 0 16.666667%; 119 | max-width: 16.666667%; 120 | } 121 | 122 | .col-3 { 123 | -ms-flex: 0 0 25%; 124 | flex: 0 0 25%; 125 | max-width: 25%; 126 | } 127 | 128 | .col-4 { 129 | -ms-flex: 0 0 33.333333%; 130 | flex: 0 0 33.333333%; 131 | max-width: 33.333333%; 132 | } 133 | 134 | .col-5 { 135 | -ms-flex: 0 0 41.666667%; 136 | flex: 0 0 41.666667%; 137 | max-width: 41.666667%; 138 | } 139 | 140 | .col-6 { 141 | -ms-flex: 0 0 50%; 142 | flex: 0 0 50%; 143 | max-width: 50%; 144 | } 145 | 146 | .col-7 { 147 | -ms-flex: 0 0 58.333333%; 148 | flex: 0 0 58.333333%; 149 | max-width: 58.333333%; 150 | } 151 | 152 | .col-8 { 153 | -ms-flex: 0 0 66.666667%; 154 | flex: 0 0 66.666667%; 155 | max-width: 66.666667%; 156 | } 157 | 158 | .col-9 { 159 | -ms-flex: 0 0 75%; 160 | flex: 0 0 75%; 161 | max-width: 75%; 162 | } 163 | 164 | .col-10 { 165 | -ms-flex: 0 0 83.333333%; 166 | flex: 0 0 83.333333%; 167 | max-width: 83.333333%; 168 | } 169 | 170 | .col-11 { 171 | -ms-flex: 0 0 91.666667%; 172 | flex: 0 0 91.666667%; 173 | max-width: 91.666667%; 174 | } 175 | 176 | .col-12 { 177 | -ms-flex: 0 0 100%; 178 | flex: 0 0 100%; 179 | max-width: 100%; 180 | } 181 | 182 | .order-first { 183 | -ms-flex-order: -1; 184 | order: -1; 185 | } 186 | 187 | .order-1 { 188 | -ms-flex-order: 1; 189 | order: 1; 190 | } 191 | 192 | .order-2 { 193 | -ms-flex-order: 2; 194 | order: 2; 195 | } 196 | 197 | .order-3 { 198 | -ms-flex-order: 3; 199 | order: 3; 200 | } 201 | 202 | .order-4 { 203 | -ms-flex-order: 4; 204 | order: 4; 205 | } 206 | 207 | .order-5 { 208 | -ms-flex-order: 5; 209 | order: 5; 210 | } 211 | 212 | .order-6 { 213 | -ms-flex-order: 6; 214 | order: 6; 215 | } 216 | 217 | .order-7 { 218 | -ms-flex-order: 7; 219 | order: 7; 220 | } 221 | 222 | .order-8 { 223 | -ms-flex-order: 8; 224 | order: 8; 225 | } 226 | 227 | .order-9 { 228 | -ms-flex-order: 9; 229 | order: 9; 230 | } 231 | 232 | .order-10 { 233 | -ms-flex-order: 10; 234 | order: 10; 235 | } 236 | 237 | .order-11 { 238 | -ms-flex-order: 11; 239 | order: 11; 240 | } 241 | 242 | .order-12 { 243 | -ms-flex-order: 12; 244 | order: 12; 245 | } 246 | 247 | .offset-1 { 248 | margin-left: 8.333333%; 249 | } 250 | 251 | .offset-2 { 252 | margin-left: 16.666667%; 253 | } 254 | 255 | .offset-3 { 256 | margin-left: 25%; 257 | } 258 | 259 | .offset-4 { 260 | margin-left: 33.333333%; 261 | } 262 | 263 | .offset-5 { 264 | margin-left: 41.666667%; 265 | } 266 | 267 | .offset-6 { 268 | margin-left: 50%; 269 | } 270 | 271 | .offset-7 { 272 | margin-left: 58.333333%; 273 | } 274 | 275 | .offset-8 { 276 | margin-left: 66.666667%; 277 | } 278 | 279 | .offset-9 { 280 | margin-left: 75%; 281 | } 282 | 283 | .offset-10 { 284 | margin-left: 83.333333%; 285 | } 286 | 287 | .offset-11 { 288 | margin-left: 91.666667%; 289 | } 290 | 291 | @media (min-width: 576px) { 292 | .col-sm { 293 | -ms-flex-preferred-size: 0; 294 | flex-basis: 0; 295 | -ms-flex-positive: 1; 296 | flex-grow: 1; 297 | max-width: 100%; 298 | } 299 | .col-sm-auto { 300 | -ms-flex: 0 0 auto; 301 | flex: 0 0 auto; 302 | width: auto; 303 | max-width: none; 304 | } 305 | .col-sm-1 { 306 | -ms-flex: 0 0 8.333333%; 307 | flex: 0 0 8.333333%; 308 | max-width: 8.333333%; 309 | } 310 | .col-sm-2 { 311 | -ms-flex: 0 0 16.666667%; 312 | flex: 0 0 16.666667%; 313 | max-width: 16.666667%; 314 | } 315 | .col-sm-3 { 316 | -ms-flex: 0 0 25%; 317 | flex: 0 0 25%; 318 | max-width: 25%; 319 | } 320 | .col-sm-4 { 321 | -ms-flex: 0 0 33.333333%; 322 | flex: 0 0 33.333333%; 323 | max-width: 33.333333%; 324 | } 325 | .col-sm-5 { 326 | -ms-flex: 0 0 41.666667%; 327 | flex: 0 0 41.666667%; 328 | max-width: 41.666667%; 329 | } 330 | .col-sm-6 { 331 | -ms-flex: 0 0 50%; 332 | flex: 0 0 50%; 333 | max-width: 50%; 334 | } 335 | .col-sm-7 { 336 | -ms-flex: 0 0 58.333333%; 337 | flex: 0 0 58.333333%; 338 | max-width: 58.333333%; 339 | } 340 | .col-sm-8 { 341 | -ms-flex: 0 0 66.666667%; 342 | flex: 0 0 66.666667%; 343 | max-width: 66.666667%; 344 | } 345 | .col-sm-9 { 346 | -ms-flex: 0 0 75%; 347 | flex: 0 0 75%; 348 | max-width: 75%; 349 | } 350 | .col-sm-10 { 351 | -ms-flex: 0 0 83.333333%; 352 | flex: 0 0 83.333333%; 353 | max-width: 83.333333%; 354 | } 355 | .col-sm-11 { 356 | -ms-flex: 0 0 91.666667%; 357 | flex: 0 0 91.666667%; 358 | max-width: 91.666667%; 359 | } 360 | .col-sm-12 { 361 | -ms-flex: 0 0 100%; 362 | flex: 0 0 100%; 363 | max-width: 100%; 364 | } 365 | .order-sm-first { 366 | -ms-flex-order: -1; 367 | order: -1; 368 | } 369 | .order-sm-1 { 370 | -ms-flex-order: 1; 371 | order: 1; 372 | } 373 | .order-sm-2 { 374 | -ms-flex-order: 2; 375 | order: 2; 376 | } 377 | .order-sm-3 { 378 | -ms-flex-order: 3; 379 | order: 3; 380 | } 381 | .order-sm-4 { 382 | -ms-flex-order: 4; 383 | order: 4; 384 | } 385 | .order-sm-5 { 386 | -ms-flex-order: 5; 387 | order: 5; 388 | } 389 | .order-sm-6 { 390 | -ms-flex-order: 6; 391 | order: 6; 392 | } 393 | .order-sm-7 { 394 | -ms-flex-order: 7; 395 | order: 7; 396 | } 397 | .order-sm-8 { 398 | -ms-flex-order: 8; 399 | order: 8; 400 | } 401 | .order-sm-9 { 402 | -ms-flex-order: 9; 403 | order: 9; 404 | } 405 | .order-sm-10 { 406 | -ms-flex-order: 10; 407 | order: 10; 408 | } 409 | .order-sm-11 { 410 | -ms-flex-order: 11; 411 | order: 11; 412 | } 413 | .order-sm-12 { 414 | -ms-flex-order: 12; 415 | order: 12; 416 | } 417 | .offset-sm-0 { 418 | margin-left: 0; 419 | } 420 | .offset-sm-1 { 421 | margin-left: 8.333333%; 422 | } 423 | .offset-sm-2 { 424 | margin-left: 16.666667%; 425 | } 426 | .offset-sm-3 { 427 | margin-left: 25%; 428 | } 429 | .offset-sm-4 { 430 | margin-left: 33.333333%; 431 | } 432 | .offset-sm-5 { 433 | margin-left: 41.666667%; 434 | } 435 | .offset-sm-6 { 436 | margin-left: 50%; 437 | } 438 | .offset-sm-7 { 439 | margin-left: 58.333333%; 440 | } 441 | .offset-sm-8 { 442 | margin-left: 66.666667%; 443 | } 444 | .offset-sm-9 { 445 | margin-left: 75%; 446 | } 447 | .offset-sm-10 { 448 | margin-left: 83.333333%; 449 | } 450 | .offset-sm-11 { 451 | margin-left: 91.666667%; 452 | } 453 | } 454 | 455 | @media (min-width: 768px) { 456 | .col-md { 457 | -ms-flex-preferred-size: 0; 458 | flex-basis: 0; 459 | -ms-flex-positive: 1; 460 | flex-grow: 1; 461 | max-width: 100%; 462 | } 463 | .col-md-auto { 464 | -ms-flex: 0 0 auto; 465 | flex: 0 0 auto; 466 | width: auto; 467 | max-width: none; 468 | } 469 | .col-md-1 { 470 | -ms-flex: 0 0 8.333333%; 471 | flex: 0 0 8.333333%; 472 | max-width: 8.333333%; 473 | } 474 | .col-md-2 { 475 | -ms-flex: 0 0 16.666667%; 476 | flex: 0 0 16.666667%; 477 | max-width: 16.666667%; 478 | } 479 | .col-md-3 { 480 | -ms-flex: 0 0 25%; 481 | flex: 0 0 25%; 482 | max-width: 25%; 483 | } 484 | .col-md-4 { 485 | -ms-flex: 0 0 33.333333%; 486 | flex: 0 0 33.333333%; 487 | max-width: 33.333333%; 488 | } 489 | .col-md-5 { 490 | -ms-flex: 0 0 41.666667%; 491 | flex: 0 0 41.666667%; 492 | max-width: 41.666667%; 493 | } 494 | .col-md-6 { 495 | -ms-flex: 0 0 50%; 496 | flex: 0 0 50%; 497 | max-width: 50%; 498 | } 499 | .col-md-7 { 500 | -ms-flex: 0 0 58.333333%; 501 | flex: 0 0 58.333333%; 502 | max-width: 58.333333%; 503 | } 504 | .col-md-8 { 505 | -ms-flex: 0 0 66.666667%; 506 | flex: 0 0 66.666667%; 507 | max-width: 66.666667%; 508 | } 509 | .col-md-9 { 510 | -ms-flex: 0 0 75%; 511 | flex: 0 0 75%; 512 | max-width: 75%; 513 | } 514 | .col-md-10 { 515 | -ms-flex: 0 0 83.333333%; 516 | flex: 0 0 83.333333%; 517 | max-width: 83.333333%; 518 | } 519 | .col-md-11 { 520 | -ms-flex: 0 0 91.666667%; 521 | flex: 0 0 91.666667%; 522 | max-width: 91.666667%; 523 | } 524 | .col-md-12 { 525 | -ms-flex: 0 0 100%; 526 | flex: 0 0 100%; 527 | max-width: 100%; 528 | } 529 | .order-md-first { 530 | -ms-flex-order: -1; 531 | order: -1; 532 | } 533 | .order-md-1 { 534 | -ms-flex-order: 1; 535 | order: 1; 536 | } 537 | .order-md-2 { 538 | -ms-flex-order: 2; 539 | order: 2; 540 | } 541 | .order-md-3 { 542 | -ms-flex-order: 3; 543 | order: 3; 544 | } 545 | .order-md-4 { 546 | -ms-flex-order: 4; 547 | order: 4; 548 | } 549 | .order-md-5 { 550 | -ms-flex-order: 5; 551 | order: 5; 552 | } 553 | .order-md-6 { 554 | -ms-flex-order: 6; 555 | order: 6; 556 | } 557 | .order-md-7 { 558 | -ms-flex-order: 7; 559 | order: 7; 560 | } 561 | .order-md-8 { 562 | -ms-flex-order: 8; 563 | order: 8; 564 | } 565 | .order-md-9 { 566 | -ms-flex-order: 9; 567 | order: 9; 568 | } 569 | .order-md-10 { 570 | -ms-flex-order: 10; 571 | order: 10; 572 | } 573 | .order-md-11 { 574 | -ms-flex-order: 11; 575 | order: 11; 576 | } 577 | .order-md-12 { 578 | -ms-flex-order: 12; 579 | order: 12; 580 | } 581 | .offset-md-0 { 582 | margin-left: 0; 583 | } 584 | .offset-md-1 { 585 | margin-left: 8.333333%; 586 | } 587 | .offset-md-2 { 588 | margin-left: 16.666667%; 589 | } 590 | .offset-md-3 { 591 | margin-left: 25%; 592 | } 593 | .offset-md-4 { 594 | margin-left: 33.333333%; 595 | } 596 | .offset-md-5 { 597 | margin-left: 41.666667%; 598 | } 599 | .offset-md-6 { 600 | margin-left: 50%; 601 | } 602 | .offset-md-7 { 603 | margin-left: 58.333333%; 604 | } 605 | .offset-md-8 { 606 | margin-left: 66.666667%; 607 | } 608 | .offset-md-9 { 609 | margin-left: 75%; 610 | } 611 | .offset-md-10 { 612 | margin-left: 83.333333%; 613 | } 614 | .offset-md-11 { 615 | margin-left: 91.666667%; 616 | } 617 | } 618 | 619 | @media (min-width: 992px) { 620 | .col-lg { 621 | -ms-flex-preferred-size: 0; 622 | flex-basis: 0; 623 | -ms-flex-positive: 1; 624 | flex-grow: 1; 625 | max-width: 100%; 626 | } 627 | .col-lg-auto { 628 | -ms-flex: 0 0 auto; 629 | flex: 0 0 auto; 630 | width: auto; 631 | max-width: none; 632 | } 633 | .col-lg-1 { 634 | -ms-flex: 0 0 8.333333%; 635 | flex: 0 0 8.333333%; 636 | max-width: 8.333333%; 637 | } 638 | .col-lg-2 { 639 | -ms-flex: 0 0 16.666667%; 640 | flex: 0 0 16.666667%; 641 | max-width: 16.666667%; 642 | } 643 | .col-lg-3 { 644 | -ms-flex: 0 0 25%; 645 | flex: 0 0 25%; 646 | max-width: 25%; 647 | } 648 | .col-lg-4 { 649 | -ms-flex: 0 0 33.333333%; 650 | flex: 0 0 33.333333%; 651 | max-width: 33.333333%; 652 | } 653 | .col-lg-5 { 654 | -ms-flex: 0 0 41.666667%; 655 | flex: 0 0 41.666667%; 656 | max-width: 41.666667%; 657 | } 658 | .col-lg-6 { 659 | -ms-flex: 0 0 50%; 660 | flex: 0 0 50%; 661 | max-width: 50%; 662 | } 663 | .col-lg-7 { 664 | -ms-flex: 0 0 58.333333%; 665 | flex: 0 0 58.333333%; 666 | max-width: 58.333333%; 667 | } 668 | .col-lg-8 { 669 | -ms-flex: 0 0 66.666667%; 670 | flex: 0 0 66.666667%; 671 | max-width: 66.666667%; 672 | } 673 | .col-lg-9 { 674 | -ms-flex: 0 0 75%; 675 | flex: 0 0 75%; 676 | max-width: 75%; 677 | } 678 | .col-lg-10 { 679 | -ms-flex: 0 0 83.333333%; 680 | flex: 0 0 83.333333%; 681 | max-width: 83.333333%; 682 | } 683 | .col-lg-11 { 684 | -ms-flex: 0 0 91.666667%; 685 | flex: 0 0 91.666667%; 686 | max-width: 91.666667%; 687 | } 688 | .col-lg-12 { 689 | -ms-flex: 0 0 100%; 690 | flex: 0 0 100%; 691 | max-width: 100%; 692 | } 693 | .order-lg-first { 694 | -ms-flex-order: -1; 695 | order: -1; 696 | } 697 | .order-lg-1 { 698 | -ms-flex-order: 1; 699 | order: 1; 700 | } 701 | .order-lg-2 { 702 | -ms-flex-order: 2; 703 | order: 2; 704 | } 705 | .order-lg-3 { 706 | -ms-flex-order: 3; 707 | order: 3; 708 | } 709 | .order-lg-4 { 710 | -ms-flex-order: 4; 711 | order: 4; 712 | } 713 | .order-lg-5 { 714 | -ms-flex-order: 5; 715 | order: 5; 716 | } 717 | .order-lg-6 { 718 | -ms-flex-order: 6; 719 | order: 6; 720 | } 721 | .order-lg-7 { 722 | -ms-flex-order: 7; 723 | order: 7; 724 | } 725 | .order-lg-8 { 726 | -ms-flex-order: 8; 727 | order: 8; 728 | } 729 | .order-lg-9 { 730 | -ms-flex-order: 9; 731 | order: 9; 732 | } 733 | .order-lg-10 { 734 | -ms-flex-order: 10; 735 | order: 10; 736 | } 737 | .order-lg-11 { 738 | -ms-flex-order: 11; 739 | order: 11; 740 | } 741 | .order-lg-12 { 742 | -ms-flex-order: 12; 743 | order: 12; 744 | } 745 | .offset-lg-0 { 746 | margin-left: 0; 747 | } 748 | .offset-lg-1 { 749 | margin-left: 8.333333%; 750 | } 751 | .offset-lg-2 { 752 | margin-left: 16.666667%; 753 | } 754 | .offset-lg-3 { 755 | margin-left: 25%; 756 | } 757 | .offset-lg-4 { 758 | margin-left: 33.333333%; 759 | } 760 | .offset-lg-5 { 761 | margin-left: 41.666667%; 762 | } 763 | .offset-lg-6 { 764 | margin-left: 50%; 765 | } 766 | .offset-lg-7 { 767 | margin-left: 58.333333%; 768 | } 769 | .offset-lg-8 { 770 | margin-left: 66.666667%; 771 | } 772 | .offset-lg-9 { 773 | margin-left: 75%; 774 | } 775 | .offset-lg-10 { 776 | margin-left: 83.333333%; 777 | } 778 | .offset-lg-11 { 779 | margin-left: 91.666667%; 780 | } 781 | } 782 | 783 | @media (min-width: 1200px) { 784 | .col-xl { 785 | -ms-flex-preferred-size: 0; 786 | flex-basis: 0; 787 | -ms-flex-positive: 1; 788 | flex-grow: 1; 789 | max-width: 100%; 790 | } 791 | .col-xl-auto { 792 | -ms-flex: 0 0 auto; 793 | flex: 0 0 auto; 794 | width: auto; 795 | max-width: none; 796 | } 797 | .col-xl-1 { 798 | -ms-flex: 0 0 8.333333%; 799 | flex: 0 0 8.333333%; 800 | max-width: 8.333333%; 801 | } 802 | .col-xl-2 { 803 | -ms-flex: 0 0 16.666667%; 804 | flex: 0 0 16.666667%; 805 | max-width: 16.666667%; 806 | } 807 | .col-xl-3 { 808 | -ms-flex: 0 0 25%; 809 | flex: 0 0 25%; 810 | max-width: 25%; 811 | } 812 | .col-xl-4 { 813 | -ms-flex: 0 0 33.333333%; 814 | flex: 0 0 33.333333%; 815 | max-width: 33.333333%; 816 | } 817 | .col-xl-5 { 818 | -ms-flex: 0 0 41.666667%; 819 | flex: 0 0 41.666667%; 820 | max-width: 41.666667%; 821 | } 822 | .col-xl-6 { 823 | -ms-flex: 0 0 50%; 824 | flex: 0 0 50%; 825 | max-width: 50%; 826 | } 827 | .col-xl-7 { 828 | -ms-flex: 0 0 58.333333%; 829 | flex: 0 0 58.333333%; 830 | max-width: 58.333333%; 831 | } 832 | .col-xl-8 { 833 | -ms-flex: 0 0 66.666667%; 834 | flex: 0 0 66.666667%; 835 | max-width: 66.666667%; 836 | } 837 | .col-xl-9 { 838 | -ms-flex: 0 0 75%; 839 | flex: 0 0 75%; 840 | max-width: 75%; 841 | } 842 | .col-xl-10 { 843 | -ms-flex: 0 0 83.333333%; 844 | flex: 0 0 83.333333%; 845 | max-width: 83.333333%; 846 | } 847 | .col-xl-11 { 848 | -ms-flex: 0 0 91.666667%; 849 | flex: 0 0 91.666667%; 850 | max-width: 91.666667%; 851 | } 852 | .col-xl-12 { 853 | -ms-flex: 0 0 100%; 854 | flex: 0 0 100%; 855 | max-width: 100%; 856 | } 857 | .order-xl-first { 858 | -ms-flex-order: -1; 859 | order: -1; 860 | } 861 | .order-xl-1 { 862 | -ms-flex-order: 1; 863 | order: 1; 864 | } 865 | .order-xl-2 { 866 | -ms-flex-order: 2; 867 | order: 2; 868 | } 869 | .order-xl-3 { 870 | -ms-flex-order: 3; 871 | order: 3; 872 | } 873 | .order-xl-4 { 874 | -ms-flex-order: 4; 875 | order: 4; 876 | } 877 | .order-xl-5 { 878 | -ms-flex-order: 5; 879 | order: 5; 880 | } 881 | .order-xl-6 { 882 | -ms-flex-order: 6; 883 | order: 6; 884 | } 885 | .order-xl-7 { 886 | -ms-flex-order: 7; 887 | order: 7; 888 | } 889 | .order-xl-8 { 890 | -ms-flex-order: 8; 891 | order: 8; 892 | } 893 | .order-xl-9 { 894 | -ms-flex-order: 9; 895 | order: 9; 896 | } 897 | .order-xl-10 { 898 | -ms-flex-order: 10; 899 | order: 10; 900 | } 901 | .order-xl-11 { 902 | -ms-flex-order: 11; 903 | order: 11; 904 | } 905 | .order-xl-12 { 906 | -ms-flex-order: 12; 907 | order: 12; 908 | } 909 | .offset-xl-0 { 910 | margin-left: 0; 911 | } 912 | .offset-xl-1 { 913 | margin-left: 8.333333%; 914 | } 915 | .offset-xl-2 { 916 | margin-left: 16.666667%; 917 | } 918 | .offset-xl-3 { 919 | margin-left: 25%; 920 | } 921 | .offset-xl-4 { 922 | margin-left: 33.333333%; 923 | } 924 | .offset-xl-5 { 925 | margin-left: 41.666667%; 926 | } 927 | .offset-xl-6 { 928 | margin-left: 50%; 929 | } 930 | .offset-xl-7 { 931 | margin-left: 58.333333%; 932 | } 933 | .offset-xl-8 { 934 | margin-left: 66.666667%; 935 | } 936 | .offset-xl-9 { 937 | margin-left: 75%; 938 | } 939 | .offset-xl-10 { 940 | margin-left: 83.333333%; 941 | } 942 | .offset-xl-11 { 943 | margin-left: 91.666667%; 944 | } 945 | } 946 | 947 | .flex-row { 948 | -ms-flex-direction: row !important; 949 | flex-direction: row !important; 950 | } 951 | 952 | .flex-column { 953 | -ms-flex-direction: column !important; 954 | flex-direction: column !important; 955 | } 956 | 957 | .flex-row-reverse { 958 | -ms-flex-direction: row-reverse !important; 959 | flex-direction: row-reverse !important; 960 | } 961 | 962 | .flex-column-reverse { 963 | -ms-flex-direction: column-reverse !important; 964 | flex-direction: column-reverse !important; 965 | } 966 | 967 | .flex-wrap { 968 | -ms-flex-wrap: wrap !important; 969 | flex-wrap: wrap !important; 970 | } 971 | 972 | .flex-nowrap { 973 | -ms-flex-wrap: nowrap !important; 974 | flex-wrap: nowrap !important; 975 | } 976 | 977 | .flex-wrap-reverse { 978 | -ms-flex-wrap: wrap-reverse !important; 979 | flex-wrap: wrap-reverse !important; 980 | } 981 | 982 | .justify-content-start { 983 | -ms-flex-pack: start !important; 984 | justify-content: flex-start !important; 985 | } 986 | 987 | .justify-content-end { 988 | -ms-flex-pack: end !important; 989 | justify-content: flex-end !important; 990 | } 991 | 992 | .justify-content-center { 993 | -ms-flex-pack: center !important; 994 | justify-content: center !important; 995 | } 996 | 997 | .justify-content-between { 998 | -ms-flex-pack: justify !important; 999 | justify-content: space-between !important; 1000 | } 1001 | 1002 | .justify-content-around { 1003 | -ms-flex-pack: distribute !important; 1004 | justify-content: space-around !important; 1005 | } 1006 | 1007 | .align-items-start { 1008 | -ms-flex-align: start !important; 1009 | align-items: flex-start !important; 1010 | } 1011 | 1012 | .align-items-end { 1013 | -ms-flex-align: end !important; 1014 | align-items: flex-end !important; 1015 | } 1016 | 1017 | .align-items-center { 1018 | -ms-flex-align: center !important; 1019 | align-items: center !important; 1020 | } 1021 | 1022 | .align-items-baseline { 1023 | -ms-flex-align: baseline !important; 1024 | align-items: baseline !important; 1025 | } 1026 | 1027 | .align-items-stretch { 1028 | -ms-flex-align: stretch !important; 1029 | align-items: stretch !important; 1030 | } 1031 | 1032 | .align-content-start { 1033 | -ms-flex-line-pack: start !important; 1034 | align-content: flex-start !important; 1035 | } 1036 | 1037 | .align-content-end { 1038 | -ms-flex-line-pack: end !important; 1039 | align-content: flex-end !important; 1040 | } 1041 | 1042 | .align-content-center { 1043 | -ms-flex-line-pack: center !important; 1044 | align-content: center !important; 1045 | } 1046 | 1047 | .align-content-between { 1048 | -ms-flex-line-pack: justify !important; 1049 | align-content: space-between !important; 1050 | } 1051 | 1052 | .align-content-around { 1053 | -ms-flex-line-pack: distribute !important; 1054 | align-content: space-around !important; 1055 | } 1056 | 1057 | .align-content-stretch { 1058 | -ms-flex-line-pack: stretch !important; 1059 | align-content: stretch !important; 1060 | } 1061 | 1062 | .align-self-auto { 1063 | -ms-flex-item-align: auto !important; 1064 | align-self: auto !important; 1065 | } 1066 | 1067 | .align-self-start { 1068 | -ms-flex-item-align: start !important; 1069 | align-self: flex-start !important; 1070 | } 1071 | 1072 | .align-self-end { 1073 | -ms-flex-item-align: end !important; 1074 | align-self: flex-end !important; 1075 | } 1076 | 1077 | .align-self-center { 1078 | -ms-flex-item-align: center !important; 1079 | align-self: center !important; 1080 | } 1081 | 1082 | .align-self-baseline { 1083 | -ms-flex-item-align: baseline !important; 1084 | align-self: baseline !important; 1085 | } 1086 | 1087 | .align-self-stretch { 1088 | -ms-flex-item-align: stretch !important; 1089 | align-self: stretch !important; 1090 | } 1091 | 1092 | @media (min-width: 576px) { 1093 | .flex-sm-row { 1094 | -ms-flex-direction: row !important; 1095 | flex-direction: row !important; 1096 | } 1097 | .flex-sm-column { 1098 | -ms-flex-direction: column !important; 1099 | flex-direction: column !important; 1100 | } 1101 | .flex-sm-row-reverse { 1102 | -ms-flex-direction: row-reverse !important; 1103 | flex-direction: row-reverse !important; 1104 | } 1105 | .flex-sm-column-reverse { 1106 | -ms-flex-direction: column-reverse !important; 1107 | flex-direction: column-reverse !important; 1108 | } 1109 | .flex-sm-wrap { 1110 | -ms-flex-wrap: wrap !important; 1111 | flex-wrap: wrap !important; 1112 | } 1113 | .flex-sm-nowrap { 1114 | -ms-flex-wrap: nowrap !important; 1115 | flex-wrap: nowrap !important; 1116 | } 1117 | .flex-sm-wrap-reverse { 1118 | -ms-flex-wrap: wrap-reverse !important; 1119 | flex-wrap: wrap-reverse !important; 1120 | } 1121 | .justify-content-sm-start { 1122 | -ms-flex-pack: start !important; 1123 | justify-content: flex-start !important; 1124 | } 1125 | .justify-content-sm-end { 1126 | -ms-flex-pack: end !important; 1127 | justify-content: flex-end !important; 1128 | } 1129 | .justify-content-sm-center { 1130 | -ms-flex-pack: center !important; 1131 | justify-content: center !important; 1132 | } 1133 | .justify-content-sm-between { 1134 | -ms-flex-pack: justify !important; 1135 | justify-content: space-between !important; 1136 | } 1137 | .justify-content-sm-around { 1138 | -ms-flex-pack: distribute !important; 1139 | justify-content: space-around !important; 1140 | } 1141 | .align-items-sm-start { 1142 | -ms-flex-align: start !important; 1143 | align-items: flex-start !important; 1144 | } 1145 | .align-items-sm-end { 1146 | -ms-flex-align: end !important; 1147 | align-items: flex-end !important; 1148 | } 1149 | .align-items-sm-center { 1150 | -ms-flex-align: center !important; 1151 | align-items: center !important; 1152 | } 1153 | .align-items-sm-baseline { 1154 | -ms-flex-align: baseline !important; 1155 | align-items: baseline !important; 1156 | } 1157 | .align-items-sm-stretch { 1158 | -ms-flex-align: stretch !important; 1159 | align-items: stretch !important; 1160 | } 1161 | .align-content-sm-start { 1162 | -ms-flex-line-pack: start !important; 1163 | align-content: flex-start !important; 1164 | } 1165 | .align-content-sm-end { 1166 | -ms-flex-line-pack: end !important; 1167 | align-content: flex-end !important; 1168 | } 1169 | .align-content-sm-center { 1170 | -ms-flex-line-pack: center !important; 1171 | align-content: center !important; 1172 | } 1173 | .align-content-sm-between { 1174 | -ms-flex-line-pack: justify !important; 1175 | align-content: space-between !important; 1176 | } 1177 | .align-content-sm-around { 1178 | -ms-flex-line-pack: distribute !important; 1179 | align-content: space-around !important; 1180 | } 1181 | .align-content-sm-stretch { 1182 | -ms-flex-line-pack: stretch !important; 1183 | align-content: stretch !important; 1184 | } 1185 | .align-self-sm-auto { 1186 | -ms-flex-item-align: auto !important; 1187 | align-self: auto !important; 1188 | } 1189 | .align-self-sm-start { 1190 | -ms-flex-item-align: start !important; 1191 | align-self: flex-start !important; 1192 | } 1193 | .align-self-sm-end { 1194 | -ms-flex-item-align: end !important; 1195 | align-self: flex-end !important; 1196 | } 1197 | .align-self-sm-center { 1198 | -ms-flex-item-align: center !important; 1199 | align-self: center !important; 1200 | } 1201 | .align-self-sm-baseline { 1202 | -ms-flex-item-align: baseline !important; 1203 | align-self: baseline !important; 1204 | } 1205 | .align-self-sm-stretch { 1206 | -ms-flex-item-align: stretch !important; 1207 | align-self: stretch !important; 1208 | } 1209 | } 1210 | 1211 | @media (min-width: 768px) { 1212 | .flex-md-row { 1213 | -ms-flex-direction: row !important; 1214 | flex-direction: row !important; 1215 | } 1216 | .flex-md-column { 1217 | -ms-flex-direction: column !important; 1218 | flex-direction: column !important; 1219 | } 1220 | .flex-md-row-reverse { 1221 | -ms-flex-direction: row-reverse !important; 1222 | flex-direction: row-reverse !important; 1223 | } 1224 | .flex-md-column-reverse { 1225 | -ms-flex-direction: column-reverse !important; 1226 | flex-direction: column-reverse !important; 1227 | } 1228 | .flex-md-wrap { 1229 | -ms-flex-wrap: wrap !important; 1230 | flex-wrap: wrap !important; 1231 | } 1232 | .flex-md-nowrap { 1233 | -ms-flex-wrap: nowrap !important; 1234 | flex-wrap: nowrap !important; 1235 | } 1236 | .flex-md-wrap-reverse { 1237 | -ms-flex-wrap: wrap-reverse !important; 1238 | flex-wrap: wrap-reverse !important; 1239 | } 1240 | .justify-content-md-start { 1241 | -ms-flex-pack: start !important; 1242 | justify-content: flex-start !important; 1243 | } 1244 | .justify-content-md-end { 1245 | -ms-flex-pack: end !important; 1246 | justify-content: flex-end !important; 1247 | } 1248 | .justify-content-md-center { 1249 | -ms-flex-pack: center !important; 1250 | justify-content: center !important; 1251 | } 1252 | .justify-content-md-between { 1253 | -ms-flex-pack: justify !important; 1254 | justify-content: space-between !important; 1255 | } 1256 | .justify-content-md-around { 1257 | -ms-flex-pack: distribute !important; 1258 | justify-content: space-around !important; 1259 | } 1260 | .align-items-md-start { 1261 | -ms-flex-align: start !important; 1262 | align-items: flex-start !important; 1263 | } 1264 | .align-items-md-end { 1265 | -ms-flex-align: end !important; 1266 | align-items: flex-end !important; 1267 | } 1268 | .align-items-md-center { 1269 | -ms-flex-align: center !important; 1270 | align-items: center !important; 1271 | } 1272 | .align-items-md-baseline { 1273 | -ms-flex-align: baseline !important; 1274 | align-items: baseline !important; 1275 | } 1276 | .align-items-md-stretch { 1277 | -ms-flex-align: stretch !important; 1278 | align-items: stretch !important; 1279 | } 1280 | .align-content-md-start { 1281 | -ms-flex-line-pack: start !important; 1282 | align-content: flex-start !important; 1283 | } 1284 | .align-content-md-end { 1285 | -ms-flex-line-pack: end !important; 1286 | align-content: flex-end !important; 1287 | } 1288 | .align-content-md-center { 1289 | -ms-flex-line-pack: center !important; 1290 | align-content: center !important; 1291 | } 1292 | .align-content-md-between { 1293 | -ms-flex-line-pack: justify !important; 1294 | align-content: space-between !important; 1295 | } 1296 | .align-content-md-around { 1297 | -ms-flex-line-pack: distribute !important; 1298 | align-content: space-around !important; 1299 | } 1300 | .align-content-md-stretch { 1301 | -ms-flex-line-pack: stretch !important; 1302 | align-content: stretch !important; 1303 | } 1304 | .align-self-md-auto { 1305 | -ms-flex-item-align: auto !important; 1306 | align-self: auto !important; 1307 | } 1308 | .align-self-md-start { 1309 | -ms-flex-item-align: start !important; 1310 | align-self: flex-start !important; 1311 | } 1312 | .align-self-md-end { 1313 | -ms-flex-item-align: end !important; 1314 | align-self: flex-end !important; 1315 | } 1316 | .align-self-md-center { 1317 | -ms-flex-item-align: center !important; 1318 | align-self: center !important; 1319 | } 1320 | .align-self-md-baseline { 1321 | -ms-flex-item-align: baseline !important; 1322 | align-self: baseline !important; 1323 | } 1324 | .align-self-md-stretch { 1325 | -ms-flex-item-align: stretch !important; 1326 | align-self: stretch !important; 1327 | } 1328 | } 1329 | 1330 | @media (min-width: 992px) { 1331 | .flex-lg-row { 1332 | -ms-flex-direction: row !important; 1333 | flex-direction: row !important; 1334 | } 1335 | .flex-lg-column { 1336 | -ms-flex-direction: column !important; 1337 | flex-direction: column !important; 1338 | } 1339 | .flex-lg-row-reverse { 1340 | -ms-flex-direction: row-reverse !important; 1341 | flex-direction: row-reverse !important; 1342 | } 1343 | .flex-lg-column-reverse { 1344 | -ms-flex-direction: column-reverse !important; 1345 | flex-direction: column-reverse !important; 1346 | } 1347 | .flex-lg-wrap { 1348 | -ms-flex-wrap: wrap !important; 1349 | flex-wrap: wrap !important; 1350 | } 1351 | .flex-lg-nowrap { 1352 | -ms-flex-wrap: nowrap !important; 1353 | flex-wrap: nowrap !important; 1354 | } 1355 | .flex-lg-wrap-reverse { 1356 | -ms-flex-wrap: wrap-reverse !important; 1357 | flex-wrap: wrap-reverse !important; 1358 | } 1359 | .justify-content-lg-start { 1360 | -ms-flex-pack: start !important; 1361 | justify-content: flex-start !important; 1362 | } 1363 | .justify-content-lg-end { 1364 | -ms-flex-pack: end !important; 1365 | justify-content: flex-end !important; 1366 | } 1367 | .justify-content-lg-center { 1368 | -ms-flex-pack: center !important; 1369 | justify-content: center !important; 1370 | } 1371 | .justify-content-lg-between { 1372 | -ms-flex-pack: justify !important; 1373 | justify-content: space-between !important; 1374 | } 1375 | .justify-content-lg-around { 1376 | -ms-flex-pack: distribute !important; 1377 | justify-content: space-around !important; 1378 | } 1379 | .align-items-lg-start { 1380 | -ms-flex-align: start !important; 1381 | align-items: flex-start !important; 1382 | } 1383 | .align-items-lg-end { 1384 | -ms-flex-align: end !important; 1385 | align-items: flex-end !important; 1386 | } 1387 | .align-items-lg-center { 1388 | -ms-flex-align: center !important; 1389 | align-items: center !important; 1390 | } 1391 | .align-items-lg-baseline { 1392 | -ms-flex-align: baseline !important; 1393 | align-items: baseline !important; 1394 | } 1395 | .align-items-lg-stretch { 1396 | -ms-flex-align: stretch !important; 1397 | align-items: stretch !important; 1398 | } 1399 | .align-content-lg-start { 1400 | -ms-flex-line-pack: start !important; 1401 | align-content: flex-start !important; 1402 | } 1403 | .align-content-lg-end { 1404 | -ms-flex-line-pack: end !important; 1405 | align-content: flex-end !important; 1406 | } 1407 | .align-content-lg-center { 1408 | -ms-flex-line-pack: center !important; 1409 | align-content: center !important; 1410 | } 1411 | .align-content-lg-between { 1412 | -ms-flex-line-pack: justify !important; 1413 | align-content: space-between !important; 1414 | } 1415 | .align-content-lg-around { 1416 | -ms-flex-line-pack: distribute !important; 1417 | align-content: space-around !important; 1418 | } 1419 | .align-content-lg-stretch { 1420 | -ms-flex-line-pack: stretch !important; 1421 | align-content: stretch !important; 1422 | } 1423 | .align-self-lg-auto { 1424 | -ms-flex-item-align: auto !important; 1425 | align-self: auto !important; 1426 | } 1427 | .align-self-lg-start { 1428 | -ms-flex-item-align: start !important; 1429 | align-self: flex-start !important; 1430 | } 1431 | .align-self-lg-end { 1432 | -ms-flex-item-align: end !important; 1433 | align-self: flex-end !important; 1434 | } 1435 | .align-self-lg-center { 1436 | -ms-flex-item-align: center !important; 1437 | align-self: center !important; 1438 | } 1439 | .align-self-lg-baseline { 1440 | -ms-flex-item-align: baseline !important; 1441 | align-self: baseline !important; 1442 | } 1443 | .align-self-lg-stretch { 1444 | -ms-flex-item-align: stretch !important; 1445 | align-self: stretch !important; 1446 | } 1447 | } 1448 | 1449 | @media (min-width: 1200px) { 1450 | .flex-xl-row { 1451 | -ms-flex-direction: row !important; 1452 | flex-direction: row !important; 1453 | } 1454 | .flex-xl-column { 1455 | -ms-flex-direction: column !important; 1456 | flex-direction: column !important; 1457 | } 1458 | .flex-xl-row-reverse { 1459 | -ms-flex-direction: row-reverse !important; 1460 | flex-direction: row-reverse !important; 1461 | } 1462 | .flex-xl-column-reverse { 1463 | -ms-flex-direction: column-reverse !important; 1464 | flex-direction: column-reverse !important; 1465 | } 1466 | .flex-xl-wrap { 1467 | -ms-flex-wrap: wrap !important; 1468 | flex-wrap: wrap !important; 1469 | } 1470 | .flex-xl-nowrap { 1471 | -ms-flex-wrap: nowrap !important; 1472 | flex-wrap: nowrap !important; 1473 | } 1474 | .flex-xl-wrap-reverse { 1475 | -ms-flex-wrap: wrap-reverse !important; 1476 | flex-wrap: wrap-reverse !important; 1477 | } 1478 | .justify-content-xl-start { 1479 | -ms-flex-pack: start !important; 1480 | justify-content: flex-start !important; 1481 | } 1482 | .justify-content-xl-end { 1483 | -ms-flex-pack: end !important; 1484 | justify-content: flex-end !important; 1485 | } 1486 | .justify-content-xl-center { 1487 | -ms-flex-pack: center !important; 1488 | justify-content: center !important; 1489 | } 1490 | .justify-content-xl-between { 1491 | -ms-flex-pack: justify !important; 1492 | justify-content: space-between !important; 1493 | } 1494 | .justify-content-xl-around { 1495 | -ms-flex-pack: distribute !important; 1496 | justify-content: space-around !important; 1497 | } 1498 | .align-items-xl-start { 1499 | -ms-flex-align: start !important; 1500 | align-items: flex-start !important; 1501 | } 1502 | .align-items-xl-end { 1503 | -ms-flex-align: end !important; 1504 | align-items: flex-end !important; 1505 | } 1506 | .align-items-xl-center { 1507 | -ms-flex-align: center !important; 1508 | align-items: center !important; 1509 | } 1510 | .align-items-xl-baseline { 1511 | -ms-flex-align: baseline !important; 1512 | align-items: baseline !important; 1513 | } 1514 | .align-items-xl-stretch { 1515 | -ms-flex-align: stretch !important; 1516 | align-items: stretch !important; 1517 | } 1518 | .align-content-xl-start { 1519 | -ms-flex-line-pack: start !important; 1520 | align-content: flex-start !important; 1521 | } 1522 | .align-content-xl-end { 1523 | -ms-flex-line-pack: end !important; 1524 | align-content: flex-end !important; 1525 | } 1526 | .align-content-xl-center { 1527 | -ms-flex-line-pack: center !important; 1528 | align-content: center !important; 1529 | } 1530 | .align-content-xl-between { 1531 | -ms-flex-line-pack: justify !important; 1532 | align-content: space-between !important; 1533 | } 1534 | .align-content-xl-around { 1535 | -ms-flex-line-pack: distribute !important; 1536 | align-content: space-around !important; 1537 | } 1538 | .align-content-xl-stretch { 1539 | -ms-flex-line-pack: stretch !important; 1540 | align-content: stretch !important; 1541 | } 1542 | .align-self-xl-auto { 1543 | -ms-flex-item-align: auto !important; 1544 | align-self: auto !important; 1545 | } 1546 | .align-self-xl-start { 1547 | -ms-flex-item-align: start !important; 1548 | align-self: flex-start !important; 1549 | } 1550 | .align-self-xl-end { 1551 | -ms-flex-item-align: end !important; 1552 | align-self: flex-end !important; 1553 | } 1554 | .align-self-xl-center { 1555 | -ms-flex-item-align: center !important; 1556 | align-self: center !important; 1557 | } 1558 | .align-self-xl-baseline { 1559 | -ms-flex-item-align: baseline !important; 1560 | align-self: baseline !important; 1561 | } 1562 | .align-self-xl-stretch { 1563 | -ms-flex-item-align: stretch !important; 1564 | align-self: stretch !important; 1565 | } 1566 | } 1567 | /*# sourceMappingURL=bootstrap-grid.css.map */ --------------------------------------------------------------------------------