mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-03 20:02:47 +00:00 
			
		
		
		
	Compare commits
	
		
			24 Commits
		
	
	
		
			access-pip
			...
			a65b1ff578
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a65b1ff578 | ||
| 
						 | 
					fe0fcb0e10 | ||
| 
						 | 
					32fa632961 | ||
| 
						 | 
					562b8d5ce0 | ||
| 
						 | 
					cbd0a41bce | ||
| 
						 | 
					c68286e010 | ||
| 
						 | 
					4a29a52f2a | ||
| 
						 | 
					991810cff5 | ||
| 
						 | 
					6025a4a606 | ||
| 
						 | 
					e1cfd394fa | ||
| 
						 | 
					882987ba68 | ||
| 
						 | 
					a03b5918d9 | ||
| 
						 | 
					43b38b2216 | ||
| 
						 | 
					543276d766 | ||
| 
						 | 
					485a0155c6 | ||
| 
						 | 
					c29c50feb9 | ||
| 
						 | 
					c191e7bd4a | ||
| 
						 | 
					8f960cf359 | ||
| 
						 | 
					ccf484c9bc | ||
| 
						 | 
					d0d2a8abd6 | ||
| 
						 | 
					03876f6a39 | ||
| 
						 | 
					cdf6f9fcfd | ||
| 
						 | 
					268da220d2 | ||
| 
						 | 
					84e1755a57 | 
@@ -5,9 +5,9 @@
 | 
				
			|||||||
!app
 | 
					!app
 | 
				
			||||||
!migrations
 | 
					!migrations
 | 
				
			||||||
!tests
 | 
					!tests
 | 
				
			||||||
!.flaskenv
 | 
					 | 
				
			||||||
!boot.sh
 | 
					!boot.sh
 | 
				
			||||||
!config.py
 | 
					!config.py
 | 
				
			||||||
!docker-nopaque-entrypoint.sh
 | 
					!docker-nopaque-entrypoint.sh
 | 
				
			||||||
!nopaque.py
 | 
					 | 
				
			||||||
!requirements.txt
 | 
					!requirements.txt
 | 
				
			||||||
 | 
					!requirements.freezed.txt
 | 
				
			||||||
 | 
					!wsgi.py
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -35,19 +35,17 @@ ENV PATH="${NOPAQUE_PYTHON3_VENV_PATH}/bin:${PATH}"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install Python dependencies
 | 
					# Install Python dependencies
 | 
				
			||||||
COPY --chown=nopaque:nopaque requirements.txt requirements.txt
 | 
					COPY --chown=nopaque:nopaque requirements.freezed.txt requirements.freezed.txt
 | 
				
			||||||
RUN python3 -m pip install --requirement requirements.txt \
 | 
					RUN python3 -m pip install --requirement requirements.freezed.txt \
 | 
				
			||||||
 && rm requirements.txt
 | 
					 && rm requirements.freezed.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install the application
 | 
					# Install the application
 | 
				
			||||||
COPY docker-nopaque-entrypoint.sh /usr/local/bin/
 | 
					COPY docker-nopaque-entrypoint.sh /usr/local/bin/
 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY --chown=nopaque:nopaque app app
 | 
					COPY --chown=nopaque:nopaque app app
 | 
				
			||||||
COPY --chown=nopaque:nopaque migrations migrations
 | 
					COPY --chown=nopaque:nopaque migrations migrations
 | 
				
			||||||
COPY --chown=nopaque:nopaque tests tests
 | 
					COPY --chown=nopaque:nopaque tests tests
 | 
				
			||||||
COPY --chown=nopaque:nopaque .flaskenv boot.sh config.py nopaque.py requirements.txt ./
 | 
					COPY --chown=nopaque:nopaque boot.sh config.py wsgi.py ./
 | 
				
			||||||
 | 
					 | 
				
			||||||
RUN mkdir logs
 | 
					RUN mkdir logs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ from docker import DockerClient
 | 
				
			|||||||
from flask import Flask
 | 
					from flask import Flask
 | 
				
			||||||
from flask_apscheduler import APScheduler
 | 
					from flask_apscheduler import APScheduler
 | 
				
			||||||
from flask_assets import Environment
 | 
					from flask_assets import Environment
 | 
				
			||||||
from flask_breadcrumbs import Breadcrumbs, default_breadcrumb_root
 | 
					 | 
				
			||||||
from flask_login import LoginManager
 | 
					from flask_login import LoginManager
 | 
				
			||||||
from flask_mail import Mail
 | 
					from flask_mail import Mail
 | 
				
			||||||
from flask_marshmallow import Marshmallow
 | 
					from flask_marshmallow import Marshmallow
 | 
				
			||||||
@@ -17,7 +16,6 @@ from flask_hashids import Hashids
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
apifairy = APIFairy()
 | 
					apifairy = APIFairy()
 | 
				
			||||||
assets = Environment()
 | 
					assets = Environment()
 | 
				
			||||||
breadcrumbs = Breadcrumbs()
 | 
					 | 
				
			||||||
db = SQLAlchemy()
 | 
					db = SQLAlchemy()
 | 
				
			||||||
docker_client = DockerClient()
 | 
					docker_client = DockerClient()
 | 
				
			||||||
hashids = Hashids()
 | 
					hashids = Hashids()
 | 
				
			||||||
@@ -33,6 +31,9 @@ scheduler = APScheduler()
 | 
				
			|||||||
socketio = SocketIO()
 | 
					socketio = SocketIO()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: Create export for lemmatized corpora
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_app(config: Config = Config) -> Flask:
 | 
					def create_app(config: Config = Config) -> Flask:
 | 
				
			||||||
    ''' Creates an initialized Flask (WSGI Application) object. '''
 | 
					    ''' Creates an initialized Flask (WSGI Application) object. '''
 | 
				
			||||||
    app = Flask(__name__)
 | 
					    app = Flask(__name__)
 | 
				
			||||||
@@ -46,7 +47,6 @@ def create_app(config: Config = Config) -> Flask:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    apifairy.init_app(app)
 | 
					    apifairy.init_app(app)
 | 
				
			||||||
    assets.init_app(app)
 | 
					    assets.init_app(app)
 | 
				
			||||||
    breadcrumbs.init_app(app)
 | 
					 | 
				
			||||||
    db.init_app(app)
 | 
					    db.init_app(app)
 | 
				
			||||||
    hashids.init_app(app)
 | 
					    hashids.init_app(app)
 | 
				
			||||||
    login.init_app(app)
 | 
					    login.init_app(app)
 | 
				
			||||||
@@ -61,23 +61,19 @@ def create_app(config: Config = Config) -> Flask:
 | 
				
			|||||||
    register_event_listeners()
 | 
					    register_event_listeners()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .admin import bp as admin_blueprint
 | 
					    from .admin import bp as admin_blueprint
 | 
				
			||||||
    default_breadcrumb_root(admin_blueprint, '.admin')
 | 
					 | 
				
			||||||
    app.register_blueprint(admin_blueprint, url_prefix='/admin')
 | 
					    app.register_blueprint(admin_blueprint, url_prefix='/admin')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .api import bp as api_blueprint
 | 
					    from .api import bp as api_blueprint
 | 
				
			||||||
    app.register_blueprint(api_blueprint, url_prefix='/api')
 | 
					    app.register_blueprint(api_blueprint, url_prefix='/api')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .auth import bp as auth_blueprint
 | 
					    from .auth import bp as auth_blueprint
 | 
				
			||||||
    default_breadcrumb_root(auth_blueprint, '.')
 | 
					 | 
				
			||||||
    app.register_blueprint(auth_blueprint)
 | 
					    app.register_blueprint(auth_blueprint)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .contributions import bp as contributions_blueprint
 | 
					    from .contributions import bp as contributions_blueprint
 | 
				
			||||||
    default_breadcrumb_root(contributions_blueprint, '.contributions')
 | 
					 | 
				
			||||||
    app.register_blueprint(contributions_blueprint, url_prefix='/contributions')
 | 
					    app.register_blueprint(contributions_blueprint, url_prefix='/contributions')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .corpora import bp as corpora_blueprint
 | 
					    from .corpora import bp as corpora_blueprint
 | 
				
			||||||
    from .corpora.cqi_over_sio import CQiNamespace
 | 
					    from .corpora.cqi_over_sio import CQiNamespace
 | 
				
			||||||
    default_breadcrumb_root(corpora_blueprint, '.corpora')
 | 
					 | 
				
			||||||
    app.register_blueprint(corpora_blueprint, cli_group='corpus', url_prefix='/corpora')
 | 
					    app.register_blueprint(corpora_blueprint, cli_group='corpus', url_prefix='/corpora')
 | 
				
			||||||
    socketio.on_namespace(CQiNamespace('/cqi_over_sio'))
 | 
					    socketio.on_namespace(CQiNamespace('/cqi_over_sio'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,23 +81,18 @@ def create_app(config: Config = Config) -> Flask:
 | 
				
			|||||||
    app.register_blueprint(errors_bp)
 | 
					    app.register_blueprint(errors_bp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .jobs import bp as jobs_blueprint
 | 
					    from .jobs import bp as jobs_blueprint
 | 
				
			||||||
    default_breadcrumb_root(jobs_blueprint, '.jobs')
 | 
					 | 
				
			||||||
    app.register_blueprint(jobs_blueprint, url_prefix='/jobs')
 | 
					    app.register_blueprint(jobs_blueprint, url_prefix='/jobs')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .main import bp as main_blueprint
 | 
					    from .main import bp as main_blueprint
 | 
				
			||||||
    default_breadcrumb_root(main_blueprint, '.')
 | 
					 | 
				
			||||||
    app.register_blueprint(main_blueprint, cli_group=None)
 | 
					    app.register_blueprint(main_blueprint, cli_group=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .services import bp as services_blueprint
 | 
					    from .services import bp as services_blueprint
 | 
				
			||||||
    default_breadcrumb_root(services_blueprint, '.services')
 | 
					 | 
				
			||||||
    app.register_blueprint(services_blueprint, url_prefix='/services')
 | 
					    app.register_blueprint(services_blueprint, url_prefix='/services')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .settings import bp as settings_blueprint
 | 
					    from .settings import bp as settings_blueprint
 | 
				
			||||||
    default_breadcrumb_root(settings_blueprint, '.settings')
 | 
					 | 
				
			||||||
    app.register_blueprint(settings_blueprint, url_prefix='/settings')
 | 
					    app.register_blueprint(settings_blueprint, url_prefix='/settings')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .users import bp as users_blueprint
 | 
					    from .users import bp as users_blueprint
 | 
				
			||||||
    default_breadcrumb_root(users_blueprint, '.users')
 | 
					 | 
				
			||||||
    app.register_blueprint(users_blueprint, cli_group='user', url_prefix='/users')
 | 
					    app.register_blueprint(users_blueprint, cli_group='user', url_prefix='/users')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .workshops import bp as workshops_blueprint
 | 
					    from .workshops import bp as workshops_blueprint
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										49
									
								
								app/admin/events.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/admin/events.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					from flask_login import current_user
 | 
				
			||||||
 | 
					from flask_socketio import disconnect, Namespace
 | 
				
			||||||
 | 
					from app import db, hashids
 | 
				
			||||||
 | 
					from app.decorators import socketio_admin_required
 | 
				
			||||||
 | 
					from app.models import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AdminNamespace(Namespace):
 | 
				
			||||||
 | 
					    def on_connect(self):
 | 
				
			||||||
 | 
					        # Check if the user is authenticated and is an administrator
 | 
				
			||||||
 | 
					        if not (current_user.is_authenticated and current_user.is_administrator):
 | 
				
			||||||
 | 
					            disconnect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @socketio_admin_required
 | 
				
			||||||
 | 
					    def on_set_user_confirmed(self, user_hashid: str, confirmed_value: bool):
 | 
				
			||||||
 | 
					        # Decode the user hashid
 | 
				
			||||||
 | 
					        user_id = hashids.decode(user_hashid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Validate user_id
 | 
				
			||||||
 | 
					        if not isinstance(user_id, int):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 400,
 | 
				
			||||||
 | 
					                'body': 'user_id is invalid'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Validate confirmed_value
 | 
				
			||||||
 | 
					        if not isinstance(confirmed_value, bool):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 400,
 | 
				
			||||||
 | 
					                'body': 'confirmed_value is invalid'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Load user from database
 | 
				
			||||||
 | 
					        user = User.query.get(user_id)
 | 
				
			||||||
 | 
					        if user is None:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 404,
 | 
				
			||||||
 | 
					                'body': 'User not found'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Update user confirmed status
 | 
				
			||||||
 | 
					        user.confirmed = confirmed_value
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'code': 200,
 | 
				
			||||||
 | 
					            'body': f'User "{user.username}" is now {"confirmed" if confirmed_value else "unconfirmed"}'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
from flask import abort, request
 | 
					from flask import abort, request
 | 
				
			||||||
from app import db
 | 
					 | 
				
			||||||
from app.decorators import content_negotiation
 | 
					from app.decorators import content_negotiation
 | 
				
			||||||
 | 
					from app import db
 | 
				
			||||||
from app.models import User
 | 
					from app.models import User
 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from flask import abort, flash, redirect, render_template, url_for
 | 
					from flask import abort, flash, redirect, render_template, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from app import db, hashids
 | 
					from app import db, hashids
 | 
				
			||||||
from app.models import Avatar, Corpus, Role, User
 | 
					from app.models import Avatar, Corpus, Role, User
 | 
				
			||||||
from app.users.settings.forms import (
 | 
					from app.users.settings.forms import (
 | 
				
			||||||
@@ -11,14 +10,9 @@ from app.users.settings.forms import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
from .forms import UpdateUserForm
 | 
					from .forms import UpdateUserForm
 | 
				
			||||||
from app.users.utils import (
 | 
					 | 
				
			||||||
    user_endpoint_arguments_constructor as user_eac,
 | 
					 | 
				
			||||||
    user_dynamic_list_constructor as user_dlc
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('')
 | 
					@bp.route('')
 | 
				
			||||||
@register_breadcrumb(bp, '.', '<i class="material-icons left">admin_panel_settings</i>Administration')
 | 
					 | 
				
			||||||
def admin():
 | 
					def admin():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'admin/admin.html.j2',
 | 
					        'admin/admin.html.j2',
 | 
				
			||||||
@@ -27,7 +21,6 @@ def admin():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/corpora')
 | 
					@bp.route('/corpora')
 | 
				
			||||||
@register_breadcrumb(bp, '.corpora', 'Corpora')
 | 
					 | 
				
			||||||
def corpora():
 | 
					def corpora():
 | 
				
			||||||
    corpora = Corpus.query.all()
 | 
					    corpora = Corpus.query.all()
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -38,7 +31,6 @@ def corpora():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/users')
 | 
					@bp.route('/users')
 | 
				
			||||||
@register_breadcrumb(bp, '.users', '<i class="material-icons left">group</i>Users')
 | 
					 | 
				
			||||||
def users():
 | 
					def users():
 | 
				
			||||||
    users = User.query.all()
 | 
					    users = User.query.all()
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -49,7 +41,6 @@ def users():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/users/<hashid:user_id>')
 | 
					@bp.route('/users/<hashid:user_id>')
 | 
				
			||||||
@register_breadcrumb(bp, '.users.entity', '', dynamic_list_constructor=user_dlc)
 | 
					 | 
				
			||||||
def user(user_id):
 | 
					def user(user_id):
 | 
				
			||||||
    user = User.query.get_or_404(user_id)
 | 
					    user = User.query.get_or_404(user_id)
 | 
				
			||||||
    corpora = Corpus.query.filter(Corpus.user == user).all()
 | 
					    corpora = Corpus.query.filter(Corpus.user == user).all()
 | 
				
			||||||
@@ -62,7 +53,6 @@ def user(user_id):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/users/<hashid:user_id>/settings', methods=['GET', 'POST'])
 | 
					@bp.route('/users/<hashid:user_id>/settings', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.users.entity.settings', '<i class="material-icons left">settings</i>Settings')
 | 
					 | 
				
			||||||
def user_settings(user_id):
 | 
					def user_settings(user_id):
 | 
				
			||||||
    user = User.query.get_or_404(user_id)
 | 
					    user = User.query.get_or_404(user_id)
 | 
				
			||||||
    update_account_information_form = UpdateAccountInformationForm(user)
 | 
					    update_account_information_form = UpdateAccountInformationForm(user)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@ from flask import abort, Blueprint
 | 
				
			|||||||
from werkzeug.exceptions import InternalServerError
 | 
					from werkzeug.exceptions import InternalServerError
 | 
				
			||||||
from app import db, hashids
 | 
					from app import db, hashids
 | 
				
			||||||
from app.models import Job, JobInput, JobStatus, TesseractOCRPipelineModel
 | 
					from app.models import Job, JobInput, JobStatus, TesseractOCRPipelineModel
 | 
				
			||||||
from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
 | 
					 | 
				
			||||||
from .auth import auth_error_responses, token_auth
 | 
					from .auth import auth_error_responses, token_auth
 | 
				
			||||||
 | 
					from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bp = Blueprint('jobs', __name__)
 | 
					bp = Blueprint('jobs', __name__)
 | 
				
			||||||
@@ -77,7 +77,7 @@ def delete_job(job_id):
 | 
				
			|||||||
    job = Job.query.get(job_id)
 | 
					    job = Job.query.get(job_id)
 | 
				
			||||||
    if job is None:
 | 
					    if job is None:
 | 
				
			||||||
        abort(404)
 | 
					        abort(404)
 | 
				
			||||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        job.delete()
 | 
					        job.delete()
 | 
				
			||||||
@@ -97,6 +97,6 @@ def get_job(job_id):
 | 
				
			|||||||
    job = Job.query.get(job_id)
 | 
					    job = Job.query.get(job_id)
 | 
				
			||||||
    if job is None:
 | 
					    if job is None:
 | 
				
			||||||
        abort(404)
 | 
					        abort(404)
 | 
				
			||||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    return job
 | 
					    return job
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,11 @@ from apifairy import authenticate, body, response
 | 
				
			|||||||
from apifairy.decorators import other_responses
 | 
					from apifairy.decorators import other_responses
 | 
				
			||||||
from flask import abort, Blueprint
 | 
					from flask import abort, Blueprint
 | 
				
			||||||
from werkzeug.exceptions import InternalServerError
 | 
					from werkzeug.exceptions import InternalServerError
 | 
				
			||||||
from app import db
 | 
					 | 
				
			||||||
from app.email import create_message, send
 | 
					from app.email import create_message, send
 | 
				
			||||||
 | 
					from app import db
 | 
				
			||||||
from app.models import User
 | 
					from app.models import User
 | 
				
			||||||
from .schemas import EmptySchema, UserSchema
 | 
					 | 
				
			||||||
from .auth import auth_error_responses, token_auth
 | 
					from .auth import auth_error_responses, token_auth
 | 
				
			||||||
 | 
					from .schemas import EmptySchema, UserSchema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bp = Blueprint('users', __name__)
 | 
					bp = Blueprint('users', __name__)
 | 
				
			||||||
@@ -60,7 +60,7 @@ def delete_user(user_id):
 | 
				
			|||||||
    user = User.query.get(user_id)
 | 
					    user = User.query.get(user_id)
 | 
				
			||||||
    if user is None:
 | 
					    if user is None:
 | 
				
			||||||
        abort(404)
 | 
					        abort(404)
 | 
				
			||||||
    if not (user == current_user or current_user.is_administrator()):
 | 
					    if not (user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    user.delete()
 | 
					    user.delete()
 | 
				
			||||||
    db.session.commit()
 | 
					    db.session.commit()
 | 
				
			||||||
@@ -78,7 +78,7 @@ def get_user(user_id):
 | 
				
			|||||||
    user = User.query.get(user_id)
 | 
					    user = User.query.get(user_id)
 | 
				
			||||||
    if user is None:
 | 
					    if user is None:
 | 
				
			||||||
        abort(404)
 | 
					        abort(404)
 | 
				
			||||||
    if not (user == current_user or current_user.is_administrator()):
 | 
					    if not (user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    return user
 | 
					    return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,6 +94,6 @@ def get_user_by_username(username):
 | 
				
			|||||||
    user = User.query.filter(User.username == username).first()
 | 
					    user = User.query.filter(User.username == username).first()
 | 
				
			||||||
    if user is None:
 | 
					    if user is None:
 | 
				
			||||||
        abort(404)
 | 
					        abort(404)
 | 
				
			||||||
    if not (user == current_user or current_user.is_administrator()):
 | 
					    if not (user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    return user
 | 
					    return user
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from flask import abort, flash, redirect, render_template, request, url_for
 | 
					from flask import abort, flash, redirect, render_template, request, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user, login_user, login_required, logout_user
 | 
					from flask_login import current_user, login_user, login_required, logout_user
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.email import create_message, send
 | 
					from app.email import create_message, send
 | 
				
			||||||
@@ -19,7 +18,9 @@ def before_request():
 | 
				
			|||||||
    Checks if a user is unconfirmed when visiting specific sites. Redirects to
 | 
					    Checks if a user is unconfirmed when visiting specific sites. Redirects to
 | 
				
			||||||
    unconfirmed view if user is unconfirmed.
 | 
					    unconfirmed view if user is unconfirmed.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    if current_user.is_authenticated:
 | 
					    if not current_user.is_authenticated:
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    current_user.ping()
 | 
					    current_user.ping()
 | 
				
			||||||
    db.session.commit()
 | 
					    db.session.commit()
 | 
				
			||||||
    if (not current_user.confirmed
 | 
					    if (not current_user.confirmed
 | 
				
			||||||
@@ -27,10 +28,11 @@ def before_request():
 | 
				
			|||||||
            and request.blueprint != 'auth'
 | 
					            and request.blueprint != 'auth'
 | 
				
			||||||
            and request.endpoint != 'static'):
 | 
					            and request.endpoint != 'static'):
 | 
				
			||||||
        return redirect(url_for('auth.unconfirmed'))
 | 
					        return redirect(url_for('auth.unconfirmed'))
 | 
				
			||||||
 | 
					    if not current_user.terms_of_use_accepted:
 | 
				
			||||||
 | 
					        return redirect(url_for('main.terms_of_use'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/register', methods=['GET', 'POST'])
 | 
					@bp.route('/register', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.register', 'Register')
 | 
					 | 
				
			||||||
def register():
 | 
					def register():
 | 
				
			||||||
    if current_user.is_authenticated:
 | 
					    if current_user.is_authenticated:
 | 
				
			||||||
        return redirect(url_for('main.dashboard'))
 | 
					        return redirect(url_for('main.dashboard'))
 | 
				
			||||||
@@ -67,7 +69,6 @@ def register():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/login', methods=['GET', 'POST'])
 | 
					@bp.route('/login', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.login', 'Login')
 | 
					 | 
				
			||||||
def login():
 | 
					def login():
 | 
				
			||||||
    if current_user.is_authenticated:
 | 
					    if current_user.is_authenticated:
 | 
				
			||||||
        return redirect(url_for('main.dashboard'))
 | 
					        return redirect(url_for('main.dashboard'))
 | 
				
			||||||
@@ -98,7 +99,6 @@ def logout():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/unconfirmed')
 | 
					@bp.route('/unconfirmed')
 | 
				
			||||||
@register_breadcrumb(bp, '.unconfirmed', 'Unconfirmed')
 | 
					 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def unconfirmed():
 | 
					def unconfirmed():
 | 
				
			||||||
    if current_user.confirmed:
 | 
					    if current_user.confirmed:
 | 
				
			||||||
@@ -141,7 +141,6 @@ def confirm(token):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/reset-password-request', methods=['GET', 'POST'])
 | 
					@bp.route('/reset-password-request', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.reset_password_request', 'Password Reset')
 | 
					 | 
				
			||||||
def reset_password_request():
 | 
					def reset_password_request():
 | 
				
			||||||
    if current_user.is_authenticated:
 | 
					    if current_user.is_authenticated:
 | 
				
			||||||
        return redirect(url_for('main.dashboard'))
 | 
					        return redirect(url_for('main.dashboard'))
 | 
				
			||||||
@@ -171,7 +170,6 @@ def reset_password_request():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/reset-password/<token>', methods=['GET', 'POST'])
 | 
					@bp.route('/reset-password/<token>', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.reset_password', 'Password Reset')
 | 
					 | 
				
			||||||
def reset_password(token):
 | 
					def reset_password(token):
 | 
				
			||||||
    if current_user.is_authenticated:
 | 
					    if current_user.is_authenticated:
 | 
				
			||||||
        return redirect(url_for('main.dashboard'))
 | 
					        return redirect(url_for('main.dashboard'))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
from flask import redirect, url_for
 | 
					from flask import redirect, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('')
 | 
					@bp.route('')
 | 
				
			||||||
@register_breadcrumb(bp, '.', '<i class="material-icons left">new_label</i>My Contributions')
 | 
					 | 
				
			||||||
def contributions():
 | 
					def contributions():
 | 
				
			||||||
    return redirect(url_for('main.dashboard', _anchor='contributions'))
 | 
					    return redirect(url_for('main.dashboard', _anchor='contributions'))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ from threading import Thread
 | 
				
			|||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.decorators import content_negotiation, permission_required
 | 
					from app.decorators import content_negotiation, permission_required
 | 
				
			||||||
from app.models import SpaCyNLPPipelineModel
 | 
					from app.models import SpaCyNLPPipelineModel
 | 
				
			||||||
from .. import bp
 | 
					from . import bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
 | 
					@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
 | 
				
			||||||
@@ -17,7 +17,7 @@ def delete_spacy_model(spacy_nlp_pipeline_model_id):
 | 
				
			|||||||
            db.session.commit()
 | 
					            db.session.commit()
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
					    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
				
			||||||
    if not (snpm.user == current_user or current_user.is_administrator()):
 | 
					    if not (snpm.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    thread = Thread(
 | 
					    thread = Thread(
 | 
				
			||||||
        target=_delete_spacy_model,
 | 
					        target=_delete_spacy_model,
 | 
				
			||||||
@@ -39,7 +39,7 @@ def update_spacy_nlp_pipeline_model_is_public(spacy_nlp_pipeline_model_id):
 | 
				
			|||||||
    if not isinstance(is_public, bool):
 | 
					    if not isinstance(is_public, bool):
 | 
				
			||||||
        abort(400)
 | 
					        abort(400)
 | 
				
			||||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
					    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
				
			||||||
    if not (snpm.user == current_user or current_user.is_administrator()):
 | 
					    if not (snpm.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    snpm.is_public = is_public
 | 
					    snpm.is_public = is_public
 | 
				
			||||||
    db.session.commit()
 | 
					    db.session.commit()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from flask import abort, flash, redirect, render_template, url_for
 | 
					from flask import abort, flash, redirect, render_template, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.models import SpaCyNLPPipelineModel
 | 
					from app.models import SpaCyNLPPipelineModel
 | 
				
			||||||
@@ -8,13 +7,9 @@ from .forms import (
 | 
				
			|||||||
    CreateSpaCyNLPPipelineModelForm,
 | 
					    CreateSpaCyNLPPipelineModelForm,
 | 
				
			||||||
    UpdateSpaCyNLPPipelineModelForm
 | 
					    UpdateSpaCyNLPPipelineModelForm
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .utils import (
 | 
					 | 
				
			||||||
    spacy_nlp_pipeline_model_dlc as spacy_nlp_pipeline_model_dlc
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/spacy-nlp-pipeline-models')
 | 
					@bp.route('/spacy-nlp-pipeline-models')
 | 
				
			||||||
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models', 'SpaCy NLP Pipeline Models')
 | 
					 | 
				
			||||||
def spacy_nlp_pipeline_models():
 | 
					def spacy_nlp_pipeline_models():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_models.html.j2',
 | 
					        'contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_models.html.j2',
 | 
				
			||||||
@@ -23,7 +18,6 @@ def spacy_nlp_pipeline_models():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/spacy-nlp-pipeline-models/create', methods=['GET', 'POST'])
 | 
					@bp.route('/spacy-nlp-pipeline-models/create', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.create', 'Create')
 | 
					 | 
				
			||||||
def create_spacy_nlp_pipeline_model():
 | 
					def create_spacy_nlp_pipeline_model():
 | 
				
			||||||
    form = CreateSpaCyNLPPipelineModelForm()
 | 
					    form = CreateSpaCyNLPPipelineModelForm()
 | 
				
			||||||
    if form.is_submitted():
 | 
					    if form.is_submitted():
 | 
				
			||||||
@@ -57,10 +51,9 @@ def create_spacy_nlp_pipeline_model():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST'])
 | 
					@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.entity', '', dynamic_list_constructor=spacy_nlp_pipeline_model_dlc)
 | 
					 | 
				
			||||||
def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id):
 | 
					def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id):
 | 
				
			||||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
					    snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
 | 
				
			||||||
    if not (snpm.user == current_user or current_user.is_administrator()):
 | 
					    if not (snpm.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    form = UpdateSpaCyNLPPipelineModelForm(data=snpm.to_json_serializeable())
 | 
					    form = UpdateSpaCyNLPPipelineModelForm(data=snpm.to_json_serializeable())
 | 
				
			||||||
    if form.validate_on_submit():
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
from flask import request, url_for
 | 
					 | 
				
			||||||
from app.models import SpaCyNLPPipelineModel
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def spacy_nlp_pipeline_model_dlc():
 | 
					 | 
				
			||||||
    snpm_id = request.view_args['spacy_nlp_pipeline_model_id']
 | 
					 | 
				
			||||||
    snpm = SpaCyNLPPipelineModel.query.get_or_404(snpm_id)
 | 
					 | 
				
			||||||
    return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            'text': f'{snpm.title} {snpm.version}',
 | 
					 | 
				
			||||||
            'url': url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=snpm_id)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
@@ -17,7 +17,7 @@ def delete_tesseract_model(tesseract_ocr_pipeline_model_id):
 | 
				
			|||||||
            db.session.commit()
 | 
					            db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
					    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
				
			||||||
    if not (topm.user == current_user or current_user.is_administrator()):
 | 
					    if not (topm.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    thread = Thread(
 | 
					    thread = Thread(
 | 
				
			||||||
        target=_delete_tesseract_ocr_pipeline_model,
 | 
					        target=_delete_tesseract_ocr_pipeline_model,
 | 
				
			||||||
@@ -39,7 +39,7 @@ def update_tesseract_ocr_pipeline_model_is_public(tesseract_ocr_pipeline_model_i
 | 
				
			|||||||
    if not isinstance(is_public, bool):
 | 
					    if not isinstance(is_public, bool):
 | 
				
			||||||
        abort(400)
 | 
					        abort(400)
 | 
				
			||||||
    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
					    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
				
			||||||
    if not (topm.user == current_user or current_user.is_administrator()):
 | 
					    if not (topm.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    topm.is_public = is_public
 | 
					    topm.is_public = is_public
 | 
				
			||||||
    db.session.commit()
 | 
					    db.session.commit()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from flask import abort, flash, redirect, render_template, url_for
 | 
					from flask import abort, flash, redirect, render_template, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.models import TesseractOCRPipelineModel
 | 
					from app.models import TesseractOCRPipelineModel
 | 
				
			||||||
@@ -8,13 +7,9 @@ from .forms import (
 | 
				
			|||||||
    CreateTesseractOCRPipelineModelForm,
 | 
					    CreateTesseractOCRPipelineModelForm,
 | 
				
			||||||
    UpdateTesseractOCRPipelineModelForm
 | 
					    UpdateTesseractOCRPipelineModelForm
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .utils import (
 | 
					 | 
				
			||||||
    tesseract_ocr_pipeline_model_dlc as tesseract_ocr_pipeline_model_dlc
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/tesseract-ocr-pipeline-models')
 | 
					@bp.route('/tesseract-ocr-pipeline-models')
 | 
				
			||||||
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models', 'Tesseract OCR Pipeline Models')
 | 
					 | 
				
			||||||
def tesseract_ocr_pipeline_models():
 | 
					def tesseract_ocr_pipeline_models():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_models.html.j2',
 | 
					        'contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_models.html.j2',
 | 
				
			||||||
@@ -23,7 +18,6 @@ def tesseract_ocr_pipeline_models():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/tesseract-ocr-pipeline-models/create', methods=['GET', 'POST'])
 | 
					@bp.route('/tesseract-ocr-pipeline-models/create', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.create', 'Create')
 | 
					 | 
				
			||||||
def create_tesseract_ocr_pipeline_model():
 | 
					def create_tesseract_ocr_pipeline_model():
 | 
				
			||||||
    form = CreateTesseractOCRPipelineModelForm()
 | 
					    form = CreateTesseractOCRPipelineModelForm()
 | 
				
			||||||
    if form.is_submitted():
 | 
					    if form.is_submitted():
 | 
				
			||||||
@@ -56,10 +50,9 @@ def create_tesseract_ocr_pipeline_model():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST'])
 | 
					@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.entity', '', dynamic_list_constructor=tesseract_ocr_pipeline_model_dlc)
 | 
					 | 
				
			||||||
def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
 | 
					def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
 | 
				
			||||||
    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
					    topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
 | 
				
			||||||
    if not (topm.user == current_user or current_user.is_administrator()):
 | 
					    if not (topm.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    form = UpdateTesseractOCRPipelineModelForm(data=topm.to_json_serializeable())
 | 
					    form = UpdateTesseractOCRPipelineModelForm(data=topm.to_json_serializeable())
 | 
				
			||||||
    if form.validate_on_submit():
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
from flask import request, url_for
 | 
					 | 
				
			||||||
from app.models import TesseractOCRPipelineModel
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def tesseract_ocr_pipeline_model_dlc():
 | 
					 | 
				
			||||||
    topm_id = request.view_args['tesseract_ocr_pipeline_model_id']
 | 
					 | 
				
			||||||
    topm = TesseractOCRPipelineModel.query.get_or_404(topm_id)
 | 
					 | 
				
			||||||
    return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            'text': f'{topm.title} {topm.version}',
 | 
					 | 
				
			||||||
            'url': url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=topm_id)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
from flask import current_app
 | 
					 | 
				
			||||||
from app import db
 | 
					 | 
				
			||||||
from app.models import User, Corpus, CorpusFile
 | 
					 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from flask import current_app
 | 
				
			||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
from typing import Dict, List
 | 
					from typing import Dict, List
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
 | 
					from app import db
 | 
				
			||||||
 | 
					from app.models import User, Corpus, CorpusFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SandpaperConverter:
 | 
					class SandpaperConverter:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,7 +99,7 @@ class CQiNamespace(Namespace):
 | 
				
			|||||||
            return {'code': 404, 'msg': 'Not Found'}
 | 
					            return {'code': 404, 'msg': 'Not Found'}
 | 
				
			||||||
        if not (db_corpus.user == current_user
 | 
					        if not (db_corpus.user == current_user
 | 
				
			||||||
                or current_user.is_following_corpus(db_corpus)
 | 
					                or current_user.is_following_corpus(db_corpus)
 | 
				
			||||||
                or current_user.is_administrator()):
 | 
					                or current_user.is_administrator):
 | 
				
			||||||
            return {'code': 403, 'msg': 'Forbidden'}
 | 
					            return {'code': 403, 'msg': 'Forbidden'}
 | 
				
			||||||
        if db_corpus.status not in [
 | 
					        if db_corpus.status not in [
 | 
				
			||||||
            CorpusStatus.BUILT,
 | 
					            CorpusStatus.BUILT,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ def corpus_follower_permission_required(*permissions):
 | 
				
			|||||||
        def decorated_function(*args, **kwargs):
 | 
					        def decorated_function(*args, **kwargs):
 | 
				
			||||||
            corpus_id = kwargs.get('corpus_id')
 | 
					            corpus_id = kwargs.get('corpus_id')
 | 
				
			||||||
            corpus = Corpus.query.get_or_404(corpus_id)
 | 
					            corpus = Corpus.query.get_or_404(corpus_id)
 | 
				
			||||||
            if not (corpus.user == current_user or current_user.is_administrator()):
 | 
					            if not (corpus.user == current_user or current_user.is_administrator):
 | 
				
			||||||
                cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
 | 
					                cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
 | 
				
			||||||
                if cfa is None:
 | 
					                if cfa is None:
 | 
				
			||||||
                    abort(403)
 | 
					                    abort(403)
 | 
				
			||||||
@@ -26,7 +26,7 @@ def corpus_owner_or_admin_required(f):
 | 
				
			|||||||
    def decorated_function(*args, **kwargs):
 | 
					    def decorated_function(*args, **kwargs):
 | 
				
			||||||
        corpus_id = kwargs.get('corpus_id')
 | 
					        corpus_id = kwargs.get('corpus_id')
 | 
				
			||||||
        corpus = Corpus.query.get_or_404(corpus_id)
 | 
					        corpus = Corpus.query.get_or_404(corpus_id)
 | 
				
			||||||
        if not (corpus.user == current_user or current_user.is_administrator()):
 | 
					        if not (corpus.user == current_user or current_user.is_administrator):
 | 
				
			||||||
            abort(403)
 | 
					            abort(403)
 | 
				
			||||||
        return f(*args, **kwargs)
 | 
					        return f(*args, **kwargs)
 | 
				
			||||||
    return decorated_function
 | 
					    return decorated_function
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ def get_corpus(corpus_hashid):
 | 
				
			|||||||
    if not (
 | 
					    if not (
 | 
				
			||||||
        corpus.is_public
 | 
					        corpus.is_public
 | 
				
			||||||
        or corpus.user == current_user
 | 
					        or corpus.user == current_user
 | 
				
			||||||
        or current_user.is_administrator()
 | 
					        or current_user.is_administrator
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
					        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
@@ -38,7 +38,7 @@ def subscribe_corpus(corpus_hashid):
 | 
				
			|||||||
    if not (
 | 
					    if not (
 | 
				
			||||||
        corpus.is_public
 | 
					        corpus.is_public
 | 
				
			||||||
        or corpus.user == current_user
 | 
					        or corpus.user == current_user
 | 
				
			||||||
        or current_user.is_administrator()
 | 
					        or current_user.is_administrator
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
					        return {'options': {'status': 403, 'statusText': 'Forbidden'}}
 | 
				
			||||||
    join_room(f'/corpora/{corpus.hashid}')
 | 
					    join_room(f'/corpora/{corpus.hashid}')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
from flask import abort, current_app
 | 
					from flask import current_app
 | 
				
			||||||
from threading import Thread
 | 
					from threading import Thread
 | 
				
			||||||
from app import db
 | 
					 | 
				
			||||||
from app.decorators import content_negotiation
 | 
					from app.decorators import content_negotiation
 | 
				
			||||||
 | 
					from app import db
 | 
				
			||||||
from app.models import CorpusFile
 | 
					from app.models import CorpusFile
 | 
				
			||||||
from ..decorators import corpus_follower_permission_required
 | 
					from ..decorators import corpus_follower_permission_required
 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,24 +6,19 @@ from flask import (
 | 
				
			|||||||
    send_from_directory,
 | 
					    send_from_directory,
 | 
				
			||||||
    url_for
 | 
					    url_for
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.models import Corpus, CorpusFile, CorpusStatus
 | 
					from app.models import Corpus, CorpusFile, CorpusStatus
 | 
				
			||||||
from ..decorators import corpus_follower_permission_required
 | 
					from ..decorators import corpus_follower_permission_required
 | 
				
			||||||
from ..utils import corpus_endpoint_arguments_constructor as corpus_eac
 | 
					 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
from .forms import CreateCorpusFileForm, UpdateCorpusFileForm
 | 
					from .forms import CreateCorpusFileForm, UpdateCorpusFileForm
 | 
				
			||||||
from .utils import corpus_file_dynamic_list_constructor as corpus_file_dlc
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:corpus_id>/files')
 | 
					@bp.route('/<hashid:corpus_id>/files')
 | 
				
			||||||
@register_breadcrumb(bp, '.entity.files', 'Files', endpoint_arguments_constructor=corpus_eac)
 | 
					 | 
				
			||||||
def corpus_files(corpus_id):
 | 
					def corpus_files(corpus_id):
 | 
				
			||||||
    return redirect(url_for('.corpus', _anchor='files', corpus_id=corpus_id))
 | 
					    return redirect(url_for('.corpus', _anchor='files', corpus_id=corpus_id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:corpus_id>/files/create', methods=['GET', 'POST'])
 | 
					@bp.route('/<hashid:corpus_id>/files/create', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.entity.files.create', 'Create', endpoint_arguments_constructor=corpus_eac)
 | 
					 | 
				
			||||||
@corpus_follower_permission_required('MANAGE_FILES')
 | 
					@corpus_follower_permission_required('MANAGE_FILES')
 | 
				
			||||||
def create_corpus_file(corpus_id):
 | 
					def create_corpus_file(corpus_id):
 | 
				
			||||||
    corpus = Corpus.query.get_or_404(corpus_id)
 | 
					    corpus = Corpus.query.get_or_404(corpus_id)
 | 
				
			||||||
@@ -65,7 +60,6 @@ def create_corpus_file(corpus_id):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:corpus_id>/files/<hashid:corpus_file_id>', methods=['GET', 'POST'])
 | 
					@bp.route('/<hashid:corpus_id>/files/<hashid:corpus_file_id>', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.entity.files.entity', '', dynamic_list_constructor=corpus_file_dlc)
 | 
					 | 
				
			||||||
@corpus_follower_permission_required('MANAGE_FILES')
 | 
					@corpus_follower_permission_required('MANAGE_FILES')
 | 
				
			||||||
def corpus_file(corpus_id, corpus_file_id):
 | 
					def corpus_file(corpus_id, corpus_file_id):
 | 
				
			||||||
    corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
 | 
					    corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
 | 
				
			||||||
@@ -94,6 +88,6 @@ def download_corpus_file(corpus_id, corpus_file_id):
 | 
				
			|||||||
        corpus_file.path.parent,
 | 
					        corpus_file.path.parent,
 | 
				
			||||||
        corpus_file.path.name,
 | 
					        corpus_file.path.name,
 | 
				
			||||||
        as_attachment=True,
 | 
					        as_attachment=True,
 | 
				
			||||||
        attachment_filename=corpus_file.filename,
 | 
					        download_name=corpus_file.filename,
 | 
				
			||||||
        mimetype=corpus_file.mimetype
 | 
					        mimetype=corpus_file.mimetype
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
from flask import request, url_for
 | 
					 | 
				
			||||||
from app.models import CorpusFile
 | 
					 | 
				
			||||||
from ..utils import corpus_endpoint_arguments_constructor as corpus_eac
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def corpus_file_dynamic_list_constructor():
 | 
					 | 
				
			||||||
    corpus_id = request.view_args['corpus_id']
 | 
					 | 
				
			||||||
    corpus_file_id = request.view_args['corpus_file_id']
 | 
					 | 
				
			||||||
    corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
 | 
					 | 
				
			||||||
    return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            'text': f'{corpus_file.author}: {corpus_file.title} ({corpus_file.publishing_year})',
 | 
					 | 
				
			||||||
            'url': url_for('.corpus_file', corpus_id=corpus_id, corpus_file_id=corpus_file_id)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
@@ -58,7 +58,7 @@ def delete_corpus_follower(corpus_id, follower_id):
 | 
				
			|||||||
        current_user.id == follower_id
 | 
					        current_user.id == follower_id
 | 
				
			||||||
        or current_user == cfa.corpus.user 
 | 
					        or current_user == cfa.corpus.user 
 | 
				
			||||||
        or CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first().role.has_permission('MANAGE_FOLLOWERS')
 | 
					        or CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first().role.has_permission('MANAGE_FOLLOWERS')
 | 
				
			||||||
        or current_user.is_administrator()):
 | 
					        or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    if current_user.id == follower_id:
 | 
					    if current_user.id == follower_id:
 | 
				
			||||||
        flash(f'You are no longer following "{cfa.corpus.title}"', 'corpus')
 | 
					        flash(f'You are no longer following "{cfa.corpus.title}"', 'corpus')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from flask import abort, flash, redirect, render_template, url_for
 | 
					from flask import abort, flash, redirect, render_template, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.models import (
 | 
					from app.models import (
 | 
				
			||||||
@@ -11,20 +10,14 @@ from app.models import (
 | 
				
			|||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
from .decorators import corpus_follower_permission_required
 | 
					from .decorators import corpus_follower_permission_required
 | 
				
			||||||
from .forms import CreateCorpusForm
 | 
					from .forms import CreateCorpusForm
 | 
				
			||||||
from .utils import (
 | 
					 | 
				
			||||||
    corpus_endpoint_arguments_constructor as corpus_eac,
 | 
					 | 
				
			||||||
    corpus_dynamic_list_constructor as corpus_dlc
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('')
 | 
					@bp.route('')
 | 
				
			||||||
@register_breadcrumb(bp, '.', '<i class="nopaque-icons left">I</i>My Corpora')
 | 
					 | 
				
			||||||
def corpora():
 | 
					def corpora():
 | 
				
			||||||
    return redirect(url_for('main.dashboard', _anchor='corpora'))
 | 
					    return redirect(url_for('main.dashboard', _anchor='corpora'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/create', methods=['GET', 'POST'])
 | 
					@bp.route('/create', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.create', 'Create')
 | 
					 | 
				
			||||||
def create_corpus():
 | 
					def create_corpus():
 | 
				
			||||||
    form = CreateCorpusForm()
 | 
					    form = CreateCorpusForm()
 | 
				
			||||||
    if form.validate_on_submit():
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
@@ -47,7 +40,6 @@ def create_corpus():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:corpus_id>')
 | 
					@bp.route('/<hashid:corpus_id>')
 | 
				
			||||||
@register_breadcrumb(bp, '.entity', '', dynamic_list_constructor=corpus_dlc)
 | 
					 | 
				
			||||||
def corpus(corpus_id):
 | 
					def corpus(corpus_id):
 | 
				
			||||||
    corpus = Corpus.query.get_or_404(corpus_id)
 | 
					    corpus = Corpus.query.get_or_404(corpus_id)
 | 
				
			||||||
    cfrs = CorpusFollowerRole.query.all()
 | 
					    cfrs = CorpusFollowerRole.query.all()
 | 
				
			||||||
@@ -55,13 +47,13 @@ def corpus(corpus_id):
 | 
				
			|||||||
    users = User.query.filter(User.is_public == True, User.id != current_user.id, User.id != corpus.user.id, User.role_id < 4).all()
 | 
					    users = User.query.filter(User.is_public == True, User.id != current_user.id, User.id != corpus.user.id, User.role_id < 4).all()
 | 
				
			||||||
    cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
 | 
					    cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
 | 
				
			||||||
    if cfa is None:
 | 
					    if cfa is None:
 | 
				
			||||||
        if corpus.user == current_user or current_user.is_administrator():
 | 
					        if corpus.user == current_user or current_user.is_administrator:
 | 
				
			||||||
            cfr = CorpusFollowerRole.query.filter_by(name='Administrator').first()
 | 
					            cfr = CorpusFollowerRole.query.filter_by(name='Administrator').first()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            cfr = CorpusFollowerRole.query.filter_by(name='Anonymous').first()
 | 
					            cfr = CorpusFollowerRole.query.filter_by(name='Anonymous').first()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        cfr = cfa.role
 | 
					        cfr = cfa.role
 | 
				
			||||||
    if corpus.user == current_user or current_user.is_administrator():
 | 
					    if corpus.user == current_user or current_user.is_administrator:
 | 
				
			||||||
        return render_template(
 | 
					        return render_template(
 | 
				
			||||||
            'corpora/corpus.html.j2',
 | 
					            'corpora/corpus.html.j2',
 | 
				
			||||||
            title=corpus.title,
 | 
					            title=corpus.title,
 | 
				
			||||||
@@ -87,7 +79,6 @@ def corpus(corpus_id):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:corpus_id>/analysis')
 | 
					@bp.route('/<hashid:corpus_id>/analysis')
 | 
				
			||||||
@corpus_follower_permission_required('VIEW')
 | 
					@corpus_follower_permission_required('VIEW')
 | 
				
			||||||
@register_breadcrumb(bp, '.entity.analysis', 'Analysis', endpoint_arguments_constructor=corpus_eac)
 | 
					 | 
				
			||||||
def analysis(corpus_id):
 | 
					def analysis(corpus_id):
 | 
				
			||||||
    corpus = Corpus.query.get_or_404(corpus_id)
 | 
					    corpus = Corpus.query.get_or_404(corpus_id)
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -108,13 +99,11 @@ def follow_corpus(corpus_id, token):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/import', methods=['GET', 'POST'])
 | 
					@bp.route('/import', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.import', 'Import')
 | 
					 | 
				
			||||||
def import_corpus():
 | 
					def import_corpus():
 | 
				
			||||||
    abort(503)
 | 
					    abort(503)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:corpus_id>/export')
 | 
					@bp.route('/<hashid:corpus_id>/export')
 | 
				
			||||||
@corpus_follower_permission_required('VIEW')
 | 
					@corpus_follower_permission_required('VIEW')
 | 
				
			||||||
@register_breadcrumb(bp, '.entity.export', 'Export', endpoint_arguments_constructor=corpus_eac)
 | 
					 | 
				
			||||||
def export_corpus(corpus_id):
 | 
					def export_corpus(corpus_id):
 | 
				
			||||||
    abort(503)
 | 
					    abort(503)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +0,0 @@
 | 
				
			|||||||
from flask import request, url_for
 | 
					 | 
				
			||||||
from app.models import Corpus
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def corpus_endpoint_arguments_constructor():
 | 
					 | 
				
			||||||
    return {'corpus_id': request.view_args['corpus_id']}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def corpus_dynamic_list_constructor():
 | 
					 | 
				
			||||||
    corpus_id = request.view_args['corpus_id']
 | 
					 | 
				
			||||||
    corpus = Corpus.query.get_or_404(corpus_id)
 | 
					 | 
				
			||||||
    return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            'text': f'<i class="material-icons left">book</i>{corpus.title}',
 | 
					 | 
				
			||||||
            'url': url_for('.corpus', corpus_id=corpus_id)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
from flask import abort, current_app, request
 | 
					from flask import abort, request
 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
from functools import wraps
 | 
					from functools import wraps
 | 
				
			||||||
from threading import Thread
 | 
					 | 
				
			||||||
from typing import List, Union
 | 
					from typing import List, Union
 | 
				
			||||||
from werkzeug.exceptions import NotAcceptable
 | 
					from werkzeug.exceptions import NotAcceptable
 | 
				
			||||||
from app.models import Permission
 | 
					from app.models import Permission
 | 
				
			||||||
@@ -24,22 +23,21 @@ def admin_required(f):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def socketio_login_required(f):
 | 
					def socketio_login_required(f):
 | 
				
			||||||
    @wraps(f)
 | 
					    @wraps(f)
 | 
				
			||||||
    def decorated_function(*args, **kwargs):
 | 
					    def wrapper(*args, **kwargs):
 | 
				
			||||||
        if current_user.is_authenticated:
 | 
					        if current_user.is_authenticated:
 | 
				
			||||||
            return f(*args, **kwargs)
 | 
					            return f(*args, **kwargs)
 | 
				
			||||||
        else:
 | 
					        return {'code': 401, 'body': 'Unauthorized'}
 | 
				
			||||||
            return {'code': 401, 'msg': 'Unauthorized'}
 | 
					    return wrapper
 | 
				
			||||||
    return decorated_function
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def socketio_permission_required(permission):
 | 
					def socketio_permission_required(permission):
 | 
				
			||||||
    def decorator(f):
 | 
					    def decorator(f):
 | 
				
			||||||
        @wraps(f)
 | 
					        @wraps(f)
 | 
				
			||||||
        def decorated_function(*args, **kwargs):
 | 
					        def wrapper(*args, **kwargs):
 | 
				
			||||||
            if not current_user.can(permission):
 | 
					            if not current_user.can(permission):
 | 
				
			||||||
                return {'code': 403, 'msg': 'Forbidden'}
 | 
					                return {'code': 403, 'body': 'Forbidden'}
 | 
				
			||||||
            return f(*args, **kwargs)
 | 
					            return f(*args, **kwargs)
 | 
				
			||||||
        return decorated_function
 | 
					        return wrapper
 | 
				
			||||||
    return decorator
 | 
					    return decorator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,24 +45,6 @@ def socketio_admin_required(f):
 | 
				
			|||||||
    return socketio_permission_required(Permission.ADMINISTRATE)(f)
 | 
					    return socketio_permission_required(Permission.ADMINISTRATE)(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def background(f):
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    ' This decorator executes a function in a Thread.
 | 
					 | 
				
			||||||
    ' Decorated functions need to be executed within a code block where an
 | 
					 | 
				
			||||||
    ' app context exists.
 | 
					 | 
				
			||||||
    '
 | 
					 | 
				
			||||||
    ' NOTE: An app object is passed as a keyword argument to the decorated
 | 
					 | 
				
			||||||
    '       function.
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    @wraps(f)
 | 
					 | 
				
			||||||
    def wrapped(*args, **kwargs):
 | 
					 | 
				
			||||||
        kwargs['app'] = current_app._get_current_object()
 | 
					 | 
				
			||||||
        thread = Thread(target=f, args=args, kwargs=kwargs)
 | 
					 | 
				
			||||||
        thread.start()
 | 
					 | 
				
			||||||
        return thread
 | 
					 | 
				
			||||||
    return wrapped
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def content_negotiation(
 | 
					def content_negotiation(
 | 
				
			||||||
    produces: Union[str, List[str], None] = None,
 | 
					    produces: Union[str, List[str], None] = None,
 | 
				
			||||||
    consumes: Union[str, List[str], None] = None
 | 
					    consumes: Union[str, List[str], None] = None
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
from .container_column import ContainerColumn
 | 
					 | 
				
			||||||
from .int_enum_column import IntEnumColumn
 | 
					 | 
				
			||||||
@@ -1,21 +0,0 @@
 | 
				
			|||||||
import json
 | 
					 | 
				
			||||||
from app import db
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ContainerColumn(db.TypeDecorator):
 | 
					 | 
				
			||||||
    impl = db.String
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, container_type, *args, **kwargs):
 | 
					 | 
				
			||||||
        super().__init__(*args, **kwargs)
 | 
					 | 
				
			||||||
        self.container_type = container_type
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def process_bind_param(self, value, dialect):
 | 
					 | 
				
			||||||
        if isinstance(value, self.container_type):
 | 
					 | 
				
			||||||
            return json.dumps(value)
 | 
					 | 
				
			||||||
        elif isinstance(value, str) and isinstance(json.loads(value), self.container_type):
 | 
					 | 
				
			||||||
            return value
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return TypeError()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def process_result_value(self, value, dialect):
 | 
					 | 
				
			||||||
        return json.loads(value)
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								app/extensions/sqlalchemy_extras/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/extensions/sqlalchemy_extras/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					from .types import ContainerColumn
 | 
				
			||||||
 | 
					from .types import IntEnumColumn
 | 
				
			||||||
@@ -1,6 +1,26 @@
 | 
				
			|||||||
 | 
					import json
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ContainerColumn(db.TypeDecorator):
 | 
				
			||||||
 | 
					    impl = db.String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, container_type, *args, **kwargs):
 | 
				
			||||||
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					        self.container_type = container_type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_bind_param(self, value, dialect):
 | 
				
			||||||
 | 
					        if isinstance(value, self.container_type):
 | 
				
			||||||
 | 
					            return json.dumps(value)
 | 
				
			||||||
 | 
					        elif isinstance(value, str) and isinstance(json.loads(value), self.container_type):
 | 
				
			||||||
 | 
					            return value
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return TypeError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_result_value(self, value, dialect):
 | 
				
			||||||
 | 
					        return json.loads(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IntEnumColumn(db.TypeDecorator):
 | 
					class IntEnumColumn(db.TypeDecorator):
 | 
				
			||||||
    impl = db.Integer
 | 
					    impl = db.Integer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										138
									
								
								app/jobs/events.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								app/jobs/events.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
				
			|||||||
 | 
					from flask import current_app
 | 
				
			||||||
 | 
					from flask_login import current_user
 | 
				
			||||||
 | 
					from flask_socketio import Namespace
 | 
				
			||||||
 | 
					from app import db, hashids, socketio
 | 
				
			||||||
 | 
					from app.extensions.flask_socketio import admin_required, login_required
 | 
				
			||||||
 | 
					from app.models import Job, JobStatus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class JobsNamespace(Namespace):
 | 
				
			||||||
 | 
					    @login_required
 | 
				
			||||||
 | 
					    def on_delete(self, job_hashid: str):
 | 
				
			||||||
 | 
					        # Decode the job hashid
 | 
				
			||||||
 | 
					        job_id = hashids.decode(job_hashid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Validate job_id
 | 
				
			||||||
 | 
					        if not isinstance(job_id, int):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 400,
 | 
				
			||||||
 | 
					                'body': 'job_id is invalid'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Load job from database
 | 
				
			||||||
 | 
					        job = Job.query.get(job_id)
 | 
				
			||||||
 | 
					        if job is None:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 404,
 | 
				
			||||||
 | 
					                'body': 'Job not found'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check if the current user is allowed to delete the job
 | 
				
			||||||
 | 
					        if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 403,
 | 
				
			||||||
 | 
					                'body': 'Forbidden'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO: This should be a method in the Job model
 | 
				
			||||||
 | 
					        def _delete_job(app, job_id):
 | 
				
			||||||
 | 
					            with app.app_context():
 | 
				
			||||||
 | 
					                job = Job.query.get(job_id)
 | 
				
			||||||
 | 
					                job.delete()
 | 
				
			||||||
 | 
					                db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Delete the job in a background task
 | 
				
			||||||
 | 
					        socketio.start_background_task(
 | 
				
			||||||
 | 
					            target=_delete_job,
 | 
				
			||||||
 | 
					            app=current_app._get_current_object(),
 | 
				
			||||||
 | 
					            job_id=job_id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'code': 202,
 | 
				
			||||||
 | 
					            'body': f'Job "{job.title}" marked for deletion'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @admin_required
 | 
				
			||||||
 | 
					    def on_get_log(self, job_hashid: str):
 | 
				
			||||||
 | 
					        # Decode the job hashid
 | 
				
			||||||
 | 
					        job_id = hashids.decode(job_hashid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Validate job_id
 | 
				
			||||||
 | 
					        if not isinstance(job_id, int):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 400,
 | 
				
			||||||
 | 
					                'body': 'job_id is invalid'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Load job from database
 | 
				
			||||||
 | 
					        job = Job.query.get(job_id)
 | 
				
			||||||
 | 
					        if job is None:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 404,
 | 
				
			||||||
 | 
					                'body': 'Job not found'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check if the job is already processed
 | 
				
			||||||
 | 
					        if job.status not in [JobStatus.COMPLETED, JobStatus.FAILED]:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 409,
 | 
				
			||||||
 | 
					                'body': 'Job is not done processing'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Read the log file
 | 
				
			||||||
 | 
					        with open(job.path / 'pipeline_data' / 'logs' / 'pyflow_log.txt') as log_file:
 | 
				
			||||||
 | 
					            job_log = log_file.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'code': 200,
 | 
				
			||||||
 | 
					            'body': job_log
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @login_required
 | 
				
			||||||
 | 
					    def on_restart(self, job_hashid: str):
 | 
				
			||||||
 | 
					        # Decode the job hashid
 | 
				
			||||||
 | 
					        job_id = hashids.decode(job_hashid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Validate job_id
 | 
				
			||||||
 | 
					        if not isinstance(job_id, int):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 400,
 | 
				
			||||||
 | 
					                'body': 'job_id is invalid'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Load job from database
 | 
				
			||||||
 | 
					        job = Job.query.get(job_id)
 | 
				
			||||||
 | 
					        if job is None:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 404,
 | 
				
			||||||
 | 
					                'body': 'Job not found'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check if the current user is allowed to restart the job
 | 
				
			||||||
 | 
					        if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'code': 403,
 | 
				
			||||||
 | 
					                'body': 'Forbidden'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO: This should be a method in the Job model
 | 
				
			||||||
 | 
					        def _restart_job(app, job_id):
 | 
				
			||||||
 | 
					            with app.app_context():
 | 
				
			||||||
 | 
					                job = Job.query.get(job_id)
 | 
				
			||||||
 | 
					                job.restart()
 | 
				
			||||||
 | 
					                db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Restart the job in a background task
 | 
				
			||||||
 | 
					        socketio.start_background_task(
 | 
				
			||||||
 | 
					            target=_restart_job,
 | 
				
			||||||
 | 
					            app=current_app._get_current_object(),
 | 
				
			||||||
 | 
					            job_id=job_id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'code': 202,
 | 
				
			||||||
 | 
					            'body': f'Job "{job.title}" restarted'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
@@ -17,7 +17,7 @@ def delete_job(job_id):
 | 
				
			|||||||
            db.session.commit()
 | 
					            db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    job = Job.query.get_or_404(job_id)
 | 
					    job = Job.query.get_or_404(job_id)
 | 
				
			||||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    thread = Thread(
 | 
					    thread = Thread(
 | 
				
			||||||
        target=_delete_job,
 | 
					        target=_delete_job,
 | 
				
			||||||
@@ -56,7 +56,7 @@ def restart_job(job_id):
 | 
				
			|||||||
            db.session.commit()
 | 
					            db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    job = Job.query.get_or_404(job_id)
 | 
					    job = Job.query.get_or_404(job_id)
 | 
				
			||||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    if job.status == JobStatus.FAILED:
 | 
					    if job.status == JobStatus.FAILED:
 | 
				
			||||||
        response = {'errors': {'message': 'Job status is not "failed"'}}
 | 
					        response = {'errors': {'message': 'Job status is not "failed"'}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,24 +5,20 @@ from flask import (
 | 
				
			|||||||
    send_from_directory,
 | 
					    send_from_directory,
 | 
				
			||||||
    url_for
 | 
					    url_for
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
from app.models import Job, JobInput, JobResult
 | 
					from app.models import Job, JobInput, JobResult
 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
from .utils import job_dynamic_list_constructor as job_dlc
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('')
 | 
					@bp.route('')
 | 
				
			||||||
@register_breadcrumb(bp, '.', '<i class="nopaque-icons left">J</i>My Jobs')
 | 
					 | 
				
			||||||
def corpora():
 | 
					def corpora():
 | 
				
			||||||
    return redirect(url_for('main.dashboard', _anchor='jobs'))
 | 
					    return redirect(url_for('main.dashboard', _anchor='jobs'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/<hashid:job_id>')
 | 
					@bp.route('/<hashid:job_id>')
 | 
				
			||||||
@register_breadcrumb(bp, '.entity', '', dynamic_list_constructor=job_dlc)
 | 
					 | 
				
			||||||
def job(job_id):
 | 
					def job(job_id):
 | 
				
			||||||
    job = Job.query.get_or_404(job_id)
 | 
					    job = Job.query.get_or_404(job_id)
 | 
				
			||||||
    if not (job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'jobs/job.html.j2',
 | 
					        'jobs/job.html.j2',
 | 
				
			||||||
@@ -34,13 +30,13 @@ def job(job_id):
 | 
				
			|||||||
@bp.route('/<hashid:job_id>/inputs/<hashid:job_input_id>/download')
 | 
					@bp.route('/<hashid:job_id>/inputs/<hashid:job_input_id>/download')
 | 
				
			||||||
def download_job_input(job_id, job_input_id):
 | 
					def download_job_input(job_id, job_input_id):
 | 
				
			||||||
    job_input = JobInput.query.filter_by(job_id=job_id, id=job_input_id).first_or_404()
 | 
					    job_input = JobInput.query.filter_by(job_id=job_id, id=job_input_id).first_or_404()
 | 
				
			||||||
    if not (job_input.job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job_input.job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    return send_from_directory(
 | 
					    return send_from_directory(
 | 
				
			||||||
        job_input.path.parent,
 | 
					        job_input.path.parent,
 | 
				
			||||||
        job_input.path.name,
 | 
					        job_input.path.name,
 | 
				
			||||||
        as_attachment=True,
 | 
					        as_attachment=True,
 | 
				
			||||||
        attachment_filename=job_input.filename,
 | 
					        download_name=job_input.filename,
 | 
				
			||||||
        mimetype=job_input.mimetype
 | 
					        mimetype=job_input.mimetype
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,12 +44,12 @@ def download_job_input(job_id, job_input_id):
 | 
				
			|||||||
@bp.route('/<hashid:job_id>/results/<hashid:job_result_id>/download')
 | 
					@bp.route('/<hashid:job_id>/results/<hashid:job_result_id>/download')
 | 
				
			||||||
def download_job_result(job_id, job_result_id):
 | 
					def download_job_result(job_id, job_result_id):
 | 
				
			||||||
    job_result = JobResult.query.filter_by(job_id=job_id, id=job_result_id).first_or_404()
 | 
					    job_result = JobResult.query.filter_by(job_id=job_id, id=job_result_id).first_or_404()
 | 
				
			||||||
    if not (job_result.job.user == current_user or current_user.is_administrator()):
 | 
					    if not (job_result.job.user == current_user or current_user.is_administrator):
 | 
				
			||||||
        abort(403)
 | 
					        abort(403)
 | 
				
			||||||
    return send_from_directory(
 | 
					    return send_from_directory(
 | 
				
			||||||
        job_result.path.parent,
 | 
					        job_result.path.parent,
 | 
				
			||||||
        job_result.path.name,
 | 
					        job_result.path.name,
 | 
				
			||||||
        as_attachment=True,
 | 
					        as_attachment=True,
 | 
				
			||||||
        attachment_filename=job_result.filename,
 | 
					        download_name=job_result.filename,
 | 
				
			||||||
        mimetype=job_result.mimetype
 | 
					        mimetype=job_result.mimetype
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
from flask import request, url_for
 | 
					 | 
				
			||||||
from app.models import Job
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def job_dynamic_list_constructor():
 | 
					 | 
				
			||||||
    job_id = request.view_args['job_id']
 | 
					 | 
				
			||||||
    job = Job.query.get_or_404(job_id)
 | 
					 | 
				
			||||||
    return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            'text': f'<i class="nopaque-icons left service-icons" data-service="{job.service}"></i>{job.title}',
 | 
					 | 
				
			||||||
            'url': url_for('.job', job_id=job_id)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
@@ -1,14 +1,11 @@
 | 
				
			|||||||
from flask import flash, redirect, render_template, url_for
 | 
					from flask import flash, redirect, render_template, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user, login_required, login_user
 | 
					from flask_login import current_user, login_required, login_user
 | 
				
			||||||
from app.auth.forms import LoginForm
 | 
					from app.auth.forms import LoginForm
 | 
				
			||||||
from app.models import Corpus, User
 | 
					from app.models import Corpus, User
 | 
				
			||||||
from sqlalchemy import or_
 | 
					 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/', methods=['GET', 'POST'])
 | 
					@bp.route('/', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.', '<i class="material-icons">home</i>')
 | 
					 | 
				
			||||||
def index():
 | 
					def index():
 | 
				
			||||||
    form = LoginForm()
 | 
					    form = LoginForm()
 | 
				
			||||||
    if form.validate_on_submit():
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
@@ -27,7 +24,6 @@ def index():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/faq')
 | 
					@bp.route('/faq')
 | 
				
			||||||
@register_breadcrumb(bp, '.faq', 'Frequently Asked Questions')
 | 
					 | 
				
			||||||
def faq():
 | 
					def faq():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'main/faq.html.j2',
 | 
					        'main/faq.html.j2',
 | 
				
			||||||
@@ -36,7 +32,6 @@ def faq():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/dashboard')
 | 
					@bp.route('/dashboard')
 | 
				
			||||||
@register_breadcrumb(bp, '.dashboard', '<i class="material-icons left">dashboard</i>Dashboard')
 | 
					 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def dashboard():
 | 
					def dashboard():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -45,8 +40,15 @@ def dashboard():
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@bp.route('/manual')
 | 
				
			||||||
 | 
					def manual():
 | 
				
			||||||
 | 
					    return render_template(
 | 
				
			||||||
 | 
					        'main/manual.html.j2',
 | 
				
			||||||
 | 
					        title='Manual'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/news')
 | 
					@bp.route('/news')
 | 
				
			||||||
@register_breadcrumb(bp, '.news', '<i class="material-icons left">email</i>News')
 | 
					 | 
				
			||||||
def news():
 | 
					def news():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'main/news.html.j2',
 | 
					        'main/news.html.j2',
 | 
				
			||||||
@@ -55,7 +57,6 @@ def news():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/privacy_policy')
 | 
					@bp.route('/privacy_policy')
 | 
				
			||||||
@register_breadcrumb(bp, '.privacy_policy', 'Private statement (GDPR)')
 | 
					 | 
				
			||||||
def privacy_policy():
 | 
					def privacy_policy():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'main/privacy_policy.html.j2',
 | 
					        'main/privacy_policy.html.j2',
 | 
				
			||||||
@@ -64,7 +65,6 @@ def privacy_policy():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/terms_of_use')
 | 
					@bp.route('/terms_of_use')
 | 
				
			||||||
@register_breadcrumb(bp, '.terms_of_use', 'Terms of Use')
 | 
					 | 
				
			||||||
def terms_of_use():
 | 
					def terms_of_use():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'main/terms_of_use.html.j2',
 | 
					        'main/terms_of_use.html.j2',
 | 
				
			||||||
@@ -73,7 +73,6 @@ def terms_of_use():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/social-area')
 | 
					@bp.route('/social-area')
 | 
				
			||||||
@register_breadcrumb(bp, '.social_area', '<i class="material-icons left">group</i>Social Area')
 | 
					 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def social_area():
 | 
					def social_area():
 | 
				
			||||||
    print('test')
 | 
					    print('test')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					from enum import Enum
 | 
				
			||||||
 | 
					from app import db, login, mail, socketio
 | 
				
			||||||
 | 
					from app.email import create_message
 | 
				
			||||||
 | 
					from .anonymous_user import *
 | 
				
			||||||
from .avatar import *
 | 
					from .avatar import *
 | 
				
			||||||
from .corpus_file import *
 | 
					from .corpus_file import *
 | 
				
			||||||
from .corpus_follower_association import *
 | 
					from .corpus_follower_association import *
 | 
				
			||||||
@@ -11,7 +15,134 @@ from .spacy_nlp_pipeline_model import *
 | 
				
			|||||||
from .tesseract_ocr_pipeline_model import *
 | 
					from .tesseract_ocr_pipeline_model import *
 | 
				
			||||||
from .token import *
 | 
					from .token import *
 | 
				
			||||||
from .user import *
 | 
					from .user import *
 | 
				
			||||||
from app import login
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db.event.listens_for(Corpus, 'after_delete')
 | 
				
			||||||
 | 
					@db.event.listens_for(CorpusFile, 'after_delete')
 | 
				
			||||||
 | 
					@db.event.listens_for(Job, 'after_delete')
 | 
				
			||||||
 | 
					@db.event.listens_for(JobInput, 'after_delete')
 | 
				
			||||||
 | 
					@db.event.listens_for(JobResult, 'after_delete')
 | 
				
			||||||
 | 
					@db.event.listens_for(SpaCyNLPPipelineModel, 'after_delete')
 | 
				
			||||||
 | 
					@db.event.listens_for(TesseractOCRPipelineModel, 'after_delete')
 | 
				
			||||||
 | 
					def resource_after_delete(mapper, connection, resource):
 | 
				
			||||||
 | 
					    print('[START] resource_after_delete')
 | 
				
			||||||
 | 
					    jsonpatch = [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            'op': 'remove',
 | 
				
			||||||
 | 
					            'path': resource.jsonpatch_path
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    room = f'/users/{resource.user_hashid}'
 | 
				
			||||||
 | 
					    print('[EMIT] PATCH', jsonpatch)
 | 
				
			||||||
 | 
					    socketio.emit('PATCH', jsonpatch, room=room)
 | 
				
			||||||
 | 
					    print('[END] resource_after_delete')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db.event.listens_for(CorpusFollowerAssociation, 'after_delete')
 | 
				
			||||||
 | 
					def cfa_after_delete_handler(mapper, connection, cfa):
 | 
				
			||||||
 | 
					    jsonpatch_path = f'/users/{cfa.corpus.user.hashid}/corpora/{cfa.corpus.hashid}/corpus_follower_associations/{cfa.hashid}'
 | 
				
			||||||
 | 
					    jsonpatch = [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            'op': 'remove',
 | 
				
			||||||
 | 
					            'path': jsonpatch_path
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    room = f'/users/{cfa.corpus.user.hashid}'
 | 
				
			||||||
 | 
					    socketio.emit('PATCH', jsonpatch, room=room)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db.event.listens_for(Corpus, 'after_insert')
 | 
				
			||||||
 | 
					@db.event.listens_for(CorpusFile, 'after_insert')
 | 
				
			||||||
 | 
					@db.event.listens_for(Job, 'after_insert')
 | 
				
			||||||
 | 
					@db.event.listens_for(JobInput, 'after_insert')
 | 
				
			||||||
 | 
					@db.event.listens_for(JobResult, 'after_insert')
 | 
				
			||||||
 | 
					@db.event.listens_for(SpaCyNLPPipelineModel, 'after_insert')
 | 
				
			||||||
 | 
					@db.event.listens_for(TesseractOCRPipelineModel, 'after_insert')
 | 
				
			||||||
 | 
					def resource_after_insert_handler(mapper, connection, resource):
 | 
				
			||||||
 | 
					    jsonpatch_value = resource.to_json_serializeable()
 | 
				
			||||||
 | 
					    for attr in mapper.relationships:
 | 
				
			||||||
 | 
					        jsonpatch_value[attr.key] = {}
 | 
				
			||||||
 | 
					    jsonpatch = [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            'op': 'add',
 | 
				
			||||||
 | 
					            'path': resource.jsonpatch_path,
 | 
				
			||||||
 | 
					            'value': jsonpatch_value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    room = f'/users/{resource.user_hashid}'
 | 
				
			||||||
 | 
					    socketio.emit('PATCH', jsonpatch, room=room)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db.event.listens_for(CorpusFollowerAssociation, 'after_insert')
 | 
				
			||||||
 | 
					def cfa_after_insert_handler(mapper, connection, cfa):
 | 
				
			||||||
 | 
					    jsonpatch_value = cfa.to_json_serializeable()
 | 
				
			||||||
 | 
					    jsonpatch_path = f'/users/{cfa.corpus.user.hashid}/corpora/{cfa.corpus.hashid}/corpus_follower_associations/{cfa.hashid}'
 | 
				
			||||||
 | 
					    jsonpatch = [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            'op': 'add',
 | 
				
			||||||
 | 
					            'path': jsonpatch_path,
 | 
				
			||||||
 | 
					            'value': jsonpatch_value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    room = f'/users/{cfa.corpus.user.hashid}'
 | 
				
			||||||
 | 
					    socketio.emit('PATCH', jsonpatch, room=room)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db.event.listens_for(Corpus, 'after_update')
 | 
				
			||||||
 | 
					@db.event.listens_for(CorpusFile, 'after_update')
 | 
				
			||||||
 | 
					@db.event.listens_for(Job, 'after_update')
 | 
				
			||||||
 | 
					@db.event.listens_for(JobInput, 'after_update')
 | 
				
			||||||
 | 
					@db.event.listens_for(JobResult, 'after_update')
 | 
				
			||||||
 | 
					@db.event.listens_for(SpaCyNLPPipelineModel, 'after_update')
 | 
				
			||||||
 | 
					@db.event.listens_for(TesseractOCRPipelineModel, 'after_update')
 | 
				
			||||||
 | 
					def resource_after_update_handler(mapper, connection, resource):
 | 
				
			||||||
 | 
					    jsonpatch = []
 | 
				
			||||||
 | 
					    for attr in db.inspect(resource).attrs:
 | 
				
			||||||
 | 
					        if attr.key in mapper.relationships:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        if not attr.load_history().has_changes():
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        jsonpatch_path = f'{resource.jsonpatch_path}/{attr.key}'
 | 
				
			||||||
 | 
					        if isinstance(attr.value, datetime):
 | 
				
			||||||
 | 
					            jsonpatch_value = f'{attr.value.isoformat()}Z'
 | 
				
			||||||
 | 
					        elif isinstance(attr.value, Enum):
 | 
				
			||||||
 | 
					            jsonpatch_value = attr.value.name
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            jsonpatch_value = attr.value
 | 
				
			||||||
 | 
					        jsonpatch.append(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'op': 'replace',
 | 
				
			||||||
 | 
					                'path': jsonpatch_path,
 | 
				
			||||||
 | 
					                'value': jsonpatch_value
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    if jsonpatch:
 | 
				
			||||||
 | 
					        room = f'/users/{resource.user_hashid}'
 | 
				
			||||||
 | 
					        socketio.emit('PATCH', jsonpatch, room=room)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db.event.listens_for(Job, 'after_update')
 | 
				
			||||||
 | 
					def job_after_update_handler(mapper, connection, job):
 | 
				
			||||||
 | 
					    for attr in db.inspect(job).attrs:
 | 
				
			||||||
 | 
					        if attr.key != 'status':
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        if not attr.load_history().has_changes():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if job.user.setting_job_status_mail_notification_level == UserSettingJobStatusMailNotificationLevel.NONE:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if job.user.setting_job_status_mail_notification_level == UserSettingJobStatusMailNotificationLevel.END:
 | 
				
			||||||
 | 
					            if job.status not in [JobStatus.COMPLETED, JobStatus.FAILED]:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        msg = create_message(
 | 
				
			||||||
 | 
					            job.user.email,
 | 
				
			||||||
 | 
					            f'Status update for your Job "{job.title}"',
 | 
				
			||||||
 | 
					            'tasks/email/notification',
 | 
				
			||||||
 | 
					            job=job
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        mail.send(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					login.anonymous_user = AnonymousUser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@login.user_loader
 | 
					@login.user_loader
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								app/models/anonymous_user.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/models/anonymous_user.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					from flask_login import AnonymousUserMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnonymousUser(AnonymousUserMixin):
 | 
				
			||||||
 | 
					    def can(self, permissions):
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def is_administrator(self):
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
@@ -9,7 +9,7 @@ import shutil
 | 
				
			|||||||
import xml.etree.ElementTree as ET
 | 
					import xml.etree.ElementTree as ET
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.converters.vrt import normalize_vrt_file
 | 
					from app.converters.vrt import normalize_vrt_file
 | 
				
			||||||
from app.ext.flask_sqlalchemy import IntEnumColumn
 | 
					from app.extensions.sqlalchemy_extras import IntEnumColumn
 | 
				
			||||||
from .corpus_follower_association import CorpusFollowerAssociation
 | 
					from .corpus_follower_association import CorpusFollowerAssociation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ from typing import Union
 | 
				
			|||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.ext.flask_sqlalchemy import ContainerColumn, IntEnumColumn
 | 
					from app.extensions.sqlalchemy_extras import ContainerColumn, IntEnumColumn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class JobStatus(IntEnum):
 | 
					class JobStatus(IntEnum):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ from pathlib import Path
 | 
				
			|||||||
import requests
 | 
					import requests
 | 
				
			||||||
import yaml
 | 
					import yaml
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.ext.flask_sqlalchemy import ContainerColumn
 | 
					from app.extensions.sqlalchemy_extras import ContainerColumn
 | 
				
			||||||
from .file_mixin import FileMixin
 | 
					from .file_mixin import FileMixin
 | 
				
			||||||
from .user import User
 | 
					from .user import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ from pathlib import Path
 | 
				
			|||||||
import requests
 | 
					import requests
 | 
				
			||||||
import yaml
 | 
					import yaml
 | 
				
			||||||
from app import db
 | 
					from app import db
 | 
				
			||||||
from app.ext.flask_sqlalchemy import ContainerColumn
 | 
					from app.extensions.sqlalchemy_extras import ContainerColumn
 | 
				
			||||||
from .file_mixin import FileMixin
 | 
					from .file_mixin import FileMixin
 | 
				
			||||||
from .user import User
 | 
					from .user import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ import re
 | 
				
			|||||||
import secrets
 | 
					import secrets
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
from app import db, hashids
 | 
					from app import db, hashids
 | 
				
			||||||
from app.ext.flask_sqlalchemy import IntEnumColumn
 | 
					from app.extensions.sqlalchemy_extras import IntEnumColumn
 | 
				
			||||||
from .corpus import Corpus
 | 
					from .corpus import Corpus
 | 
				
			||||||
from .corpus_follower_association import CorpusFollowerAssociation
 | 
					from .corpus_follower_association import CorpusFollowerAssociation
 | 
				
			||||||
from .corpus_follower_role import CorpusFollowerRole
 | 
					from .corpus_follower_role import CorpusFollowerRole
 | 
				
			||||||
@@ -132,6 +132,10 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
				
			|||||||
    def __repr__(self):
 | 
					    def __repr__(self):
 | 
				
			||||||
        return f'<User {self.username}>'
 | 
					        return f'<User {self.username}>'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def is_administrator(self):
 | 
				
			||||||
 | 
					        return self.can(Permission.ADMINISTRATE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def jsonpatch_path(self):
 | 
					    def jsonpatch_path(self):
 | 
				
			||||||
        return f'/users/{self.hashid}'
 | 
					        return f'/users/{self.hashid}'
 | 
				
			||||||
@@ -142,7 +146,8 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @password.setter
 | 
					    @password.setter
 | 
				
			||||||
    def password(self, password):
 | 
					    def password(self, password):
 | 
				
			||||||
        self.password_hash = generate_password_hash(password)
 | 
					        #pbkdf2:sha256
 | 
				
			||||||
 | 
					        self.password_hash = generate_password_hash(password, method='pbkdf2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def path(self) -> Path:
 | 
					    def path(self) -> Path:
 | 
				
			||||||
@@ -294,9 +299,6 @@ class User(HashidMixin, UserMixin, db.Model):
 | 
				
			|||||||
            algorithm='HS256'
 | 
					            algorithm='HS256'
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def is_administrator(self):
 | 
					 | 
				
			||||||
        return self.can(Permission.ADMINISTRATE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def ping(self):
 | 
					    def ping(self):
 | 
				
			||||||
        self.last_seen = datetime.utcnow()
 | 
					        self.last_seen = datetime.utcnow()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from flask import abort, current_app, flash, Markup, redirect, render_template, request, url_for
 | 
					from flask import abort, current_app, flash, redirect, render_template, request, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
from app import db, hashids
 | 
					from app import db, hashids
 | 
				
			||||||
@@ -20,13 +19,11 @@ from .forms import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/services')
 | 
					@bp.route('/services')
 | 
				
			||||||
@register_breadcrumb(bp, '.', 'Services')
 | 
					 | 
				
			||||||
def services():
 | 
					def services():
 | 
				
			||||||
    return redirect(url_for('main.dashboard'))
 | 
					    return redirect(url_for('main.dashboard'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/file-setup-pipeline', methods=['GET', 'POST'])
 | 
					@bp.route('/file-setup-pipeline', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.file_setup_pipeline', '<i class="nopaque-icons service-icons left" data-service="file-setup-pipeline"></i>File Setup')
 | 
					 | 
				
			||||||
def file_setup_pipeline():
 | 
					def file_setup_pipeline():
 | 
				
			||||||
    service = 'file-setup-pipeline'
 | 
					    service = 'file-setup-pipeline'
 | 
				
			||||||
    service_manifest = SERVICES[service]
 | 
					    service_manifest = SERVICES[service]
 | 
				
			||||||
@@ -56,7 +53,7 @@ def file_setup_pipeline():
 | 
				
			|||||||
                abort(500)
 | 
					                abort(500)
 | 
				
			||||||
        job.status = JobStatus.SUBMITTED
 | 
					        job.status = JobStatus.SUBMITTED
 | 
				
			||||||
        db.session.commit()
 | 
					        db.session.commit()
 | 
				
			||||||
        message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
 | 
					        message = f'Job "<a href="{job.url}">{job.title}</a>" created'
 | 
				
			||||||
        flash(message, 'job')
 | 
					        flash(message, 'job')
 | 
				
			||||||
        return {}, 201, {'Location': job.url}
 | 
					        return {}, 201, {'Location': job.url}
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -67,7 +64,6 @@ def file_setup_pipeline():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/tesseract-ocr-pipeline', methods=['GET', 'POST'])
 | 
					@bp.route('/tesseract-ocr-pipeline', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.tesseract_ocr_pipeline', '<i class="nopaque-icons service-icons left" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline')
 | 
					 | 
				
			||||||
def tesseract_ocr_pipeline():
 | 
					def tesseract_ocr_pipeline():
 | 
				
			||||||
    service_name = 'tesseract-ocr-pipeline'
 | 
					    service_name = 'tesseract-ocr-pipeline'
 | 
				
			||||||
    service_manifest = SERVICES[service_name]
 | 
					    service_manifest = SERVICES[service_name]
 | 
				
			||||||
@@ -100,7 +96,7 @@ def tesseract_ocr_pipeline():
 | 
				
			|||||||
            abort(500)
 | 
					            abort(500)
 | 
				
			||||||
        job.status = JobStatus.SUBMITTED
 | 
					        job.status = JobStatus.SUBMITTED
 | 
				
			||||||
        db.session.commit()
 | 
					        db.session.commit()
 | 
				
			||||||
        message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
 | 
					        message = f'Job "<a href="{job.url}">{job.title}</a>" created'
 | 
				
			||||||
        flash(message, 'job')
 | 
					        flash(message, 'job')
 | 
				
			||||||
        return {}, 201, {'Location': job.url}
 | 
					        return {}, 201, {'Location': job.url}
 | 
				
			||||||
    tesseract_ocr_pipeline_models = [
 | 
					    tesseract_ocr_pipeline_models = [
 | 
				
			||||||
@@ -118,7 +114,6 @@ def tesseract_ocr_pipeline():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/transkribus-htr-pipeline', methods=['GET', 'POST'])
 | 
					@bp.route('/transkribus-htr-pipeline', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.transkribus_htr_pipeline', '<i class="nopaque-icons service-icons left" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline')
 | 
					 | 
				
			||||||
def transkribus_htr_pipeline():
 | 
					def transkribus_htr_pipeline():
 | 
				
			||||||
    if not current_app.config.get('NOPAQUE_TRANSKRIBUS_ENABLED'):
 | 
					    if not current_app.config.get('NOPAQUE_TRANSKRIBUS_ENABLED'):
 | 
				
			||||||
        abort(404)
 | 
					        abort(404)
 | 
				
			||||||
@@ -164,7 +159,7 @@ def transkribus_htr_pipeline():
 | 
				
			|||||||
            abort(500)
 | 
					            abort(500)
 | 
				
			||||||
        job.status = JobStatus.SUBMITTED
 | 
					        job.status = JobStatus.SUBMITTED
 | 
				
			||||||
        db.session.commit()
 | 
					        db.session.commit()
 | 
				
			||||||
        message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
 | 
					        message = f'Job "<a href="{job.url}">{job.title}</a>" created'
 | 
				
			||||||
        flash(message, 'job')
 | 
					        flash(message, 'job')
 | 
				
			||||||
        return {}, 201, {'Location': job.url}
 | 
					        return {}, 201, {'Location': job.url}
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -176,7 +171,6 @@ def transkribus_htr_pipeline():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/spacy-nlp-pipeline', methods=['GET', 'POST'])
 | 
					@bp.route('/spacy-nlp-pipeline', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.spacy_nlp_pipeline', '<i class="nopaque-icons service-icons left" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline')
 | 
					 | 
				
			||||||
def spacy_nlp_pipeline():
 | 
					def spacy_nlp_pipeline():
 | 
				
			||||||
    service = 'spacy-nlp-pipeline'
 | 
					    service = 'spacy-nlp-pipeline'
 | 
				
			||||||
    service_manifest = SERVICES[service]
 | 
					    service_manifest = SERVICES[service]
 | 
				
			||||||
@@ -210,7 +204,7 @@ def spacy_nlp_pipeline():
 | 
				
			|||||||
            abort(500)
 | 
					            abort(500)
 | 
				
			||||||
        job.status = JobStatus.SUBMITTED
 | 
					        job.status = JobStatus.SUBMITTED
 | 
				
			||||||
        db.session.commit()
 | 
					        db.session.commit()
 | 
				
			||||||
        message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
 | 
					        message = f'Job "<a href="{job.url}">{job.title}</a>" created'
 | 
				
			||||||
        flash(message, 'job')
 | 
					        flash(message, 'job')
 | 
				
			||||||
        return {}, 201, {'Location': job.url}
 | 
					        return {}, 201, {'Location': job.url}
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
@@ -223,7 +217,6 @@ def spacy_nlp_pipeline():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/corpus-analysis')
 | 
					@bp.route('/corpus-analysis')
 | 
				
			||||||
@register_breadcrumb(bp, '.corpus_analysis', '<i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus Analysis')
 | 
					 | 
				
			||||||
def corpus_analysis():
 | 
					def corpus_analysis():
 | 
				
			||||||
    return render_template(
 | 
					    return render_template(
 | 
				
			||||||
        'services/corpus_analysis.html.j2',
 | 
					        'services/corpus_analysis.html.j2',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,10 @@
 | 
				
			|||||||
from flask import g, url_for
 | 
					from flask import g, url_for
 | 
				
			||||||
from flask_breadcrumbs import register_breadcrumb
 | 
					 | 
				
			||||||
from flask_login import current_user
 | 
					from flask_login import current_user
 | 
				
			||||||
from app.users.settings.routes import settings as settings_route
 | 
					from app.users.settings.routes import settings as settings_route
 | 
				
			||||||
from . import bp
 | 
					from . import bp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/settings', methods=['GET', 'POST'])
 | 
					@bp.route('/settings', methods=['GET', 'POST'])
 | 
				
			||||||
@register_breadcrumb(bp, '.', '<i class="material-icons left">settings</i>Settings')
 | 
					 | 
				
			||||||
def settings():
 | 
					def settings():
 | 
				
			||||||
    g._nopaque_redirect_location_on_post = url_for('.settings')
 | 
					    g._nopaque_redirect_location_on_post = url_for('.settings')
 | 
				
			||||||
    return settings_route(current_user.id)
 | 
					    return settings_route(current_user.id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,290 +0,0 @@
 | 
				
			|||||||
/// Map deep get
 | 
					 | 
				
			||||||
/// @author Kitty Giraudel
 | 
					 | 
				
			||||||
/// @access public
 | 
					 | 
				
			||||||
/// @param {Map} $map - Map
 | 
					 | 
				
			||||||
/// @param {Arglist} $keys - Key chain
 | 
					 | 
				
			||||||
/// @return {*} - Desired value
 | 
					 | 
				
			||||||
@function map-deep-get($map, $keys...) {
 | 
					 | 
				
			||||||
    @each $key in $keys {
 | 
					 | 
				
			||||||
        $map: map-get($map, $key);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    @return $map;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$color: (
 | 
					 | 
				
			||||||
  "baseline": (
 | 
					 | 
				
			||||||
    "primary": #00426f,
 | 
					 | 
				
			||||||
    "primary-variant": #1a5c89,
 | 
					 | 
				
			||||||
    "secondary": #00426f,
 | 
					 | 
				
			||||||
    "secondary-variant": #1a5c89,
 | 
					 | 
				
			||||||
    "background": #ffffff,
 | 
					 | 
				
			||||||
    "surface": #ffffff,
 | 
					 | 
				
			||||||
    "error": #b00020
 | 
					 | 
				
			||||||
  ),
 | 
					 | 
				
			||||||
  "social-area": (
 | 
					 | 
				
			||||||
    "base": #d6ae86,
 | 
					 | 
				
			||||||
    "darken": #C98536,
 | 
					 | 
				
			||||||
    "lighten": #EAE2DB
 | 
					 | 
				
			||||||
  ),
 | 
					 | 
				
			||||||
  "service": (
 | 
					 | 
				
			||||||
    "corpus-analysis": (
 | 
					 | 
				
			||||||
      "base": #aa9cc9,
 | 
					 | 
				
			||||||
      "darken": #6b3f89,
 | 
					 | 
				
			||||||
      "lighten": #ebe8f6
 | 
					 | 
				
			||||||
    ),
 | 
					 | 
				
			||||||
    "file-setup-pipeline": (
 | 
					 | 
				
			||||||
      "base": #d5dc95,
 | 
					 | 
				
			||||||
      "darken": #a1b300,
 | 
					 | 
				
			||||||
      "lighten": #f2f3e1
 | 
					 | 
				
			||||||
    ),
 | 
					 | 
				
			||||||
    "spacy-nlp-pipeline": (
 | 
					 | 
				
			||||||
      "base": #98acd2,
 | 
					 | 
				
			||||||
      "darken": #0064a3,
 | 
					 | 
				
			||||||
      "lighten": #e5e8f5
 | 
					 | 
				
			||||||
    ),
 | 
					 | 
				
			||||||
    "tesseract-ocr-pipeline": (
 | 
					 | 
				
			||||||
      "base": #a9d8c8,
 | 
					 | 
				
			||||||
      "darken": #00a58b,
 | 
					 | 
				
			||||||
      "lighten": #e7f4f1
 | 
					 | 
				
			||||||
    ),
 | 
					 | 
				
			||||||
    "transkribus-htr-pipeline": (
 | 
					 | 
				
			||||||
      "base": #607d8b,
 | 
					 | 
				
			||||||
      "darken": #37474f,
 | 
					 | 
				
			||||||
      "lighten": #cfd8dc
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  ),
 | 
					 | 
				
			||||||
  "status": (
 | 
					 | 
				
			||||||
    "corpus": (
 | 
					 | 
				
			||||||
      "UNPREPARED": #9e9e9e,
 | 
					 | 
				
			||||||
      "QUEUED": #2196f3,
 | 
					 | 
				
			||||||
      "BUILDING": #ffc107,
 | 
					 | 
				
			||||||
      "BUILT": #4caf50,
 | 
					 | 
				
			||||||
      "FAILED": #f44336,
 | 
					 | 
				
			||||||
      "STARTING_ANALYSIS_SESSION": #2196f3,
 | 
					 | 
				
			||||||
      "RUNNING_ANALYSIS_SESSION": #4caf50,
 | 
					 | 
				
			||||||
      "CANCELING_ANALYSIS_SESSION": #ff5722
 | 
					 | 
				
			||||||
    ),
 | 
					 | 
				
			||||||
    "job": (
 | 
					 | 
				
			||||||
      "INITIALIZING": #9e9e9e,
 | 
					 | 
				
			||||||
      "SUBMITTED": #9e9e9e,
 | 
					 | 
				
			||||||
      "QUEUED": #2196f3,
 | 
					 | 
				
			||||||
      "RUNNING": #ffc107,
 | 
					 | 
				
			||||||
      "CANCELING": #ff5722,
 | 
					 | 
				
			||||||
      "CANCELED": #ff5722,
 | 
					 | 
				
			||||||
      "COMPLETED": #4caf50,
 | 
					 | 
				
			||||||
      "FAILED": #f44336
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  ),
 | 
					 | 
				
			||||||
  "s-attr": (
 | 
					 | 
				
			||||||
    "PERSON": #a6e22d,
 | 
					 | 
				
			||||||
    "PER": #a6e22d,
 | 
					 | 
				
			||||||
    "NORP": #ef60b4,
 | 
					 | 
				
			||||||
    "FACILITY": #43c6fc,
 | 
					 | 
				
			||||||
    "ORG": #43c6fc,
 | 
					 | 
				
			||||||
    "GPE": #fd9720,
 | 
					 | 
				
			||||||
    "LOC": #fd9720,
 | 
					 | 
				
			||||||
    "PRODUCT": #a99dfb,
 | 
					 | 
				
			||||||
    "MISC": #a99dfb,
 | 
					 | 
				
			||||||
    "EVENT": #fc0,
 | 
					 | 
				
			||||||
    "WORK_OF_ART": #fc0,
 | 
					 | 
				
			||||||
    "LANGUAGE": #fc0,
 | 
					 | 
				
			||||||
    "DATE": #2fbbab,
 | 
					 | 
				
			||||||
    "TIME": #2fbbab,
 | 
					 | 
				
			||||||
    "PERCENT": #bbb,
 | 
					 | 
				
			||||||
    "MONEY": #bbb,
 | 
					 | 
				
			||||||
    "QUANTITY": #bbb,
 | 
					 | 
				
			||||||
    "ORDINAL": #bbb,
 | 
					 | 
				
			||||||
    "CARDINAL": #bbb
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@each $key, $color-code in map-get($color, "baseline") {
 | 
					 | 
				
			||||||
  .#{$key}-color {
 | 
					 | 
				
			||||||
    background-color: $color-code !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .#{$key}-color-border {
 | 
					 | 
				
			||||||
    border-color: $color-code !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .#{$key}-color-text {
 | 
					 | 
				
			||||||
    color: $color-code !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@each $key, $color-code in map-get($color, "social-area") {
 | 
					 | 
				
			||||||
  .social-area-color-#{$key} {
 | 
					 | 
				
			||||||
    background-color: $color-code !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .social-area-color-border-#{$key} {
 | 
					 | 
				
			||||||
    border-color: $color-code !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@each $service-name, $color-palette in map-get($color, "service") {
 | 
					 | 
				
			||||||
  .service-color[data-service="#{$service-name}"] {
 | 
					 | 
				
			||||||
    background-color: map-get($color-palette, "base") !important;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &.darken {
 | 
					 | 
				
			||||||
      background-color: map-get($color-palette, "darken") !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &.lighten {
 | 
					 | 
				
			||||||
      background-color: map-get($color-palette, "lighten") !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .service-color-border[data-service="#{$service-name}"] {
 | 
					 | 
				
			||||||
    border-color: map-get($color-palette, "base") !important;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &.border-darken {
 | 
					 | 
				
			||||||
      border-color: map-get($color-palette, "darken") !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &.border-lighten {
 | 
					 | 
				
			||||||
      border-color: map-get($color-palette, "lighten") !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .service-color-text[data-service="#{$service-name}"] {
 | 
					 | 
				
			||||||
    color: map-get($color-palette, "base") !important;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &.text-darken {
 | 
					 | 
				
			||||||
      color: map-get($color-palette, "darken") !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &.text-lighten {
 | 
					 | 
				
			||||||
      color: map-get($color-palette, "lighten") !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .service-scheme[data-service="#{$service-name}"] {
 | 
					 | 
				
			||||||
    background-color: map-get($color-palette, "lighten");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .btn, .btn-small, .btn-large, .btn-floating {
 | 
					 | 
				
			||||||
      background-color: map-get($color-palette, "darken");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      &:hover {
 | 
					 | 
				
			||||||
        background-color: map-get($color-palette, "base");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .pagination {
 | 
					 | 
				
			||||||
      li.active {
 | 
					 | 
				
			||||||
        background-color: map-get($color-palette, "darken");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .table-of-contents {
 | 
					 | 
				
			||||||
      a.active, a:hover {
 | 
					 | 
				
			||||||
        border-color: map-get($color-palette, "darken");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .tabs {
 | 
					 | 
				
			||||||
      .tab {
 | 
					 | 
				
			||||||
        &.disabled {
 | 
					 | 
				
			||||||
          a {
 | 
					 | 
				
			||||||
            color: inherit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            &:hover {
 | 
					 | 
				
			||||||
              color: change-color(map-get($color-palette, "darken"), $alpha: 0.15);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        a {
 | 
					 | 
				
			||||||
          color: inherit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          &:focus, &:hover, &.active {
 | 
					 | 
				
			||||||
            color: map-get($color-palette, "darken");
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          &:focus, &.active, &.active:focus {
 | 
					 | 
				
			||||||
            background-color: change-color(map-get($color-palette, "darken"), $alpha: 0.15);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      .indicator {
 | 
					 | 
				
			||||||
        background-color: map-get($color-palette, "darken");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@each $ressource-name, $color-palette in map-get($color, "status") {
 | 
					 | 
				
			||||||
  @each $key, $color-code in $color-palette {
 | 
					 | 
				
			||||||
    .#{$ressource-name}-status-color[data-status="#{$key}"] {
 | 
					 | 
				
			||||||
      background-color: $color-code !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .#{$ressource-name}-status-color-border[data-status="#{$key}"] {
 | 
					 | 
				
			||||||
      border-color: $color-code !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .#{$ressource-name}-status-color-text[data-status="#{$key}"] {
 | 
					 | 
				
			||||||
      color: $color-code !important;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@each $key, $color-code in map-get($color, "s-attr") {
 | 
					 | 
				
			||||||
  .chip.s-attr[data-s-attr-type="ent"][data-s-attr-ent-type="#{$key}"] {
 | 
					 | 
				
			||||||
    background-color: $color-code !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
main {
 | 
					 | 
				
			||||||
  .btn, .btn-small, .btn-large, .btn-floating {
 | 
					 | 
				
			||||||
    background-color: map-deep-get($color, "baseline", "secondary");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &:hover {
 | 
					 | 
				
			||||||
      background-color: map-deep-get($color, "baseline", "secondary-variant");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .pagination {
 | 
					 | 
				
			||||||
    li.active {
 | 
					 | 
				
			||||||
      background-color: map-deep-get($color, "baseline", "secondary");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .table-of-contents {
 | 
					 | 
				
			||||||
    a.active, a:hover {
 | 
					 | 
				
			||||||
      border-color: map-deep-get($color, "baseline", "secondary");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .tabs {
 | 
					 | 
				
			||||||
    .tab {
 | 
					 | 
				
			||||||
      &.disabled {
 | 
					 | 
				
			||||||
        a {
 | 
					 | 
				
			||||||
          color: inherit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          &:hover {
 | 
					 | 
				
			||||||
            color: change-color(map-deep-get($color, "baseline", "secondary"), $alpha: 0.15);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      a {
 | 
					 | 
				
			||||||
        color: inherit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        &:focus, &:hover, &.active {
 | 
					 | 
				
			||||||
          color: map-deep-get($color, "baseline", "secondary");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        &:focus, &.active, &.active:focus {
 | 
					 | 
				
			||||||
          background-color: change-color(map-deep-get($color, "baseline", "secondary"), $alpha: 0.15);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .indicator {
 | 
					 | 
				
			||||||
      background-color: map-deep-get($color, "baseline", "secondary");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
.parallax-container .parallax {
 | 
					 | 
				
			||||||
  z-index: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.autocomplete-content {
 | 
					 | 
				
			||||||
  width: 100% !important;
 | 
					 | 
				
			||||||
  left: 0 !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * The sidenav-fixed class is used which causes the sidenav to be fixed and open
 | 
					 | 
				
			||||||
 * on large screens and hides to the regular functionality on smaller screens.
 | 
					 | 
				
			||||||
 * In order to prevent the sidenav to overlap the content, the content (in our
 | 
					 | 
				
			||||||
 * case header, main and footer) gets an offset equal to the width of the
 | 
					 | 
				
			||||||
 * sidenav.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@media only screen and (min-width : 993px) {
 | 
					 | 
				
			||||||
  header, main, footer {padding-left: 300px;}
 | 
					 | 
				
			||||||
  .modal:not(.bottom-sheet) {left: 300px;}
 | 
					 | 
				
			||||||
  .navbar-fixed > nav {width: calc(100% - 300px)}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,67 +0,0 @@
 | 
				
			|||||||
/* Change navbar height bacause an extended and fixed navbar is used */
 | 
					 | 
				
			||||||
.navbar-fixed {
 | 
					 | 
				
			||||||
  height: 112px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Change placholdertext color of file uplaod fields */
 | 
					 | 
				
			||||||
::placeholder {
 | 
					 | 
				
			||||||
  color: #9e9e9e;
 | 
					 | 
				
			||||||
  opacity: 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * changes preoloader size etc. to fit visually better with the chip status
 | 
					 | 
				
			||||||
 * indicator of jobs
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
.status-spinner {
 | 
					 | 
				
			||||||
  margin-bottom: -10px;
 | 
					 | 
				
			||||||
  width: 30px !important;
 | 
					 | 
				
			||||||
  height: 30px !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#manual-modal .manual-chapter-title {
 | 
					 | 
				
			||||||
  display: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.show-if-only-child:not(:only-child) {
 | 
					 | 
				
			||||||
  display: none !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.btn-scale-x2 {
 | 
					 | 
				
			||||||
  transform: scale(2);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.btn-scale-x2 .nopaque-icons.service-icons {
 | 
					 | 
				
			||||||
  font-size: 2.5rem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Fix material icon vertical alignment when nested in various elements */
 | 
					 | 
				
			||||||
h1 .nopaque-icons, h2 .nopaque-icons, h3 .nopaque-icons, h4 .nopaque-icons, .tab .nopaque-icons, .tab .material-icons {
 | 
					 | 
				
			||||||
  line-height: inherit;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.corpus-status-text, .job-status-text {text-transform: lowercase;}
 | 
					 | 
				
			||||||
.corpus-status-text[data-status]:empty::before, .job-status-text[data-status]:empty::before {content: attr(data-status);}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.service-scheme[data-service="file-setup-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "E";}
 | 
					 | 
				
			||||||
.service-scheme[data-service="tesseract-ocr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
 | 
					 | 
				
			||||||
.service-scheme[data-service="transkribus-htr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
 | 
					 | 
				
			||||||
.service-scheme[data-service="spacy-nlp-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "G";}
 | 
					 | 
				
			||||||
.service-scheme[data-service="corpus-analysis"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "H";}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.nopaque-icons.service-icons[data-service="file-setup-pipeline"]:empty::before {content: "E";}
 | 
					 | 
				
			||||||
.nopaque-icons.service-icons[data-service="tesseract-ocr-pipeline"]:empty::before {content: "F";}
 | 
					 | 
				
			||||||
.nopaque-icons.service-icons[data-service="transkribus-htr-pipeline"]:empty::before {content: "F";}
 | 
					 | 
				
			||||||
.nopaque-icons.service-icons[data-service="spacy-nlp-pipeline"]:empty::before {content: "G";}
 | 
					 | 
				
			||||||
.nopaque-icons.service-icons[data-service="corpus-analysis"]:empty::before {content: "H";}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[draggable="true"] {cursor: move !important;}
 | 
					 | 
				
			||||||
.clickable {cursor: pointer !important;}
 | 
					 | 
				
			||||||
.chip.s-attr .chip.p-attr {background-color: inherit;}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.width-25 {width: 25%;}
 | 
					 | 
				
			||||||
.width-50 {width: 50%;}
 | 
					 | 
				
			||||||
.width-75 {width: 75%;}
 | 
					 | 
				
			||||||
.width-100 {width: 100%;}
 | 
					 | 
				
			||||||
							
								
								
									
										22
									
								
								app/static/external/JSON-Patch/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/static/external/JSON-Patch/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					(The MIT License)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2013, 2014, 2020 Joachim Wester
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining
 | 
				
			||||||
 | 
					a copy of this software and associated documentation files (the
 | 
				
			||||||
 | 
					'Software'), to deal in the Software without restriction, including
 | 
				
			||||||
 | 
					without limitation the rights to use, copy, modify, merge, publish,
 | 
				
			||||||
 | 
					distribute, sublicense, and/or sell copies of the Software, and to
 | 
				
			||||||
 | 
					permit persons to whom the Software is furnished to do so, subject to
 | 
				
			||||||
 | 
					the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be
 | 
				
			||||||
 | 
					included in all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 | 
				
			||||||
 | 
					EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
				
			||||||
 | 
					IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
				
			||||||
 | 
					CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 | 
				
			||||||
 | 
					TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 | 
				
			||||||
 | 
					SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
							
								
								
									
										1
									
								
								app/static/external/JSON-Patch/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/external/JSON-Patch/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					3.1.1
 | 
				
			||||||
							
								
								
									
										928
									
								
								app/static/external/JSON-Patch/js/fast-json-patch.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										928
									
								
								app/static/external/JSON-Patch/js/fast-json-patch.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,928 @@
 | 
				
			|||||||
 | 
					/*! fast-json-patch, version: 3.1.1 */
 | 
				
			||||||
 | 
					var jsonpatch =
 | 
				
			||||||
 | 
					/******/ (function(modules) { // webpackBootstrap
 | 
				
			||||||
 | 
					/******/ 	// The module cache
 | 
				
			||||||
 | 
					/******/ 	var installedModules = {};
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// The require function
 | 
				
			||||||
 | 
					/******/ 	function __webpack_require__(moduleId) {
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 		// Check if module is in cache
 | 
				
			||||||
 | 
					/******/ 		if(installedModules[moduleId]) {
 | 
				
			||||||
 | 
					/******/ 			return installedModules[moduleId].exports;
 | 
				
			||||||
 | 
					/******/ 		}
 | 
				
			||||||
 | 
					/******/ 		// Create a new module (and put it into the cache)
 | 
				
			||||||
 | 
					/******/ 		var module = installedModules[moduleId] = {
 | 
				
			||||||
 | 
					/******/ 			i: moduleId,
 | 
				
			||||||
 | 
					/******/ 			l: false,
 | 
				
			||||||
 | 
					/******/ 			exports: {}
 | 
				
			||||||
 | 
					/******/ 		};
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 		// Execute the module function
 | 
				
			||||||
 | 
					/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 		// Flag the module as loaded
 | 
				
			||||||
 | 
					/******/ 		module.l = true;
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 		// Return the exports of the module
 | 
				
			||||||
 | 
					/******/ 		return module.exports;
 | 
				
			||||||
 | 
					/******/ 	}
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// expose the modules object (__webpack_modules__)
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.m = modules;
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// expose the module cache
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.c = installedModules;
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// define getter function for harmony exports
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.d = function(exports, name, getter) {
 | 
				
			||||||
 | 
					/******/ 		if(!__webpack_require__.o(exports, name)) {
 | 
				
			||||||
 | 
					/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
 | 
				
			||||||
 | 
					/******/ 		}
 | 
				
			||||||
 | 
					/******/ 	};
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// define __esModule on exports
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.r = function(exports) {
 | 
				
			||||||
 | 
					/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
 | 
				
			||||||
 | 
					/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
 | 
				
			||||||
 | 
					/******/ 		}
 | 
				
			||||||
 | 
					/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
 | 
				
			||||||
 | 
					/******/ 	};
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// create a fake namespace object
 | 
				
			||||||
 | 
					/******/ 	// mode & 1: value is a module id, require it
 | 
				
			||||||
 | 
					/******/ 	// mode & 2: merge all properties of value into the ns
 | 
				
			||||||
 | 
					/******/ 	// mode & 4: return value when already ns object
 | 
				
			||||||
 | 
					/******/ 	// mode & 8|1: behave like require
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.t = function(value, mode) {
 | 
				
			||||||
 | 
					/******/ 		if(mode & 1) value = __webpack_require__(value);
 | 
				
			||||||
 | 
					/******/ 		if(mode & 8) return value;
 | 
				
			||||||
 | 
					/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
 | 
				
			||||||
 | 
					/******/ 		var ns = Object.create(null);
 | 
				
			||||||
 | 
					/******/ 		__webpack_require__.r(ns);
 | 
				
			||||||
 | 
					/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
 | 
				
			||||||
 | 
					/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
 | 
				
			||||||
 | 
					/******/ 		return ns;
 | 
				
			||||||
 | 
					/******/ 	};
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// getDefaultExport function for compatibility with non-harmony modules
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.n = function(module) {
 | 
				
			||||||
 | 
					/******/ 		var getter = module && module.__esModule ?
 | 
				
			||||||
 | 
					/******/ 			function getDefault() { return module['default']; } :
 | 
				
			||||||
 | 
					/******/ 			function getModuleExports() { return module; };
 | 
				
			||||||
 | 
					/******/ 		__webpack_require__.d(getter, 'a', getter);
 | 
				
			||||||
 | 
					/******/ 		return getter;
 | 
				
			||||||
 | 
					/******/ 	};
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// Object.prototype.hasOwnProperty.call
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// __webpack_public_path__
 | 
				
			||||||
 | 
					/******/ 	__webpack_require__.p = "";
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/
 | 
				
			||||||
 | 
					/******/ 	// Load entry module and return exports
 | 
				
			||||||
 | 
					/******/ 	return __webpack_require__(__webpack_require__.s = 2);
 | 
				
			||||||
 | 
					/******/ })
 | 
				
			||||||
 | 
					/************************************************************************/
 | 
				
			||||||
 | 
					/******/ ([
 | 
				
			||||||
 | 
					/* 0 */
 | 
				
			||||||
 | 
					/***/ (function(module, exports) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * https://github.com/Starcounter-Jack/JSON-Patch
 | 
				
			||||||
 | 
					 * (c) 2017-2022 Joachim Wester
 | 
				
			||||||
 | 
					 * MIT licensed
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var __extends = (this && this.__extends) || (function () {
 | 
				
			||||||
 | 
					    var extendStatics = function (d, b) {
 | 
				
			||||||
 | 
					        extendStatics = Object.setPrototypeOf ||
 | 
				
			||||||
 | 
					            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
 | 
				
			||||||
 | 
					            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
 | 
				
			||||||
 | 
					        return extendStatics(d, b);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return function (d, b) {
 | 
				
			||||||
 | 
					        extendStatics(d, b);
 | 
				
			||||||
 | 
					        function __() { this.constructor = d; }
 | 
				
			||||||
 | 
					        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					Object.defineProperty(exports, "__esModule", { value: true });
 | 
				
			||||||
 | 
					var _hasOwnProperty = Object.prototype.hasOwnProperty;
 | 
				
			||||||
 | 
					function hasOwnProperty(obj, key) {
 | 
				
			||||||
 | 
					    return _hasOwnProperty.call(obj, key);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.hasOwnProperty = hasOwnProperty;
 | 
				
			||||||
 | 
					function _objectKeys(obj) {
 | 
				
			||||||
 | 
					    if (Array.isArray(obj)) {
 | 
				
			||||||
 | 
					        var keys_1 = new Array(obj.length);
 | 
				
			||||||
 | 
					        for (var k = 0; k < keys_1.length; k++) {
 | 
				
			||||||
 | 
					            keys_1[k] = "" + k;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return keys_1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (Object.keys) {
 | 
				
			||||||
 | 
					        return Object.keys(obj);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var keys = [];
 | 
				
			||||||
 | 
					    for (var i in obj) {
 | 
				
			||||||
 | 
					        if (hasOwnProperty(obj, i)) {
 | 
				
			||||||
 | 
					            keys.push(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return keys;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports._objectKeys = _objectKeys;
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* Deeply clone the object.
 | 
				
			||||||
 | 
					* https://jsperf.com/deep-copy-vs-json-stringify-json-parse/25 (recursiveDeepCopy)
 | 
				
			||||||
 | 
					* @param  {any} obj value to clone
 | 
				
			||||||
 | 
					* @return {any} cloned obj
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					function _deepClone(obj) {
 | 
				
			||||||
 | 
					    switch (typeof obj) {
 | 
				
			||||||
 | 
					        case "object":
 | 
				
			||||||
 | 
					            return JSON.parse(JSON.stringify(obj)); //Faster than ES5 clone - http://jsperf.com/deep-cloning-of-objects/5
 | 
				
			||||||
 | 
					        case "undefined":
 | 
				
			||||||
 | 
					            return null; //this is how JSON.stringify behaves for array items
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return obj; //no need to clone primitives
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports._deepClone = _deepClone;
 | 
				
			||||||
 | 
					//3x faster than cached /^\d+$/.test(str)
 | 
				
			||||||
 | 
					function isInteger(str) {
 | 
				
			||||||
 | 
					    var i = 0;
 | 
				
			||||||
 | 
					    var len = str.length;
 | 
				
			||||||
 | 
					    var charCode;
 | 
				
			||||||
 | 
					    while (i < len) {
 | 
				
			||||||
 | 
					        charCode = str.charCodeAt(i);
 | 
				
			||||||
 | 
					        if (charCode >= 48 && charCode <= 57) {
 | 
				
			||||||
 | 
					            i++;
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.isInteger = isInteger;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* Escapes a json pointer path
 | 
				
			||||||
 | 
					* @param path The raw pointer
 | 
				
			||||||
 | 
					* @return the Escaped path
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					function escapePathComponent(path) {
 | 
				
			||||||
 | 
					    if (path.indexOf('/') === -1 && path.indexOf('~') === -1)
 | 
				
			||||||
 | 
					        return path;
 | 
				
			||||||
 | 
					    return path.replace(/~/g, '~0').replace(/\//g, '~1');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.escapePathComponent = escapePathComponent;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Unescapes a json pointer path
 | 
				
			||||||
 | 
					 * @param path The escaped pointer
 | 
				
			||||||
 | 
					 * @return The unescaped path
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function unescapePathComponent(path) {
 | 
				
			||||||
 | 
					    return path.replace(/~1/g, '/').replace(/~0/g, '~');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.unescapePathComponent = unescapePathComponent;
 | 
				
			||||||
 | 
					function _getPathRecursive(root, obj) {
 | 
				
			||||||
 | 
					    var found;
 | 
				
			||||||
 | 
					    for (var key in root) {
 | 
				
			||||||
 | 
					        if (hasOwnProperty(root, key)) {
 | 
				
			||||||
 | 
					            if (root[key] === obj) {
 | 
				
			||||||
 | 
					                return escapePathComponent(key) + '/';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (typeof root[key] === 'object') {
 | 
				
			||||||
 | 
					                found = _getPathRecursive(root[key], obj);
 | 
				
			||||||
 | 
					                if (found != '') {
 | 
				
			||||||
 | 
					                    return escapePathComponent(key) + '/' + found;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return '';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports._getPathRecursive = _getPathRecursive;
 | 
				
			||||||
 | 
					function getPath(root, obj) {
 | 
				
			||||||
 | 
					    if (root === obj) {
 | 
				
			||||||
 | 
					        return '/';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var path = _getPathRecursive(root, obj);
 | 
				
			||||||
 | 
					    if (path === '') {
 | 
				
			||||||
 | 
					        throw new Error("Object not found in root");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return "/" + path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.getPath = getPath;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* Recursively checks whether an object has any undefined values inside.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					function hasUndefined(obj) {
 | 
				
			||||||
 | 
					    if (obj === undefined) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (obj) {
 | 
				
			||||||
 | 
					        if (Array.isArray(obj)) {
 | 
				
			||||||
 | 
					            for (var i_1 = 0, len = obj.length; i_1 < len; i_1++) {
 | 
				
			||||||
 | 
					                if (hasUndefined(obj[i_1])) {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (typeof obj === "object") {
 | 
				
			||||||
 | 
					            var objKeys = _objectKeys(obj);
 | 
				
			||||||
 | 
					            var objKeysLength = objKeys.length;
 | 
				
			||||||
 | 
					            for (var i = 0; i < objKeysLength; i++) {
 | 
				
			||||||
 | 
					                if (hasUndefined(obj[objKeys[i]])) {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.hasUndefined = hasUndefined;
 | 
				
			||||||
 | 
					function patchErrorMessageFormatter(message, args) {
 | 
				
			||||||
 | 
					    var messageParts = [message];
 | 
				
			||||||
 | 
					    for (var key in args) {
 | 
				
			||||||
 | 
					        var value = typeof args[key] === 'object' ? JSON.stringify(args[key], null, 2) : args[key]; // pretty print
 | 
				
			||||||
 | 
					        if (typeof value !== 'undefined') {
 | 
				
			||||||
 | 
					            messageParts.push(key + ": " + value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return messageParts.join('\n');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var PatchError = /** @class */ (function (_super) {
 | 
				
			||||||
 | 
					    __extends(PatchError, _super);
 | 
				
			||||||
 | 
					    function PatchError(message, name, index, operation, tree) {
 | 
				
			||||||
 | 
					        var _newTarget = this.constructor;
 | 
				
			||||||
 | 
					        var _this = _super.call(this, patchErrorMessageFormatter(message, { name: name, index: index, operation: operation, tree: tree })) || this;
 | 
				
			||||||
 | 
					        _this.name = name;
 | 
				
			||||||
 | 
					        _this.index = index;
 | 
				
			||||||
 | 
					        _this.operation = operation;
 | 
				
			||||||
 | 
					        _this.tree = tree;
 | 
				
			||||||
 | 
					        Object.setPrototypeOf(_this, _newTarget.prototype); // restore prototype chain, see https://stackoverflow.com/a/48342359
 | 
				
			||||||
 | 
					        _this.message = patchErrorMessageFormatter(message, { name: name, index: index, operation: operation, tree: tree });
 | 
				
			||||||
 | 
					        return _this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return PatchError;
 | 
				
			||||||
 | 
					}(Error));
 | 
				
			||||||
 | 
					exports.PatchError = PatchError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***/ }),
 | 
				
			||||||
 | 
					/* 1 */
 | 
				
			||||||
 | 
					/***/ (function(module, exports, __webpack_require__) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Object.defineProperty(exports, "__esModule", { value: true });
 | 
				
			||||||
 | 
					var helpers_js_1 = __webpack_require__(0);
 | 
				
			||||||
 | 
					exports.JsonPatchError = helpers_js_1.PatchError;
 | 
				
			||||||
 | 
					exports.deepClone = helpers_js_1._deepClone;
 | 
				
			||||||
 | 
					/* We use a Javascript hash to store each
 | 
				
			||||||
 | 
					 function. Each hash entry (property) uses
 | 
				
			||||||
 | 
					 the operation identifiers specified in rfc6902.
 | 
				
			||||||
 | 
					 In this way, we can map each patch operation
 | 
				
			||||||
 | 
					 to its dedicated function in efficient way.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* The operations applicable to an object */
 | 
				
			||||||
 | 
					var objOps = {
 | 
				
			||||||
 | 
					    add: function (obj, key, document) {
 | 
				
			||||||
 | 
					        obj[key] = this.value;
 | 
				
			||||||
 | 
					        return { newDocument: document };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    remove: function (obj, key, document) {
 | 
				
			||||||
 | 
					        var removed = obj[key];
 | 
				
			||||||
 | 
					        delete obj[key];
 | 
				
			||||||
 | 
					        return { newDocument: document, removed: removed };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    replace: function (obj, key, document) {
 | 
				
			||||||
 | 
					        var removed = obj[key];
 | 
				
			||||||
 | 
					        obj[key] = this.value;
 | 
				
			||||||
 | 
					        return { newDocument: document, removed: removed };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    move: function (obj, key, document) {
 | 
				
			||||||
 | 
					        /* in case move target overwrites an existing value,
 | 
				
			||||||
 | 
					        return the removed value, this can be taxing performance-wise,
 | 
				
			||||||
 | 
					        and is potentially unneeded */
 | 
				
			||||||
 | 
					        var removed = getValueByPointer(document, this.path);
 | 
				
			||||||
 | 
					        if (removed) {
 | 
				
			||||||
 | 
					            removed = helpers_js_1._deepClone(removed);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var originalValue = applyOperation(document, { op: "remove", path: this.from }).removed;
 | 
				
			||||||
 | 
					        applyOperation(document, { op: "add", path: this.path, value: originalValue });
 | 
				
			||||||
 | 
					        return { newDocument: document, removed: removed };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    copy: function (obj, key, document) {
 | 
				
			||||||
 | 
					        var valueToCopy = getValueByPointer(document, this.from);
 | 
				
			||||||
 | 
					        // enforce copy by value so further operations don't affect source (see issue #177)
 | 
				
			||||||
 | 
					        applyOperation(document, { op: "add", path: this.path, value: helpers_js_1._deepClone(valueToCopy) });
 | 
				
			||||||
 | 
					        return { newDocument: document };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    test: function (obj, key, document) {
 | 
				
			||||||
 | 
					        return { newDocument: document, test: _areEquals(obj[key], this.value) };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    _get: function (obj, key, document) {
 | 
				
			||||||
 | 
					        this.value = obj[key];
 | 
				
			||||||
 | 
					        return { newDocument: document };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/* The operations applicable to an array. Many are the same as for the object */
 | 
				
			||||||
 | 
					var arrOps = {
 | 
				
			||||||
 | 
					    add: function (arr, i, document) {
 | 
				
			||||||
 | 
					        if (helpers_js_1.isInteger(i)) {
 | 
				
			||||||
 | 
					            arr.splice(i, 0, this.value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else { // array props
 | 
				
			||||||
 | 
					            arr[i] = this.value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // this may be needed when using '-' in an array
 | 
				
			||||||
 | 
					        return { newDocument: document, index: i };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    remove: function (arr, i, document) {
 | 
				
			||||||
 | 
					        var removedList = arr.splice(i, 1);
 | 
				
			||||||
 | 
					        return { newDocument: document, removed: removedList[0] };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    replace: function (arr, i, document) {
 | 
				
			||||||
 | 
					        var removed = arr[i];
 | 
				
			||||||
 | 
					        arr[i] = this.value;
 | 
				
			||||||
 | 
					        return { newDocument: document, removed: removed };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    move: objOps.move,
 | 
				
			||||||
 | 
					    copy: objOps.copy,
 | 
				
			||||||
 | 
					    test: objOps.test,
 | 
				
			||||||
 | 
					    _get: objOps._get
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Retrieves a value from a JSON document by a JSON pointer.
 | 
				
			||||||
 | 
					 * Returns the value.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param document The document to get the value from
 | 
				
			||||||
 | 
					 * @param pointer an escaped JSON pointer
 | 
				
			||||||
 | 
					 * @return The retrieved value
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function getValueByPointer(document, pointer) {
 | 
				
			||||||
 | 
					    if (pointer == '') {
 | 
				
			||||||
 | 
					        return document;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var getOriginalDestination = { op: "_get", path: pointer };
 | 
				
			||||||
 | 
					    applyOperation(document, getOriginalDestination);
 | 
				
			||||||
 | 
					    return getOriginalDestination.value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.getValueByPointer = getValueByPointer;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Apply a single JSON Patch Operation on a JSON document.
 | 
				
			||||||
 | 
					 * Returns the {newDocument, result} of the operation.
 | 
				
			||||||
 | 
					 * It modifies the `document` and `operation` objects - it gets the values by reference.
 | 
				
			||||||
 | 
					 * If you would like to avoid touching your values, clone them:
 | 
				
			||||||
 | 
					 * `jsonpatch.applyOperation(document, jsonpatch._deepClone(operation))`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param document The document to patch
 | 
				
			||||||
 | 
					 * @param operation The operation to apply
 | 
				
			||||||
 | 
					 * @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation.
 | 
				
			||||||
 | 
					 * @param mutateDocument Whether to mutate the original document or clone it before applying
 | 
				
			||||||
 | 
					 * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
 | 
				
			||||||
 | 
					 * @return `{newDocument, result}` after the operation
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function applyOperation(document, operation, validateOperation, mutateDocument, banPrototypeModifications, index) {
 | 
				
			||||||
 | 
					    if (validateOperation === void 0) { validateOperation = false; }
 | 
				
			||||||
 | 
					    if (mutateDocument === void 0) { mutateDocument = true; }
 | 
				
			||||||
 | 
					    if (banPrototypeModifications === void 0) { banPrototypeModifications = true; }
 | 
				
			||||||
 | 
					    if (index === void 0) { index = 0; }
 | 
				
			||||||
 | 
					    if (validateOperation) {
 | 
				
			||||||
 | 
					        if (typeof validateOperation == 'function') {
 | 
				
			||||||
 | 
					            validateOperation(operation, 0, document, operation.path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            validator(operation, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* ROOT OPERATIONS */
 | 
				
			||||||
 | 
					    if (operation.path === "") {
 | 
				
			||||||
 | 
					        var returnValue = { newDocument: document };
 | 
				
			||||||
 | 
					        if (operation.op === 'add') {
 | 
				
			||||||
 | 
					            returnValue.newDocument = operation.value;
 | 
				
			||||||
 | 
					            return returnValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === 'replace') {
 | 
				
			||||||
 | 
					            returnValue.newDocument = operation.value;
 | 
				
			||||||
 | 
					            returnValue.removed = document; //document we removed
 | 
				
			||||||
 | 
					            return returnValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === 'move' || operation.op === 'copy') { // it's a move or copy to root
 | 
				
			||||||
 | 
					            returnValue.newDocument = getValueByPointer(document, operation.from); // get the value by json-pointer in `from` field
 | 
				
			||||||
 | 
					            if (operation.op === 'move') { // report removed item
 | 
				
			||||||
 | 
					                returnValue.removed = document;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return returnValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === 'test') {
 | 
				
			||||||
 | 
					            returnValue.test = _areEquals(document, operation.value);
 | 
				
			||||||
 | 
					            if (returnValue.test === false) {
 | 
				
			||||||
 | 
					                throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            returnValue.newDocument = document;
 | 
				
			||||||
 | 
					            return returnValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === 'remove') { // a remove on root
 | 
				
			||||||
 | 
					            returnValue.removed = document;
 | 
				
			||||||
 | 
					            returnValue.newDocument = null;
 | 
				
			||||||
 | 
					            return returnValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === '_get') {
 | 
				
			||||||
 | 
					            operation.value = document;
 | 
				
			||||||
 | 
					            return returnValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else { /* bad operation */
 | 
				
			||||||
 | 
					            if (validateOperation) {
 | 
				
			||||||
 | 
					                throw new exports.JsonPatchError('Operation `op` property is not one of operations defined in RFC-6902', 'OPERATION_OP_INVALID', index, operation, document);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                return returnValue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } /* END ROOT OPERATIONS */
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        if (!mutateDocument) {
 | 
				
			||||||
 | 
					            document = helpers_js_1._deepClone(document);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var path = operation.path || "";
 | 
				
			||||||
 | 
					        var keys = path.split('/');
 | 
				
			||||||
 | 
					        var obj = document;
 | 
				
			||||||
 | 
					        var t = 1; //skip empty element - http://jsperf.com/to-shift-or-not-to-shift
 | 
				
			||||||
 | 
					        var len = keys.length;
 | 
				
			||||||
 | 
					        var existingPathFragment = undefined;
 | 
				
			||||||
 | 
					        var key = void 0;
 | 
				
			||||||
 | 
					        var validateFunction = void 0;
 | 
				
			||||||
 | 
					        if (typeof validateOperation == 'function') {
 | 
				
			||||||
 | 
					            validateFunction = validateOperation;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            validateFunction = validator;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while (true) {
 | 
				
			||||||
 | 
					            key = keys[t];
 | 
				
			||||||
 | 
					            if (key && key.indexOf('~') != -1) {
 | 
				
			||||||
 | 
					                key = helpers_js_1.unescapePathComponent(key);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (banPrototypeModifications &&
 | 
				
			||||||
 | 
					                (key == '__proto__' ||
 | 
				
			||||||
 | 
					                    (key == 'prototype' && t > 0 && keys[t - 1] == 'constructor'))) {
 | 
				
			||||||
 | 
					                throw new TypeError('JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (validateOperation) {
 | 
				
			||||||
 | 
					                if (existingPathFragment === undefined) {
 | 
				
			||||||
 | 
					                    if (obj[key] === undefined) {
 | 
				
			||||||
 | 
					                        existingPathFragment = keys.slice(0, t).join('/');
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (t == len - 1) {
 | 
				
			||||||
 | 
					                        existingPathFragment = operation.path;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (existingPathFragment !== undefined) {
 | 
				
			||||||
 | 
					                        validateFunction(operation, 0, document, existingPathFragment);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            t++;
 | 
				
			||||||
 | 
					            if (Array.isArray(obj)) {
 | 
				
			||||||
 | 
					                if (key === '-') {
 | 
				
			||||||
 | 
					                    key = obj.length;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    if (validateOperation && !helpers_js_1.isInteger(key)) {
 | 
				
			||||||
 | 
					                        throw new exports.JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index", "OPERATION_PATH_ILLEGAL_ARRAY_INDEX", index, operation, document);
 | 
				
			||||||
 | 
					                    } // only parse key when it's an integer for `arr.prop` to work
 | 
				
			||||||
 | 
					                    else if (helpers_js_1.isInteger(key)) {
 | 
				
			||||||
 | 
					                        key = ~~key;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (t >= len) {
 | 
				
			||||||
 | 
					                    if (validateOperation && operation.op === "add" && key > obj.length) {
 | 
				
			||||||
 | 
					                        throw new exports.JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array", "OPERATION_VALUE_OUT_OF_BOUNDS", index, operation, document);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    var returnValue = arrOps[operation.op].call(operation, obj, key, document); // Apply patch
 | 
				
			||||||
 | 
					                    if (returnValue.test === false) {
 | 
				
			||||||
 | 
					                        throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return returnValue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                if (t >= len) {
 | 
				
			||||||
 | 
					                    var returnValue = objOps[operation.op].call(operation, obj, key, document); // Apply patch
 | 
				
			||||||
 | 
					                    if (returnValue.test === false) {
 | 
				
			||||||
 | 
					                        throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return returnValue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            obj = obj[key];
 | 
				
			||||||
 | 
					            // If we have more keys in the path, but the next value isn't a non-null object,
 | 
				
			||||||
 | 
					            // throw an OPERATION_PATH_UNRESOLVABLE error instead of iterating again.
 | 
				
			||||||
 | 
					            if (validateOperation && t < len && (!obj || typeof obj !== "object")) {
 | 
				
			||||||
 | 
					                throw new exports.JsonPatchError('Cannot perform operation at the desired path', 'OPERATION_PATH_UNRESOLVABLE', index, operation, document);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.applyOperation = applyOperation;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Apply a full JSON Patch array on a JSON document.
 | 
				
			||||||
 | 
					 * Returns the {newDocument, result} of the patch.
 | 
				
			||||||
 | 
					 * It modifies the `document` object and `patch` - it gets the values by reference.
 | 
				
			||||||
 | 
					 * If you would like to avoid touching your values, clone them:
 | 
				
			||||||
 | 
					 * `jsonpatch.applyPatch(document, jsonpatch._deepClone(patch))`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param document The document to patch
 | 
				
			||||||
 | 
					 * @param patch The patch to apply
 | 
				
			||||||
 | 
					 * @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation.
 | 
				
			||||||
 | 
					 * @param mutateDocument Whether to mutate the original document or clone it before applying
 | 
				
			||||||
 | 
					 * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
 | 
				
			||||||
 | 
					 * @return An array of `{newDocument, result}` after the patch
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function applyPatch(document, patch, validateOperation, mutateDocument, banPrototypeModifications) {
 | 
				
			||||||
 | 
					    if (mutateDocument === void 0) { mutateDocument = true; }
 | 
				
			||||||
 | 
					    if (banPrototypeModifications === void 0) { banPrototypeModifications = true; }
 | 
				
			||||||
 | 
					    if (validateOperation) {
 | 
				
			||||||
 | 
					        if (!Array.isArray(patch)) {
 | 
				
			||||||
 | 
					            throw new exports.JsonPatchError('Patch sequence must be an array', 'SEQUENCE_NOT_AN_ARRAY');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!mutateDocument) {
 | 
				
			||||||
 | 
					        document = helpers_js_1._deepClone(document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var results = new Array(patch.length);
 | 
				
			||||||
 | 
					    for (var i = 0, length_1 = patch.length; i < length_1; i++) {
 | 
				
			||||||
 | 
					        // we don't need to pass mutateDocument argument because if it was true, we already deep cloned the object, we'll just pass `true`
 | 
				
			||||||
 | 
					        results[i] = applyOperation(document, patch[i], validateOperation, true, banPrototypeModifications, i);
 | 
				
			||||||
 | 
					        document = results[i].newDocument; // in case root was replaced
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    results.newDocument = document;
 | 
				
			||||||
 | 
					    return results;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.applyPatch = applyPatch;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Apply a single JSON Patch Operation on a JSON document.
 | 
				
			||||||
 | 
					 * Returns the updated document.
 | 
				
			||||||
 | 
					 * Suitable as a reducer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param document The document to patch
 | 
				
			||||||
 | 
					 * @param operation The operation to apply
 | 
				
			||||||
 | 
					 * @return The updated document
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function applyReducer(document, operation, index) {
 | 
				
			||||||
 | 
					    var operationResult = applyOperation(document, operation);
 | 
				
			||||||
 | 
					    if (operationResult.test === false) { // failed test
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return operationResult.newDocument;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.applyReducer = applyReducer;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Validates a single operation. Called from `jsonpatch.validate`. Throws `JsonPatchError` in case of an error.
 | 
				
			||||||
 | 
					 * @param {object} operation - operation object (patch)
 | 
				
			||||||
 | 
					 * @param {number} index - index of operation in the sequence
 | 
				
			||||||
 | 
					 * @param {object} [document] - object where the operation is supposed to be applied
 | 
				
			||||||
 | 
					 * @param {string} [existingPathFragment] - comes along with `document`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function validator(operation, index, document, existingPathFragment) {
 | 
				
			||||||
 | 
					    if (typeof operation !== 'object' || operation === null || Array.isArray(operation)) {
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation is not an object', 'OPERATION_NOT_AN_OBJECT', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (!objOps[operation.op]) {
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation `op` property is not one of operations defined in RFC-6902', 'OPERATION_OP_INVALID', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (typeof operation.path !== 'string') {
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation `path` property is not a string', 'OPERATION_PATH_INVALID', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (operation.path.indexOf('/') !== 0 && operation.path.length > 0) {
 | 
				
			||||||
 | 
					        // paths that aren't empty string should start with "/"
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation `path` property must start with "/"', 'OPERATION_PATH_INVALID', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if ((operation.op === 'move' || operation.op === 'copy') && typeof operation.from !== 'string') {
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation `from` property is not present (applicable in `move` and `copy` operations)', 'OPERATION_FROM_REQUIRED', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && operation.value === undefined) {
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_REQUIRED', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && helpers_js_1.hasUndefined(operation.value)) {
 | 
				
			||||||
 | 
					        throw new exports.JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED', index, operation, document);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (document) {
 | 
				
			||||||
 | 
					        if (operation.op == "add") {
 | 
				
			||||||
 | 
					            var pathLen = operation.path.split("/").length;
 | 
				
			||||||
 | 
					            var existingPathLen = existingPathFragment.split("/").length;
 | 
				
			||||||
 | 
					            if (pathLen !== existingPathLen + 1 && pathLen !== existingPathLen) {
 | 
				
			||||||
 | 
					                throw new exports.JsonPatchError('Cannot perform an `add` operation at the desired path', 'OPERATION_PATH_CANNOT_ADD', index, operation, document);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === 'replace' || operation.op === 'remove' || operation.op === '_get') {
 | 
				
			||||||
 | 
					            if (operation.path !== existingPathFragment) {
 | 
				
			||||||
 | 
					                throw new exports.JsonPatchError('Cannot perform the operation at a path that does not exist', 'OPERATION_PATH_UNRESOLVABLE', index, operation, document);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (operation.op === 'move' || operation.op === 'copy') {
 | 
				
			||||||
 | 
					            var existingValue = { op: "_get", path: operation.from, value: undefined };
 | 
				
			||||||
 | 
					            var error = validate([existingValue], document);
 | 
				
			||||||
 | 
					            if (error && error.name === 'OPERATION_PATH_UNRESOLVABLE') {
 | 
				
			||||||
 | 
					                throw new exports.JsonPatchError('Cannot perform the operation from a path that does not exist', 'OPERATION_FROM_UNRESOLVABLE', index, operation, document);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.validator = validator;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object document.
 | 
				
			||||||
 | 
					 * If error is encountered, returns a JsonPatchError object
 | 
				
			||||||
 | 
					 * @param sequence
 | 
				
			||||||
 | 
					 * @param document
 | 
				
			||||||
 | 
					 * @returns {JsonPatchError|undefined}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function validate(sequence, document, externalValidator) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        if (!Array.isArray(sequence)) {
 | 
				
			||||||
 | 
					            throw new exports.JsonPatchError('Patch sequence must be an array', 'SEQUENCE_NOT_AN_ARRAY');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (document) {
 | 
				
			||||||
 | 
					            //clone document and sequence so that we can safely try applying operations
 | 
				
			||||||
 | 
					            applyPatch(helpers_js_1._deepClone(document), helpers_js_1._deepClone(sequence), externalValidator || true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            externalValidator = externalValidator || validator;
 | 
				
			||||||
 | 
					            for (var i = 0; i < sequence.length; i++) {
 | 
				
			||||||
 | 
					                externalValidator(sequence[i], i, document, undefined);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (e) {
 | 
				
			||||||
 | 
					        if (e instanceof exports.JsonPatchError) {
 | 
				
			||||||
 | 
					            return e;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            throw e;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.validate = validate;
 | 
				
			||||||
 | 
					// based on https://github.com/epoberezkin/fast-deep-equal
 | 
				
			||||||
 | 
					// MIT License
 | 
				
			||||||
 | 
					// Copyright (c) 2017 Evgeny Poberezkin
 | 
				
			||||||
 | 
					// Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					// of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					// in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					// copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					// furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					// The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					// copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					// SOFTWARE.
 | 
				
			||||||
 | 
					function _areEquals(a, b) {
 | 
				
			||||||
 | 
					    if (a === b)
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    if (a && b && typeof a == 'object' && typeof b == 'object') {
 | 
				
			||||||
 | 
					        var arrA = Array.isArray(a), arrB = Array.isArray(b), i, length, key;
 | 
				
			||||||
 | 
					        if (arrA && arrB) {
 | 
				
			||||||
 | 
					            length = a.length;
 | 
				
			||||||
 | 
					            if (length != b.length)
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            for (i = length; i-- !== 0;)
 | 
				
			||||||
 | 
					                if (!_areEquals(a[i], b[i]))
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (arrA != arrB)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        var keys = Object.keys(a);
 | 
				
			||||||
 | 
					        length = keys.length;
 | 
				
			||||||
 | 
					        if (length !== Object.keys(b).length)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        for (i = length; i-- !== 0;)
 | 
				
			||||||
 | 
					            if (!b.hasOwnProperty(keys[i]))
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					        for (i = length; i-- !== 0;) {
 | 
				
			||||||
 | 
					            key = keys[i];
 | 
				
			||||||
 | 
					            if (!_areEquals(a[key], b[key]))
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return a !== a && b !== b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports._areEquals = _areEquals;
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***/ }),
 | 
				
			||||||
 | 
					/* 2 */
 | 
				
			||||||
 | 
					/***/ (function(module, exports, __webpack_require__) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var core = __webpack_require__(1);
 | 
				
			||||||
 | 
					Object.assign(exports, core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var duplex = __webpack_require__(3);
 | 
				
			||||||
 | 
					Object.assign(exports, duplex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var helpers = __webpack_require__(0);
 | 
				
			||||||
 | 
					exports.JsonPatchError = helpers.PatchError;
 | 
				
			||||||
 | 
					exports.deepClone = helpers._deepClone;
 | 
				
			||||||
 | 
					exports.escapePathComponent = helpers.escapePathComponent;
 | 
				
			||||||
 | 
					exports.unescapePathComponent = helpers.unescapePathComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***/ }),
 | 
				
			||||||
 | 
					/* 3 */
 | 
				
			||||||
 | 
					/***/ (function(module, exports, __webpack_require__) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Object.defineProperty(exports, "__esModule", { value: true });
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * https://github.com/Starcounter-Jack/JSON-Patch
 | 
				
			||||||
 | 
					 * (c) 2017-2021 Joachim Wester
 | 
				
			||||||
 | 
					 * MIT license
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var helpers_js_1 = __webpack_require__(0);
 | 
				
			||||||
 | 
					var core_js_1 = __webpack_require__(1);
 | 
				
			||||||
 | 
					var beforeDict = new WeakMap();
 | 
				
			||||||
 | 
					var Mirror = /** @class */ (function () {
 | 
				
			||||||
 | 
					    function Mirror(obj) {
 | 
				
			||||||
 | 
					        this.observers = new Map();
 | 
				
			||||||
 | 
					        this.obj = obj;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return Mirror;
 | 
				
			||||||
 | 
					}());
 | 
				
			||||||
 | 
					var ObserverInfo = /** @class */ (function () {
 | 
				
			||||||
 | 
					    function ObserverInfo(callback, observer) {
 | 
				
			||||||
 | 
					        this.callback = callback;
 | 
				
			||||||
 | 
					        this.observer = observer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ObserverInfo;
 | 
				
			||||||
 | 
					}());
 | 
				
			||||||
 | 
					function getMirror(obj) {
 | 
				
			||||||
 | 
					    return beforeDict.get(obj);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function getObserverFromMirror(mirror, callback) {
 | 
				
			||||||
 | 
					    return mirror.observers.get(callback);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function removeObserverFromMirror(mirror, observer) {
 | 
				
			||||||
 | 
					    mirror.observers.delete(observer.callback);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Detach an observer from an object
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function unobserve(root, observer) {
 | 
				
			||||||
 | 
					    observer.unobserve();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.unobserve = unobserve;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Observes changes made to an object, which can then be retrieved using generate
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function observe(obj, callback) {
 | 
				
			||||||
 | 
					    var patches = [];
 | 
				
			||||||
 | 
					    var observer;
 | 
				
			||||||
 | 
					    var mirror = getMirror(obj);
 | 
				
			||||||
 | 
					    if (!mirror) {
 | 
				
			||||||
 | 
					        mirror = new Mirror(obj);
 | 
				
			||||||
 | 
					        beforeDict.set(obj, mirror);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        var observerInfo = getObserverFromMirror(mirror, callback);
 | 
				
			||||||
 | 
					        observer = observerInfo && observerInfo.observer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (observer) {
 | 
				
			||||||
 | 
					        return observer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    observer = {};
 | 
				
			||||||
 | 
					    mirror.value = helpers_js_1._deepClone(obj);
 | 
				
			||||||
 | 
					    if (callback) {
 | 
				
			||||||
 | 
					        observer.callback = callback;
 | 
				
			||||||
 | 
					        observer.next = null;
 | 
				
			||||||
 | 
					        var dirtyCheck = function () {
 | 
				
			||||||
 | 
					            generate(observer);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        var fastCheck = function () {
 | 
				
			||||||
 | 
					            clearTimeout(observer.next);
 | 
				
			||||||
 | 
					            observer.next = setTimeout(dirtyCheck);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        if (typeof window !== 'undefined') { //not Node
 | 
				
			||||||
 | 
					            window.addEventListener('mouseup', fastCheck);
 | 
				
			||||||
 | 
					            window.addEventListener('keyup', fastCheck);
 | 
				
			||||||
 | 
					            window.addEventListener('mousedown', fastCheck);
 | 
				
			||||||
 | 
					            window.addEventListener('keydown', fastCheck);
 | 
				
			||||||
 | 
					            window.addEventListener('change', fastCheck);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    observer.patches = patches;
 | 
				
			||||||
 | 
					    observer.object = obj;
 | 
				
			||||||
 | 
					    observer.unobserve = function () {
 | 
				
			||||||
 | 
					        generate(observer);
 | 
				
			||||||
 | 
					        clearTimeout(observer.next);
 | 
				
			||||||
 | 
					        removeObserverFromMirror(mirror, observer);
 | 
				
			||||||
 | 
					        if (typeof window !== 'undefined') {
 | 
				
			||||||
 | 
					            window.removeEventListener('mouseup', fastCheck);
 | 
				
			||||||
 | 
					            window.removeEventListener('keyup', fastCheck);
 | 
				
			||||||
 | 
					            window.removeEventListener('mousedown', fastCheck);
 | 
				
			||||||
 | 
					            window.removeEventListener('keydown', fastCheck);
 | 
				
			||||||
 | 
					            window.removeEventListener('change', fastCheck);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    mirror.observers.set(callback, new ObserverInfo(callback, observer));
 | 
				
			||||||
 | 
					    return observer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.observe = observe;
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate an array of patches from an observer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function generate(observer, invertible) {
 | 
				
			||||||
 | 
					    if (invertible === void 0) { invertible = false; }
 | 
				
			||||||
 | 
					    var mirror = beforeDict.get(observer.object);
 | 
				
			||||||
 | 
					    _generate(mirror.value, observer.object, observer.patches, "", invertible);
 | 
				
			||||||
 | 
					    if (observer.patches.length) {
 | 
				
			||||||
 | 
					        core_js_1.applyPatch(mirror.value, observer.patches);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var temp = observer.patches;
 | 
				
			||||||
 | 
					    if (temp.length > 0) {
 | 
				
			||||||
 | 
					        observer.patches = [];
 | 
				
			||||||
 | 
					        if (observer.callback) {
 | 
				
			||||||
 | 
					            observer.callback(temp);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return temp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.generate = generate;
 | 
				
			||||||
 | 
					// Dirty check if obj is different from mirror, generate patches and update mirror
 | 
				
			||||||
 | 
					function _generate(mirror, obj, patches, path, invertible) {
 | 
				
			||||||
 | 
					    if (obj === mirror) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (typeof obj.toJSON === "function") {
 | 
				
			||||||
 | 
					        obj = obj.toJSON();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var newKeys = helpers_js_1._objectKeys(obj);
 | 
				
			||||||
 | 
					    var oldKeys = helpers_js_1._objectKeys(mirror);
 | 
				
			||||||
 | 
					    var changed = false;
 | 
				
			||||||
 | 
					    var deleted = false;
 | 
				
			||||||
 | 
					    //if ever "move" operation is implemented here, make sure this test runs OK: "should not generate the same patch twice (move)"
 | 
				
			||||||
 | 
					    for (var t = oldKeys.length - 1; t >= 0; t--) {
 | 
				
			||||||
 | 
					        var key = oldKeys[t];
 | 
				
			||||||
 | 
					        var oldVal = mirror[key];
 | 
				
			||||||
 | 
					        if (helpers_js_1.hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
 | 
				
			||||||
 | 
					            var newVal = obj[key];
 | 
				
			||||||
 | 
					            if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null && Array.isArray(oldVal) === Array.isArray(newVal)) {
 | 
				
			||||||
 | 
					                _generate(oldVal, newVal, patches, path + "/" + helpers_js_1.escapePathComponent(key), invertible);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                if (oldVal !== newVal) {
 | 
				
			||||||
 | 
					                    changed = true;
 | 
				
			||||||
 | 
					                    if (invertible) {
 | 
				
			||||||
 | 
					                        patches.push({ op: "test", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(oldVal) });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    patches.push({ op: "replace", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(newVal) });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (Array.isArray(mirror) === Array.isArray(obj)) {
 | 
				
			||||||
 | 
					            if (invertible) {
 | 
				
			||||||
 | 
					                patches.push({ op: "test", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(oldVal) });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            patches.push({ op: "remove", path: path + "/" + helpers_js_1.escapePathComponent(key) });
 | 
				
			||||||
 | 
					            deleted = true; // property has been deleted
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            if (invertible) {
 | 
				
			||||||
 | 
					                patches.push({ op: "test", path: path, value: mirror });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            patches.push({ op: "replace", path: path, value: obj });
 | 
				
			||||||
 | 
					            changed = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!deleted && newKeys.length == oldKeys.length) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (var t = 0; t < newKeys.length; t++) {
 | 
				
			||||||
 | 
					        var key = newKeys[t];
 | 
				
			||||||
 | 
					        if (!helpers_js_1.hasOwnProperty(mirror, key) && obj[key] !== undefined) {
 | 
				
			||||||
 | 
					            patches.push({ op: "add", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(obj[key]) });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Create an array of patches from the differences in two objects
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function compare(tree1, tree2, invertible) {
 | 
				
			||||||
 | 
					    if (invertible === void 0) { invertible = false; }
 | 
				
			||||||
 | 
					    var patches = [];
 | 
				
			||||||
 | 
					    _generate(tree1, tree2, patches, '', invertible);
 | 
				
			||||||
 | 
					    return patches;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					exports.compare = compare;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***/ })
 | 
				
			||||||
 | 
					/******/ ]);
 | 
				
			||||||
							
								
								
									
										14
									
								
								app/static/external/JSON-Patch/js/fast-json-patch.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/static/external/JSON-Patch/js/fast-json-patch.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										21
									
								
								app/static/external/list.js/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/static/external/list.js/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2011-2018 Jonny Strömberg, jonnystromberg.com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 | 
					all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
				
			||||||
 | 
					THE SOFTWARE.
 | 
				
			||||||
							
								
								
									
										1
									
								
								app/static/external/list.js/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/external/list.js/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					2.3.1
 | 
				
			||||||
							
								
								
									
										2020
									
								
								app/static/external/list.js/js/list.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2020
									
								
								app/static/external/list.js/js/list.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								app/static/external/list.js/js/list.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/external/list.js/js/list.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								app/static/external/list.js/js/list.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/static/external/list.js/js/list.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								app/static/external/list.js/js/list.min.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/external/list.js/js/list.min.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"version":3,"file":"list.min.js","sources":["webpack://List/list.min.js"],"mappings":"AAAA","sourceRoot":""}
 | 
				
			||||||
							
								
								
									
										202
									
								
								app/static/external/material-design-icons/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								app/static/external/material-design-icons/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					                                 Apache License
 | 
				
			||||||
 | 
					                           Version 2.0, January 2004
 | 
				
			||||||
 | 
					                        http://www.apache.org/licenses/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   1. Definitions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "License" shall mean the terms and conditions for use, reproduction,
 | 
				
			||||||
 | 
					      and distribution as defined by Sections 1 through 9 of this document.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Licensor" shall mean the copyright owner or entity authorized by
 | 
				
			||||||
 | 
					      the copyright owner that is granting the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Legal Entity" shall mean the union of the acting entity and all
 | 
				
			||||||
 | 
					      other entities that control, are controlled by, or are under common
 | 
				
			||||||
 | 
					      control with that entity. For the purposes of this definition,
 | 
				
			||||||
 | 
					      "control" means (i) the power, direct or indirect, to cause the
 | 
				
			||||||
 | 
					      direction or management of such entity, whether by contract or
 | 
				
			||||||
 | 
					      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
				
			||||||
 | 
					      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "You" (or "Your") shall mean an individual or Legal Entity
 | 
				
			||||||
 | 
					      exercising permissions granted by this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Source" form shall mean the preferred form for making modifications,
 | 
				
			||||||
 | 
					      including but not limited to software source code, documentation
 | 
				
			||||||
 | 
					      source, and configuration files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Object" form shall mean any form resulting from mechanical
 | 
				
			||||||
 | 
					      transformation or translation of a Source form, including but
 | 
				
			||||||
 | 
					      not limited to compiled object code, generated documentation,
 | 
				
			||||||
 | 
					      and conversions to other media types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Work" shall mean the work of authorship, whether in Source or
 | 
				
			||||||
 | 
					      Object form, made available under the License, as indicated by a
 | 
				
			||||||
 | 
					      copyright notice that is included in or attached to the work
 | 
				
			||||||
 | 
					      (an example is provided in the Appendix below).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Derivative Works" shall mean any work, whether in Source or Object
 | 
				
			||||||
 | 
					      form, that is based on (or derived from) the Work and for which the
 | 
				
			||||||
 | 
					      editorial revisions, annotations, elaborations, or other modifications
 | 
				
			||||||
 | 
					      represent, as a whole, an original work of authorship. For the purposes
 | 
				
			||||||
 | 
					      of this License, Derivative Works shall not include works that remain
 | 
				
			||||||
 | 
					      separable from, or merely link (or bind by name) to the interfaces of,
 | 
				
			||||||
 | 
					      the Work and Derivative Works thereof.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Contribution" shall mean any work of authorship, including
 | 
				
			||||||
 | 
					      the original version of the Work and any modifications or additions
 | 
				
			||||||
 | 
					      to that Work or Derivative Works thereof, that is intentionally
 | 
				
			||||||
 | 
					      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
				
			||||||
 | 
					      or by an individual or Legal Entity authorized to submit on behalf of
 | 
				
			||||||
 | 
					      the copyright owner. For the purposes of this definition, "submitted"
 | 
				
			||||||
 | 
					      means any form of electronic, verbal, or written communication sent
 | 
				
			||||||
 | 
					      to the Licensor or its representatives, including but not limited to
 | 
				
			||||||
 | 
					      communication on electronic mailing lists, source code control systems,
 | 
				
			||||||
 | 
					      and issue tracking systems that are managed by, or on behalf of, the
 | 
				
			||||||
 | 
					      Licensor for the purpose of discussing and improving the Work, but
 | 
				
			||||||
 | 
					      excluding communication that is conspicuously marked or otherwise
 | 
				
			||||||
 | 
					      designated in writing by the copyright owner as "Not a Contribution."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
				
			||||||
 | 
					      on behalf of whom a Contribution has been received by Licensor and
 | 
				
			||||||
 | 
					      subsequently incorporated within the Work.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
				
			||||||
 | 
					      this License, each Contributor hereby grants to You a perpetual,
 | 
				
			||||||
 | 
					      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
				
			||||||
 | 
					      copyright license to reproduce, prepare Derivative Works of,
 | 
				
			||||||
 | 
					      publicly display, publicly perform, sublicense, and distribute the
 | 
				
			||||||
 | 
					      Work and such Derivative Works in Source or Object form.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   3. Grant of Patent License. Subject to the terms and conditions of
 | 
				
			||||||
 | 
					      this License, each Contributor hereby grants to You a perpetual,
 | 
				
			||||||
 | 
					      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
				
			||||||
 | 
					      (except as stated in this section) patent license to make, have made,
 | 
				
			||||||
 | 
					      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
				
			||||||
 | 
					      where such license applies only to those patent claims licensable
 | 
				
			||||||
 | 
					      by such Contributor that are necessarily infringed by their
 | 
				
			||||||
 | 
					      Contribution(s) alone or by combination of their Contribution(s)
 | 
				
			||||||
 | 
					      with the Work to which such Contribution(s) was submitted. If You
 | 
				
			||||||
 | 
					      institute patent litigation against any entity (including a
 | 
				
			||||||
 | 
					      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
				
			||||||
 | 
					      or a Contribution incorporated within the Work constitutes direct
 | 
				
			||||||
 | 
					      or contributory patent infringement, then any patent licenses
 | 
				
			||||||
 | 
					      granted to You under this License for that Work shall terminate
 | 
				
			||||||
 | 
					      as of the date such litigation is filed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   4. Redistribution. You may reproduce and distribute copies of the
 | 
				
			||||||
 | 
					      Work or Derivative Works thereof in any medium, with or without
 | 
				
			||||||
 | 
					      modifications, and in Source or Object form, provided that You
 | 
				
			||||||
 | 
					      meet the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      (a) You must give any other recipients of the Work or
 | 
				
			||||||
 | 
					          Derivative Works a copy of this License; and
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      (b) You must cause any modified files to carry prominent notices
 | 
				
			||||||
 | 
					          stating that You changed the files; and
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      (c) You must retain, in the Source form of any Derivative Works
 | 
				
			||||||
 | 
					          that You distribute, all copyright, patent, trademark, and
 | 
				
			||||||
 | 
					          attribution notices from the Source form of the Work,
 | 
				
			||||||
 | 
					          excluding those notices that do not pertain to any part of
 | 
				
			||||||
 | 
					          the Derivative Works; and
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      (d) If the Work includes a "NOTICE" text file as part of its
 | 
				
			||||||
 | 
					          distribution, then any Derivative Works that You distribute must
 | 
				
			||||||
 | 
					          include a readable copy of the attribution notices contained
 | 
				
			||||||
 | 
					          within such NOTICE file, excluding those notices that do not
 | 
				
			||||||
 | 
					          pertain to any part of the Derivative Works, in at least one
 | 
				
			||||||
 | 
					          of the following places: within a NOTICE text file distributed
 | 
				
			||||||
 | 
					          as part of the Derivative Works; within the Source form or
 | 
				
			||||||
 | 
					          documentation, if provided along with the Derivative Works; or,
 | 
				
			||||||
 | 
					          within a display generated by the Derivative Works, if and
 | 
				
			||||||
 | 
					          wherever such third-party notices normally appear. The contents
 | 
				
			||||||
 | 
					          of the NOTICE file are for informational purposes only and
 | 
				
			||||||
 | 
					          do not modify the License. You may add Your own attribution
 | 
				
			||||||
 | 
					          notices within Derivative Works that You distribute, alongside
 | 
				
			||||||
 | 
					          or as an addendum to the NOTICE text from the Work, provided
 | 
				
			||||||
 | 
					          that such additional attribution notices cannot be construed
 | 
				
			||||||
 | 
					          as modifying the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      You may add Your own copyright statement to Your modifications and
 | 
				
			||||||
 | 
					      may provide additional or different license terms and conditions
 | 
				
			||||||
 | 
					      for use, reproduction, or distribution of Your modifications, or
 | 
				
			||||||
 | 
					      for any such Derivative Works as a whole, provided Your use,
 | 
				
			||||||
 | 
					      reproduction, and distribution of the Work otherwise complies with
 | 
				
			||||||
 | 
					      the conditions stated in this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
				
			||||||
 | 
					      any Contribution intentionally submitted for inclusion in the Work
 | 
				
			||||||
 | 
					      by You to the Licensor shall be under the terms and conditions of
 | 
				
			||||||
 | 
					      this License, without any additional terms or conditions.
 | 
				
			||||||
 | 
					      Notwithstanding the above, nothing herein shall supersede or modify
 | 
				
			||||||
 | 
					      the terms of any separate license agreement you may have executed
 | 
				
			||||||
 | 
					      with Licensor regarding such Contributions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   6. Trademarks. This License does not grant permission to use the trade
 | 
				
			||||||
 | 
					      names, trademarks, service marks, or product names of the Licensor,
 | 
				
			||||||
 | 
					      except as required for reasonable and customary use in describing the
 | 
				
			||||||
 | 
					      origin of the Work and reproducing the content of the NOTICE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
				
			||||||
 | 
					      agreed to in writing, Licensor provides the Work (and each
 | 
				
			||||||
 | 
					      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
				
			||||||
 | 
					      implied, including, without limitation, any warranties or conditions
 | 
				
			||||||
 | 
					      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
				
			||||||
 | 
					      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
				
			||||||
 | 
					      appropriateness of using or redistributing the Work and assume any
 | 
				
			||||||
 | 
					      risks associated with Your exercise of permissions under this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   8. Limitation of Liability. In no event and under no legal theory,
 | 
				
			||||||
 | 
					      whether in tort (including negligence), contract, or otherwise,
 | 
				
			||||||
 | 
					      unless required by applicable law (such as deliberate and grossly
 | 
				
			||||||
 | 
					      negligent acts) or agreed to in writing, shall any Contributor be
 | 
				
			||||||
 | 
					      liable to You for damages, including any direct, indirect, special,
 | 
				
			||||||
 | 
					      incidental, or consequential damages of any character arising as a
 | 
				
			||||||
 | 
					      result of this License or out of the use or inability to use the
 | 
				
			||||||
 | 
					      Work (including but not limited to damages for loss of goodwill,
 | 
				
			||||||
 | 
					      work stoppage, computer failure or malfunction, or any and all
 | 
				
			||||||
 | 
					      other commercial damages or losses), even if such Contributor
 | 
				
			||||||
 | 
					      has been advised of the possibility of such damages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   9. Accepting Warranty or Additional Liability. While redistributing
 | 
				
			||||||
 | 
					      the Work or Derivative Works thereof, You may choose to offer,
 | 
				
			||||||
 | 
					      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
				
			||||||
 | 
					      or other liability obligations and/or rights consistent with this
 | 
				
			||||||
 | 
					      License. However, in accepting such obligations, You may act only
 | 
				
			||||||
 | 
					      on Your own behalf and on Your sole responsibility, not on behalf
 | 
				
			||||||
 | 
					      of any other Contributor, and only if You agree to indemnify,
 | 
				
			||||||
 | 
					      defend, and hold each Contributor harmless for any liability
 | 
				
			||||||
 | 
					      incurred by, or claims asserted against, such Contributor by reason
 | 
				
			||||||
 | 
					      of your accepting any such warranty or additional liability.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   APPENDIX: How to apply the Apache License to your work.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      To apply the Apache License to your work, attach the following
 | 
				
			||||||
 | 
					      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
				
			||||||
 | 
					      replaced with your own identifying information. (Don't include
 | 
				
			||||||
 | 
					      the brackets!)  The text should be enclosed in the appropriate
 | 
				
			||||||
 | 
					      comment syntax for the file format. We also recommend that a
 | 
				
			||||||
 | 
					      file or class name and description of purpose be included on the
 | 
				
			||||||
 | 
					      same "printed page" as the copyright notice for easier
 | 
				
			||||||
 | 
					      identification within third-party archives.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Copyright [yyyy] [name of copyright owner]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					   you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					   You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					   distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					   See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					   limitations under the License.
 | 
				
			||||||
							
								
								
									
										1
									
								
								app/static/external/material-design-icons/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/external/material-design-icons/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					https://github.com/google/material-design-icons/tree/f7bd4f25f3764883717c09a1fd867f560c9a9581
 | 
				
			||||||
							
								
								
									
										37
									
								
								app/static/external/material-design-icons/css/material-icons.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								app/static/external/material-design-icons/css/material-icons.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					@font-face {
 | 
				
			||||||
 | 
					  font-family: "Material Icons";
 | 
				
			||||||
 | 
					  font-style: normal;
 | 
				
			||||||
 | 
					  font-weight: 400;
 | 
				
			||||||
 | 
					  /* For IE6-8 */
 | 
				
			||||||
 | 
					  /* src: url("../font/MaterialIcons-Regular.eot"); */
 | 
				
			||||||
 | 
					  src: local("Material Icons"),
 | 
				
			||||||
 | 
					    local("MaterialIcons-Regular"),
 | 
				
			||||||
 | 
					    /* url("../font/MaterialIcons-Regular.woff2") format('woff2'), */
 | 
				
			||||||
 | 
					    /* url("../font/MaterialIcons-Regular.woff") format('woff'), */
 | 
				
			||||||
 | 
					    url("../font/MaterialIcons-Regular.ttf") format("truetype");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.material-icons {
 | 
				
			||||||
 | 
					  font-family: 'Material Icons';
 | 
				
			||||||
 | 
					  font-weight: normal;
 | 
				
			||||||
 | 
					  font-style: normal;
 | 
				
			||||||
 | 
					  font-size: 24px;  /* Preferred icon size */
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  line-height: 1;
 | 
				
			||||||
 | 
					  text-transform: none;
 | 
				
			||||||
 | 
					  letter-spacing: normal;
 | 
				
			||||||
 | 
					  word-wrap: normal;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					  direction: ltr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Support for all WebKit browsers. */
 | 
				
			||||||
 | 
					  -webkit-font-smoothing: antialiased;
 | 
				
			||||||
 | 
					  /* Support for Safari and Chrome. */
 | 
				
			||||||
 | 
					  text-rendering: optimizeLegibility;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Support for Firefox. */
 | 
				
			||||||
 | 
					  -moz-osx-font-smoothing: grayscale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Support for IE. */
 | 
				
			||||||
 | 
					  font-feature-settings: 'liga';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2235
									
								
								app/static/external/material-design-icons/font/MaterialIcons-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2235
									
								
								app/static/external/material-design-icons/font/MaterialIcons-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIcons-Regular.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIcons-Regular.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2195
									
								
								app/static/external/material-design-icons/font/MaterialIconsOutlined-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2195
									
								
								app/static/external/material-design-icons/font/MaterialIconsOutlined-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsOutlined-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsOutlined-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2200
									
								
								app/static/external/material-design-icons/font/MaterialIconsRound-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2200
									
								
								app/static/external/material-design-icons/font/MaterialIconsRound-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsRound-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsRound-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2200
									
								
								app/static/external/material-design-icons/font/MaterialIconsSharp-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2200
									
								
								app/static/external/material-design-icons/font/MaterialIconsSharp-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsSharp-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsSharp-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2238
									
								
								app/static/external/material-design-icons/font/MaterialIconsTwoTone-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2238
									
								
								app/static/external/material-design-icons/font/MaterialIconsTwoTone-Regular.codepoints
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsTwoTone-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/external/material-design-icons/font/MaterialIconsTwoTone-Regular.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										21
									
								
								app/static/external/materialize/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/static/external/materialize/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2014-2018 Materialize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
							
								
								
									
										1
									
								
								app/static/external/materialize/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/static/external/materialize/VERSION
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					1.0.0
 | 
				
			||||||
							
								
								
									
										9067
									
								
								app/static/external/materialize/css/materialize.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9067
									
								
								app/static/external/materialize/css/materialize.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										13
									
								
								app/static/external/materialize/css/materialize.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/static/external/materialize/css/materialize.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										12374
									
								
								app/static/external/materialize/js/materialize.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12374
									
								
								app/static/external/materialize/js/materialize.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										6
									
								
								app/static/external/materialize/js/materialize.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/static/external/materialize/js/materialize.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										55
									
								
								app/static/external/materialize/sass/components/_badges.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								app/static/external/materialize/sass/components/_badges.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					// Badges
 | 
				
			||||||
 | 
					span.badge {
 | 
				
			||||||
 | 
					  min-width: 3rem;
 | 
				
			||||||
 | 
					  padding: 0 6px;
 | 
				
			||||||
 | 
					  margin-left: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-size: 1rem;
 | 
				
			||||||
 | 
					  line-height: $badge-height;
 | 
				
			||||||
 | 
					  height: $badge-height;
 | 
				
			||||||
 | 
					  color: color('grey', 'darken-1');
 | 
				
			||||||
 | 
					  float: right;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.new {
 | 
				
			||||||
 | 
					    font-weight: 300;
 | 
				
			||||||
 | 
					    font-size: 0.8rem;
 | 
				
			||||||
 | 
					    color: #fff;
 | 
				
			||||||
 | 
					    background-color: $badge-bg-color;
 | 
				
			||||||
 | 
					    border-radius: 2px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.new:after {
 | 
				
			||||||
 | 
					    content: " new";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &[data-badge-caption]::after {
 | 
				
			||||||
 | 
					    content: " " attr(data-badge-caption);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Special cases
 | 
				
			||||||
 | 
					nav ul a span.badge {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  float: none;
 | 
				
			||||||
 | 
					  margin-left: 4px;
 | 
				
			||||||
 | 
					  line-height: $badge-height;
 | 
				
			||||||
 | 
					  height: $badge-height;
 | 
				
			||||||
 | 
					  -webkit-font-smoothing: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Line height centering
 | 
				
			||||||
 | 
					.collection-item span.badge {
 | 
				
			||||||
 | 
					  margin-top: calc(#{$collection-line-height / 2} - #{$badge-height / 2});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.collapsible span.badge {
 | 
				
			||||||
 | 
					  margin-left: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.sidenav span.badge {
 | 
				
			||||||
 | 
					  margin-top: calc(#{$sidenav-line-height / 2} - #{$badge-height / 2});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table span.badge {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  float: none;
 | 
				
			||||||
 | 
					  margin-left: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										322
									
								
								app/static/external/materialize/sass/components/_buttons.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								app/static/external/materialize/sass/components/_buttons.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					// shared styles
 | 
				
			||||||
 | 
					.btn,
 | 
				
			||||||
 | 
					.btn-flat {
 | 
				
			||||||
 | 
					  border: $button-border;
 | 
				
			||||||
 | 
					  border-radius: $button-radius;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  height: $button-height;
 | 
				
			||||||
 | 
					  line-height: $button-height;
 | 
				
			||||||
 | 
					  padding: $button-padding;
 | 
				
			||||||
 | 
					  text-transform: uppercase;
 | 
				
			||||||
 | 
					  vertical-align: middle;
 | 
				
			||||||
 | 
					  -webkit-tap-highlight-color: transparent; // Gets rid of tap active state
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Disabled shared style
 | 
				
			||||||
 | 
					.btn.disabled,
 | 
				
			||||||
 | 
					.btn-floating.disabled,
 | 
				
			||||||
 | 
					.btn-large.disabled,
 | 
				
			||||||
 | 
					.btn-small.disabled,
 | 
				
			||||||
 | 
					.btn-flat.disabled,
 | 
				
			||||||
 | 
					.btn:disabled,
 | 
				
			||||||
 | 
					.btn-floating:disabled,
 | 
				
			||||||
 | 
					.btn-large:disabled,
 | 
				
			||||||
 | 
					.btn-small:disabled,
 | 
				
			||||||
 | 
					.btn-flat:disabled,
 | 
				
			||||||
 | 
					.btn[disabled],
 | 
				
			||||||
 | 
					.btn-floating[disabled],
 | 
				
			||||||
 | 
					.btn-large[disabled],
 | 
				
			||||||
 | 
					.btn-small[disabled],
 | 
				
			||||||
 | 
					.btn-flat[disabled] {
 | 
				
			||||||
 | 
					  pointer-events: none;
 | 
				
			||||||
 | 
					  background-color: $button-disabled-background !important;
 | 
				
			||||||
 | 
					  box-shadow: none;
 | 
				
			||||||
 | 
					  color: $button-disabled-color !important;
 | 
				
			||||||
 | 
					  cursor: default;
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    background-color: $button-disabled-background !important;
 | 
				
			||||||
 | 
					    color: $button-disabled-color !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shared icon styles
 | 
				
			||||||
 | 
					.btn,
 | 
				
			||||||
 | 
					.btn-floating,
 | 
				
			||||||
 | 
					.btn-large,
 | 
				
			||||||
 | 
					.btn-small,
 | 
				
			||||||
 | 
					.btn-flat {
 | 
				
			||||||
 | 
					  font-size: $button-font-size;
 | 
				
			||||||
 | 
					  outline: 0;
 | 
				
			||||||
 | 
					  i {
 | 
				
			||||||
 | 
					    font-size: $button-icon-font-size;
 | 
				
			||||||
 | 
					    line-height: inherit;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shared focus button style
 | 
				
			||||||
 | 
					.btn,
 | 
				
			||||||
 | 
					.btn-floating {
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    background-color: darken($button-raised-background, 10%);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Raised Button
 | 
				
			||||||
 | 
					.btn {
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  color: $button-raised-color;
 | 
				
			||||||
 | 
					  background-color: $button-raised-background;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  letter-spacing: .5px;
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					  transition: background-color .2s ease-out;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    background-color: $button-raised-background-hover;
 | 
				
			||||||
 | 
					    @extend .z-depth-1-half;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Floating button
 | 
				
			||||||
 | 
					.btn-floating {
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    background-color: $button-floating-background-hover;
 | 
				
			||||||
 | 
					    @extend .z-depth-1-half;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &:before {
 | 
				
			||||||
 | 
					    border-radius: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.btn-large {
 | 
				
			||||||
 | 
					    &.halfway-fab {
 | 
				
			||||||
 | 
					      bottom: -$button-floating-large-size / 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    width: $button-floating-large-size;
 | 
				
			||||||
 | 
					    height: $button-floating-large-size;
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					    i {
 | 
				
			||||||
 | 
					      line-height: $button-floating-large-size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.btn-small {
 | 
				
			||||||
 | 
					    &.halfway-fab {
 | 
				
			||||||
 | 
					      bottom: -$button-floating-small-size / 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    width: $button-floating-small-size;
 | 
				
			||||||
 | 
					    height: $button-floating-small-size;
 | 
				
			||||||
 | 
					    i {
 | 
				
			||||||
 | 
					      line-height: $button-floating-small-size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.halfway-fab {
 | 
				
			||||||
 | 
					    &.left {
 | 
				
			||||||
 | 
					      right: auto;
 | 
				
			||||||
 | 
					      left: 24px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    right: 24px;
 | 
				
			||||||
 | 
					    bottom: -$button-floating-size / 2;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  color: $button-floating-color;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  z-index: 1;
 | 
				
			||||||
 | 
					  width: $button-floating-size;
 | 
				
			||||||
 | 
					  height: $button-floating-size;
 | 
				
			||||||
 | 
					  line-height: $button-floating-size;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  background-color: $button-floating-background;
 | 
				
			||||||
 | 
					  border-radius: $button-floating-radius;
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					  transition: background-color .3s;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  vertical-align: middle;
 | 
				
			||||||
 | 
					  i {
 | 
				
			||||||
 | 
					    width: inherit;
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    color: $button-floating-color;
 | 
				
			||||||
 | 
					    font-size: $button-large-icon-font-size;
 | 
				
			||||||
 | 
					    line-height: $button-floating-size;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// button fix
 | 
				
			||||||
 | 
					button.btn-floating {
 | 
				
			||||||
 | 
					  border: $button-border;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fixed Action Button
 | 
				
			||||||
 | 
					.fixed-action-btn {
 | 
				
			||||||
 | 
					  &.active {
 | 
				
			||||||
 | 
					    ul {
 | 
				
			||||||
 | 
					      visibility: visible;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Directions
 | 
				
			||||||
 | 
					  &.direction-left,
 | 
				
			||||||
 | 
					  &.direction-right {
 | 
				
			||||||
 | 
					    padding: 0 0 0 15px;
 | 
				
			||||||
 | 
					    ul {
 | 
				
			||||||
 | 
					      text-align: right;
 | 
				
			||||||
 | 
					      right: 64px;
 | 
				
			||||||
 | 
					      top: 50%;
 | 
				
			||||||
 | 
					      transform: translateY(-50%);
 | 
				
			||||||
 | 
					      height: 100%;
 | 
				
			||||||
 | 
					      left: auto;
 | 
				
			||||||
 | 
					      /*width 100% only goes to width of button container */
 | 
				
			||||||
 | 
					      width: 500px;
 | 
				
			||||||
 | 
					      li {
 | 
				
			||||||
 | 
					        display: inline-block;
 | 
				
			||||||
 | 
					        margin: 7.5px 15px 0 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.direction-right {
 | 
				
			||||||
 | 
					    padding: 0 15px 0 0;
 | 
				
			||||||
 | 
					    ul {
 | 
				
			||||||
 | 
					      text-align: left;
 | 
				
			||||||
 | 
					      direction: rtl;
 | 
				
			||||||
 | 
					      left: 64px;
 | 
				
			||||||
 | 
					      right: auto;
 | 
				
			||||||
 | 
					      li {
 | 
				
			||||||
 | 
					        margin: 7.5px 0 0 15px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.direction-bottom {
 | 
				
			||||||
 | 
					    padding: 0 0 15px 0;
 | 
				
			||||||
 | 
					    ul {
 | 
				
			||||||
 | 
					      top: 64px;
 | 
				
			||||||
 | 
					      bottom: auto;
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      flex-direction: column-reverse;
 | 
				
			||||||
 | 
					      li {
 | 
				
			||||||
 | 
					        margin: 15px 0 0 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.toolbar {
 | 
				
			||||||
 | 
					    &.active {
 | 
				
			||||||
 | 
					      &>a i {
 | 
				
			||||||
 | 
					        opacity: 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					    height: $button-floating-large-size;
 | 
				
			||||||
 | 
					    ul {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      z-index: 1;
 | 
				
			||||||
 | 
					      li {
 | 
				
			||||||
 | 
					        flex: 1;
 | 
				
			||||||
 | 
					        display: inline-block;
 | 
				
			||||||
 | 
					        margin: 0;
 | 
				
			||||||
 | 
					        height: 100%;
 | 
				
			||||||
 | 
					        transition: none;
 | 
				
			||||||
 | 
					        a {
 | 
				
			||||||
 | 
					          display: block;
 | 
				
			||||||
 | 
					          overflow: hidden;
 | 
				
			||||||
 | 
					          position: relative;
 | 
				
			||||||
 | 
					          width: 100%;
 | 
				
			||||||
 | 
					          height: 100%;
 | 
				
			||||||
 | 
					          background-color: transparent;
 | 
				
			||||||
 | 
					          box-shadow: none;
 | 
				
			||||||
 | 
					          color: #fff;
 | 
				
			||||||
 | 
					          line-height: $button-floating-large-size;
 | 
				
			||||||
 | 
					          z-index: 1;
 | 
				
			||||||
 | 
					          i {
 | 
				
			||||||
 | 
					            line-height: inherit;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  right: 23px;
 | 
				
			||||||
 | 
					  bottom: 23px;
 | 
				
			||||||
 | 
					  padding-top: 15px;
 | 
				
			||||||
 | 
					  margin-bottom: 0;
 | 
				
			||||||
 | 
					  z-index: 997;
 | 
				
			||||||
 | 
					  ul {
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    bottom: 64px;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    visibility: hidden;
 | 
				
			||||||
 | 
					    li {
 | 
				
			||||||
 | 
					      margin-bottom: 15px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    a.btn-floating {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .fab-backdrop {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    z-index: -1;
 | 
				
			||||||
 | 
					    width: $button-floating-size;
 | 
				
			||||||
 | 
					    height: $button-floating-size;
 | 
				
			||||||
 | 
					    background-color: $button-floating-background;
 | 
				
			||||||
 | 
					    border-radius: $button-floating-radius;
 | 
				
			||||||
 | 
					    transform: scale(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Flat button
 | 
				
			||||||
 | 
					.btn-flat {
 | 
				
			||||||
 | 
					  box-shadow: none;
 | 
				
			||||||
 | 
					  background-color: transparent;
 | 
				
			||||||
 | 
					  color: $button-flat-color;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: background-color .2s;
 | 
				
			||||||
 | 
					  &:focus,
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    box-shadow: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    background-color: rgba(0, 0, 0, .1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.disabled,
 | 
				
			||||||
 | 
					  &.btn-flat[disabled]  {
 | 
				
			||||||
 | 
					    background-color: transparent !important;
 | 
				
			||||||
 | 
					    color: $button-flat-disabled-color !important;
 | 
				
			||||||
 | 
					    cursor: default;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Large button
 | 
				
			||||||
 | 
					.btn-large {
 | 
				
			||||||
 | 
					  @extend .btn;
 | 
				
			||||||
 | 
					  height: $button-large-height;
 | 
				
			||||||
 | 
					  line-height: $button-large-height;
 | 
				
			||||||
 | 
					  font-size: $button-large-font-size;
 | 
				
			||||||
 | 
					  padding: 0 28px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  i {
 | 
				
			||||||
 | 
					    font-size: $button-large-icon-font-size;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Small button
 | 
				
			||||||
 | 
					.btn-small {
 | 
				
			||||||
 | 
					  @extend .btn;
 | 
				
			||||||
 | 
					  height: $button-small-height;
 | 
				
			||||||
 | 
					  line-height: $button-small-height;
 | 
				
			||||||
 | 
					  font-size: $button-small-font-size;
 | 
				
			||||||
 | 
					  i {
 | 
				
			||||||
 | 
					    font-size: $button-small-icon-font-size;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Block button
 | 
				
			||||||
 | 
					.btn-block {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										195
									
								
								app/static/external/materialize/sass/components/_cards.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								app/static/external/materialize/sass/components/_cards.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,195 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card-panel {
 | 
				
			||||||
 | 
					  transition: box-shadow .25s;
 | 
				
			||||||
 | 
					  padding: $card-padding;
 | 
				
			||||||
 | 
					  margin: $element-top-margin 0 $element-bottom-margin 0;
 | 
				
			||||||
 | 
					  border-radius: 2px;
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					  background-color: $card-bg-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  margin: $element-top-margin 0 $element-bottom-margin 0;
 | 
				
			||||||
 | 
					  background-color: $card-bg-color;
 | 
				
			||||||
 | 
					  transition: box-shadow .25s;
 | 
				
			||||||
 | 
					  border-radius: 2px;
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .card-title {
 | 
				
			||||||
 | 
					    font-size: 24px;
 | 
				
			||||||
 | 
					    font-weight: 300;
 | 
				
			||||||
 | 
					    &.activator {
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Card Sizes
 | 
				
			||||||
 | 
					  &.small, &.medium, &.large {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .card-image {
 | 
				
			||||||
 | 
					      max-height: 60%;
 | 
				
			||||||
 | 
					      overflow: hidden;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .card-image + .card-content {
 | 
				
			||||||
 | 
					      max-height: 40%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .card-content {
 | 
				
			||||||
 | 
					      max-height: 100%;
 | 
				
			||||||
 | 
					      overflow: hidden;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .card-action {
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      right: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.small {
 | 
				
			||||||
 | 
					    height: 300px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.medium {
 | 
				
			||||||
 | 
					    height: 400px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.large {
 | 
				
			||||||
 | 
					    height: 500px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Horizontal Cards
 | 
				
			||||||
 | 
					  &.horizontal {
 | 
				
			||||||
 | 
					    &.small, &.medium, &.large {
 | 
				
			||||||
 | 
					      .card-image {
 | 
				
			||||||
 | 
					        height: 100%;
 | 
				
			||||||
 | 
					        max-height: none;
 | 
				
			||||||
 | 
					        overflow: visible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        img {
 | 
				
			||||||
 | 
					          height: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .card-image {
 | 
				
			||||||
 | 
					      max-width: 50%;
 | 
				
			||||||
 | 
					      img {
 | 
				
			||||||
 | 
					        border-radius: 2px 0 0 2px;
 | 
				
			||||||
 | 
					        max-width: 100%;
 | 
				
			||||||
 | 
					        width: auto;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .card-stacked {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      flex-direction: column;
 | 
				
			||||||
 | 
					      flex: 1;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .card-content {
 | 
				
			||||||
 | 
					        flex-grow: 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Sticky Action Section
 | 
				
			||||||
 | 
					  &.sticky-action {
 | 
				
			||||||
 | 
					    .card-action {
 | 
				
			||||||
 | 
					      z-index: 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .card-reveal {
 | 
				
			||||||
 | 
					      z-index: 1;
 | 
				
			||||||
 | 
					      padding-bottom: 64px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .card-image {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Image background for content
 | 
				
			||||||
 | 
					    img {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      border-radius: 2px 2px 0 0;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      right: 0;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      width: 100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .card-title {
 | 
				
			||||||
 | 
					      color: $card-bg-color;
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      max-width: 100%;
 | 
				
			||||||
 | 
					      padding: $card-padding;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .card-content {
 | 
				
			||||||
 | 
					    padding: $card-padding;
 | 
				
			||||||
 | 
					    border-radius: 0 0 2px 2px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p {
 | 
				
			||||||
 | 
					      margin: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .card-title {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      line-height: 32px;
 | 
				
			||||||
 | 
					      margin-bottom: 8px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      i {
 | 
				
			||||||
 | 
					        line-height: 32px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .card-action {
 | 
				
			||||||
 | 
					    &:last-child {
 | 
				
			||||||
 | 
					      border-radius: 0 0 2px 2px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    background-color: inherit; // Use inherit to inherit color classes
 | 
				
			||||||
 | 
					    border-top: 1px solid rgba(160,160,160,.2);
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    padding: 16px $card-padding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a:not(.btn):not(.btn-large):not(.btn-floating) {
 | 
				
			||||||
 | 
					      color: $card-link-color;
 | 
				
			||||||
 | 
					      margin-right: $card-padding;
 | 
				
			||||||
 | 
					      transition: color .3s ease;
 | 
				
			||||||
 | 
					      text-transform: uppercase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &:hover { color: $card-link-color-light; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .card-reveal {
 | 
				
			||||||
 | 
					    padding: $card-padding;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    background-color: $card-bg-color;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    overflow-y: auto;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    top: 100%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    z-index: 3;
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .card-title {
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										90
									
								
								app/static/external/materialize/sass/components/_carousel.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								app/static/external/materialize/sass/components/_carousel.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					.carousel {
 | 
				
			||||||
 | 
					  &.carousel-slider {
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .carousel-fixed-item {
 | 
				
			||||||
 | 
					      &.with-indicators {
 | 
				
			||||||
 | 
					        bottom: 68px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      right: 0;
 | 
				
			||||||
 | 
					      bottom: 20px;
 | 
				
			||||||
 | 
					      z-index: 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .carousel-item {
 | 
				
			||||||
 | 
					      width: 100%;
 | 
				
			||||||
 | 
					      height: 100%;
 | 
				
			||||||
 | 
					      min-height: $carousel-height;
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      h2 {
 | 
				
			||||||
 | 
					        font-size: 24px;
 | 
				
			||||||
 | 
					        font-weight: 500;
 | 
				
			||||||
 | 
					        line-height: 32px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      p {
 | 
				
			||||||
 | 
					        font-size: 15px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: $carousel-height;
 | 
				
			||||||
 | 
					  perspective: 500px;
 | 
				
			||||||
 | 
					  transform-style: preserve-3d;
 | 
				
			||||||
 | 
					  transform-origin: 0% 50%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .carousel-item {
 | 
				
			||||||
 | 
					    visibility: hidden;
 | 
				
			||||||
 | 
					    width: $carousel-item-width;
 | 
				
			||||||
 | 
					    height: $carousel-item-height;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > img {
 | 
				
			||||||
 | 
					      width: 100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .indicators {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .indicator-item {
 | 
				
			||||||
 | 
					      &.active {
 | 
				
			||||||
 | 
					        background-color: #fff;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					      height: 8px;
 | 
				
			||||||
 | 
					      width: 8px;
 | 
				
			||||||
 | 
					      margin: 24px 4px;
 | 
				
			||||||
 | 
					      background-color: rgba(255,255,255,.5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      transition: background-color .3s;
 | 
				
			||||||
 | 
					      border-radius: 50%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Materialbox compatibility
 | 
				
			||||||
 | 
					  &.scrolling .carousel-item .materialboxed,
 | 
				
			||||||
 | 
					  .carousel-item:not(.active) .materialboxed {
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										90
									
								
								app/static/external/materialize/sass/components/_chips.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								app/static/external/materialize/sass/components/_chips.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					.chip {
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    outline: none;
 | 
				
			||||||
 | 
					    background-color: $chip-selected-color;
 | 
				
			||||||
 | 
					    color: #fff;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  height: 32px;
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  color: rgba(0,0,0,.6);
 | 
				
			||||||
 | 
					  line-height: 32px;
 | 
				
			||||||
 | 
					  padding: 0 12px;
 | 
				
			||||||
 | 
					  border-radius: 16px;
 | 
				
			||||||
 | 
					  background-color: $chip-bg-color;
 | 
				
			||||||
 | 
					  margin-bottom: $chip-margin;
 | 
				
			||||||
 | 
					  margin-right: $chip-margin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > img {
 | 
				
			||||||
 | 
					    float: left;
 | 
				
			||||||
 | 
					    margin: 0 8px 0 -12px;
 | 
				
			||||||
 | 
					    height: 32px;
 | 
				
			||||||
 | 
					    width: 32px;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .close {
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    float: right;
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    line-height: 32px;
 | 
				
			||||||
 | 
					    padding-left: 8px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.chips {
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  border-bottom: 1px solid $chip-border-color;
 | 
				
			||||||
 | 
					  box-shadow: none;
 | 
				
			||||||
 | 
					  margin: $input-margin;
 | 
				
			||||||
 | 
					  min-height: 45px;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  transition: all .3s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.focus {
 | 
				
			||||||
 | 
					    border-bottom: 1px solid $chip-selected-color;
 | 
				
			||||||
 | 
					    box-shadow: 0 1px 0 0 $chip-selected-color;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    cursor: text;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .input {
 | 
				
			||||||
 | 
					    background: none;
 | 
				
			||||||
 | 
					    border: 0;
 | 
				
			||||||
 | 
					    color: rgba(0,0,0,.6);
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    font-size: $input-font-size;
 | 
				
			||||||
 | 
					    height: $input-height;
 | 
				
			||||||
 | 
					    line-height: 32px;
 | 
				
			||||||
 | 
					    outline: 0;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    padding: 0 !important;
 | 
				
			||||||
 | 
					    width: 120px !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .input:focus {
 | 
				
			||||||
 | 
					    border: 0 !important;
 | 
				
			||||||
 | 
					    box-shadow: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Autocomplete
 | 
				
			||||||
 | 
					  .autocomplete-content {
 | 
				
			||||||
 | 
					    margin-top: 0;
 | 
				
			||||||
 | 
					    margin-bottom: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Form prefix
 | 
				
			||||||
 | 
					.prefix ~ .chips {
 | 
				
			||||||
 | 
					  margin-left: 3rem;
 | 
				
			||||||
 | 
					  width: 92%;
 | 
				
			||||||
 | 
					  width: calc(100% - 3rem);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.chips:empty ~ label  {
 | 
				
			||||||
 | 
					  font-size: 0.8rem;
 | 
				
			||||||
 | 
					  transform: translateY(-140%);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										91
									
								
								app/static/external/materialize/sass/components/_collapsible.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								app/static/external/materialize/sass/components/_collapsible.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					.collapsible {
 | 
				
			||||||
 | 
					  border-top: 1px solid $collapsible-border-color;
 | 
				
			||||||
 | 
					  border-right: 1px solid $collapsible-border-color;
 | 
				
			||||||
 | 
					  border-left: 1px solid $collapsible-border-color;
 | 
				
			||||||
 | 
					  margin: $element-top-margin 0 $element-bottom-margin 0;
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.collapsible-header {
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    outline: 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  -webkit-tap-highlight-color: transparent;
 | 
				
			||||||
 | 
					  line-height: 1.5;
 | 
				
			||||||
 | 
					  padding: 1rem;
 | 
				
			||||||
 | 
					  background-color: $collapsible-header-color;
 | 
				
			||||||
 | 
					  border-bottom: 1px solid $collapsible-border-color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  i {
 | 
				
			||||||
 | 
					    width: 2rem;
 | 
				
			||||||
 | 
					    font-size: 1.6rem;
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    margin-right: 1rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.keyboard-focused .collapsible-header:focus {
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.collapsible-body {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					  border-bottom: 1px solid $collapsible-border-color;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  padding: 2rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sidenav collapsible styling
 | 
				
			||||||
 | 
					.sidenav,
 | 
				
			||||||
 | 
					.sidenav.fixed {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .collapsible {
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    box-shadow: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    li { padding: 0; }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .collapsible-header {
 | 
				
			||||||
 | 
					    background-color: transparent;
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    line-height: inherit;
 | 
				
			||||||
 | 
					    height: inherit;
 | 
				
			||||||
 | 
					    padding: 0 $sidenav-padding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:hover { background-color: rgba(0,0,0,.05); }
 | 
				
			||||||
 | 
					    i { line-height: inherit; }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .collapsible-body {
 | 
				
			||||||
 | 
					    border: 0;
 | 
				
			||||||
 | 
					    background-color: $collapsible-header-color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    li a {
 | 
				
			||||||
 | 
					      padding: 0 (7.5px + $sidenav-padding)
 | 
				
			||||||
 | 
					               0 (15px + $sidenav-padding);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Popout Collapsible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.collapsible.popout {
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  box-shadow: none;
 | 
				
			||||||
 | 
					  > li {
 | 
				
			||||||
 | 
					    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
 | 
				
			||||||
 | 
					    // transform: scaleX(.92);
 | 
				
			||||||
 | 
					    margin: 0 24px;
 | 
				
			||||||
 | 
					    transition: margin .35s cubic-bezier(0.250, 0.460, 0.450, 0.940);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  > li.active {
 | 
				
			||||||
 | 
					    box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
 | 
				
			||||||
 | 
					    margin: 16px 0;
 | 
				
			||||||
 | 
					    // transform: scaleX(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								app/static/external/materialize/sass/components/_color-classes.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/static/external/materialize/sass/components/_color-classes.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					// Color Classes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@each $color_name, $color in $colors {
 | 
				
			||||||
 | 
					  @each $color_type, $color_value in $color {
 | 
				
			||||||
 | 
					    @if $color_type == "base" {
 | 
				
			||||||
 | 
					      .#{$color_name} {
 | 
				
			||||||
 | 
					        background-color: $color_value !important;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .#{$color_name}-text {
 | 
				
			||||||
 | 
					        color: $color_value !important;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @else if $color_name != "shades" {
 | 
				
			||||||
 | 
					      .#{$color_name}.#{$color_type} {
 | 
				
			||||||
 | 
					        background-color: $color_value !important;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .#{$color_name}-text.text-#{$color_type} {
 | 
				
			||||||
 | 
					        color: $color_value !important;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shade classes
 | 
				
			||||||
 | 
					@each $color, $color_value in $shades {
 | 
				
			||||||
 | 
					  .#{$color} {
 | 
				
			||||||
 | 
					    background-color: $color_value !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .#{$color}-text {
 | 
				
			||||||
 | 
					    color: $color_value !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										370
									
								
								app/static/external/materialize/sass/components/_color-variables.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										370
									
								
								app/static/external/materialize/sass/components/_color-variables.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,370 @@
 | 
				
			|||||||
 | 
					// Google Color Palette defined: http://www.google.com/design/spec/style/color.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$materialize-red: (
 | 
				
			||||||
 | 
					  "base":       #e51c23,
 | 
				
			||||||
 | 
					  "lighten-5":  #fdeaeb,
 | 
				
			||||||
 | 
					  "lighten-4":  #f8c1c3,
 | 
				
			||||||
 | 
					  "lighten-3":  #f3989b,
 | 
				
			||||||
 | 
					  "lighten-2":  #ee6e73,
 | 
				
			||||||
 | 
					  "lighten-1":  #ea454b,
 | 
				
			||||||
 | 
					  "darken-1":   #d0181e,
 | 
				
			||||||
 | 
					  "darken-2":   #b9151b,
 | 
				
			||||||
 | 
					  "darken-3":   #a21318,
 | 
				
			||||||
 | 
					  "darken-4":   #8b1014,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$red: (
 | 
				
			||||||
 | 
					  "base":       #F44336,
 | 
				
			||||||
 | 
					  "lighten-5":  #FFEBEE,
 | 
				
			||||||
 | 
					  "lighten-4":  #FFCDD2,
 | 
				
			||||||
 | 
					  "lighten-3":  #EF9A9A,
 | 
				
			||||||
 | 
					  "lighten-2":  #E57373,
 | 
				
			||||||
 | 
					  "lighten-1":  #EF5350,
 | 
				
			||||||
 | 
					  "darken-1":   #E53935,
 | 
				
			||||||
 | 
					  "darken-2":   #D32F2F,
 | 
				
			||||||
 | 
					  "darken-3":   #C62828,
 | 
				
			||||||
 | 
					  "darken-4":   #B71C1C,
 | 
				
			||||||
 | 
					  "accent-1":    #FF8A80,
 | 
				
			||||||
 | 
					  "accent-2":    #FF5252,
 | 
				
			||||||
 | 
					  "accent-3":    #FF1744,
 | 
				
			||||||
 | 
					  "accent-4":    #D50000
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$pink: (
 | 
				
			||||||
 | 
					  "base":       #e91e63,
 | 
				
			||||||
 | 
					  "lighten-5":  #fce4ec,
 | 
				
			||||||
 | 
					  "lighten-4":  #f8bbd0,
 | 
				
			||||||
 | 
					  "lighten-3":  #f48fb1,
 | 
				
			||||||
 | 
					  "lighten-2":  #f06292,
 | 
				
			||||||
 | 
					  "lighten-1":  #ec407a,
 | 
				
			||||||
 | 
					  "darken-1":   #d81b60,
 | 
				
			||||||
 | 
					  "darken-2":   #c2185b,
 | 
				
			||||||
 | 
					  "darken-3":   #ad1457,
 | 
				
			||||||
 | 
					  "darken-4":   #880e4f,
 | 
				
			||||||
 | 
					  "accent-1":    #ff80ab,
 | 
				
			||||||
 | 
					  "accent-2":    #ff4081,
 | 
				
			||||||
 | 
					  "accent-3":    #f50057,
 | 
				
			||||||
 | 
					  "accent-4":    #c51162
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$purple: (
 | 
				
			||||||
 | 
					  "base":       #9c27b0,
 | 
				
			||||||
 | 
					  "lighten-5":  #f3e5f5,
 | 
				
			||||||
 | 
					  "lighten-4":  #e1bee7,
 | 
				
			||||||
 | 
					  "lighten-3":  #ce93d8,
 | 
				
			||||||
 | 
					  "lighten-2":  #ba68c8,
 | 
				
			||||||
 | 
					  "lighten-1":  #ab47bc,
 | 
				
			||||||
 | 
					  "darken-1":   #8e24aa,
 | 
				
			||||||
 | 
					  "darken-2":   #7b1fa2,
 | 
				
			||||||
 | 
					  "darken-3":   #6a1b9a,
 | 
				
			||||||
 | 
					  "darken-4":   #4a148c,
 | 
				
			||||||
 | 
					  "accent-1":    #ea80fc,
 | 
				
			||||||
 | 
					  "accent-2":    #e040fb,
 | 
				
			||||||
 | 
					  "accent-3":    #d500f9,
 | 
				
			||||||
 | 
					  "accent-4":    #aa00ff
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$deep-purple: (
 | 
				
			||||||
 | 
					  "base":       #673ab7,
 | 
				
			||||||
 | 
					  "lighten-5":  #ede7f6,
 | 
				
			||||||
 | 
					  "lighten-4":  #d1c4e9,
 | 
				
			||||||
 | 
					  "lighten-3":  #b39ddb,
 | 
				
			||||||
 | 
					  "lighten-2":  #9575cd,
 | 
				
			||||||
 | 
					  "lighten-1":  #7e57c2,
 | 
				
			||||||
 | 
					  "darken-1":   #5e35b1,
 | 
				
			||||||
 | 
					  "darken-2":   #512da8,
 | 
				
			||||||
 | 
					  "darken-3":   #4527a0,
 | 
				
			||||||
 | 
					  "darken-4":   #311b92,
 | 
				
			||||||
 | 
					  "accent-1":    #b388ff,
 | 
				
			||||||
 | 
					  "accent-2":    #7c4dff,
 | 
				
			||||||
 | 
					  "accent-3":    #651fff,
 | 
				
			||||||
 | 
					  "accent-4":    #6200ea
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$indigo: (
 | 
				
			||||||
 | 
					  "base":       #3f51b5,
 | 
				
			||||||
 | 
					  "lighten-5":  #e8eaf6,
 | 
				
			||||||
 | 
					  "lighten-4":  #c5cae9,
 | 
				
			||||||
 | 
					  "lighten-3":  #9fa8da,
 | 
				
			||||||
 | 
					  "lighten-2":  #7986cb,
 | 
				
			||||||
 | 
					  "lighten-1":  #5c6bc0,
 | 
				
			||||||
 | 
					  "darken-1":   #3949ab,
 | 
				
			||||||
 | 
					  "darken-2":   #303f9f,
 | 
				
			||||||
 | 
					  "darken-3":   #283593,
 | 
				
			||||||
 | 
					  "darken-4":   #1a237e,
 | 
				
			||||||
 | 
					  "accent-1":    #8c9eff,
 | 
				
			||||||
 | 
					  "accent-2":    #536dfe,
 | 
				
			||||||
 | 
					  "accent-3":    #3d5afe,
 | 
				
			||||||
 | 
					  "accent-4":    #304ffe
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$blue: (
 | 
				
			||||||
 | 
					  "base":       #2196F3,
 | 
				
			||||||
 | 
					  "lighten-5":  #E3F2FD,
 | 
				
			||||||
 | 
					  "lighten-4":  #BBDEFB,
 | 
				
			||||||
 | 
					  "lighten-3":  #90CAF9,
 | 
				
			||||||
 | 
					  "lighten-2":  #64B5F6,
 | 
				
			||||||
 | 
					  "lighten-1":  #42A5F5,
 | 
				
			||||||
 | 
					  "darken-1":   #1E88E5,
 | 
				
			||||||
 | 
					  "darken-2":   #1976D2,
 | 
				
			||||||
 | 
					  "darken-3":   #1565C0,
 | 
				
			||||||
 | 
					  "darken-4":   #0D47A1,
 | 
				
			||||||
 | 
					  "accent-1":    #82B1FF,
 | 
				
			||||||
 | 
					  "accent-2":    #448AFF,
 | 
				
			||||||
 | 
					  "accent-3":    #2979FF,
 | 
				
			||||||
 | 
					  "accent-4":    #2962FF
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$light-blue: (
 | 
				
			||||||
 | 
					  "base":       #03a9f4,
 | 
				
			||||||
 | 
					  "lighten-5":  #e1f5fe,
 | 
				
			||||||
 | 
					  "lighten-4":  #b3e5fc,
 | 
				
			||||||
 | 
					  "lighten-3":  #81d4fa,
 | 
				
			||||||
 | 
					  "lighten-2":  #4fc3f7,
 | 
				
			||||||
 | 
					  "lighten-1":  #29b6f6,
 | 
				
			||||||
 | 
					  "darken-1":   #039be5,
 | 
				
			||||||
 | 
					  "darken-2":   #0288d1,
 | 
				
			||||||
 | 
					  "darken-3":   #0277bd,
 | 
				
			||||||
 | 
					  "darken-4":   #01579b,
 | 
				
			||||||
 | 
					  "accent-1":    #80d8ff,
 | 
				
			||||||
 | 
					  "accent-2":    #40c4ff,
 | 
				
			||||||
 | 
					  "accent-3":    #00b0ff,
 | 
				
			||||||
 | 
					  "accent-4":    #0091ea
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$cyan: (
 | 
				
			||||||
 | 
					  "base":       #00bcd4,
 | 
				
			||||||
 | 
					  "lighten-5":  #e0f7fa,
 | 
				
			||||||
 | 
					  "lighten-4":  #b2ebf2,
 | 
				
			||||||
 | 
					  "lighten-3":  #80deea,
 | 
				
			||||||
 | 
					  "lighten-2":  #4dd0e1,
 | 
				
			||||||
 | 
					  "lighten-1":  #26c6da,
 | 
				
			||||||
 | 
					  "darken-1":   #00acc1,
 | 
				
			||||||
 | 
					  "darken-2":   #0097a7,
 | 
				
			||||||
 | 
					  "darken-3":   #00838f,
 | 
				
			||||||
 | 
					  "darken-4":   #006064,
 | 
				
			||||||
 | 
					  "accent-1":    #84ffff,
 | 
				
			||||||
 | 
					  "accent-2":    #18ffff,
 | 
				
			||||||
 | 
					  "accent-3":    #00e5ff,
 | 
				
			||||||
 | 
					  "accent-4":    #00b8d4
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$teal: (
 | 
				
			||||||
 | 
					  "base":       #009688,
 | 
				
			||||||
 | 
					  "lighten-5":  #e0f2f1,
 | 
				
			||||||
 | 
					  "lighten-4":  #b2dfdb,
 | 
				
			||||||
 | 
					  "lighten-3":  #80cbc4,
 | 
				
			||||||
 | 
					  "lighten-2":  #4db6ac,
 | 
				
			||||||
 | 
					  "lighten-1":  #26a69a,
 | 
				
			||||||
 | 
					  "darken-1":   #00897b,
 | 
				
			||||||
 | 
					  "darken-2":   #00796b,
 | 
				
			||||||
 | 
					  "darken-3":   #00695c,
 | 
				
			||||||
 | 
					  "darken-4":   #004d40,
 | 
				
			||||||
 | 
					  "accent-1":    #a7ffeb,
 | 
				
			||||||
 | 
					  "accent-2":    #64ffda,
 | 
				
			||||||
 | 
					  "accent-3":    #1de9b6,
 | 
				
			||||||
 | 
					  "accent-4":    #00bfa5
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$green: (
 | 
				
			||||||
 | 
					  "base":       #4CAF50,
 | 
				
			||||||
 | 
					  "lighten-5":  #E8F5E9,
 | 
				
			||||||
 | 
					  "lighten-4":  #C8E6C9,
 | 
				
			||||||
 | 
					  "lighten-3":  #A5D6A7,
 | 
				
			||||||
 | 
					  "lighten-2":  #81C784,
 | 
				
			||||||
 | 
					  "lighten-1":  #66BB6A,
 | 
				
			||||||
 | 
					  "darken-1":   #43A047,
 | 
				
			||||||
 | 
					  "darken-2":   #388E3C,
 | 
				
			||||||
 | 
					  "darken-3":   #2E7D32,
 | 
				
			||||||
 | 
					  "darken-4":   #1B5E20,
 | 
				
			||||||
 | 
					  "accent-1":    #B9F6CA,
 | 
				
			||||||
 | 
					  "accent-2":    #69F0AE,
 | 
				
			||||||
 | 
					  "accent-3":    #00E676,
 | 
				
			||||||
 | 
					  "accent-4":    #00C853
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$light-green: (
 | 
				
			||||||
 | 
					  "base":       #8bc34a,
 | 
				
			||||||
 | 
					  "lighten-5":  #f1f8e9,
 | 
				
			||||||
 | 
					  "lighten-4":  #dcedc8,
 | 
				
			||||||
 | 
					  "lighten-3":  #c5e1a5,
 | 
				
			||||||
 | 
					  "lighten-2":  #aed581,
 | 
				
			||||||
 | 
					  "lighten-1":  #9ccc65,
 | 
				
			||||||
 | 
					  "darken-1":   #7cb342,
 | 
				
			||||||
 | 
					  "darken-2":   #689f38,
 | 
				
			||||||
 | 
					  "darken-3":   #558b2f,
 | 
				
			||||||
 | 
					  "darken-4":   #33691e,
 | 
				
			||||||
 | 
					  "accent-1":    #ccff90,
 | 
				
			||||||
 | 
					  "accent-2":    #b2ff59,
 | 
				
			||||||
 | 
					  "accent-3":    #76ff03,
 | 
				
			||||||
 | 
					  "accent-4":    #64dd17
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$lime: (
 | 
				
			||||||
 | 
					  "base":       #cddc39,
 | 
				
			||||||
 | 
					  "lighten-5":  #f9fbe7,
 | 
				
			||||||
 | 
					  "lighten-4":  #f0f4c3,
 | 
				
			||||||
 | 
					  "lighten-3":  #e6ee9c,
 | 
				
			||||||
 | 
					  "lighten-2":  #dce775,
 | 
				
			||||||
 | 
					  "lighten-1":  #d4e157,
 | 
				
			||||||
 | 
					  "darken-1":   #c0ca33,
 | 
				
			||||||
 | 
					  "darken-2":   #afb42b,
 | 
				
			||||||
 | 
					  "darken-3":   #9e9d24,
 | 
				
			||||||
 | 
					  "darken-4":   #827717,
 | 
				
			||||||
 | 
					  "accent-1":    #f4ff81,
 | 
				
			||||||
 | 
					  "accent-2":    #eeff41,
 | 
				
			||||||
 | 
					  "accent-3":    #c6ff00,
 | 
				
			||||||
 | 
					  "accent-4":    #aeea00
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$yellow: (
 | 
				
			||||||
 | 
					  "base":       #ffeb3b,
 | 
				
			||||||
 | 
					  "lighten-5":  #fffde7,
 | 
				
			||||||
 | 
					  "lighten-4":  #fff9c4,
 | 
				
			||||||
 | 
					  "lighten-3":  #fff59d,
 | 
				
			||||||
 | 
					  "lighten-2":  #fff176,
 | 
				
			||||||
 | 
					  "lighten-1":  #ffee58,
 | 
				
			||||||
 | 
					  "darken-1":   #fdd835,
 | 
				
			||||||
 | 
					  "darken-2":   #fbc02d,
 | 
				
			||||||
 | 
					  "darken-3":   #f9a825,
 | 
				
			||||||
 | 
					  "darken-4":   #f57f17,
 | 
				
			||||||
 | 
					  "accent-1":    #ffff8d,
 | 
				
			||||||
 | 
					  "accent-2":    #ffff00,
 | 
				
			||||||
 | 
					  "accent-3":    #ffea00,
 | 
				
			||||||
 | 
					  "accent-4":    #ffd600
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$amber: (
 | 
				
			||||||
 | 
					  "base":       #ffc107,
 | 
				
			||||||
 | 
					  "lighten-5":  #fff8e1,
 | 
				
			||||||
 | 
					  "lighten-4":  #ffecb3,
 | 
				
			||||||
 | 
					  "lighten-3":  #ffe082,
 | 
				
			||||||
 | 
					  "lighten-2":  #ffd54f,
 | 
				
			||||||
 | 
					  "lighten-1":  #ffca28,
 | 
				
			||||||
 | 
					  "darken-1":   #ffb300,
 | 
				
			||||||
 | 
					  "darken-2":   #ffa000,
 | 
				
			||||||
 | 
					  "darken-3":   #ff8f00,
 | 
				
			||||||
 | 
					  "darken-4":   #ff6f00,
 | 
				
			||||||
 | 
					  "accent-1":    #ffe57f,
 | 
				
			||||||
 | 
					  "accent-2":    #ffd740,
 | 
				
			||||||
 | 
					  "accent-3":    #ffc400,
 | 
				
			||||||
 | 
					  "accent-4":    #ffab00
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$orange: (
 | 
				
			||||||
 | 
					  "base":       #ff9800,
 | 
				
			||||||
 | 
					  "lighten-5":  #fff3e0,
 | 
				
			||||||
 | 
					  "lighten-4":  #ffe0b2,
 | 
				
			||||||
 | 
					  "lighten-3":  #ffcc80,
 | 
				
			||||||
 | 
					  "lighten-2":  #ffb74d,
 | 
				
			||||||
 | 
					  "lighten-1":  #ffa726,
 | 
				
			||||||
 | 
					  "darken-1":   #fb8c00,
 | 
				
			||||||
 | 
					  "darken-2":   #f57c00,
 | 
				
			||||||
 | 
					  "darken-3":   #ef6c00,
 | 
				
			||||||
 | 
					  "darken-4":   #e65100,
 | 
				
			||||||
 | 
					  "accent-1":    #ffd180,
 | 
				
			||||||
 | 
					  "accent-2":    #ffab40,
 | 
				
			||||||
 | 
					  "accent-3":    #ff9100,
 | 
				
			||||||
 | 
					  "accent-4":    #ff6d00
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$deep-orange: (
 | 
				
			||||||
 | 
					  "base":       #ff5722,
 | 
				
			||||||
 | 
					  "lighten-5":  #fbe9e7,
 | 
				
			||||||
 | 
					  "lighten-4":  #ffccbc,
 | 
				
			||||||
 | 
					  "lighten-3":  #ffab91,
 | 
				
			||||||
 | 
					  "lighten-2":  #ff8a65,
 | 
				
			||||||
 | 
					  "lighten-1":  #ff7043,
 | 
				
			||||||
 | 
					  "darken-1":   #f4511e,
 | 
				
			||||||
 | 
					  "darken-2":   #e64a19,
 | 
				
			||||||
 | 
					  "darken-3":   #d84315,
 | 
				
			||||||
 | 
					  "darken-4":   #bf360c,
 | 
				
			||||||
 | 
					  "accent-1":    #ff9e80,
 | 
				
			||||||
 | 
					  "accent-2":    #ff6e40,
 | 
				
			||||||
 | 
					  "accent-3":    #ff3d00,
 | 
				
			||||||
 | 
					  "accent-4":    #dd2c00
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$brown: (
 | 
				
			||||||
 | 
					  "base":       #795548,
 | 
				
			||||||
 | 
					  "lighten-5":  #efebe9,
 | 
				
			||||||
 | 
					  "lighten-4":  #d7ccc8,
 | 
				
			||||||
 | 
					  "lighten-3":  #bcaaa4,
 | 
				
			||||||
 | 
					  "lighten-2":  #a1887f,
 | 
				
			||||||
 | 
					  "lighten-1":  #8d6e63,
 | 
				
			||||||
 | 
					  "darken-1":   #6d4c41,
 | 
				
			||||||
 | 
					  "darken-2":   #5d4037,
 | 
				
			||||||
 | 
					  "darken-3":   #4e342e,
 | 
				
			||||||
 | 
					  "darken-4":   #3e2723
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$blue-grey: (
 | 
				
			||||||
 | 
					  "base":       #607d8b,
 | 
				
			||||||
 | 
					  "lighten-5":  #eceff1,
 | 
				
			||||||
 | 
					  "lighten-4":  #cfd8dc,
 | 
				
			||||||
 | 
					  "lighten-3":  #b0bec5,
 | 
				
			||||||
 | 
					  "lighten-2":  #90a4ae,
 | 
				
			||||||
 | 
					  "lighten-1":  #78909c,
 | 
				
			||||||
 | 
					  "darken-1":   #546e7a,
 | 
				
			||||||
 | 
					  "darken-2":   #455a64,
 | 
				
			||||||
 | 
					  "darken-3":   #37474f,
 | 
				
			||||||
 | 
					  "darken-4":   #263238
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$grey: (
 | 
				
			||||||
 | 
					  "base":       #9e9e9e,
 | 
				
			||||||
 | 
					  "lighten-5":  #fafafa,
 | 
				
			||||||
 | 
					  "lighten-4":  #f5f5f5,
 | 
				
			||||||
 | 
					  "lighten-3":  #eeeeee,
 | 
				
			||||||
 | 
					  "lighten-2":  #e0e0e0,
 | 
				
			||||||
 | 
					  "lighten-1":  #bdbdbd,
 | 
				
			||||||
 | 
					  "darken-1":   #757575,
 | 
				
			||||||
 | 
					  "darken-2":   #616161,
 | 
				
			||||||
 | 
					  "darken-3":   #424242,
 | 
				
			||||||
 | 
					  "darken-4":   #212121
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$shades: (
 | 
				
			||||||
 | 
					  "black":        #000000,
 | 
				
			||||||
 | 
					  "white":        #FFFFFF,
 | 
				
			||||||
 | 
					  "transparent":  transparent
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$colors: (
 | 
				
			||||||
 | 
					  "materialize-red": $materialize-red,
 | 
				
			||||||
 | 
					  "red": $red,
 | 
				
			||||||
 | 
					  "pink": $pink,
 | 
				
			||||||
 | 
					  "purple": $purple,
 | 
				
			||||||
 | 
					  "deep-purple": $deep-purple,
 | 
				
			||||||
 | 
					  "indigo": $indigo,
 | 
				
			||||||
 | 
					  "blue": $blue,
 | 
				
			||||||
 | 
					  "light-blue": $light-blue,
 | 
				
			||||||
 | 
					  "cyan": $cyan,
 | 
				
			||||||
 | 
					  "teal": $teal,
 | 
				
			||||||
 | 
					  "green": $green,
 | 
				
			||||||
 | 
					  "light-green": $light-green,
 | 
				
			||||||
 | 
					  "lime": $lime,
 | 
				
			||||||
 | 
					  "yellow": $yellow,
 | 
				
			||||||
 | 
					  "amber": $amber,
 | 
				
			||||||
 | 
					  "orange": $orange,
 | 
				
			||||||
 | 
					  "deep-orange": $deep-orange,
 | 
				
			||||||
 | 
					  "brown": $brown,
 | 
				
			||||||
 | 
					  "blue-grey": $blue-grey,
 | 
				
			||||||
 | 
					  "grey": $grey,
 | 
				
			||||||
 | 
					  "shades": $shades
 | 
				
			||||||
 | 
					) !default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// usage: color("name_of_color", "type_of_color")
 | 
				
			||||||
 | 
					// to avoid to repeating map-get($colors, ...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@function color($color, $type) {
 | 
				
			||||||
 | 
					  @if map-has-key($colors, $color) {
 | 
				
			||||||
 | 
					    $curr_color: map-get($colors, $color);
 | 
				
			||||||
 | 
					    @if map-has-key($curr_color, $type) {
 | 
				
			||||||
 | 
					      @return map-get($curr_color, $type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  @warn "Unknown `#{$color}` - `#{$type}` in $colors.";
 | 
				
			||||||
 | 
					  @return null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										191
									
								
								app/static/external/materialize/sass/components/_datepicker.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								app/static/external/materialize/sass/components/_datepicker.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					/* Modal */
 | 
				
			||||||
 | 
					.datepicker-modal {
 | 
				
			||||||
 | 
					  max-width: 325px;
 | 
				
			||||||
 | 
					  min-width: 300px;
 | 
				
			||||||
 | 
					  max-height: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.datepicker-container.modal-content {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.datepicker-controls {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  width: 280px;
 | 
				
			||||||
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .selects-container {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .select-wrapper {
 | 
				
			||||||
 | 
					    input {
 | 
				
			||||||
 | 
					      &:focus {
 | 
				
			||||||
 | 
					        border-bottom: none;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      border-bottom: none;
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					      margin: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .caret {
 | 
				
			||||||
 | 
					      display: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .select-year input {
 | 
				
			||||||
 | 
					    width: 50px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .select-month input {
 | 
				
			||||||
 | 
					    width: 70px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.month-prev, .month-next {
 | 
				
			||||||
 | 
					  margin-top: 4px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  background-color: transparent;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Date Display */
 | 
				
			||||||
 | 
					.datepicker-date-display {
 | 
				
			||||||
 | 
					  flex: 1 auto;
 | 
				
			||||||
 | 
					  background-color: $secondary-color;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  padding: 20px 22px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .year-text {
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    font-size: 1.5rem;
 | 
				
			||||||
 | 
					    line-height: 25px;
 | 
				
			||||||
 | 
					    color: $datepicker-year;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .date-text {
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    font-size: 2.8rem;
 | 
				
			||||||
 | 
					    line-height: 47px;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Calendar */
 | 
				
			||||||
 | 
					.datepicker-calendar-container {
 | 
				
			||||||
 | 
					  flex: 2.5 auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.datepicker-table {
 | 
				
			||||||
 | 
					  width: 280px;
 | 
				
			||||||
 | 
					  font-size: 1rem;
 | 
				
			||||||
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  thead {
 | 
				
			||||||
 | 
					    border-bottom: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  th {
 | 
				
			||||||
 | 
					    padding: 10px 5px;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tr {
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  abbr {
 | 
				
			||||||
 | 
					    text-decoration: none;
 | 
				
			||||||
 | 
					    color: $datepicker-calendar-header-color;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  td {
 | 
				
			||||||
 | 
					    &.is-today {
 | 
				
			||||||
 | 
					      color: $secondary-color;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.is-selected {
 | 
				
			||||||
 | 
					      background-color: $secondary-color;
 | 
				
			||||||
 | 
					      color: #fff;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.is-outside-current-month,
 | 
				
			||||||
 | 
					    &.is-disabled {
 | 
				
			||||||
 | 
					      color: $datepicker-disabled-day-color;
 | 
				
			||||||
 | 
					      pointer-events: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.datepicker-day-button {
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    background-color: $datepicker-day-focus;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  background-color: transparent;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  line-height: 38px;
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  padding: 0 5px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  color: inherit;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Footer */
 | 
				
			||||||
 | 
					.datepicker-footer {
 | 
				
			||||||
 | 
					  width: 280px;
 | 
				
			||||||
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					  padding-bottom: 5px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.datepicker-cancel,
 | 
				
			||||||
 | 
					.datepicker-clear,
 | 
				
			||||||
 | 
					.datepicker-today,
 | 
				
			||||||
 | 
					.datepicker-done {
 | 
				
			||||||
 | 
					  color: $secondary-color;
 | 
				
			||||||
 | 
					  padding: 0 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.datepicker-clear {
 | 
				
			||||||
 | 
					  color: $error-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Media Queries */
 | 
				
			||||||
 | 
					@media #{$medium-and-up} {
 | 
				
			||||||
 | 
					  .datepicker-modal {
 | 
				
			||||||
 | 
					    max-width: 625px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .datepicker-container.modal-content {
 | 
				
			||||||
 | 
					    flex-direction: row;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .datepicker-date-display {
 | 
				
			||||||
 | 
					    flex: 0 1 270px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .datepicker-controls,
 | 
				
			||||||
 | 
					  .datepicker-table,
 | 
				
			||||||
 | 
					  .datepicker-footer {
 | 
				
			||||||
 | 
					    width: 320px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .datepicker-day-button {
 | 
				
			||||||
 | 
					    line-height: 44px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										85
									
								
								app/static/external/materialize/sass/components/_dropdown.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								app/static/external/materialize/sass/components/_dropdown.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					.dropdown-content {
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    outline: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					  background-color: $dropdown-bg-color;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					  min-width: 100px;
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					  opacity: 0;
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  z-index: 9999; // TODO: Check if this doesn't break other things
 | 
				
			||||||
 | 
					  transform-origin: 0 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  li {
 | 
				
			||||||
 | 
					    &:hover, &.active {
 | 
				
			||||||
 | 
					      background-color: $dropdown-hover-bg-color;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:focus {
 | 
				
			||||||
 | 
					      outline: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.divider {
 | 
				
			||||||
 | 
					      min-height: 0;
 | 
				
			||||||
 | 
					      height: 1px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > a, & > span {
 | 
				
			||||||
 | 
					      font-size: 16px;
 | 
				
			||||||
 | 
					      color: $dropdown-color;
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      line-height: 22px;
 | 
				
			||||||
 | 
					      padding: (($dropdown-item-height - 22) / 2) 16px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > span > label {
 | 
				
			||||||
 | 
					      top: 1px;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      height: 18px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Icon alignment override
 | 
				
			||||||
 | 
					    & > a > i {
 | 
				
			||||||
 | 
					      height: inherit;
 | 
				
			||||||
 | 
					      line-height: inherit;
 | 
				
			||||||
 | 
					      float: left;
 | 
				
			||||||
 | 
					      margin: 0 24px 0 0;
 | 
				
			||||||
 | 
					      width: 24px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clear: both;
 | 
				
			||||||
 | 
					    color: $off-black;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    min-height: $dropdown-item-height;
 | 
				
			||||||
 | 
					    line-height: 1.5rem;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    text-align: left;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body.keyboard-focused {
 | 
				
			||||||
 | 
					  .dropdown-content li:focus {
 | 
				
			||||||
 | 
					    background-color: darken($dropdown-hover-bg-color, 8%);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Input field specificity bugfix
 | 
				
			||||||
 | 
					.input-field.col .dropdown-content [type="checkbox"] + label {
 | 
				
			||||||
 | 
					  top: 1px;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  height: 18px;
 | 
				
			||||||
 | 
					  transform: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.dropdown-trigger {
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										769
									
								
								app/static/external/materialize/sass/components/_global.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										769
									
								
								app/static/external/materialize/sass/components/_global.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,769 @@
 | 
				
			|||||||
 | 
					//Default styles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					html {
 | 
				
			||||||
 | 
					 box-sizing: border-box;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*, *:before, *:after {
 | 
				
			||||||
 | 
					 box-sizing: inherit;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					  // display: flex;
 | 
				
			||||||
 | 
					  // min-height: 100vh;
 | 
				
			||||||
 | 
					  // flex-direction: column;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					  // flex: 1 0 auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button,
 | 
				
			||||||
 | 
					input,
 | 
				
			||||||
 | 
					optgroup,
 | 
				
			||||||
 | 
					select,
 | 
				
			||||||
 | 
					textarea {
 | 
				
			||||||
 | 
					  font-family: $font-stack;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ul {
 | 
				
			||||||
 | 
					  &:not(.browser-default) {
 | 
				
			||||||
 | 
					    padding-left: 0;
 | 
				
			||||||
 | 
					    list-style-type: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > li {
 | 
				
			||||||
 | 
					      list-style-type: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
						color: $link-color;
 | 
				
			||||||
 | 
						text-decoration: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Gets rid of tap active state
 | 
				
			||||||
 | 
					  -webkit-tap-highlight-color: transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Positioning
 | 
				
			||||||
 | 
					.valign-wrapper {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// classic clearfix
 | 
				
			||||||
 | 
					.clearfix {
 | 
				
			||||||
 | 
					  clear: both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Z-levels
 | 
				
			||||||
 | 
					.z-depth-0 {
 | 
				
			||||||
 | 
					  box-shadow: none !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 2dp elevation modified*/
 | 
				
			||||||
 | 
					.z-depth-1 {
 | 
				
			||||||
 | 
					  box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14),
 | 
				
			||||||
 | 
					              0 3px 1px -2px rgba(0,0,0,0.12),
 | 
				
			||||||
 | 
					              0 1px 5px 0 rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.z-depth-1-half {
 | 
				
			||||||
 | 
					  box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 6dp elevation modified*/
 | 
				
			||||||
 | 
					.z-depth-2 {
 | 
				
			||||||
 | 
					  box-shadow: 0 4px 5px 0 rgba(0,0,0,0.14),
 | 
				
			||||||
 | 
					              0 1px 10px 0 rgba(0,0,0,0.12),
 | 
				
			||||||
 | 
					              0 2px 4px -1px rgba(0,0,0,0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 12dp elevation modified*/
 | 
				
			||||||
 | 
					.z-depth-3 {
 | 
				
			||||||
 | 
					  box-shadow: 0 8px 17px 2px rgba(0,0,0,0.14),
 | 
				
			||||||
 | 
					              0 3px 14px 2px rgba(0,0,0,0.12),
 | 
				
			||||||
 | 
					              0 5px 5px -3px rgba(0, 0, 0, 0.2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 16dp elevation */
 | 
				
			||||||
 | 
					.z-depth-4 {
 | 
				
			||||||
 | 
					  box-shadow: 0 16px 24px 2px rgba(0,0,0,0.14),
 | 
				
			||||||
 | 
					              0 6px 30px 5px rgba(0,0,0,0.12),
 | 
				
			||||||
 | 
					              0 8px 10px -7px rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 24dp elevation */
 | 
				
			||||||
 | 
					.z-depth-5 {
 | 
				
			||||||
 | 
					  box-shadow: 0 24px 38px 3px rgba(0,0,0,0.14),
 | 
				
			||||||
 | 
					              0 9px 46px 8px rgba(0,0,0,0.12),
 | 
				
			||||||
 | 
					              0 11px 15px -7px rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.hoverable {
 | 
				
			||||||
 | 
					  transition: box-shadow .25s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Dividers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.divider {
 | 
				
			||||||
 | 
					  height: 1px;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  background-color: color("grey", "lighten-2");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Blockquote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					blockquote {
 | 
				
			||||||
 | 
					  margin: 20px 0;
 | 
				
			||||||
 | 
					  padding-left: 1.5rem;
 | 
				
			||||||
 | 
					  border-left: 5px solid $primary-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Icon Styles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					i {
 | 
				
			||||||
 | 
					  line-height: inherit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.left {
 | 
				
			||||||
 | 
					    float: left;
 | 
				
			||||||
 | 
					    margin-right: 15px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.right {
 | 
				
			||||||
 | 
					    float: right;
 | 
				
			||||||
 | 
					    margin-left: 15px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.tiny {
 | 
				
			||||||
 | 
					    font-size: 1rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.small {
 | 
				
			||||||
 | 
					    font-size: 2rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.medium {
 | 
				
			||||||
 | 
					    font-size: 4rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.large {
 | 
				
			||||||
 | 
					    font-size: 6rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Images
 | 
				
			||||||
 | 
					img.responsive-img,
 | 
				
			||||||
 | 
					video.responsive-video {
 | 
				
			||||||
 | 
					  max-width: 100%;
 | 
				
			||||||
 | 
					  height: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pagination
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pagination {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  li {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    border-radius: 2px;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    vertical-align: top;
 | 
				
			||||||
 | 
					    height: 30px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a {
 | 
				
			||||||
 | 
					      color: #444;
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					      font-size: 1.2rem;
 | 
				
			||||||
 | 
					      padding: 0 10px;
 | 
				
			||||||
 | 
					      line-height: 30px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.active a { color: #fff; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.active { background-color: $primary-color; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.disabled a {
 | 
				
			||||||
 | 
					      cursor: default;
 | 
				
			||||||
 | 
					      color: #999;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i {
 | 
				
			||||||
 | 
					      font-size: 2rem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  li.pages ul li {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    float: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@media #{$medium-and-down} {
 | 
				
			||||||
 | 
					  .pagination {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    li.prev,
 | 
				
			||||||
 | 
					    li.next {
 | 
				
			||||||
 | 
					      width: 10%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    li.pages {
 | 
				
			||||||
 | 
					      width: 80%;
 | 
				
			||||||
 | 
					      overflow: hidden;
 | 
				
			||||||
 | 
					      white-space: nowrap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Breadcrumbs
 | 
				
			||||||
 | 
					.breadcrumb {
 | 
				
			||||||
 | 
					  font-size: 18px;
 | 
				
			||||||
 | 
					  color: rgba(255,255,255, .7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  i,
 | 
				
			||||||
 | 
					  [class^="mdi-"], [class*="mdi-"],
 | 
				
			||||||
 | 
					  i.material-icons {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    float: left;
 | 
				
			||||||
 | 
					    font-size: 24px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:before {
 | 
				
			||||||
 | 
					    content: '\E5CC';
 | 
				
			||||||
 | 
					    color: rgba(255,255,255, .7);
 | 
				
			||||||
 | 
					    vertical-align: top;
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    font-family: 'Material Icons';
 | 
				
			||||||
 | 
					    font-weight: normal;
 | 
				
			||||||
 | 
					    font-style: normal;
 | 
				
			||||||
 | 
					    font-size: 25px;
 | 
				
			||||||
 | 
					    margin: 0 10px 0 8px;
 | 
				
			||||||
 | 
					    -webkit-font-smoothing: antialiased;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:first-child:before {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:last-child {
 | 
				
			||||||
 | 
					    color: #fff;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Parallax
 | 
				
			||||||
 | 
					.parallax-container {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  height: 500px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .parallax {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    z-index: -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    img {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      left: 50%;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      min-width: 100%;
 | 
				
			||||||
 | 
					      min-height: 100%;
 | 
				
			||||||
 | 
					      transform: translate3d(0,0,0);
 | 
				
			||||||
 | 
					      transform: translateX(-50%);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pushpin
 | 
				
			||||||
 | 
					.pin-top, .pin-bottom {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.pinned {
 | 
				
			||||||
 | 
					  position: fixed !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*********************
 | 
				
			||||||
 | 
					  Transition Classes
 | 
				
			||||||
 | 
					**********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ul.staggered-list li {
 | 
				
			||||||
 | 
					  opacity: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fade-in {
 | 
				
			||||||
 | 
					  opacity: 0;
 | 
				
			||||||
 | 
					  transform-origin: 0 50%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*********************
 | 
				
			||||||
 | 
					  Media Query Classes
 | 
				
			||||||
 | 
					**********************/
 | 
				
			||||||
 | 
					.hide-on-small-only, .hide-on-small-and-down {
 | 
				
			||||||
 | 
					  @media #{$small-and-down} {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.hide-on-med-and-down {
 | 
				
			||||||
 | 
					  @media #{$medium-and-down} {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.hide-on-med-and-up {
 | 
				
			||||||
 | 
					  @media #{$medium-and-up} {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.hide-on-med-only {
 | 
				
			||||||
 | 
					  @media only screen and (min-width: $small-screen) and (max-width: $medium-screen) {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.hide-on-large-only {
 | 
				
			||||||
 | 
					  @media #{$large-and-up} {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.hide-on-extra-large-only {
 | 
				
			||||||
 | 
					  @media #{$extra-large-and-up} {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.show-on-extra-large {
 | 
				
			||||||
 | 
					  @media #{$extra-large-and-up} {
 | 
				
			||||||
 | 
					    display: block !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.show-on-large {
 | 
				
			||||||
 | 
					  @media #{$large-and-up} {
 | 
				
			||||||
 | 
					    display: block !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.show-on-medium {
 | 
				
			||||||
 | 
					  @media only screen and (min-width: $small-screen) and (max-width: $medium-screen) {
 | 
				
			||||||
 | 
					    display: block !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.show-on-small {
 | 
				
			||||||
 | 
					  @media #{$small-and-down} {
 | 
				
			||||||
 | 
					    display: block !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.show-on-medium-and-up {
 | 
				
			||||||
 | 
					  @media #{$medium-and-up} {
 | 
				
			||||||
 | 
					    display: block !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.show-on-medium-and-down {
 | 
				
			||||||
 | 
					  @media #{$medium-and-down} {
 | 
				
			||||||
 | 
					    display: block !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Center text on mobile
 | 
				
			||||||
 | 
					.center-on-small-only {
 | 
				
			||||||
 | 
					  @media #{$small-and-down} {
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Footer
 | 
				
			||||||
 | 
					.page-footer {
 | 
				
			||||||
 | 
					  padding-top: 20px;
 | 
				
			||||||
 | 
					  color: $footer-font-color;
 | 
				
			||||||
 | 
					  background-color: $footer-bg-color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .footer-copyright {
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    min-height: 50px;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    justify-content: space-between;
 | 
				
			||||||
 | 
					    padding: 10px 0px;
 | 
				
			||||||
 | 
					    color: $footer-copyright-font-color;
 | 
				
			||||||
 | 
					    background-color: $footer-copyright-bg-color;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tables
 | 
				
			||||||
 | 
					table, th, td {
 | 
				
			||||||
 | 
					   border: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table {
 | 
				
			||||||
 | 
					  width:100%;
 | 
				
			||||||
 | 
					  display: table;
 | 
				
			||||||
 | 
					  border-collapse: collapse;
 | 
				
			||||||
 | 
					  border-spacing: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.striped {
 | 
				
			||||||
 | 
					    tr {
 | 
				
			||||||
 | 
					      border-bottom: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > tbody {
 | 
				
			||||||
 | 
					      > tr:nth-child(odd) {
 | 
				
			||||||
 | 
					        background-color: $table-striped-color;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      > tr > td {
 | 
				
			||||||
 | 
					        border-radius: 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.highlight > tbody > tr {
 | 
				
			||||||
 | 
					    transition: background-color .25s ease;
 | 
				
			||||||
 | 
					    &:hover {
 | 
				
			||||||
 | 
					      background-color: $table-striped-color;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.centered {
 | 
				
			||||||
 | 
					    thead tr th, tbody tr td {
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tr {
 | 
				
			||||||
 | 
					  border-bottom: 1px solid $table-border-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td, th{
 | 
				
			||||||
 | 
					  padding: 15px 5px;
 | 
				
			||||||
 | 
					  display: table-cell;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  vertical-align: middle;
 | 
				
			||||||
 | 
					  border-radius: 2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Responsive Table
 | 
				
			||||||
 | 
					@media #{$medium-and-down} {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  table.responsive-table {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    border-collapse: collapse;
 | 
				
			||||||
 | 
					    border-spacing: 0;
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    td:empty:before {
 | 
				
			||||||
 | 
					      content: '\00a0';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    th,
 | 
				
			||||||
 | 
					    td {
 | 
				
			||||||
 | 
					      margin: 0;
 | 
				
			||||||
 | 
					      vertical-align: top;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    th { text-align: left; }
 | 
				
			||||||
 | 
					    thead {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      float: left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      tr {
 | 
				
			||||||
 | 
					        display: block;
 | 
				
			||||||
 | 
					        padding: 0 10px 0 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        th::before {
 | 
				
			||||||
 | 
					          content: "\00a0";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    tbody {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      width: auto;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      overflow-x: auto;
 | 
				
			||||||
 | 
					      white-space: nowrap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      tr {
 | 
				
			||||||
 | 
					        display: inline-block;
 | 
				
			||||||
 | 
					        vertical-align: top;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    th {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      text-align: right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    td {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      min-height: 1.25em;
 | 
				
			||||||
 | 
					      text-align: left;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    tr {
 | 
				
			||||||
 | 
					      border-bottom: none;
 | 
				
			||||||
 | 
					      padding: 0 10px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* sort out borders */
 | 
				
			||||||
 | 
					    thead {
 | 
				
			||||||
 | 
					      border: 0;
 | 
				
			||||||
 | 
					      border-right: 1px solid $table-border-color;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Collections
 | 
				
			||||||
 | 
					.collection {
 | 
				
			||||||
 | 
					  margin: $element-top-margin 0 $element-bottom-margin 0;
 | 
				
			||||||
 | 
					  border: 1px solid $collection-border-color;
 | 
				
			||||||
 | 
					  border-radius: 2px;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .collection-item {
 | 
				
			||||||
 | 
					    background-color: $collection-bg-color;
 | 
				
			||||||
 | 
					    line-height: $collection-line-height;
 | 
				
			||||||
 | 
					    padding: 10px 20px;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    border-bottom: 1px solid $collection-border-color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Avatar Collection
 | 
				
			||||||
 | 
					    &.avatar {
 | 
				
			||||||
 | 
					      min-height: 84px;
 | 
				
			||||||
 | 
					      padding-left: 72px;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Don't style circles inside preloader classes.
 | 
				
			||||||
 | 
					      &:not(.circle-clipper) > .circle,
 | 
				
			||||||
 | 
					      :not(.circle-clipper) > .circle {
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        width: 42px;
 | 
				
			||||||
 | 
					        height: 42px;
 | 
				
			||||||
 | 
					        overflow: hidden;
 | 
				
			||||||
 | 
					        left: 15px;
 | 
				
			||||||
 | 
					        display: inline-block;
 | 
				
			||||||
 | 
					        vertical-align: middle;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      i.circle {
 | 
				
			||||||
 | 
					        font-size: 18px;
 | 
				
			||||||
 | 
					        line-height: 42px;
 | 
				
			||||||
 | 
					        color: #fff;
 | 
				
			||||||
 | 
					        background-color: #999;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .title {
 | 
				
			||||||
 | 
					        font-size: 16px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      p {
 | 
				
			||||||
 | 
					        margin: 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .secondary-content {
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        top: 16px;
 | 
				
			||||||
 | 
					        right: 16px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:last-child {
 | 
				
			||||||
 | 
					      border-bottom: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.active {
 | 
				
			||||||
 | 
					      background-color: $collection-active-bg-color;
 | 
				
			||||||
 | 
					      color: $collection-active-color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .secondary-content {
 | 
				
			||||||
 | 
					        color: #fff;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  a.collection-item{
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    transition: .25s;
 | 
				
			||||||
 | 
					    color: $collection-link-color;
 | 
				
			||||||
 | 
					    &:not(.active) {
 | 
				
			||||||
 | 
					      &:hover {
 | 
				
			||||||
 | 
					        background-color: $collection-hover-bg-color;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.with-header {
 | 
				
			||||||
 | 
					    .collection-header {
 | 
				
			||||||
 | 
					      background-color: $collection-bg-color;
 | 
				
			||||||
 | 
					      border-bottom: 1px solid $collection-border-color;
 | 
				
			||||||
 | 
					      padding: 10px 20px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .collection-item {
 | 
				
			||||||
 | 
					      padding-left: 30px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .collection-item.avatar {
 | 
				
			||||||
 | 
					      padding-left: 72px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// Made less specific to allow easier overriding
 | 
				
			||||||
 | 
					.secondary-content {
 | 
				
			||||||
 | 
					  float: right;
 | 
				
			||||||
 | 
					  color: $secondary-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.collapsible .collection {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Responsive Videos
 | 
				
			||||||
 | 
					.video-container {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    padding-bottom: 56.25%;
 | 
				
			||||||
 | 
					    height: 0;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iframe, object, embed {
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      width: 100%;
 | 
				
			||||||
 | 
					      height: 100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Progress Bar
 | 
				
			||||||
 | 
					.progress {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    height: 4px;
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    background-color: lighten($progress-bar-color, 40%);
 | 
				
			||||||
 | 
					    border-radius: 2px;
 | 
				
			||||||
 | 
					    margin: $element-top-margin 0 $element-bottom-margin 0;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					  .determinate {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    background-color: $progress-bar-color;
 | 
				
			||||||
 | 
					    transition: width .3s linear;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .indeterminate {
 | 
				
			||||||
 | 
					    background-color: $progress-bar-color;
 | 
				
			||||||
 | 
					    &:before {
 | 
				
			||||||
 | 
					      content: '';
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      background-color: inherit;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      left:0;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      will-change: left, right;
 | 
				
			||||||
 | 
					      // Custom bezier
 | 
				
			||||||
 | 
					      animation: indeterminate 2.1s cubic-bezier(0.650, 0.815, 0.735, 0.395) infinite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    &:after {
 | 
				
			||||||
 | 
					      content: '';
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      background-color: inherit;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      left:0;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      will-change: left, right;
 | 
				
			||||||
 | 
					      // Custom bezier
 | 
				
			||||||
 | 
					      animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.840, 0.440, 1.000) infinite;
 | 
				
			||||||
 | 
					      animation-delay: 1.15s;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@keyframes indeterminate {
 | 
				
			||||||
 | 
					    0% {
 | 
				
			||||||
 | 
					      left: -35%;
 | 
				
			||||||
 | 
					      right:100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    60% {
 | 
				
			||||||
 | 
					      left: 100%;
 | 
				
			||||||
 | 
					      right: -90%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    100% {
 | 
				
			||||||
 | 
					      left: 100%;
 | 
				
			||||||
 | 
					      right: -90%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes indeterminate-short {
 | 
				
			||||||
 | 
					    0% {
 | 
				
			||||||
 | 
					      left: -200%;
 | 
				
			||||||
 | 
					      right: 100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    60% {
 | 
				
			||||||
 | 
					      left: 107%;
 | 
				
			||||||
 | 
					      right: -8%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    100% {
 | 
				
			||||||
 | 
					      left: 107%;
 | 
				
			||||||
 | 
					      right: -8%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*******************
 | 
				
			||||||
 | 
					  Utility Classes
 | 
				
			||||||
 | 
					*******************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.hide {
 | 
				
			||||||
 | 
					  display: none !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Text Align
 | 
				
			||||||
 | 
					.left-align {
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.right-align {
 | 
				
			||||||
 | 
					  text-align: right
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.center, .center-align {
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.left {
 | 
				
			||||||
 | 
					  float: left !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.right {
 | 
				
			||||||
 | 
					  float: right !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// No Text Select
 | 
				
			||||||
 | 
					.no-select {
 | 
				
			||||||
 | 
					  user-select: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.circle {
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.center-block {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  margin-left: auto;
 | 
				
			||||||
 | 
					  margin-right: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.truncate {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.no-padding {
 | 
				
			||||||
 | 
					  padding: 0 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										156
									
								
								app/static/external/materialize/sass/components/_grid.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								app/static/external/materialize/sass/components/_grid.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					.container {
 | 
				
			||||||
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					  max-width: 1280px;
 | 
				
			||||||
 | 
					  width: 90%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@media #{$medium-and-up} {
 | 
				
			||||||
 | 
					  .container {
 | 
				
			||||||
 | 
					    width: 85%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@media #{$large-and-up} {
 | 
				
			||||||
 | 
					  .container {
 | 
				
			||||||
 | 
					    width: 70%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.col .row {
 | 
				
			||||||
 | 
					  margin-left: (-1 * $gutter-width / 2);
 | 
				
			||||||
 | 
					  margin-right: (-1 * $gutter-width / 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.section {
 | 
				
			||||||
 | 
					  padding-top: 1rem;
 | 
				
			||||||
 | 
					  padding-bottom: 1rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.no-pad {
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.no-pad-bot {
 | 
				
			||||||
 | 
					    padding-bottom: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.no-pad-top {
 | 
				
			||||||
 | 
					    padding-top: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mixins to eliminate code repitition
 | 
				
			||||||
 | 
					@mixin reset-offset {
 | 
				
			||||||
 | 
					  margin-left: auto;
 | 
				
			||||||
 | 
					  left: auto;
 | 
				
			||||||
 | 
					  right: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@mixin grid-classes($size, $i, $perc) {
 | 
				
			||||||
 | 
					  &.offset-#{$size}#{$i} {
 | 
				
			||||||
 | 
					    margin-left: $perc;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.pull-#{$size}#{$i} {
 | 
				
			||||||
 | 
					    right: $perc;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.push-#{$size}#{$i} {
 | 
				
			||||||
 | 
					    left: $perc;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.row {
 | 
				
			||||||
 | 
					  margin-left: auto;
 | 
				
			||||||
 | 
					  margin-right: auto;
 | 
				
			||||||
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Clear floating children
 | 
				
			||||||
 | 
					  &:after {
 | 
				
			||||||
 | 
					    content: "";
 | 
				
			||||||
 | 
					    display: table;
 | 
				
			||||||
 | 
					    clear: both;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .col {
 | 
				
			||||||
 | 
					    float: left;
 | 
				
			||||||
 | 
					    box-sizing: border-box;
 | 
				
			||||||
 | 
					    padding: 0 $gutter-width / 2;
 | 
				
			||||||
 | 
					    min-height: 1px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &[class*="push-"],
 | 
				
			||||||
 | 
					    &[class*="pull-"] {
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $i: 1;
 | 
				
			||||||
 | 
					    @while $i <= $num-cols {
 | 
				
			||||||
 | 
					      $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					      &.s#{$i} {
 | 
				
			||||||
 | 
					        width: $perc;
 | 
				
			||||||
 | 
					        @include reset-offset;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      $i: $i + 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $i: 1;
 | 
				
			||||||
 | 
					    @while $i <= $num-cols {
 | 
				
			||||||
 | 
					      $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					      @include grid-classes("s", $i, $perc);
 | 
				
			||||||
 | 
					      $i: $i + 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @media #{$medium-and-up} {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $i: 1;
 | 
				
			||||||
 | 
					      @while $i <= $num-cols {
 | 
				
			||||||
 | 
					        $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					        &.m#{$i} {
 | 
				
			||||||
 | 
					          width: $perc;
 | 
				
			||||||
 | 
					          @include reset-offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $i: $i + 1
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $i: 1;
 | 
				
			||||||
 | 
					      @while $i <= $num-cols {
 | 
				
			||||||
 | 
					        $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					        @include grid-classes("m", $i, $perc);
 | 
				
			||||||
 | 
					        $i: $i + 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @media #{$large-and-up} {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $i: 1;
 | 
				
			||||||
 | 
					      @while $i <= $num-cols {
 | 
				
			||||||
 | 
					        $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					        &.l#{$i} {
 | 
				
			||||||
 | 
					          width: $perc;
 | 
				
			||||||
 | 
					          @include reset-offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $i: $i + 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $i: 1;
 | 
				
			||||||
 | 
					      @while $i <= $num-cols {
 | 
				
			||||||
 | 
					        $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					        @include grid-classes("l", $i, $perc);
 | 
				
			||||||
 | 
					        $i: $i + 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @media #{$extra-large-and-up} {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $i: 1;
 | 
				
			||||||
 | 
					      @while $i <= $num-cols {
 | 
				
			||||||
 | 
					        $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					        &.xl#{$i} {
 | 
				
			||||||
 | 
					          width: $perc;
 | 
				
			||||||
 | 
					          @include reset-offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $i: $i + 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $i: 1;
 | 
				
			||||||
 | 
					      @while $i <= $num-cols {
 | 
				
			||||||
 | 
					        $perc: unquote((100 / ($num-cols / $i)) + "%");
 | 
				
			||||||
 | 
					        @include grid-classes("xl", $i, $perc);
 | 
				
			||||||
 | 
					        $i: $i + 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								app/static/external/materialize/sass/components/_icons-material-design.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/static/external/materialize/sass/components/_icons-material-design.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					/* This is needed for some mobile phones to display the Google Icon font properly */
 | 
				
			||||||
 | 
					.material-icons {
 | 
				
			||||||
 | 
					  text-rendering: optimizeLegibility;
 | 
				
			||||||
 | 
					  font-feature-settings: 'liga';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								app/static/external/materialize/sass/components/_materialbox.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/static/external/materialize/sass/components/_materialbox.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					.materialboxed {
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    &:not(.active) {
 | 
				
			||||||
 | 
					      opacity: .8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  cursor: zoom-in;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  transition: opacity .4s;
 | 
				
			||||||
 | 
					  -webkit-backface-visibility: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.active {
 | 
				
			||||||
 | 
					    cursor: zoom-out;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#materialbox-overlay {
 | 
				
			||||||
 | 
					  position:fixed;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  bottom: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  background-color: #292929;
 | 
				
			||||||
 | 
					  z-index: 1000;
 | 
				
			||||||
 | 
					  will-change: opacity;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.materialbox-caption {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  line-height: 50px;
 | 
				
			||||||
 | 
					  bottom: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  padding: 0% 15%;
 | 
				
			||||||
 | 
					  height: 50px;
 | 
				
			||||||
 | 
					  z-index: 1000;
 | 
				
			||||||
 | 
					  -webkit-font-smoothing: antialiased;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										94
									
								
								app/static/external/materialize/sass/components/_modal.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								app/static/external/materialize/sass/components/_modal.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					.modal {
 | 
				
			||||||
 | 
					  &:focus {
 | 
				
			||||||
 | 
					    outline: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @extend .z-depth-5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  background-color: #fafafa;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  max-height: 70%;
 | 
				
			||||||
 | 
					  width: 55%;
 | 
				
			||||||
 | 
					  margin: auto;
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  border-radius: 2px;
 | 
				
			||||||
 | 
					  will-change: top, opacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @media #{$medium-and-down} {
 | 
				
			||||||
 | 
					   width: 80%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  h1,h2,h3,h4 {
 | 
				
			||||||
 | 
					    margin-top: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .modal-content {
 | 
				
			||||||
 | 
					    padding: 24px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .modal-close {
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .modal-footer {
 | 
				
			||||||
 | 
					    border-radius: 0 0 2px 2px;
 | 
				
			||||||
 | 
					    background-color: #fafafa;
 | 
				
			||||||
 | 
					    padding: 4px 6px;
 | 
				
			||||||
 | 
					    height: 56px;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    text-align: right;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .btn, .btn-flat {
 | 
				
			||||||
 | 
					      margin: 6px 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.modal-overlay {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  z-index: 999;
 | 
				
			||||||
 | 
					  top: -25%;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  bottom: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  height: 125%;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  background: #000;
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  will-change: opacity;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Modal with fixed action footer
 | 
				
			||||||
 | 
					.modal.modal-fixed-footer {
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  height: 70%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .modal-content {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    height: calc(100% - 56px);
 | 
				
			||||||
 | 
					    max-height: 100%;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    overflow-y: auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .modal-footer {
 | 
				
			||||||
 | 
					    border-top: 1px solid rgba(0,0,0,.1);
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Modal Bottom Sheet Style
 | 
				
			||||||
 | 
					.modal.bottom-sheet {
 | 
				
			||||||
 | 
					  top: auto;
 | 
				
			||||||
 | 
					  bottom: -100%;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  max-height: 45%;
 | 
				
			||||||
 | 
					  border-radius: 0;
 | 
				
			||||||
 | 
					  will-change: bottom, opacity;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										208
									
								
								app/static/external/materialize/sass/components/_navbar.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								app/static/external/materialize/sass/components/_navbar.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,208 @@
 | 
				
			|||||||
 | 
					nav {
 | 
				
			||||||
 | 
					  &.nav-extended {
 | 
				
			||||||
 | 
					    height: auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .nav-wrapper {
 | 
				
			||||||
 | 
					      min-height: $navbar-height-mobile;
 | 
				
			||||||
 | 
					      height: auto;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .nav-content {
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      line-height: normal;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  color: $navbar-font-color;
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					  background-color: $primary-color;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: $navbar-height-mobile;
 | 
				
			||||||
 | 
					  line-height: $navbar-line-height-mobile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  a { color: $navbar-font-color; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  i,
 | 
				
			||||||
 | 
					  [class^="mdi-"], [class*="mdi-"],
 | 
				
			||||||
 | 
					  i.material-icons {
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    font-size: 24px;
 | 
				
			||||||
 | 
					    height: $navbar-height-mobile;
 | 
				
			||||||
 | 
					    line-height: $navbar-line-height-mobile;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .nav-wrapper {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @media #{$large-and-up} {
 | 
				
			||||||
 | 
					    a.sidenav-trigger { display: none; }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Collapse button
 | 
				
			||||||
 | 
					  .sidenav-trigger {
 | 
				
			||||||
 | 
					    float: left;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    z-index: 1;
 | 
				
			||||||
 | 
					    height: $navbar-height-mobile;
 | 
				
			||||||
 | 
					    margin: 0 18px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i {
 | 
				
			||||||
 | 
					      height: $navbar-height-mobile;
 | 
				
			||||||
 | 
					      line-height: $navbar-line-height-mobile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Logo
 | 
				
			||||||
 | 
					  .brand-logo {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    color: $navbar-font-color;
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    font-size: $navbar-brand-font-size;
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.center {
 | 
				
			||||||
 | 
					      left: 50%;
 | 
				
			||||||
 | 
					      transform: translateX(-50%);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @media #{$medium-and-down} {
 | 
				
			||||||
 | 
					      left: 50%;
 | 
				
			||||||
 | 
					      transform: translateX(-50%);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.left, &.right {
 | 
				
			||||||
 | 
					        padding: 0;
 | 
				
			||||||
 | 
					        transform: none;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.left { left: 0.5rem; }
 | 
				
			||||||
 | 
					      &.right {
 | 
				
			||||||
 | 
					        right: 0.5rem;
 | 
				
			||||||
 | 
					        left: auto;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.right {
 | 
				
			||||||
 | 
					      right: 0.5rem;
 | 
				
			||||||
 | 
					      padding: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i,
 | 
				
			||||||
 | 
					    [class^="mdi-"], [class*="mdi-"],
 | 
				
			||||||
 | 
					    i.material-icons {
 | 
				
			||||||
 | 
					      float: left;
 | 
				
			||||||
 | 
					      margin-right: 15px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Title
 | 
				
			||||||
 | 
					  .nav-title {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    font-size: 32px;
 | 
				
			||||||
 | 
					    padding: 28px 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Navbar Links
 | 
				
			||||||
 | 
					  ul {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    li {
 | 
				
			||||||
 | 
					      transition: background-color .3s;
 | 
				
			||||||
 | 
					      float: left;
 | 
				
			||||||
 | 
					      padding: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.active {
 | 
				
			||||||
 | 
					        background-color: rgba(0,0,0,.1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    a {
 | 
				
			||||||
 | 
					      transition: background-color .3s;
 | 
				
			||||||
 | 
					      font-size: $navbar-font-size;
 | 
				
			||||||
 | 
					      color: $navbar-font-color;
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					      padding: 0 15px;
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.btn, &.btn-large, &.btn-flat, &.btn-floating {
 | 
				
			||||||
 | 
					        margin-top: -2px;
 | 
				
			||||||
 | 
					        margin-left: 15px;
 | 
				
			||||||
 | 
					        margin-right: 15px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        & > .material-icons {
 | 
				
			||||||
 | 
					          height: inherit;
 | 
				
			||||||
 | 
					          line-height: inherit;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &:hover {
 | 
				
			||||||
 | 
					        background-color: rgba(0,0,0,.1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.left {
 | 
				
			||||||
 | 
					      float: left;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Navbar Search Form
 | 
				
			||||||
 | 
					  form {
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .input-field {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    input {
 | 
				
			||||||
 | 
					      height: 100%;
 | 
				
			||||||
 | 
					      font-size: 1.2rem;
 | 
				
			||||||
 | 
					      border: none;
 | 
				
			||||||
 | 
					      padding-left: 2rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &:focus, &[type=text]:valid, &[type=password]:valid,
 | 
				
			||||||
 | 
					      &[type=email]:valid, &[type=url]:valid, &[type=date]:valid {
 | 
				
			||||||
 | 
					        border: none;
 | 
				
			||||||
 | 
					        box-shadow: none;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    label {
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      i {
 | 
				
			||||||
 | 
					        color: rgba(255,255,255,.7);
 | 
				
			||||||
 | 
					        transition: color .3s;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      &.active i { color: $navbar-font-color; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fixed Navbar
 | 
				
			||||||
 | 
					.navbar-fixed {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  height: $navbar-height-mobile;
 | 
				
			||||||
 | 
					  z-index: 997;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nav {
 | 
				
			||||||
 | 
					    position: fixed;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@media #{$medium-and-up} {
 | 
				
			||||||
 | 
					  nav.nav-extended .nav-wrapper {
 | 
				
			||||||
 | 
					    min-height: $navbar-height;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  nav, nav .nav-wrapper i, nav a.sidenav-trigger, nav a.sidenav-trigger i {
 | 
				
			||||||
 | 
					    height: $navbar-height;
 | 
				
			||||||
 | 
					    line-height: $navbar-line-height;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .navbar-fixed {
 | 
				
			||||||
 | 
					    height: $navbar-height;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										447
									
								
								app/static/external/materialize/sass/components/_normalize.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								app/static/external/materialize/sass/components/_normalize.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,447 @@
 | 
				
			|||||||
 | 
					/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Document
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Correct the line height in all browsers.
 | 
				
			||||||
 | 
					 * 2. Prevent adjustments of font size after orientation changes in
 | 
				
			||||||
 | 
					 *    IE on Windows Phone and in iOS.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					html {
 | 
				
			||||||
 | 
					  line-height: 1.15; /* 1 */
 | 
				
			||||||
 | 
					  -ms-text-size-adjust: 100%; /* 2 */
 | 
				
			||||||
 | 
					  -webkit-text-size-adjust: 100%; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sections
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove the margin in all browsers (opinionated).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in IE 9-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					article,
 | 
				
			||||||
 | 
					aside,
 | 
				
			||||||
 | 
					footer,
 | 
				
			||||||
 | 
					header,
 | 
				
			||||||
 | 
					nav,
 | 
				
			||||||
 | 
					section {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Correct the font size and margin on `h1` elements within `section` and
 | 
				
			||||||
 | 
					 * `article` contexts in Chrome, Firefox, and Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					h1 {
 | 
				
			||||||
 | 
					  font-size: 2em;
 | 
				
			||||||
 | 
					  margin: 0.67em 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Grouping content
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in IE 9-.
 | 
				
			||||||
 | 
					 * 1. Add the correct display in IE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					figcaption,
 | 
				
			||||||
 | 
					figure,
 | 
				
			||||||
 | 
					main { /* 1 */
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct margin in IE 8.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					figure {
 | 
				
			||||||
 | 
					  margin: 1em 40px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Add the correct box sizing in Firefox.
 | 
				
			||||||
 | 
					 * 2. Show the overflow in Edge and IE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hr {
 | 
				
			||||||
 | 
					  box-sizing: content-box; /* 1 */
 | 
				
			||||||
 | 
					  height: 0; /* 1 */
 | 
				
			||||||
 | 
					  overflow: visible; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Correct the inheritance and scaling of font size in all browsers.
 | 
				
			||||||
 | 
					 * 2. Correct the odd `em` font sizing in all browsers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pre {
 | 
				
			||||||
 | 
					  font-family: monospace, monospace; /* 1 */
 | 
				
			||||||
 | 
					  font-size: 1em; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Text-level semantics
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Remove the gray background on active links in IE 10.
 | 
				
			||||||
 | 
					 * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
					  background-color: transparent; /* 1 */
 | 
				
			||||||
 | 
					  -webkit-text-decoration-skip: objects; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Remove the bottom border in Chrome 57- and Firefox 39-.
 | 
				
			||||||
 | 
					 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abbr[title] {
 | 
				
			||||||
 | 
					  border-bottom: none; /* 1 */
 | 
				
			||||||
 | 
					  text-decoration: underline; /* 2 */
 | 
				
			||||||
 | 
					  text-decoration: underline dotted; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					b,
 | 
				
			||||||
 | 
					strong {
 | 
				
			||||||
 | 
					  font-weight: inherit;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct font weight in Chrome, Edge, and Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					b,
 | 
				
			||||||
 | 
					strong {
 | 
				
			||||||
 | 
					  font-weight: bolder;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Correct the inheritance and scaling of font size in all browsers.
 | 
				
			||||||
 | 
					 * 2. Correct the odd `em` font sizing in all browsers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code,
 | 
				
			||||||
 | 
					kbd,
 | 
				
			||||||
 | 
					samp {
 | 
				
			||||||
 | 
					  font-family: monospace, monospace; /* 1 */
 | 
				
			||||||
 | 
					  font-size: 1em; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct font style in Android 4.3-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dfn {
 | 
				
			||||||
 | 
					  font-style: italic;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct background and color in IE 9-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mark {
 | 
				
			||||||
 | 
					  background-color: #ff0;
 | 
				
			||||||
 | 
					  color: #000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct font size in all browsers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					small {
 | 
				
			||||||
 | 
					  font-size: 80%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Prevent `sub` and `sup` elements from affecting the line height in
 | 
				
			||||||
 | 
					 * all browsers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sub,
 | 
				
			||||||
 | 
					sup {
 | 
				
			||||||
 | 
					  font-size: 75%;
 | 
				
			||||||
 | 
					  line-height: 0;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  vertical-align: baseline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sub {
 | 
				
			||||||
 | 
					  bottom: -0.25em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sup {
 | 
				
			||||||
 | 
					  top: -0.5em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Embedded content
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in IE 9-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					audio,
 | 
				
			||||||
 | 
					video {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in iOS 4-7.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					audio:not([controls]) {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					  height: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove the border on images inside links in IE 10-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					img {
 | 
				
			||||||
 | 
					  border-style: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Hide the overflow in IE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					svg:not(:root) {
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Forms
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Change the font styles in all browsers (opinionated).
 | 
				
			||||||
 | 
					 * 2. Remove the margin in Firefox and Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button,
 | 
				
			||||||
 | 
					input,
 | 
				
			||||||
 | 
					optgroup,
 | 
				
			||||||
 | 
					select,
 | 
				
			||||||
 | 
					textarea {
 | 
				
			||||||
 | 
					  font-family: sans-serif; /* 1 */
 | 
				
			||||||
 | 
					  font-size: 100%; /* 1 */
 | 
				
			||||||
 | 
					  line-height: 1.15; /* 1 */
 | 
				
			||||||
 | 
					  margin: 0; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Show the overflow in IE.
 | 
				
			||||||
 | 
					 * 1. Show the overflow in Edge.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button,
 | 
				
			||||||
 | 
					input { /* 1 */
 | 
				
			||||||
 | 
					  overflow: visible;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 | 
				
			||||||
 | 
					 * 1. Remove the inheritance of text transform in Firefox.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button,
 | 
				
			||||||
 | 
					select { /* 1 */
 | 
				
			||||||
 | 
					  text-transform: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
 | 
				
			||||||
 | 
					 *    controls in Android 4.
 | 
				
			||||||
 | 
					 * 2. Correct the inability to style clickable types in iOS and Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button,
 | 
				
			||||||
 | 
					html [type="button"], /* 1 */
 | 
				
			||||||
 | 
					[type="reset"],
 | 
				
			||||||
 | 
					[type="submit"] {
 | 
				
			||||||
 | 
					  -webkit-appearance: button; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove the inner border and padding in Firefox.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button::-moz-focus-inner,
 | 
				
			||||||
 | 
					[type="button"]::-moz-focus-inner,
 | 
				
			||||||
 | 
					[type="reset"]::-moz-focus-inner,
 | 
				
			||||||
 | 
					[type="submit"]::-moz-focus-inner {
 | 
				
			||||||
 | 
					  border-style: none;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Restore the focus styles unset by the previous rule.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button:-moz-focusring,
 | 
				
			||||||
 | 
					[type="button"]:-moz-focusring,
 | 
				
			||||||
 | 
					[type="reset"]:-moz-focusring,
 | 
				
			||||||
 | 
					[type="submit"]:-moz-focusring {
 | 
				
			||||||
 | 
					  outline: 1px dotted ButtonText;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Correct the padding in Firefox.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fieldset {
 | 
				
			||||||
 | 
					  padding: 0.35em 0.75em 0.625em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Correct the text wrapping in Edge and IE.
 | 
				
			||||||
 | 
					 * 2. Correct the color inheritance from `fieldset` elements in IE.
 | 
				
			||||||
 | 
					 * 3. Remove the padding so developers are not caught out when they zero out
 | 
				
			||||||
 | 
					 *    `fieldset` elements in all browsers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					legend {
 | 
				
			||||||
 | 
					  box-sizing: border-box; /* 1 */
 | 
				
			||||||
 | 
					  color: inherit; /* 2 */
 | 
				
			||||||
 | 
					  display: table; /* 1 */
 | 
				
			||||||
 | 
					  max-width: 100%; /* 1 */
 | 
				
			||||||
 | 
					  padding: 0; /* 3 */
 | 
				
			||||||
 | 
					  white-space: normal; /* 1 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Add the correct display in IE 9-.
 | 
				
			||||||
 | 
					 * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					progress {
 | 
				
			||||||
 | 
					  display: inline-block; /* 1 */
 | 
				
			||||||
 | 
					  vertical-align: baseline; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove the default vertical scrollbar in IE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					textarea {
 | 
				
			||||||
 | 
					  overflow: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Add the correct box sizing in IE 10-.
 | 
				
			||||||
 | 
					 * 2. Remove the padding in IE 10-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[type="checkbox"],
 | 
				
			||||||
 | 
					[type="radio"] {
 | 
				
			||||||
 | 
					  box-sizing: border-box; /* 1 */
 | 
				
			||||||
 | 
					  padding: 0; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Correct the cursor style of increment and decrement buttons in Chrome.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[type="number"]::-webkit-inner-spin-button,
 | 
				
			||||||
 | 
					[type="number"]::-webkit-outer-spin-button {
 | 
				
			||||||
 | 
					  height: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Correct the odd appearance in Chrome and Safari.
 | 
				
			||||||
 | 
					 * 2. Correct the outline style in Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[type="search"] {
 | 
				
			||||||
 | 
					  -webkit-appearance: textfield; /* 1 */
 | 
				
			||||||
 | 
					  outline-offset: -2px; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[type="search"]::-webkit-search-cancel-button,
 | 
				
			||||||
 | 
					[type="search"]::-webkit-search-decoration {
 | 
				
			||||||
 | 
					  -webkit-appearance: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 1. Correct the inability to style clickable types in iOS and Safari.
 | 
				
			||||||
 | 
					 * 2. Change font properties to `inherit` in Safari.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::-webkit-file-upload-button {
 | 
				
			||||||
 | 
					  -webkit-appearance: button; /* 1 */
 | 
				
			||||||
 | 
					  font: inherit; /* 2 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Interactive
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Add the correct display in IE 9-.
 | 
				
			||||||
 | 
					 * 1. Add the correct display in Edge, IE, and Firefox.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					details, /* 1 */
 | 
				
			||||||
 | 
					menu {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Add the correct display in all browsers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					summary {
 | 
				
			||||||
 | 
					  display: list-item;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Scripting
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in IE 9-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					canvas {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in IE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Hidden
 | 
				
			||||||
 | 
					   ========================================================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add the correct display in IE 10-.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[hidden] {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										334
									
								
								app/static/external/materialize/sass/components/_preloader.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								app/static/external/materialize/sass/components/_preloader.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,334 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					    @license
 | 
				
			||||||
 | 
					    Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 | 
				
			||||||
 | 
					    This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 | 
				
			||||||
 | 
					    The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 | 
				
			||||||
 | 
					    The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 | 
				
			||||||
 | 
					    Code distributed by Google as part of the polymer project is also
 | 
				
			||||||
 | 
					    subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**************************/
 | 
				
			||||||
 | 
					/* STYLES FOR THE SPINNER */
 | 
				
			||||||
 | 
					/**************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Constants:
 | 
				
			||||||
 | 
					 *      STROKEWIDTH = 3px
 | 
				
			||||||
 | 
					 *      ARCSIZE     = 270 degrees (amount of circle the arc takes up)
 | 
				
			||||||
 | 
					 *      ARCTIME     = 1333ms (time it takes to expand and contract arc)
 | 
				
			||||||
 | 
					 *      ARCSTARTROT = 216 degrees (how much the start location of the arc
 | 
				
			||||||
 | 
					 *                                should rotate each time, 216 gives us a
 | 
				
			||||||
 | 
					 *                                5 pointed star shape (it's 360/5 * 3).
 | 
				
			||||||
 | 
					 *                                For a 7 pointed star, we might do
 | 
				
			||||||
 | 
					 *                                360/7 * 3 = 154.286)
 | 
				
			||||||
 | 
					 *      CONTAINERWIDTH = 28px
 | 
				
			||||||
 | 
					 *      SHRINK_TIME = 400ms
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.preloader-wrapper {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  width: 50px;
 | 
				
			||||||
 | 
					  height: 50px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.small {
 | 
				
			||||||
 | 
					    width: 36px;
 | 
				
			||||||
 | 
					    height: 36px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.big {
 | 
				
			||||||
 | 
					    width: 64px;
 | 
				
			||||||
 | 
					    height: 64px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.active {
 | 
				
			||||||
 | 
					    /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
 | 
				
			||||||
 | 
					    -webkit-animation: container-rotate 1568ms linear infinite;
 | 
				
			||||||
 | 
					    animation: container-rotate 1568ms linear infinite;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes container-rotate {
 | 
				
			||||||
 | 
					  to { -webkit-transform: rotate(360deg) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes container-rotate {
 | 
				
			||||||
 | 
					  to { transform: rotate(360deg) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.spinner-layer {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  opacity: 0;
 | 
				
			||||||
 | 
					  border-color: $spinner-default-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.spinner-blue,
 | 
				
			||||||
 | 
					.spinner-blue-only {
 | 
				
			||||||
 | 
					  border-color: #4285f4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.spinner-red,
 | 
				
			||||||
 | 
					.spinner-red-only {
 | 
				
			||||||
 | 
					  border-color: #db4437;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.spinner-yellow,
 | 
				
			||||||
 | 
					.spinner-yellow-only {
 | 
				
			||||||
 | 
					  border-color: #f4b400;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.spinner-green,
 | 
				
			||||||
 | 
					.spinner-green-only {
 | 
				
			||||||
 | 
					  border-color: #0f9d58;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
 | 
				
			||||||
 | 
					 * guarantee that the animation will start _exactly_ after that value. So we avoid using
 | 
				
			||||||
 | 
					 * animation-delay and instead set custom keyframes for each color (as redundant as it
 | 
				
			||||||
 | 
					 * seems).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We write out each animation in full (instead of separating animation-name,
 | 
				
			||||||
 | 
					 * animation-duration, etc.) because under the polyfill, Safari does not recognize those
 | 
				
			||||||
 | 
					 * specific properties properly, treats them as -webkit-animation, and overrides the
 | 
				
			||||||
 | 
					 * other animation rules. See https://github.com/Polymer/platform/issues/53.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-blue {
 | 
				
			||||||
 | 
					  /* durations: 4 * ARCTIME */
 | 
				
			||||||
 | 
					  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-red {
 | 
				
			||||||
 | 
					  /* durations: 4 * ARCTIME */
 | 
				
			||||||
 | 
					  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-yellow {
 | 
				
			||||||
 | 
					  /* durations: 4 * ARCTIME */
 | 
				
			||||||
 | 
					  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-green {
 | 
				
			||||||
 | 
					  /* durations: 4 * ARCTIME */
 | 
				
			||||||
 | 
					  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active .spinner-layer,
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-blue-only,
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-red-only,
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-yellow-only,
 | 
				
			||||||
 | 
					.active .spinner-layer.spinner-green-only {
 | 
				
			||||||
 | 
					  /* durations: 4 * ARCTIME */
 | 
				
			||||||
 | 
					  opacity: 1;
 | 
				
			||||||
 | 
					  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes fill-unfill-rotate {
 | 
				
			||||||
 | 
					  12.5% { -webkit-transform: rotate(135deg);  } /* 0.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  25%   { -webkit-transform: rotate(270deg);  } /* 1   * ARCSIZE */
 | 
				
			||||||
 | 
					  37.5% { -webkit-transform: rotate(405deg);  } /* 1.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  50%   { -webkit-transform: rotate(540deg);  } /* 2   * ARCSIZE */
 | 
				
			||||||
 | 
					  62.5% { -webkit-transform: rotate(675deg);  } /* 2.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  75%   { -webkit-transform: rotate(810deg);  } /* 3   * ARCSIZE */
 | 
				
			||||||
 | 
					  87.5% { -webkit-transform: rotate(945deg);  } /* 3.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  to    { -webkit-transform: rotate(1080deg); } /* 4   * ARCSIZE */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes fill-unfill-rotate {
 | 
				
			||||||
 | 
					  12.5% { transform: rotate(135deg);  } /* 0.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  25%   { transform: rotate(270deg);  } /* 1   * ARCSIZE */
 | 
				
			||||||
 | 
					  37.5% { transform: rotate(405deg);  } /* 1.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  50%   { transform: rotate(540deg);  } /* 2   * ARCSIZE */
 | 
				
			||||||
 | 
					  62.5% { transform: rotate(675deg);  } /* 2.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  75%   { transform: rotate(810deg);  } /* 3   * ARCSIZE */
 | 
				
			||||||
 | 
					  87.5% { transform: rotate(945deg);  } /* 3.5 * ARCSIZE */
 | 
				
			||||||
 | 
					  to    { transform: rotate(1080deg); } /* 4   * ARCSIZE */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes blue-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 1; }
 | 
				
			||||||
 | 
					  25% { opacity: 1; }
 | 
				
			||||||
 | 
					  26% { opacity: 0; }
 | 
				
			||||||
 | 
					  89% { opacity: 0; }
 | 
				
			||||||
 | 
					  90% { opacity: 1; }
 | 
				
			||||||
 | 
					  100% { opacity: 1; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes blue-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 1; }
 | 
				
			||||||
 | 
					  25% { opacity: 1; }
 | 
				
			||||||
 | 
					  26% { opacity: 0; }
 | 
				
			||||||
 | 
					  89% { opacity: 0; }
 | 
				
			||||||
 | 
					  90% { opacity: 1; }
 | 
				
			||||||
 | 
					  100% { opacity: 1; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes red-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 0; }
 | 
				
			||||||
 | 
					  15% { opacity: 0; }
 | 
				
			||||||
 | 
					  25% { opacity: 1; }
 | 
				
			||||||
 | 
					  50% { opacity: 1; }
 | 
				
			||||||
 | 
					  51% { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes red-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 0; }
 | 
				
			||||||
 | 
					  15% { opacity: 0; }
 | 
				
			||||||
 | 
					  25% { opacity: 1; }
 | 
				
			||||||
 | 
					  50% { opacity: 1; }
 | 
				
			||||||
 | 
					  51% { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes yellow-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 0; }
 | 
				
			||||||
 | 
					  40% { opacity: 0; }
 | 
				
			||||||
 | 
					  50% { opacity: 1; }
 | 
				
			||||||
 | 
					  75% { opacity: 1; }
 | 
				
			||||||
 | 
					  76% { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes yellow-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 0; }
 | 
				
			||||||
 | 
					  40% { opacity: 0; }
 | 
				
			||||||
 | 
					  50% { opacity: 1; }
 | 
				
			||||||
 | 
					  75% { opacity: 1; }
 | 
				
			||||||
 | 
					  76% { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes green-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 0; }
 | 
				
			||||||
 | 
					  65% { opacity: 0; }
 | 
				
			||||||
 | 
					  75% { opacity: 1; }
 | 
				
			||||||
 | 
					  90% { opacity: 1; }
 | 
				
			||||||
 | 
					  100% { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes green-fade-in-out {
 | 
				
			||||||
 | 
					  from { opacity: 0; }
 | 
				
			||||||
 | 
					  65% { opacity: 0; }
 | 
				
			||||||
 | 
					  75% { opacity: 1; }
 | 
				
			||||||
 | 
					  90% { opacity: 1; }
 | 
				
			||||||
 | 
					  100% { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Patch the gap that appear between the two adjacent div.circle-clipper while the
 | 
				
			||||||
 | 
					 * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					.gap-patch {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 45%;
 | 
				
			||||||
 | 
					  width: 10%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  border-color: inherit;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.gap-patch .circle {
 | 
				
			||||||
 | 
					  width: 1000%;
 | 
				
			||||||
 | 
					  left: -450%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.circle-clipper {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  width: 50%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  border-color: inherit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .circle {
 | 
				
			||||||
 | 
					    width: 200%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    border-width: 3px; /* STROKEWIDTH */
 | 
				
			||||||
 | 
					    border-style: solid;
 | 
				
			||||||
 | 
					    border-color: inherit;
 | 
				
			||||||
 | 
					    border-bottom-color: transparent !important;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    -webkit-animation: none;
 | 
				
			||||||
 | 
					    animation: none;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.left .circle {
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    border-right-color: transparent !important;
 | 
				
			||||||
 | 
					    -webkit-transform: rotate(129deg);
 | 
				
			||||||
 | 
					    transform: rotate(129deg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.right .circle {
 | 
				
			||||||
 | 
					    left: -100%;
 | 
				
			||||||
 | 
					    border-left-color: transparent !important;
 | 
				
			||||||
 | 
					    -webkit-transform: rotate(-129deg);
 | 
				
			||||||
 | 
					    transform: rotate(-129deg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active .circle-clipper.left .circle {
 | 
				
			||||||
 | 
					  /* duration: ARCTIME */
 | 
				
			||||||
 | 
					  -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active .circle-clipper.right .circle {
 | 
				
			||||||
 | 
					  /* duration: ARCTIME */
 | 
				
			||||||
 | 
					  -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					  animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes left-spin {
 | 
				
			||||||
 | 
					  from { -webkit-transform: rotate(130deg); }
 | 
				
			||||||
 | 
					  50% { -webkit-transform: rotate(-5deg); }
 | 
				
			||||||
 | 
					  to { -webkit-transform: rotate(130deg); }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes left-spin {
 | 
				
			||||||
 | 
					  from { transform: rotate(130deg); }
 | 
				
			||||||
 | 
					  50% { transform: rotate(-5deg); }
 | 
				
			||||||
 | 
					  to { transform: rotate(130deg); }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes right-spin {
 | 
				
			||||||
 | 
					  from { -webkit-transform: rotate(-130deg); }
 | 
				
			||||||
 | 
					  50% { -webkit-transform: rotate(5deg); }
 | 
				
			||||||
 | 
					  to { -webkit-transform: rotate(-130deg); }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes right-spin {
 | 
				
			||||||
 | 
					  from { transform: rotate(-130deg); }
 | 
				
			||||||
 | 
					  50% { transform: rotate(5deg); }
 | 
				
			||||||
 | 
					  to { transform: rotate(-130deg); }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#spinnerContainer.cooldown {
 | 
				
			||||||
 | 
					  /* duration: SHRINK_TIME */
 | 
				
			||||||
 | 
					  -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
 | 
				
			||||||
 | 
					  animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@-webkit-keyframes fade-out {
 | 
				
			||||||
 | 
					  from { opacity: 1; }
 | 
				
			||||||
 | 
					  to { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes fade-out {
 | 
				
			||||||
 | 
					  from { opacity: 1; }
 | 
				
			||||||
 | 
					  to { opacity: 0; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								app/static/external/materialize/sass/components/_pulse.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/static/external/materialize/sass/components/_pulse.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					.pulse {
 | 
				
			||||||
 | 
					  &::before {
 | 
				
			||||||
 | 
					    content: '';
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    background-color: inherit;
 | 
				
			||||||
 | 
					    border-radius: inherit;
 | 
				
			||||||
 | 
					    transition: opacity .3s, transform .3s;
 | 
				
			||||||
 | 
					    animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite;
 | 
				
			||||||
 | 
					    z-index: -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  overflow: visible;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes pulse-animation {
 | 
				
			||||||
 | 
					  0% {
 | 
				
			||||||
 | 
					    opacity: 1;
 | 
				
			||||||
 | 
					    transform: scale(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  50% {
 | 
				
			||||||
 | 
					    opacity: 0;
 | 
				
			||||||
 | 
					    transform: scale(1.5);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  100% {
 | 
				
			||||||
 | 
					    opacity: 0;
 | 
				
			||||||
 | 
					    transform: scale(1.5);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										216
									
								
								app/static/external/materialize/sass/components/_sidenav.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								app/static/external/materialize/sass/components/_sidenav.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					.sidenav {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  width: $sidenav-width;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  transform: translateX(-100%);
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  height: calc(100% + 60px);
 | 
				
			||||||
 | 
					  height: -moz-calc(100%); //Temporary Firefox Fix
 | 
				
			||||||
 | 
					  padding-bottom: 60px;
 | 
				
			||||||
 | 
					  background-color: $sidenav-bg-color;
 | 
				
			||||||
 | 
					  z-index: 999;
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					  will-change: transform;
 | 
				
			||||||
 | 
					  backface-visibility: hidden;
 | 
				
			||||||
 | 
					  transform: translateX(-105%);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @extend .z-depth-1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Right Align
 | 
				
			||||||
 | 
					  &.right-aligned {
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    transform: translateX(105%);
 | 
				
			||||||
 | 
					    left: auto;
 | 
				
			||||||
 | 
					    transform: translateX(100%);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .collapsible {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  li {
 | 
				
			||||||
 | 
					    float: none;
 | 
				
			||||||
 | 
					    line-height: $sidenav-line-height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.active { background-color: rgba(0,0,0,.05); }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  li > a {
 | 
				
			||||||
 | 
					    color: $sidenav-font-color;
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    font-size: $sidenav-font-size;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					    height: $sidenav-item-height;
 | 
				
			||||||
 | 
					    line-height: $sidenav-line-height;
 | 
				
			||||||
 | 
					    padding: 0 ($sidenav-padding * 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:hover { background-color: rgba(0,0,0,.05);}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.btn, &.btn-large, &.btn-flat, &.btn-floating {
 | 
				
			||||||
 | 
					      margin: 10px 15px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.btn,
 | 
				
			||||||
 | 
					    &.btn-large,
 | 
				
			||||||
 | 
					    &.btn-floating { color: $button-raised-color; }
 | 
				
			||||||
 | 
					    &.btn-flat { color: $button-flat-color; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.btn:hover,
 | 
				
			||||||
 | 
					    &.btn-large:hover { background-color: lighten($button-raised-background, 5%); }
 | 
				
			||||||
 | 
					    &.btn-floating:hover { background-color: $button-raised-background; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > i,
 | 
				
			||||||
 | 
					    & > [class^="mdi-"], li > a > [class*="mdi-"],
 | 
				
			||||||
 | 
					    & > i.material-icons {
 | 
				
			||||||
 | 
					      float: left;
 | 
				
			||||||
 | 
					      height: $sidenav-item-height;
 | 
				
			||||||
 | 
					      line-height: $sidenav-line-height;
 | 
				
			||||||
 | 
					      margin: 0 ($sidenav-padding * 2) 0 0;
 | 
				
			||||||
 | 
					      width: $sidenav-item-height / 2;
 | 
				
			||||||
 | 
					      color: rgba(0,0,0,.54);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .divider {
 | 
				
			||||||
 | 
					    margin: ($sidenav-padding / 2) 0 0 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .subheader {
 | 
				
			||||||
 | 
					    &:hover {
 | 
				
			||||||
 | 
					      background-color: transparent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cursor: initial;
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					    color: rgba(0,0,0,.54);
 | 
				
			||||||
 | 
					    font-size: $sidenav-font-size;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					    line-height: $sidenav-line-height;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .user-view {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    padding: ($sidenav-padding * 2) ($sidenav-padding * 2) 0;
 | 
				
			||||||
 | 
					    margin-bottom: $sidenav-padding / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > a {
 | 
				
			||||||
 | 
					      &:hover { background-color: transparent; }
 | 
				
			||||||
 | 
					      height: auto;
 | 
				
			||||||
 | 
					      padding: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .background {
 | 
				
			||||||
 | 
					      overflow: hidden;
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      right: 0;
 | 
				
			||||||
 | 
					      bottom: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      z-index: -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .circle, .name, .email {
 | 
				
			||||||
 | 
					      display: block;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .circle {
 | 
				
			||||||
 | 
					      height: 64px;
 | 
				
			||||||
 | 
					      width: 64px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .name,
 | 
				
			||||||
 | 
					    .email {
 | 
				
			||||||
 | 
					      font-size: $sidenav-font-size;
 | 
				
			||||||
 | 
					      line-height: $sidenav-line-height / 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .name {
 | 
				
			||||||
 | 
					      margin-top: 16px;
 | 
				
			||||||
 | 
					      font-weight: 500;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .email {
 | 
				
			||||||
 | 
					      padding-bottom: 16px;
 | 
				
			||||||
 | 
					      font-weight: 400;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Touch interaction
 | 
				
			||||||
 | 
					.drag-target {
 | 
				
			||||||
 | 
					  // Right Align
 | 
				
			||||||
 | 
					  &.right-aligned {
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  z-index: 998;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fixed Sidenav shown
 | 
				
			||||||
 | 
					.sidenav.sidenav-fixed {
 | 
				
			||||||
 | 
					  // Right Align
 | 
				
			||||||
 | 
					  &.right-aligned {
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    left: auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  transform: translateX(0);
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fixed Sidenav hide on smaller
 | 
				
			||||||
 | 
					@media #{$medium-and-down} {
 | 
				
			||||||
 | 
					  .sidenav {
 | 
				
			||||||
 | 
					    &.sidenav-fixed {
 | 
				
			||||||
 | 
					      transform: translateX(-105%);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.right-aligned {
 | 
				
			||||||
 | 
					        transform: translateX(105%);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > a {
 | 
				
			||||||
 | 
					      padding: 0 $sidenav-padding;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .user-view {
 | 
				
			||||||
 | 
					      padding: $sidenav-padding $sidenav-padding 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sidenav .collapsible-body > ul:not(.collapsible) > li.active,
 | 
				
			||||||
 | 
					.sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active {
 | 
				
			||||||
 | 
					  background-color: $primary-color;
 | 
				
			||||||
 | 
					  a {
 | 
				
			||||||
 | 
					    color: $sidenav-bg-color;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.sidenav .collapsible-body {
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sidenav-overlay {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  opacity: 0;
 | 
				
			||||||
 | 
					  height: 120vh;
 | 
				
			||||||
 | 
					  background-color: rgba(0,0,0,.5);
 | 
				
			||||||
 | 
					  z-index: 997;
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								app/static/external/materialize/sass/components/_slider.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								app/static/external/materialize/sass/components/_slider.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					.slider {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  height: 400px;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Fullscreen slider
 | 
				
			||||||
 | 
					  &.fullscreen {
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ul.slides {
 | 
				
			||||||
 | 
					      height: 100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ul.indicators {
 | 
				
			||||||
 | 
					      z-index: 2;
 | 
				
			||||||
 | 
					      bottom: 30px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .slides {
 | 
				
			||||||
 | 
					    background-color: $slider-bg-color;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    height: 400px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    li {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
 | 
					      left: 0;
 | 
				
			||||||
 | 
					      z-index: 1;
 | 
				
			||||||
 | 
					      width: 100%;
 | 
				
			||||||
 | 
					      height: inherit;
 | 
				
			||||||
 | 
					      overflow: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      img {
 | 
				
			||||||
 | 
					        height: 100%;
 | 
				
			||||||
 | 
					        width: 100%;
 | 
				
			||||||
 | 
					        background-size: cover;
 | 
				
			||||||
 | 
					        background-position: center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .caption {
 | 
				
			||||||
 | 
					        color: #fff;
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        top: 15%;
 | 
				
			||||||
 | 
					        left: 15%;
 | 
				
			||||||
 | 
					        width: 70%;
 | 
				
			||||||
 | 
					        opacity: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        p { color: $slider-bg-color-light; }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.active {
 | 
				
			||||||
 | 
					        z-index: 2;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .indicators {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .indicator-item {
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					      height: 16px;
 | 
				
			||||||
 | 
					      width: 16px;
 | 
				
			||||||
 | 
					      margin: 0 12px;
 | 
				
			||||||
 | 
					      background-color: $slider-bg-color-light;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      transition: background-color .3s;
 | 
				
			||||||
 | 
					      border-radius: 50%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.active {
 | 
				
			||||||
 | 
					        background-color: $slider-indicator-color;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user