Compare commits
	
		
			1 Commits 
		
	
	
		
			main
			...
			developmen
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						a5187c751a | 5 years ago | 
@ -0,0 +1,158 @@ | 
				
			|||||||
 | 
					#!/usr/bin/env python | 
				
			||||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- IMPORTS | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- PYTHON IMPORTS --- """ | 
				
			||||||
 | 
					import os | 
				
			||||||
 | 
					from os.path import dirname, abspath | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- STASHR CORE IMPORTS --- """ | 
				
			||||||
 | 
					from stashr import log, utils | 
				
			||||||
 | 
					from stashr import database as stashr_database | 
				
			||||||
 | 
					from stashr.stashr import stashr_notification, stashr_notification | 
				
			||||||
 | 
					from stashr.api import create_json_return | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- STASHR PLUGIN IMPORTS --- """ | 
				
			||||||
 | 
					from . import forms | 
				
			||||||
 | 
					from .config import pushconfig | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- STASHR PLUGIN DEPENDENCY IMPORTS --- """ | 
				
			||||||
 | 
					try: | 
				
			||||||
 | 
					    from pushbullet import Pushbullet | 
				
			||||||
 | 
					except: | 
				
			||||||
 | 
					    utils.install_package('pushbullet.py') | 
				
			||||||
 | 
					    from pushbullet import Pushbullet | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- FLASK EXTENSION IMPORTS --- """ | 
				
			||||||
 | 
					from flask_login import login_required, current_user | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- STASHR DEPENDENCY IMPORTS --- """ | 
				
			||||||
 | 
					from flask import Blueprint, render_template, request, redirect, flash, url_for | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- CREATE LOGGER --- """ | 
				
			||||||
 | 
					logger = log.stashr_logger(__name__) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- PLUGIN | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__plugin_name__ = "Stashr Pushbullet" | 
				
			||||||
 | 
					__version__ = "0.1.0" | 
				
			||||||
 | 
					__author__ = "Stashr" | 
				
			||||||
 | 
					__description__ = "Send notifications via Pushbullet" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------ | 
				
			||||||
 | 
					- PUSHBULLET OBJECT | 
				
			||||||
 | 
					------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pb = None | 
				
			||||||
 | 
					pb_active = False | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------ | 
				
			||||||
 | 
					- PLUGIN ROUTES | 
				
			||||||
 | 
					------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- DEFINE BLUEPRINT --- """ | 
				
			||||||
 | 
					bp = Blueprint('pushbullet', __name__, root_path=dirname(abspath(__file__)), template_folder='templates', static_folder='static') | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- PAGES --- """ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@bp.route('/settings', methods=['GET', 'POST']) | 
				
			||||||
 | 
					@login_required | 
				
			||||||
 | 
					def pushbullet_settings_page(): | 
				
			||||||
 | 
					     | 
				
			||||||
 | 
					    if current_user.role != 'admin': | 
				
			||||||
 | 
					        flash('Permission Denied', 'error') | 
				
			||||||
 | 
					        return redirect(url_for('index_page')) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    settings_form = forms.settings_form() | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if request.method == 'POST': | 
				
			||||||
 | 
					        if settings_form.validate(): | 
				
			||||||
 | 
					            pushconfig['PUSHBULLET']['api_key'] = settings_form.api_key.data | 
				
			||||||
 | 
					            pushconfig['PUSHBULLET']['channel'] = settings_form.channel.data | 
				
			||||||
 | 
					            pushconfig.write() | 
				
			||||||
 | 
					            define_pushbullet() | 
				
			||||||
 | 
					            flash('Pushbullet Settings Updated', 'success') | 
				
			||||||
 | 
					        else: | 
				
			||||||
 | 
					            for error in settings_form.errors.items(): | 
				
			||||||
 | 
					                flash(f'{error[0]}: {error[1]}', 'error') | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return render_template( | 
				
			||||||
 | 
					        'pushbullet_settings.html', | 
				
			||||||
 | 
					        title='Pushbullet Settings', | 
				
			||||||
 | 
					        settings_form=settings_form | 
				
			||||||
 | 
					    ) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- API --- """ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@bp.route('/api/settings', methods=['GET']) | 
				
			||||||
 | 
					def api_get_settings(): | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    user = current_user | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not user.is_authenticated: | 
				
			||||||
 | 
					        api_key = request.args.get('api_key') | 
				
			||||||
 | 
					        if api_key == "": | 
				
			||||||
 | 
					            return create_json_return('100') | 
				
			||||||
 | 
					        user = stashr_database.session \ | 
				
			||||||
 | 
					            .query(stashr_database.Users) \ | 
				
			||||||
 | 
					            .filter(stashr_database.Users.api_key == api_key) \ | 
				
			||||||
 | 
					            .first() | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if user is None: | 
				
			||||||
 | 
					        return create_json_return('100') | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if user.role.lower() != 'admin': | 
				
			||||||
 | 
					        return create_json_return('401') | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    settings = pushconfig | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return create_json_return('200', results=settings) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------ | 
				
			||||||
 | 
					- PLUGIN FUNCTIONS | 
				
			||||||
 | 
					------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --- Subscribe to stashr_notifications signal --- # | 
				
			||||||
 | 
					@stashr_notification.connect | 
				
			||||||
 | 
					def send_notification(*args, **kwargs): | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global pb | 
				
			||||||
 | 
					    global pb_active | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not pb_active: | 
				
			||||||
 | 
					        define_pushbullet() | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if 'title' in kwargs and 'message' in kwargs: | 
				
			||||||
 | 
					        pb_channel = pb.get_channel(pushconfig['PUSHBULLET']['channel']) | 
				
			||||||
 | 
					        pb_channel.push_note(kwargs['title'], kwargs['message']) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def define_pushbullet(): | 
				
			||||||
 | 
					    global pb | 
				
			||||||
 | 
					    global pb_active | 
				
			||||||
 | 
					    try: | 
				
			||||||
 | 
					        pb = Pushbullet(pushconfig['PUSHBULLET']['api_key']) | 
				
			||||||
 | 
					        pb_active = True | 
				
			||||||
 | 
					    except Exception as e: | 
				
			||||||
 | 
					        logger.error(e) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------ | 
				
			||||||
 | 
					- REGISTER PLUGIN | 
				
			||||||
 | 
					------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def register(): | 
				
			||||||
 | 
					    return dict( | 
				
			||||||
 | 
					        bep=dict( | 
				
			||||||
 | 
					            blueprint=bp, | 
				
			||||||
 | 
					            prefix='/pushbullet' | 
				
			||||||
 | 
					        ), | 
				
			||||||
 | 
					        tep = dict( | 
				
			||||||
 | 
					            settings_menu='pushbullet_tep_settings_menu.html', | 
				
			||||||
 | 
					        ) | 
				
			||||||
 | 
					    ) | 
				
			||||||
@ -0,0 +1,59 @@ | 
				
			|||||||
 | 
					#!/usr/bin/env python | 
				
			||||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- IMPORTS | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- PYTHON IMPORTS --- """ | 
				
			||||||
 | 
					import os, io, shutil | 
				
			||||||
 | 
					from os.path import dirname, abspath | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from configobj import ConfigObj | 
				
			||||||
 | 
					from validate import Validator | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- PUSHBULLET CONFIG | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PushConfig(ConfigObj): | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configspec = u""" | 
				
			||||||
 | 
					[PUSHBULLET] | 
				
			||||||
 | 
					api_key = string(default='') | 
				
			||||||
 | 
					channel = string(default='') | 
				
			||||||
 | 
					    """ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self): | 
				
			||||||
 | 
					        super(PushConfig, self).__init__() | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        configspecfile = os.path.join( | 
				
			||||||
 | 
					            dirname(abspath(__file__)), | 
				
			||||||
 | 
					            'configspec.ini' | 
				
			||||||
 | 
					        ) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not os.path.exists(configspecfile): | 
				
			||||||
 | 
					            with open(configspecfile, 'w') as fd: | 
				
			||||||
 | 
					                shutil.copyfileobj(io.StringIO(PushConfig.configspec), fd) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.filename = os.path.join( | 
				
			||||||
 | 
					            dirname(abspath(__file__)), | 
				
			||||||
 | 
					            'config.ini' | 
				
			||||||
 | 
					        ) | 
				
			||||||
 | 
					        self.configspec = configspecfile | 
				
			||||||
 | 
					        self.encoding = "UTF8" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tmp = ConfigObj(self.filename, configspec=self.configspec, encoding=self.encoding) | 
				
			||||||
 | 
					        validator = Validator() | 
				
			||||||
 | 
					        tmp.validate(validator, copy=True) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.merge(tmp) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not os.path.exists(self.filename): | 
				
			||||||
 | 
					            self.write() | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- CONFIGURATION DEFINITION | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pushconfig = PushConfig() | 
				
			||||||
@ -0,0 +1,37 @@ | 
				
			|||||||
 | 
					#!/usr/bin/env python | 
				
			||||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- IMPORTS | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- HUEY IMPORT --- """ | 
				
			||||||
 | 
					""" --- PYTHON IMPORTS --- """ | 
				
			||||||
 | 
					""" --- STASHR DEPENDENCY IMPORTS --- """ | 
				
			||||||
 | 
					""" --- STASHR CORE IMPORTS --- """ | 
				
			||||||
 | 
					from stashr import log, database | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- FLASK EXTENSION IMPORTS --- """ | 
				
			||||||
 | 
					from flask_wtf import FlaskForm | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from wtforms import StringField, SubmitField | 
				
			||||||
 | 
					from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError, NumberRange | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" --- CREATE LOGGER --- """ | 
				
			||||||
 | 
					logger = log.stashr_logger(__name__) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""------------------------------------------------------------------------------------------- | 
				
			||||||
 | 
					-- FORMS | 
				
			||||||
 | 
					-------------------------------------------------------------------------------------------""" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class settings_form(FlaskForm): | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    api_key = StringField( | 
				
			||||||
 | 
					        'Pushbullet API Key', | 
				
			||||||
 | 
					    ) | 
				
			||||||
 | 
					    channel = StringField( | 
				
			||||||
 | 
					        'Pushbullet Channel', | 
				
			||||||
 | 
					    ) | 
				
			||||||
 | 
					    settings_button = SubmitField( | 
				
			||||||
 | 
					        'Save', | 
				
			||||||
 | 
					    ) | 
				
			||||||
@ -0,0 +1,126 @@ | 
				
			|||||||
 | 
					{% extends "settings_page.html" %} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block header_script_files %} | 
				
			||||||
 | 
					<script src="https://unpkg.com/axios/dist/axios.min.js"></script> | 
				
			||||||
 | 
					{% endblock %} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block settings_pane %} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div id="app"> | 
				
			||||||
 | 
					    <settings ref="settings" v-bind:settings="settings"></settings> | 
				
			||||||
 | 
					    <modals ref="modal" v-bind:settings="settings"></modals> | 
				
			||||||
 | 
					</div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block script %} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.component('settings', { | 
				
			||||||
 | 
					    props: ['settings'], | 
				
			||||||
 | 
					    template: ` | 
				
			||||||
 | 
					    <div class="row r-10 m-2"> | 
				
			||||||
 | 
					        <div class="col col-12"> | 
				
			||||||
 | 
					            <div class="row"> | 
				
			||||||
 | 
					                <div class="col-sm-12 col-md-6 text-center text-md-start"> | 
				
			||||||
 | 
					                    <h2>Thumbnailer</h2> | 
				
			||||||
 | 
					                </div> | 
				
			||||||
 | 
					            </div> | 
				
			||||||
 | 
					            <hr /> | 
				
			||||||
 | 
					            <div class="row"> | 
				
			||||||
 | 
					                <ul class="nav nav-tabs" id="myTab" role="tablist"> | 
				
			||||||
 | 
					                    <li class="nav-item" role="presentation"> | 
				
			||||||
 | 
					                        <button class="nav-link active" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings" type="button" role="tab" aria-controls="settings" aria-selected="true">Settings</button> | 
				
			||||||
 | 
					                      </li> | 
				
			||||||
 | 
					                </ul> | 
				
			||||||
 | 
					                <div class="tab-content py-2" id="myTabContent"> | 
				
			||||||
 | 
					                    <div class="tab-pane fade show active" id="settings" role="tabpanel" aria-labelledby="settings-tab"> | 
				
			||||||
 | 
					                        <div class="row"> | 
				
			||||||
 | 
					                            <table class="table table-striped"> | 
				
			||||||
 | 
					                                <tbody> | 
				
			||||||
 | 
					                                    <tr> | 
				
			||||||
 | 
					                                        <th scope="row">{{ settings_form.api_key.label.text }}</th><td>[[ settings.PUSHBULLET.api_key ]]</td> | 
				
			||||||
 | 
					                                    </tr> | 
				
			||||||
 | 
					                                    <tr> | 
				
			||||||
 | 
					                                        <th scope="row">{{ settings_form.channel.label.text }}</th><td>[[ settings.PUSHBULLET.channel ]]</td> | 
				
			||||||
 | 
					                                    </tr> | 
				
			||||||
 | 
					                                </tbody> | 
				
			||||||
 | 
					                            </table> | 
				
			||||||
 | 
					                        </div> | 
				
			||||||
 | 
					                        <div class="row w-100"> | 
				
			||||||
 | 
					                            <div class="col-12 text-end my-2"> | 
				
			||||||
 | 
					                                <button type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#settingsModal">Modify Settings</button> | 
				
			||||||
 | 
					                            </div> | 
				
			||||||
 | 
					                        </div> | 
				
			||||||
 | 
					                    </div> | 
				
			||||||
 | 
					                </div> | 
				
			||||||
 | 
					            </div> | 
				
			||||||
 | 
					        </div> | 
				
			||||||
 | 
					    </div> | 
				
			||||||
 | 
					    `, | 
				
			||||||
 | 
					    methods: {}, | 
				
			||||||
 | 
					    delimiters: ["[[","]]"] | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.component('modals',{ | 
				
			||||||
 | 
					    props: ['settings'], | 
				
			||||||
 | 
					    template: ` | 
				
			||||||
 | 
					    <div> | 
				
			||||||
 | 
					        <div class="modal" id="settingsModal" role="dialog" aria-labelledby="settingsModal" aria-hidden="true"> | 
				
			||||||
 | 
					            <div class="modal-dialog modal-dialog-centered" role="document"> | 
				
			||||||
 | 
					                <div class="modal-content"> | 
				
			||||||
 | 
					                    <div class="modal-header"> | 
				
			||||||
 | 
					                        <h5 class="modal-title" id="notesModalTitle"> | 
				
			||||||
 | 
					                            Modify App Settings | 
				
			||||||
 | 
					                        </h5> | 
				
			||||||
 | 
					                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | 
				
			||||||
 | 
					                    </div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <form method="POST"> | 
				
			||||||
 | 
					                    <div class="modal-body"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            {{ settings_form.csrf_token }} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <div class="mb-3"> | 
				
			||||||
 | 
					                                {{ settings_form.api_key.label }} | 
				
			||||||
 | 
					                                {{ settings_form.api_key(class_='form-control', placeholder=settings_form.api_key.label.text) }} | 
				
			||||||
 | 
					                            </div> | 
				
			||||||
 | 
					                            <div class="mb-3"> | 
				
			||||||
 | 
					                                {{ settings_form.channel.label }} | 
				
			||||||
 | 
					                                {{ settings_form.channel(class_='form-control', placeholder=settings_form.channel.label.text) }} | 
				
			||||||
 | 
					                            </div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    </div> | 
				
			||||||
 | 
					                    <div class="modal-footer"> | 
				
			||||||
 | 
					                        {{ settings_form.settings_button(class_='btn btn-success') }} | 
				
			||||||
 | 
					                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> | 
				
			||||||
 | 
					                    </div> | 
				
			||||||
 | 
					                    </form> | 
				
			||||||
 | 
					                </div> | 
				
			||||||
 | 
					            </div> | 
				
			||||||
 | 
					        </div> | 
				
			||||||
 | 
					    </div> | 
				
			||||||
 | 
					    `, | 
				
			||||||
 | 
					    methods: {}, | 
				
			||||||
 | 
					    delimiters: ["[[","]]"] | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var app = new Vue({ | 
				
			||||||
 | 
					    el: '#app', | 
				
			||||||
 | 
					    data: { | 
				
			||||||
 | 
					        settings: [] | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    created() { | 
				
			||||||
 | 
					        this.getSettings() | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    methods: { | 
				
			||||||
 | 
					        getSettings() { | 
				
			||||||
 | 
					            axios.get('{{ url_for('pushbullet.api_get_settings') }}') | 
				
			||||||
 | 
					                .then(res => { | 
				
			||||||
 | 
					                    this.settings = res.data.results; | 
				
			||||||
 | 
					                }) | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    delimiters: ["[[","]]"] | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %} | 
				
			||||||
@ -0,0 +1,6 @@ | 
				
			|||||||
 | 
					<li class="nav-item"> | 
				
			||||||
 | 
					    <a class="nav-link{% if request.path == url_for('pushbullet.pushbullet_settings_page') %} active{% endif %}" href="{{ url_for('pushbullet.pushbullet_settings_page') }}"> | 
				
			||||||
 | 
					        <i class="fas fa-bell"></i> | 
				
			||||||
 | 
					        Pushbullet | 
				
			||||||
 | 
					    </a> | 
				
			||||||
 | 
					</li> | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue