├── biblioteca_guerrilla └── app │ ├── __init__.py │ ├── tests │ ├── __init__,py │ ├── data │ │ └── biblioteca_calibre │ │ │ ├── metadata.db │ │ │ ├── Aaron Swartz │ │ │ └── Manifiesto por la Guerrilla del Acceso Abierto (3) │ │ │ │ ├── cover.jpg │ │ │ │ ├── Manifiesto por la Guerrilla del Acceso Abi - Aaron Swartz.pdf │ │ │ │ └── metadata.opf │ │ │ ├── En Defensa del Software Libre │ │ │ └── Licencia de Produccion de Pares (Version legible por humanas) (2) │ │ │ │ ├── cover.jpg │ │ │ │ ├── Licencia de Produccion de Pares (Version l - En Defensa del Software Libre.epub │ │ │ │ └── metadata.opf │ │ │ └── metadata_db_prefs_backup.json │ └── calibre_connector_test.py │ ├── utils │ ├── __init__.py │ ├── urls.py │ └── books.py │ ├── connector │ ├── __init__.py │ ├── calibre │ │ ├── __init__.py │ │ ├── tests │ │ │ ├── __init__.py │ │ │ └── tests.py │ │ └── calibre.py │ └── dbprovider.py │ ├── static │ ├── img │ │ ├── bg-logo.png │ │ ├── logo-alpha.png │ │ └── bg-logo.svg │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.ttf │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-solid-900.woff2 │ │ ├── fa-regular-400.woff2 │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── css │ │ ├── custom.css │ │ ├── aside.css │ │ └── font-awesome.css │ └── js │ │ └── bulma.js │ ├── templates │ ├── central.html │ ├── header.html │ ├── footer.html │ ├── sidebar.html │ ├── list_of_books.html │ ├── list_of_entries.html │ ├── base.html │ ├── book.html │ └── index.html │ ├── freeze.py │ ├── settings.py │ ├── translations │ ├── es_AR.po │ └── es_AR │ │ └── LC_MESSAGES │ │ └── messages.po │ └── main.py ├── babel.cfg ├── HISTORY.rst ├── setup.py ├── AUTHORS.rst ├── requirements.txt ├── MANIFEST.in ├── .editorconfig ├── .github └── ISSUE_TEMPLATE.md ├── Pipfile ├── requirements_dev.txt ├── .prospector.yml ├── LICENSE ├── .gitignore ├── README.md ├── setup.cfg ├── .pre-commit-config.yaml ├── Makefile └── CONTRIBUTING.rst /biblioteca_guerrilla/app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/__init__,py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/connector/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/connector/calibre/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/connector/calibre/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /babel.cfg: -------------------------------------------------------------------------------- 1 | [python: **.py] 2 | [jinja2: **/templates/**.html] 3 | extensions=jinja2.ext.autoescape,jinja2.ext.with_ 4 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 5 | 0.1.0 (2018-02-02) 6 | ------------------ 7 | 8 | * First release on PyPI. 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """The setup script.""" 5 | 6 | from setuptools import setup 7 | setup() 8 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/img/bg-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/img/bg-logo.png -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/img/logo-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/img/logo-alpha.png -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/central.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | {% block listado %} 4 | {% endblock %} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-brands-400.eot -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-solid-900.eot -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-solid-900.woff -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-brands-400.woff -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-regular-400.eot -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-regular-400.woff -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/static/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/metadata.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/tests/data/biblioteca_calibre/metadata.db -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/css/custom.css: -------------------------------------------------------------------------------- 1 | .dt { 2 | margin-top: 1rem; 3 | margin-bottom: 0rem !important; 4 | } 5 | 6 | .do-not-break{ 7 | word-break: keep-all !important; 8 | } 9 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * KaZe 9 | 10 | Contributors 11 | ------------ 12 | 13 | None yet. Why not be the first? 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -i https://pypi.python.org/simple 2 | babel==2.6.0 3 | click==7.0 4 | flask-babel==0.12.2 5 | flask==1.0.2 6 | frozen-flask==0.15 7 | itsdangerous==1.1.0 8 | jinja2==2.10 9 | markupsafe==1.1.0 10 | pytz==2018.9 11 | pyyaml==3.13 12 | werkzeug==0.14.1 13 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/Aaron Swartz/Manifiesto por la Guerrilla del Acceso Abierto (3)/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/tests/data/biblioteca_calibre/Aaron Swartz/Manifiesto por la Guerrilla del Acceso Abierto (3)/cover.jpg -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.md 6 | 7 | recursive-include tests * 8 | recursive-exclude * __pycache__ 9 | recursive-exclude * *.py[co] 10 | 11 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif 12 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/En Defensa del Software Libre/Licencia de Produccion de Pares (Version legible por humanas) (2)/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/tests/data/biblioteca_calibre/En Defensa del Software Libre/Licencia de Produccion de Pares (Version legible por humanas) (2)/cover.jpg -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/Aaron Swartz/Manifiesto por la Guerrilla del Acceso Abierto (3)/Manifiesto por la Guerrilla del Acceso Abi - Aaron Swartz.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/tests/data/biblioteca_calibre/Aaron Swartz/Manifiesto por la Guerrilla del Acceso Abierto (3)/Manifiesto por la Guerrilla del Acceso Abi - Aaron Swartz.pdf -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * Biblioteca Guerrilla version: 2 | * Python version: 3 | * Operating System: 4 | 5 | ### Description 6 | 7 | Describe what you were trying to get done. 8 | Tell us what happened, what went wrong, and what you expected to happen. 9 | 10 | ### What I Did 11 | 12 | ``` 13 | Paste the command(s) you ran and the output. 14 | If there was a crash, please include the traceback here. 15 | ``` 16 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | click = "==7.0" 10 | itsdangerous = "==1.1.0" 11 | pytz = "==2018.9" 12 | Babel = "==2.6.0" 13 | Flask-Babel = "==0.12.2" 14 | Flask = "==1.0.2" 15 | Frozen-Flask = "==0.15" 16 | Jinja2 = "==2.10" 17 | MarkupSafe = "==1.1.0" 18 | PyYAML = "==3.13" 19 | Werkzeug = "==0.14.1" 20 | 21 | [requires] 22 | python_version = "3.7" 23 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/freeze.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import click 3 | import main 4 | from flask_frozen import Freezer 5 | 6 | freezer = Freezer(main.app) 7 | 8 | 9 | if __name__ == '__main__': 10 | 11 | with click.progressbar( 12 | freezer.freeze_yield(), 13 | item_show_func=lambda p: p.url if p else 'Done!') as urls: 14 | for url in urls: 15 | # everything is already happening, just pass 16 | pass 17 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/js/bulma.js: -------------------------------------------------------------------------------- 1 | // The following code is based off a toggle menu by @Bradcomp 2 | // source: https://gist.github.com/Bradcomp/a9ef2ef322a8e8017443b626208999c1 3 | (function() { 4 | var burger = document.querySelector('.nav-toggle'); 5 | var menu = document.querySelector('.nav-menu'); 6 | burger.addEventListener('click', function() { 7 | burger.classList.toggle('is-active'); 8 | menu.classList.toggle('is-active'); 9 | }); 10 | })(); 11 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/En Defensa del Software Libre/Licencia de Produccion de Pares (Version legible por humanas) (2)/Licencia de Produccion de Pares (Version l - En Defensa del Software Libre.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elKaZe/biblioteca-guerrilla/HEAD/biblioteca_guerrilla/app/tests/data/biblioteca_calibre/En Defensa del Software Libre/Licencia de Produccion de Pares (Version legible por humanas) (2)/Licencia de Produccion de Pares (Version l - En Defensa del Software Libre.epub -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/utils/urls.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # vim:fenc=utf-8 4 | # 5 | # Copyright © 2017 Kaze 6 | # 7 | # Distributed under terms of the GPLv3+ license. 8 | 9 | """ 10 | Functions to work with urls 11 | """ 12 | 13 | import urllib 14 | 15 | 16 | def urlencode(s, safe="/"): 17 | s = urllib.parse.quote_plus(s, safe=safe) 18 | return s 19 | 20 | 21 | def urldecode(s): 22 | s = urllib.parse.unquote_plus(s) 23 | return s 24 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/footer.html: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim:fenc=utf-8 3 | # 4 | # 5 | # Distributed under terms of the GPLv3+ license. 6 | # 7 | # 8 | import os 9 | 10 | PROJECT_PATH = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] 11 | 12 | 13 | # Admin data 14 | ADMIN_NAME = "kaze" 15 | ADMIN_EMAIL = "kaze@rlab.be" 16 | 17 | # Connector 18 | CONNECTOR = "connector.calibre.calibre" 19 | CONNECTOR_OPTIONS = { 20 | "path": os.path.realpath('/home/facu/Biblioteca de calibre/metadata.db'), 21 | } 22 | BASE_BOOK_PATH = os.path.realpath('/home/facu/Biblioteca de calibre/') 23 | 24 | # Frozen-Flask 25 | FREEZER_DESTINATION = "/tmp/biblioteca-guerrilla/" 26 | FREEZER_RELATIVE_URLS = False 27 | 28 | # Languages 29 | BABEL_DEFAULT_LOCALE = "es" 30 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/sidebar.html: -------------------------------------------------------------------------------- 1 | 10 | 19 | -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | -i https://pypi.python.org/simple 2 | alabaster==0.7.11 3 | argh==0.26.2 4 | astroid==2.0.1 5 | babel==2.6.0 6 | bumpversion==0.5.3 7 | configparser==3.5.0 8 | coverage==4.1 9 | docutils==0.14 10 | dodgy==0.1.9 11 | flake8-polyfill==1.0.2 12 | flake8==2.6.0 13 | futures==3.1.1 14 | imagesize==1.0.0 15 | isort==4.3.4 16 | itsdangerous==1.1.0 17 | jinja2==2.10 18 | lazy-object-proxy==1.3.1 19 | markupsafe==1.1.0 20 | mccabe==0.5.3 21 | pathtools==0.1.2 22 | pep8-naming==0.7.0 23 | pluggy==0.3.1 24 | prospector==1.0 25 | py==1.5.4 26 | pycodestyle==2.0.0 27 | pydocstyle==2.1.1 28 | pyflakes==1.2.3 29 | pygments==2.2.0 30 | pylint-common==0.2.5 31 | pylint-plugin-utils==0.4 32 | pylint==2.0.1 33 | pytz==2018.9 34 | pyyaml==3.13 35 | requirements-detector==0.6 36 | setoptconf==0.2.0 37 | six==1.12.0 38 | snowballstemmer==1.2.1 39 | sphinx==1.4.8 40 | tox==2.3.1 41 | typing==3.6.4 42 | virtualenv==16.0.0 43 | watchdog==0.8.3 44 | wrapt==1.10.11 45 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/list_of_books.html: -------------------------------------------------------------------------------- 1 | {% extends "central.html" %} 2 | {% block listado %} 3 | 4 | {% macro genera_item_book(title, author, ruta_cover) %} 5 | 6 |
7 | {{ _('Book cover') }} 8 |
9 |
{{ title }}
10 |
{{ author }}
11 |
12 | {% endmacro %} 13 | {% macro genera_columnas(books) %} 14 | {% for book in books %} 15 |
16 | {{ genera_item_book(book.title, book.author, book.cover) }} 17 |
18 | {% endfor %} 19 | 20 | {% endmacro %} 21 |
22 | {% include "sidebar.html" %} 23 |
24 |
{{ title|capitalize }}
25 |
26 | {{ genera_columnas(books) }} 27 |
28 |
29 |
30 | 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/list_of_entries.html: -------------------------------------------------------------------------------- 1 | {% extends "central.html" %} 2 | {% block listado %} 3 | 4 | {% macro genera_lista(entries) %} 5 | 7 | {% for key, value in entries|dictsort %} 8 |
9 |
10 |
{{key}}
11 | {% for element in value %} 12 |
13 | 14 | {{ element.element|truncate(50, True)|capitalize }} 15 | 16 |
17 | {% endfor %} 18 |
19 |
20 | {% endfor %} 21 | {% endmacro %} 22 | 23 |
24 | {% include "sidebar.html" %} 25 | 26 |
27 |
{{ title|capitalize }}
28 |
29 | {{ genera_lista(entries) }} 30 | 31 |
32 |
33 |
34 | 35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /.prospector.yml: -------------------------------------------------------------------------------- 1 | 2 | output-format: grouped 3 | # autodetect: false 4 | strictness: veryhigh 5 | doc-warnings: true 6 | test-warnings: false 7 | max-line-length: 80 8 | 9 | ignore-paths: 10 | - docs/ 11 | - tests/ 12 | - examples/ 13 | - env 14 | - venv 15 | 16 | # ignore-patterns: 17 | # - (^|/)skip(this)?(/|$) 18 | 19 | frosted: 20 | run: false 21 | 22 | pyroma: 23 | run: false 24 | 25 | pylint: 26 | run: false 27 | disable: 28 | - missing-docstring 29 | # - bad-builtin 30 | # - too-few-public-methods 31 | # - star-args 32 | # - method-hidden 33 | # - access-member-before-definition 34 | 35 | pep8: 36 | full: true 37 | disable: 38 | - E501 39 | - D101 40 | - D102 41 | - D105 42 | - E121 43 | - E123 44 | - E126 45 | - E226 46 | - E24 47 | - E704 48 | - W503 49 | - W504 50 | - N813 51 | - E731 52 | options: 53 | max-line-length: 80 54 | 55 | pep257: 56 | run: false 57 | disable: 58 | - D100 59 | - D101 60 | - D102 61 | - D103 62 | - D205 63 | - D400 64 | - D401 65 | - D211 66 | - D204 67 | - D107 68 | - D202 69 | - D105 70 | - D209 71 | - D213 72 | 73 | mccabe: 74 | run: false 75 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/Aaron Swartz/Manifiesto por la Guerrilla del Acceso Abierto (3)/metadata.opf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3 5 | 4112cd0e-79e6-482c-b7a8-8b755a864c29 6 | Manifiesto por la Guerrilla del Acceso Abierto 7 | Aaron Swartz 8 | calibre (2.78.0) [https://calibre-ebook.com] 9 | 0101-01-01T00:00:00+00:00 10 | spa 11 | eng 12 | hacker 13 | libertad 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Biblioteca Guerrilla 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% block extra_css %} 21 | {% endblock %} 22 | 23 | 24 | 25 | 26 | {% include "header.html" %} 27 | {% block content %} 28 | {% endblock %} 29 |
30 | {% include "footer.html" %} 31 |
32 | 33 | 34 | {% block extra_js %} 35 | {% endblock %} 36 | 37 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/En Defensa del Software Libre/Licencia de Produccion de Pares (Version legible por humanas) (2)/metadata.opf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2 5 | ecadf73f-544f-4e8b-a68e-08a328afd2cf 6 | Licencia de Producción de Pares (Versión legible por humanas) 7 | En Defensa del Software Libre 8 | calibre (2.78.0) [https://calibre-ebook.com] 9 | 2017-01-09T17:36:04+00:00 10 | EDSL 11 | spa 12 | licencia 13 | hacker 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | GNU GENERAL PUBLIC LICENSE 3 | Version 3, 29 June 2007 4 | 5 | Simple static website generator to share books 🕮 6 | Copyright (C) 2018 KaZe 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | 21 | Also add information on how to contact you by electronic and paper mail. 22 | 23 | You should also get your employer (if you work as a programmer) or school, 24 | if any, to sign a "copyright disclaimer" for the program, if necessary. 25 | For more information on this, and how to apply and follow the GNU GPL, see 26 | . 27 | 28 | The GNU General Public License does not permit incorporating your program 29 | into proprietary programs. If your program is a subroutine library, you 30 | may consider it more useful to permit linking proprietary applications with 31 | the library. If this is what you want to do, use the GNU Lesser General 32 | Public License instead of this License. But first, please read 33 | . 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | zapana.xml 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Biblioteca Guerrilla 2 | 3 | ### ¿Qué es? 4 | Biblioteca Guerrilla es una aplicación para generar un catalogo web de libros 5 | y embeberlo en un router (o cualquier dispositivo :D). 6 | 7 | ### ¿Y cómo funciona esto? 8 | Actualmente la unica manera de generar el catalogo es usando una biblioteca de [Calibre](https://calibre-ebook.com/), 9 | 10 | ### Instalación 11 | 12 | Vas a necesitar `pipenv` para correr todo. Se puede instalar con 13 | 14 | ``` 15 | pip install pipenv --user 16 | ``` 17 | 18 | Y luego en el directorio de la aplicación instalamos las dependencias: 19 | 20 | ``` 21 | pipenv install 22 | ``` 23 | 24 | Antes de generar el sitio, hay que entrar al entorno de trabajo: 25 | 26 | ``` 27 | pipenv shell 28 | ``` 29 | 30 | ### ¡Mandale mecha! 31 | Asegurate que todos los libros tengan la portada generada, eso lo conseguis 32 | desde calibre, chequea las opciones de **modificar metadatos en masa** 33 | 34 | Edita __app/settings.py__: 35 | ``` 36 | CONECTOR_OPCIONES = { 37 | "ruta": "ruta/a/la/base/de/datos/de/calibre/metadata.db" 38 | } 39 | RUTA_BASE_LIBROS = "ruta/a/la/bibliotecaDeCalibre/" 40 | ``` 41 | generamos la web estatica: 42 | 43 | ``` 44 | make generate-static-website 45 | ``` 46 | 47 | dentro de **/tmp/biblioteca-guerrilla/** tedremos la web. 48 | 49 | ### ¿Cómo iniciar el server de pruebas? 50 | 51 | Ejecutamos el siguiente comando 52 | ``` 53 | make start-test-server 54 | ``` 55 | 56 | Ingresamos a http://localhost:5000/ para ver el sitio 57 | 58 | ### ¡Quiero colabrar! 59 | - Si encontras errores levantá un issue. 60 | - ¡Los parches son más que bienvenidos! 61 | - Si queres traducir entra 62 | [acá](https://www.transifex.com/biblioteca-guerrilla/biblioteca-guerrilla) 63 | 64 | ### ¿Qué licencia tiene? 65 | GPLv3+, chequea el archivo [LICENCE](LICENCE) 66 | 67 | --------------------------- 68 | 69 | Inspirado en [Letras viajeras](https://github.com/gcoop-libre/letras_viajeras/) de la cooperativa [GCOOP](https://www.gcoop.coop/) 70 | 71 | Tema basado en [aside](https://github.com/dansup/bulma-templates/blob/gh-pages/css/aside.css) de [dansup](https://github.com/dansup) con licencia MIT 72 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/css/aside.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; 3 | height: 100%; 4 | } 5 | .button.is-success { 6 | background-color: #2EB398; 7 | } 8 | 9 | .aside { 10 | background-color: #232B2D; 11 | } 12 | .aside .uploader { 13 | background-color: #2EB398; 14 | height: 95px; 15 | margin:0 -10px; 16 | padding: 25px 30px; 17 | } 18 | .aside .uploader .button { 19 | background-color: transparent; 20 | border: 3px dashed #F6F7F7; 21 | padding: 20px 70px; 22 | color: #F6F7F7; 23 | } 24 | .aside .main { 25 | padding: 40px; 26 | color: #6F7B7E; 27 | } 28 | .aside .title { 29 | color: #6F7B7E; 30 | font-size: 12px; 31 | font-weight: bold; 32 | text-transform: uppercase; 33 | } 34 | .aside .main .item { 35 | display: block; 36 | padding: 10px 0; 37 | color: #6F7B7E; 38 | } 39 | .aside .main .item.active { 40 | color: #F6F7F7; 41 | } 42 | .aside .main .icon { 43 | font-size: 19px; 44 | padding-right: 30px; 45 | } 46 | .aside .main .name { 47 | font-size: 16px; 48 | font-weight: bold; 49 | } 50 | .content { 51 | display: block; 52 | background-color: #fff; 53 | padding: 40px 20px; 54 | } 55 | .nav.menu { 56 | background-color: #fff; 57 | border-bottom: 1px solid #e1e1e1; 58 | z-index: 1; 59 | } 60 | .nav.menu .nav-item .icon-btn { 61 | border: 3px solid #B7C6C9; 62 | border-radius: 90px; 63 | padding: 5px 7px; 64 | color: #B7C6C9; 65 | } 66 | .nav.menu .nav-item .icon-btn.thin { 67 | padding: 5px 8px; 68 | } 69 | .nav.menu .nav-item.is-active .icon-btn { 70 | color: #2EB398; 71 | border: 3px solid #2EB398; 72 | } 73 | .nav.menu .nav-item .icon-btn .fa { 74 | font-size: 20px; 75 | color: #B7C6C9; 76 | } 77 | .nav.menu .nav-item.is-active .icon-btn .fa { 78 | color: #2EB398; 79 | } 80 | .files { 81 | padding: 50px 0; 82 | } 83 | .file { 84 | display: block; 85 | padding: 20px; 86 | } 87 | a.file:not(.button) { 88 | border-bottom: none; 89 | border-radius: 4px; 90 | } 91 | .file:hover, .file.active, .file:active { 92 | background-color: #E4E9EB; 93 | } 94 | .file .image img { 95 | padding-bottom: 10px; 96 | } 97 | .file .name { 98 | font-weight: bold; 99 | word-wrap: break-word; 100 | word-break: break-all; 101 | font-size: 16px; 102 | color: #69707a; 103 | } 104 | .file .timestamp { 105 | font-weight: bold; 106 | font-size: 14px; 107 | color: #B9C2C4; 108 | } 109 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # See: https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata 2 | [metadata] 3 | name=biblioteca_guerrilla 4 | version=0.1.0 5 | description=Simple static website generator to share books 🕮 6 | author=KaZe 7 | author_email=kaze@rlab.be 8 | url=https://github.com/elkaze/biblioteca_guerrilla 9 | download_url=https://github.com/elkaze/biblioteca_guerrilla 10 | maintainer = KaZe 11 | maintainer_email = kaze@rlab.be 12 | keywords = books, sharing, calibre, static, website, generator 13 | license = GPL-3 LGPL-3 14 | platforms = Linux, Darwin, Windows 15 | project_urls = 16 | Docs = https://github.com/elKaZe/biblioteca-guerrilla/blob/master/README.md 17 | Bugs = https://github.com/elKaZe/biblioteca-guerrilla/issues 18 | # C.I. = https://travis-ci.org/example/example 19 | 20 | license_file = LICENSE 21 | long_description = file: README.md 22 | long_description_content_type = text/markdown 23 | classifiers = 24 | Development Status :: 4 - Beta 25 | Environment :: Console 26 | Environment :: Web Environment 27 | Intended Audience :: Education 28 | Intended Audience :: End Users/Desktop 29 | Natural Language :: English 30 | License :: OSI Approved :: GNU General Public License (GPL) 31 | License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) 32 | Operating System :: OS Independent 33 | Operating System :: POSIX :: Linux 34 | Operating System :: Microsoft :: Windows 35 | Operating System :: MacOS :: MacOS X 36 | Programming Language :: Python 37 | Programming Language :: Python :: 3 38 | Topic :: Communications :: File Sharing 39 | Topic :: Education 40 | Topic :: Internet :: WWW/HTTP 41 | Topic :: Utilities 42 | 43 | 44 | [options] 45 | zip_safe = True 46 | include_package_data = True 47 | python_requires = >=3.6 48 | tests_require = isort ; prospector ; pre-commit ; pre-commit-hooks 49 | install_requires = pip 50 | setup_requires = pip ; cython 51 | packages = find: 52 | 53 | [bdist_wheel] 54 | universal = 1 55 | python-tag = py36 56 | 57 | [install_lib] 58 | compile = 0 59 | optimize = 2 60 | 61 | [bdist_egg] 62 | exclude-source-files = true 63 | 64 | # [options.package_data] 65 | # * = *.pxd, *.pyx, *.json, *.txt 66 | 67 | # [options.exclude_package_data] 68 | # ;* = *.c, *.so, *.js 69 | 70 | [options.entry_points] 71 | console_scripts = 72 | biblioteca-guerrilla = biblioteca_guerrilla.app.freeze:main 73 | # bar = other_module:some_func 74 | # gui_scripts = 75 | # baz = my_package_gui:start_func 76 | 77 | # [options.packages.find] 78 | # where = . 79 | # include = *.py, *.pyw 80 | # exclude = *.c, *.so, *.js, *.tests, *.tests.*, tests.*, tests 81 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/connector/dbprovider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim:fenc=utf-8 3 | # 4 | # 5 | # Distributed under terms of the GPLv3+ license. 6 | 7 | """Utilities for the database""" 8 | 9 | import abc 10 | from importlib import import_module 11 | 12 | import settings 13 | 14 | 15 | class ConnectorABS(metaclass=abc.ABCMeta): 16 | """Metaclass to make connectors extend it""" 17 | @abc.abstractmethod 18 | def __init__(): 19 | """Initialize""" 20 | pass 21 | 22 | @abc.abstractmethod 23 | def connect(): 24 | """Connect and create db cursor""" 25 | pass 26 | 27 | @abc.abstractmethod 28 | def desconnect(): 29 | """Desconnect""" 30 | pass 31 | 32 | @abc.abstractmethod 33 | def get_all(): 34 | """Get all the books""" 35 | pass 36 | 37 | @abc.abstractmethod 38 | def get_by_author(self, author): 39 | """Obtain all books from an author""" 40 | pass 41 | 42 | @abc.abstractmethod 43 | def get_author_of_book(self, book_id): 44 | """Obtain the authors of a book""" 45 | 46 | @abc.abstractmethod 47 | def get_authors(): 48 | "Obtain all the authors in the library" 49 | pass 50 | 51 | @abc.abstractmethod 52 | def get_book_by_name(self, book_name): 53 | "Obtain a book by its name" 54 | pass 55 | 56 | @abc.abstractmethod 57 | def get_books_by_serie(self, serie): 58 | "Obtains all the books from a serie" 59 | pass 60 | 61 | @abc.abstractmethod 62 | def get_books_by_tag(self, tag): 63 | "Obtain all the books with the tag""" 64 | pass 65 | 66 | @abc.abstractmethod 67 | def get_tags_from_book(self, book_id): 68 | "Get tags from a book" 69 | pass 70 | 71 | @abc.abstractmethod 72 | def get_series_from_book(self, book_id): 73 | "Obtain the tags from a book" 74 | pass 75 | 76 | @abc.abstractmethod 77 | def get_tags(): 78 | "Obtain all the tags" 79 | pass 80 | 81 | @abc.abstractmethod 82 | def get_formats(self, book_id): 83 | "Returns a list with the all the formats and the name of the file" 84 | pass 85 | 86 | @abc.abstractmethod 87 | def get_synopsis(self, book_id): 88 | "Get the synopsis of a book" 89 | pass 90 | 91 | 92 | def instance_connector(): 93 | "Initialize and instance the connector according the configuration" 94 | 95 | # Import the module 96 | module = import_module(settings.CONNECTOR) 97 | # Instance the module 98 | con = module.Connector(**settings.CONNECTOR_OPTIONS) 99 | return con 100 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Automagic Multi-Language Static Analysis on Commit, before Push. 2 | # Install on local: pip install pre-commit pre-commit-hooks 3 | # Use in C.I.;Force Run: pre-commit run --all-files 4 | # Auto-Update all hooks: pre-commit autoupdate 5 | # Run all hooks on Push: pre-commit install --hook-type pre-push 6 | # Run all hooks on Commit: pre-commit install 7 | # Drop all hooks on Push: pre-commit uninstall --hook-type pre-push 8 | # Drop all hooks on Commit: pre-commit uninstall 9 | # http://pre-commit.com https://github.com/pre-commit 10 | 11 | 12 | - repo: https://github.com/pre-commit/pre-commit-hooks 13 | sha: master # v0.9.1 # Or SemVer of latest release. Or SHA1. 14 | minimum_pre_commit_version: 0.16.2 # From: pre-commit --version 15 | description: Static analysis to check files for best practices. 16 | files: 'app/' 17 | execlude: 18 | -'.*test.*' 19 | stages: [commit, push] # When to run. 20 | hooks: 21 | - id: end-of-file-fixer # Check that Text files ends with new line. 22 | - id: trailing-whitespace # Check for empty trailing white spaces. 23 | - id: check-added-large-files # Check for Text files > 500 Kilobytes. 24 | - id: check-byte-order-marker # Check for BOM byte-order marker on files. 25 | - id: check-case-conflict # Check conflicts for case-insensitive FS. 26 | - id: check-docstring-first # Check for DocStrings placement (if any). 27 | - id: check-merge-conflict # Check for committing Unmerged files. 28 | - id: check-symlinks # Check for SymLinks pointing nowhere. 29 | - id: debug-statements # Check for pdb/ipdb breakpoints in code. 30 | - id: fix-encoding-pragma # Add # -*- coding: utf-8 -*- to .py files. 31 | - id: requirements-txt-fixer # Alphabetically sorts requirements.txt 32 | - id: check-ast # Check for Invalid Broken Python code. 33 | - id: detect-private-key # Check for committing Private Keys. 34 | - id: forbid-new-submodules # Prevent addition of new Git SubModules. 35 | - id: check-executables-have-shebangs # Check if executable have SheBang. 36 | - id: check-json # Check JSON files are valid (if any). 37 | - id: check-yaml # Check YAML files are valid (if any). 38 | - id: check-xml # Check XML files are valid (if any). 39 | - id: autopep8-wrapper # Fix all PEP8 Lint Errors on Python files. 40 | args: ['--in-place', '--list-fixes', '--ignore=E501,D101,D102,D105,E121,E123,E126,E226,E24,E704,W503,W504,E731'] 41 | # - id: flake8 # Lint all Python files using Flake8. 42 | # args: ['--statistics', '--ignore=E501,D101,D102,D105,E121,E123,E126,E226,E24,E704,W503,W504,E731','--exclude=app/conector/calibre/tests/'] 43 | 44 | 45 | - repo: git://github.com/FalconSocial/pre-commit-python-sorter 46 | sha: master 47 | hooks: 48 | - id: python-import-sorter 49 | args: ['--silent-overwrite'] 50 | 51 | 52 | # - repo: git://github.com/guykisel/prospector-mirror 53 | # sha: master 54 | # hooks: 55 | # - id: prospector 56 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/calibre_connector_test.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # vim:fenc=utf-8 4 | # 5 | # Distributed under terms of the GPLv3+ license. 6 | 7 | """ 8 | Test para el connector de calibre 9 | 10 | """ 11 | 12 | import unittest 13 | 14 | from app.connector.calibre import Connector 15 | from app.dbprovider import ConnectorABS 16 | 17 | 18 | class CalibreConnectorTestCase(unittest.TestCase): 19 | 20 | def setUp(self): 21 | self.con = Connector( 22 | **{'path': "app/tests/data/biblioteca_calibre/metadata.db"}) 23 | self.con.connect() 24 | 25 | def tearDown(self): 26 | self.con.desconnect() 27 | 28 | def test_instancia(self): 29 | """verifica que extienda y sea instancia de dbprovider""" 30 | self.assertTrue( 31 | issubclass(Connector, ConnectorABS) 32 | ) 33 | self.assertTrue( 34 | isinstance( 35 | Connector( 36 | ** 37 | {'path': "app/tests/data/biblioteca_calibre/metadata.db"}), 38 | ConnectorABS)) 39 | 40 | # Verificamos el error al pasarle una path invalida 41 | with self.assertRaises(FileNotFoundError): 42 | Connector(**{'path': ""}) 43 | 44 | def test_get_authors(self): 45 | """Testeamos la obtencion de authors""" 46 | # tenemos tres 47 | authors = self.con.get_authors() 48 | self.assertEqual(len(authors), 3) 49 | 50 | def test_get_all(self): 51 | """Testeamos la obtencion todo""" 52 | # tenemos tres 53 | books = self.con.get_all() 54 | self.assertEqual(len(books), 3) 55 | 56 | # cantidad de atributos 57 | for l in books: 58 | self.assertEqual(len(l), 4) 59 | 60 | def test_get_by_author(self): 61 | """Traemos todos los books por cada author""" 62 | 63 | authors = self.con.get_authors() 64 | for a in authors: 65 | books = self.con.get_by_author(a) 66 | self.assertNotEqual(len(books), 0) 67 | 68 | def test_get_tags(self): 69 | """Testeamos la obtencion de tags""" 70 | tags = self.con.get_tags() 71 | self.assertEqual(len(tags), 5) 72 | 73 | def test_get_books_by_tags(self): 74 | """Traemos todos los books por cada tag""" 75 | 76 | tags = self.con.get_tags() 77 | for e in tags: 78 | books = self.con.get_books_by_tag(e) 79 | self.assertNotEqual(len(books), 0) 80 | 81 | # Etiqueta inexistente 82 | books = self.con.get_books_by_tag("asddwjijijij") 83 | self.assertEqual(len(books), 0) 84 | 85 | def test_get_formats(self): 86 | """Traemos los format de un book""" 87 | 88 | books = self.con.get_all() 89 | 90 | for l in books: 91 | format = self.con.get_formats(l.get("id")) 92 | self.assertNotEqual(len(format), 0) 93 | 94 | # Sin format 95 | format = self.con.get_formats("8798798798798") 96 | self.assertEqual(len(format), 0) 97 | 98 | 99 | if __name__ == '__main__': 100 | unittest.main() 101 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/utils/books.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # vim:fenc=utf-8 4 | # 5 | # 6 | # Distributed under terms of the GPLv3+ license. 7 | 8 | """ 9 | Functions to make easy to work with books 10 | 11 | """ 12 | 13 | import os 14 | 15 | from .urls import urlencode 16 | 17 | 18 | def add_tags(books, connector): 19 | """add tags""" 20 | 21 | for book in books: 22 | tags = connector.get_tags_from_book(book.get("id", '')) 23 | book["tags"] = tags 24 | return books 25 | 26 | 27 | def add_format(books, connector): 28 | """Add the file type and the path of the book using a dict 29 | ex: book["format"] -> {'pdf', '/tmp/book.pdf'}""" 30 | 31 | for book in books: 32 | dic_format = {} 33 | format = connector.get_formats(book['id']) 34 | for element_fomart in format: 35 | filet_type = (element_fomart[0]).lower() 36 | file_name = element_fomart[1] + "." + filet_type 37 | 38 | file_path = os.path.join( 39 | book['path'], 40 | file_name) 41 | # Encode at saving 42 | dic_format[filet_type] = urlencode(file_path) 43 | 44 | book["format"] = dic_format 45 | 46 | return books 47 | 48 | 49 | def add_cover_path(books, connector): 50 | """Add the the path of the cover the the list of books, the "book" is a 51 | dictionary""" 52 | 53 | cover_file_name = "cover.jpg" 54 | 55 | for book in books: 56 | ruta_cover = os.path.join( 57 | book.get('path'), 58 | cover_file_name) 59 | book["cover"] = urlencode(ruta_cover) 60 | 61 | return books 62 | 63 | 64 | def simplify_date(books): 65 | """simplify the date 66 | ej: 0101-01-01 00:00:00+00:00 67 | 0101 68 | """ 69 | 70 | for book in books: 71 | # Obtengo el año de publicacion, que son los primeros 4 caracteres 72 | book["publication_date"] = book.get("publication_date", "")[:4] 73 | 74 | return books 75 | 76 | 77 | def add_authors(books, connector): 78 | """Add the authors of the book""" 79 | 80 | for book in books: 81 | authors = connector.get_author_of_book(book.get("id", '')) 82 | book["authors"] = authors 83 | 84 | return books 85 | 86 | 87 | def add_synopsis(books, connector): 88 | """Add the synopsis of the book""" 89 | 90 | for book in books: 91 | synopsis = connector.get_synopsis(book.get("id", '')) 92 | book["sinopsis"] = "".join(synopsis) 93 | 94 | return books 95 | 96 | 97 | def add_series(books, connector): 98 | """Add the series of the book""" 99 | 100 | for book in books: 101 | series = connector.get_series_from_book(book.get("id", '')) 102 | book["series"] = series 103 | return books 104 | 105 | 106 | def normalize_book(books, connector): 107 | "Normalize the attributes of books" 108 | 109 | books = simplify_date(books) 110 | books = add_tags(books, connector) 111 | books = add_synopsis(books, connector) 112 | books = add_authors(books, connector) 113 | books = add_series(books, connector) 114 | books = add_format(books, connector) 115 | normalized_books = add_cover_path(books, connector) 116 | return normalized_books 117 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean clean-test clean-pyc clean-build docs help start-test-server generate-static-website 2 | .DEFAULT_GOAL := help 3 | define BROWSER_PYSCRIPT 4 | import os, webbrowser, sys 5 | try: 6 | from urllib import pathname2url 7 | except: 8 | from urllib.request import pathname2url 9 | 10 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 11 | endef 12 | export BROWSER_PYSCRIPT 13 | 14 | define PRINT_HELP_PYSCRIPT 15 | import re, sys 16 | 17 | for line in sys.stdin: 18 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) 19 | if match: 20 | target, help = match.groups() 21 | print("%-20s %s" % (target, help)) 22 | endef 23 | export PRINT_HELP_PYSCRIPT 24 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 25 | 26 | help: 27 | @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) 28 | 29 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 30 | 31 | 32 | clean-build: ## remove build artifacts 33 | rm -fr build/ 34 | rm -fr dist/ 35 | rm -fr .eggs/ 36 | find . -name '*.egg-info' -exec rm -fr {} + 37 | find . -name '*.egg' -exec rm -f {} + 38 | 39 | clean-pyc: ## remove Python file artifacts 40 | find . -name '*.pyc' -exec rm -f {} + 41 | find . -name '*.pyo' -exec rm -f {} + 42 | find . -name '*~' -exec rm -f {} + 43 | find . -name '__pycache__' -exec rm -fr {} + 44 | 45 | clean-test: ## remove test and coverage artifacts 46 | rm -fr .tox/ 47 | rm -f .coverage 48 | rm -fr htmlcov/ 49 | 50 | # lint: ## check style with flake8 51 | # flake8 biblioteca_guerrilla tests 52 | 53 | # test: ## run tests quickly with the default Python 54 | 55 | # python setup.py test 56 | 57 | # test-all: ## run tests on every Python version with tox 58 | # tox 59 | 60 | # coverage: ## check code coverage quickly with the default Python 61 | # coverage run --source biblioteca_guerrilla setup.py test 62 | # coverage report -m 63 | # coverage html 64 | # $(BROWSER) htmlcov/index.html 65 | 66 | # docs: ## generate Sphinx HTML documentation, including API docs 67 | # rm -f docs/biblioteca_guerrilla.rst 68 | # rm -f docs/modules.rst 69 | # sphinx-apidoc -o docs/ biblioteca_guerrilla 70 | # $(MAKE) -C docs clean 71 | # $(MAKE) -C docs html 72 | # $(BROWSER) docs/_build/html/index.html 73 | 74 | # servedocs: docs ## compile the docs watching for changes 75 | # watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 76 | 77 | # release: clean ## package and upload a release 78 | # python setup.py sdist upload 79 | # python setup.py bdist_wheel upload 80 | 81 | # dist: clean ## builds source and wheel package 82 | # python setup.py sdist 83 | # python setup.py bdist_wheel 84 | # ls -l dist 85 | 86 | # install: clean ## install the package to the active Python's site-packages 87 | # python setup.py install 88 | 89 | start-test-server: clean ## runs tests server to see what the app generates 90 | export FLASK_DEBUG=1; export FLASK_APP=main.py; cd biblioteca_guerrilla/app; python -m flask run 91 | 92 | generate-static-website: clean ## generate the static website 93 | cd biblioteca_guerrilla/app; python freeze.py 94 | 95 | babel-extract-messages: ## extracts strings from code to translate 96 | pybabel extract --project='Biblioteca Guerrilla' --sort-by-file -F babel.cfg -o messages/messages.pot biblioteca_guerrilla/app/ 97 | 98 | babel-compile-translations: ## compile translations 99 | pybabel compile -f -d biblioteca_guerrilla/app/translations 100 | 101 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/book.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "central.html" %} 3 | {% block content%} 4 | 5 | 6 |
7 | {% include "sidebar.html" %} 8 |
9 |
{{ title }}
10 |
11 |
12 |
13 | {{ _('Book cover') }} 14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 33 | 34 | 35 | 43 | 54 | 55 | 56 | 57 | 66 | 67 | 68 |
{{ _('Title') }}: {{ book.title|capitalize }} 23 | 24 | {% if book.tags%} 25 | {{ _('Labels:') }} 26 | {% for tag in book.tags %} 27 | 28 | {{ tag|capitalize }} 29 | 30 | {% endfor %} 31 | {% endif %} 32 |
{{ _('Author:') }} 36 | {% for author in book.authors %} 37 | 38 | {{ author}} 39 | 40 | {% endfor %} 41 | 42 | 44 | 45 | {% if book.series%} 46 | {{ _('Collection:') }} 47 | {% for serie in book.series%} 48 | 49 | {{ serie|capitalize }} 50 | 51 | {% endfor %} 52 | {% endif %} 53 |
{{ _('Year of publication:') }} {{ book.publication_date}} 58 | 59 | {{ _('Download:') }} 60 | {% for formato, path in book.format.items() %} 61 | 62 | {{ formato|upper}} 63 | 64 | {% endfor %} 65 |
69 | {% if book.sinopsis %} 70 | {{ _('Synopsis:') }} 71 |

72 | {{ book.sinopsis|safe}} 73 |

74 | {% endif %} 75 |
76 |
77 |
78 | 79 | {% endblock %} 80 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! Every 8 | little bit helps, and credit will always be given. 9 | 10 | You can contribute in many ways: 11 | 12 | Types of Contributions 13 | ---------------------- 14 | 15 | Report Bugs 16 | ~~~~~~~~~~~ 17 | 18 | Report bugs at https://github.com/elkaze/biblioteca_guerrilla/issues. 19 | 20 | If you are reporting a bug, please include: 21 | 22 | * Your operating system name and version. 23 | * Any details about your local setup that might be helpful in troubleshooting. 24 | * Detailed steps to reproduce the bug. 25 | 26 | Fix Bugs 27 | ~~~~~~~~ 28 | 29 | Look through the GitHub issues for bugs. Anything tagged with "bug" 30 | and "help wanted" is open to whoever wants to implement it. 31 | 32 | Implement Features 33 | ~~~~~~~~~~~~~~~~~~ 34 | 35 | Look through the GitHub issues for features. Anything tagged with "enhancement" 36 | and "help wanted" is open to whoever wants to implement it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | Biblioteca Guerrilla could always use more documentation, whether as part of the 42 | official Biblioteca Guerrilla docs, in docstrings, or even on the web in blog posts, 43 | articles, and such. 44 | 45 | Submit Feedback 46 | ~~~~~~~~~~~~~~~ 47 | 48 | The best way to send feedback is to file an issue at https://github.com/elkaze/biblioteca_guerrilla/issues. 49 | 50 | If you are proposing a feature: 51 | 52 | * Explain in detail how it would work. 53 | * Keep the scope as narrow as possible, to make it easier to implement. 54 | * Remember that this is a volunteer-driven project, and that contributions 55 | are welcome :) 56 | 57 | Get Started! 58 | ------------ 59 | 60 | Ready to contribute? Here's how to set up `biblioteca_guerrilla` for local development. 61 | 62 | 1. Fork the `biblioteca_guerrilla` repo on GitHub. 63 | 2. Clone your fork locally:: 64 | 65 | $ git clone git@github.com:your_name_here/biblioteca_guerrilla.git 66 | 67 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 68 | 69 | $ mkvirtualenv biblioteca_guerrilla 70 | $ cd biblioteca_guerrilla/ 71 | $ python setup.py develop 72 | 73 | 4. Create a branch for local development:: 74 | 75 | $ git checkout -b name-of-your-bugfix-or-feature 76 | 77 | Now you can make your changes locally. 78 | 79 | 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: 80 | 81 | $ flake8 biblioteca_guerrilla tests 82 | $ python setup.py test or py.test 83 | $ tox 84 | 85 | To get flake8 and tox, just pip install them into your virtualenv. 86 | 87 | 6. Commit your changes and push your branch to GitHub:: 88 | 89 | $ git add . 90 | $ git commit -m "Your detailed description of your changes." 91 | $ git push origin name-of-your-bugfix-or-feature 92 | 93 | 7. Submit a pull request through the GitHub website. 94 | 95 | Pull Request Guidelines 96 | ----------------------- 97 | 98 | Before you submit a pull request, check that it meets these guidelines: 99 | 100 | 1. The pull request should include tests. 101 | 2. If the pull request adds functionality, the docs should be updated. Put 102 | your new functionality into a function with a docstring, and add the 103 | feature to the list in README.md. 104 | 3. The pull request should work for Python 3.3, 3.4 and 3.5, and for PyPy. 105 | and make sure that the tests pass for all supported Python versions. 106 | 107 | Tips 108 | ---- 109 | 110 | To run a subset of tests:: 111 | 112 | 113 | $ python -m unittest tests.test_biblioteca_guerrilla 114 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/translations/es_AR.po: -------------------------------------------------------------------------------- 1 | # Kaze , 2017. #zanata 2 | # Kaze , 2018. #zanata 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: Biblioteca Guerrilla VERSION\n" 6 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 7 | "POT-Creation-Date: 2018-01-08 10:58-0300\n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | "PO-Revision-Date: 2018-02-02 07:24-0500\n" 12 | "Last-Translator: Kaze \n" 13 | "Language-Team: Spanish (Argentina)\n" 14 | "Language: es-AR\n" 15 | "X-Generator: Zanata 3.9.6\n" 16 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 17 | 18 | #: app/main.py:54 app/templates/index.html:28 19 | msgid "Books" 20 | msgstr "Libros" 21 | 22 | #: app/main.py:57 app/templates/index.html:42 23 | msgid "Authors" 24 | msgstr "Autores" 25 | 26 | #: app/main.py:60 app/templates/index.html:49 27 | msgid "Categories" 28 | msgstr "Categorías" 29 | 30 | #: app/main.py:66 app/templates/index.html:35 31 | msgid "Series" 32 | msgstr "Series" 33 | 34 | #: app/main.py:78 app/main.py:79 35 | msgid "Not set" 36 | msgstr "No definido" 37 | 38 | #: app/main.py:254 39 | msgid "All books:" 40 | msgstr "Todos los books:" 41 | 42 | #: app/templates/footer.html:5 43 | msgid "" 44 | "by KaZe. This source code " 45 | "is under\n" 46 | " GPLv3+ license. Website content is under a " 47 | "different license." 48 | msgstr "" 49 | "por KaZe. El código fuente " 50 | "esta licenciado bajo GPLv3+. El contenido del sitio cuenta " 51 | "con distintas licencias." 52 | 53 | #: app/templates/header.html:18 54 | msgid "Languages" 55 | msgstr "Idiomas" 56 | 57 | #: app/templates/index.html:12 58 | msgid "Welcome!" 59 | msgstr "¡Bienvenidx!" 60 | 61 | #: app/templates/index.html:15 62 | msgid "On the left bar you will find the categories organising the books." 63 | msgstr "" 64 | "En la barra de la izquierda vas a encontrar categorías que organizan los " 65 | "books." 66 | 67 | #: app/templates/index.html:21 68 | msgid "This node has:" 69 | msgstr "Este nodo cuenta con:" 70 | 71 | #: app/templates/index.html:60 72 | msgid "To read the books we recommend the following applications:" 73 | msgstr "Para leer los books te recomendamos las siguientes aplicaciones:" 74 | 75 | #: app/templates/index.html:67 76 | msgid "System" 77 | msgstr "Sistema" 78 | 79 | #: app/templates/index.html:70 80 | msgid "Application" 81 | msgstr "Aplicación" 82 | 83 | #: app/templates/index.html:97 84 | msgid "Run your own node:" 85 | msgstr "Armá tu propio nodo:" 86 | 87 | #: app/templates/index.html:101 88 | msgid "Hey! Do you like the idea?" 89 | msgstr "Che! ¿Te gusta la idea?" 90 | 91 | #: app/templates/index.html:103 92 | msgid "" 93 | "Running your own node is very cheap and easy: you need a router, a Raspberry " 94 | "PI or just a computer." 95 | msgstr "" 96 | "Armar tu propio nodo es muy barato y fácil, solo tenes que tener un Router, " 97 | "una Respberry PI o incluso una computadora común." 98 | 99 | #: app/templates/index.html:105 100 | #, python-format 101 | msgid "" 102 | "Talk to the admin ( %(name)s ) of this node or send him/her an E-mail ." 104 | msgstr "" 105 | "Charla con quien administre ( %(name)s ) este nodo o mandale un E-mail ." 107 | 108 | #: app/templates/index.html:107 109 | msgid "" 110 | "If you have suggestions, ideas, complaints or anything else, you can send an " 111 | "E-mail to the author, his address is in the footer." 112 | msgstr "" 113 | "Si tenes sugerencias, ideas, quejas, o cualquier otra cosa, podes enviarle " 114 | "un E-mail al author, su dirección esta en el pie de pagina." 115 | 116 | #: app/templates/book.html:21 117 | msgid "Title" 118 | msgstr "Titulo" 119 | 120 | #: app/templates/book.html:25 121 | msgid "Labels:" 122 | msgstr "Etiquetas:" 123 | 124 | #: app/templates/book.html:35 125 | msgid "Author:" 126 | msgstr "Autor:" 127 | 128 | #: app/templates/book.html:46 129 | msgid "Collection:" 130 | msgstr "Colección:" 131 | 132 | #: app/templates/book.html:56 133 | msgid "Year of publication:" 134 | msgstr "Año de publicación:" 135 | 136 | #: app/templates/book.html:59 137 | msgid "Download:" 138 | msgstr "Descarga:" 139 | 140 | #: app/templates/book.html:70 141 | msgid "Synopsis:" 142 | msgstr "Sinopsis:" 143 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/translations/es_AR/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Kaze , 2017. #zanata 2 | # Kaze , 2018. #zanata 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: Biblioteca Guerrilla VERSION\n" 6 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 7 | "POT-Creation-Date: 2018-01-08 10:58-0300\n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | "PO-Revision-Date: 2018-02-02 07:24-0500\n" 12 | "Last-Translator: Kaze \n" 13 | "Language-Team: Spanish (Argentina)\n" 14 | "Language: es-AR\n" 15 | "X-Generator: Zanata 3.9.6\n" 16 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 17 | 18 | #: app/main.py:54 app/templates/index.html:28 19 | msgid "Books" 20 | msgstr "Libros" 21 | 22 | #: app/main.py:57 app/templates/index.html:42 23 | msgid "Authors" 24 | msgstr "Autores" 25 | 26 | #: app/main.py:60 app/templates/index.html:49 27 | msgid "Categories" 28 | msgstr "Categorías" 29 | 30 | #: app/main.py:66 app/templates/index.html:35 31 | msgid "Series" 32 | msgstr "Series" 33 | 34 | #: app/main.py:78 app/main.py:79 35 | msgid "Not set" 36 | msgstr "No definido" 37 | 38 | #: app/main.py:254 39 | msgid "All books:" 40 | msgstr "Todos los books:" 41 | 42 | #: app/templates/footer.html:5 43 | msgid "" 44 | "by KaZe. This source code " 45 | "is under\n" 46 | " GPLv3+ license. Website content is under a " 47 | "different license." 48 | msgstr "" 49 | "por KaZe. El código fuente " 50 | "esta licenciado bajo GPLv3+. El contenido del sitio cuenta " 51 | "con distintas licencias." 52 | 53 | #: app/templates/header.html:18 54 | msgid "Languages" 55 | msgstr "Idiomas" 56 | 57 | #: app/templates/index.html:12 58 | msgid "Welcome!" 59 | msgstr "¡Bienvenidx!" 60 | 61 | #: app/templates/index.html:15 62 | msgid "On the left bar you will find the categories organising the books." 63 | msgstr "" 64 | "En la barra de la izquierda vas a encontrar categorías que organizan los " 65 | "books." 66 | 67 | #: app/templates/index.html:21 68 | msgid "This node has:" 69 | msgstr "Este nodo cuenta con:" 70 | 71 | #: app/templates/index.html:60 72 | msgid "To read the books we recommend the following applications:" 73 | msgstr "Para leer los books te recomendamos las siguientes aplicaciones:" 74 | 75 | #: app/templates/index.html:67 76 | msgid "System" 77 | msgstr "Sistema" 78 | 79 | #: app/templates/index.html:70 80 | msgid "Application" 81 | msgstr "Aplicación" 82 | 83 | #: app/templates/index.html:97 84 | msgid "Run your own node:" 85 | msgstr "Armá tu propio nodo:" 86 | 87 | #: app/templates/index.html:101 88 | msgid "Hey! Do you like the idea?" 89 | msgstr "Che! ¿Te gusta la idea?" 90 | 91 | #: app/templates/index.html:103 92 | msgid "" 93 | "Running your own node is very cheap and easy: you need a router, a Raspberry " 94 | "PI or just a computer." 95 | msgstr "" 96 | "Armar tu propio nodo es muy barato y fácil, solo tenes que tener un Router, " 97 | "una Respberry PI o incluso una computadora común." 98 | 99 | #: app/templates/index.html:105 100 | #, python-format 101 | msgid "" 102 | "Talk to the admin ( %(name)s ) of this node or send him/her an E-mail ." 104 | msgstr "" 105 | "Charla con quien administre ( %(name)s ) este nodo o mandale un E-mail ." 107 | 108 | #: app/templates/index.html:107 109 | msgid "" 110 | "If you have suggestions, ideas, complaints or anything else, you can send an " 111 | "E-mail to the author, his address is in the footer." 112 | msgstr "" 113 | "Si tenes sugerencias, ideas, quejas, o cualquier otra cosa, podes enviarle " 114 | "un E-mail al author, su dirección esta en el pie de pagina." 115 | 116 | #: app/templates/book.html:21 117 | msgid "Title" 118 | msgstr "Titulo" 119 | 120 | #: app/templates/book.html:25 121 | msgid "Labels:" 122 | msgstr "Etiquetas:" 123 | 124 | #: app/templates/book.html:35 125 | msgid "Author:" 126 | msgstr "Autor:" 127 | 128 | #: app/templates/book.html:46 129 | msgid "Collection:" 130 | msgstr "Colección:" 131 | 132 | #: app/templates/book.html:56 133 | msgid "Year of publication:" 134 | msgstr "Año de publicación:" 135 | 136 | #: app/templates/book.html:59 137 | msgid "Download:" 138 | msgstr "Descarga:" 139 | 140 | #: app/templates/book.html:70 141 | msgid "Synopsis:" 142 | msgstr "Sinopsis:" 143 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/connector/calibre/tests/tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | """Unittest.""" 6 | 7 | 8 | import unittest 9 | 10 | 11 | def setUpModule(): 12 | pass 13 | 14 | 15 | def tearDownModule(): 16 | pass 17 | 18 | 19 | class TestCalibre(unittest.TestCase): 20 | 21 | """Unittest.""" 22 | 23 | def setUp(self): 24 | """Method to prepare the test fixture. Run BEFORE the test methods.""" 25 | pass 26 | 27 | def tearDown(self): 28 | """Method to tear down the test fixture. Run AFTER the test methods.""" 29 | pass 30 | 31 | def addCleanup(self, function, *args, **kwargs): 32 | """Function called AFTER tearDown() to clean resources used on test.""" 33 | pass 34 | 35 | @classmethod 36 | def setUpClass(cls): 37 | """Class method called BEFORE tests in an individual class run. """ 38 | pass # Probably you may not use this one. See setUp(). 39 | 40 | @classmethod 41 | def tearDownClass(cls): 42 | """Class method called AFTER tests in an individual class run. """ 43 | pass # Probably you may not use this one. See tearDown(). 44 | 45 | @unittest.skip("Demonstrating skipping") # Skips this test only 46 | @unittest.skipIf( 47 | "boolean_condition", 48 | "Reason to Skip Test here.") # Skips this test only 49 | @unittest.skipUnless( 50 | "boolean_condition", 51 | "Reason to Skip Test here.") # Skips this test only 52 | # This test MUST fail. If test fails, then is Ok. 53 | @unittest.expectedFailure 54 | def test_dummy(self): 55 | # Skips this test only 56 | self.skipTest("Just examples, use as template!.") 57 | self.assertEqual(a, b) # a == b 58 | self.assertNotEqual(a, b) # a != b 59 | self.assertTrue(x) # bool(x) is True 60 | self.assertFalse(x) # bool(x) is False 61 | self.assertIs(a, b) # a is b 62 | self.assertIsNot(a, b) # a is not b 63 | self.assertIsNone(x) # x is None 64 | self.assertIsNotNone(x) # x is not None 65 | self.assertIn(a, b) # a in b 66 | self.assertNotIn(a, b) # a not in b 67 | self.assertIsInstance(a, b) # isinstance(a, b) 68 | self.assertNotIsInstance(a, b) # not isinstance(a, b) 69 | self.assertAlmostEqual(a, b) # round(a-b, 7) == 0 70 | self.assertNotAlmostEqual(a, b) # round(a-b, 7) != 0 71 | self.assertGreater(a, b) # a > b 72 | self.assertGreaterEqual(a, b) # a >= b 73 | self.assertLess(a, b) # a < b 74 | self.assertLessEqual(a, b) # a <= b 75 | self.assertRegex(s, r) # r.search(s) 76 | self.assertNotRegex(s, r) # not r.search(s) 77 | # sorted(a) == sorted(b) and works with unhashable objs 78 | self.assertItemsEqual(a, b) 79 | # all the key/value pairs in a exist in b 80 | self.assertDictContainsSubset(a, b) 81 | # a and b have the same elements in the same number, regardless of 82 | # their order 83 | self.assertCountEqual(a, b) 84 | # Compare different types of objects 85 | self.assertMultiLineEqual(a, b) # Compare strings 86 | self.assertSequenceEqual(a, b) # Compare sequences 87 | self.assertListEqual(a, b) # Compare lists 88 | self.assertTupleEqual(a, b) # Compare tuples 89 | self.assertSetEqual(a, b) # Compare sets 90 | self.assertDictEqual(a, b) # Compare dicts 91 | # To Test code that MUST Raise Exceptions: 92 | # callable Must raise SomeException 93 | self.assertRaises(SomeException, callable, *args, **kwds) 94 | with self.assertRaises(SomeException) as cm: 95 | do_something_that_raises() # This line Must raise SomeException 96 | # To Test code that MUST Raise Warnings (see std lib warning module): 97 | # callable Must raise SomeWarning 98 | self.assertWarns(SomeWarning, callable, *args, **kwds) 99 | with self.assertWarns(SomeWarning) as cm: 100 | do_something_that_warns() # This line Must raise SomeWarning 101 | # Assert messages on a Logger log object. 102 | self.assertLogs(logger, level) 103 | with self.assertLogs('foo', level='INFO') as cm: 104 | # cm.output is 'example message' 105 | logging.getLogger('foo').info('example message') 106 | 107 | 108 | if __name__.__contains__("__main__"): 109 | print(__doc__) 110 | unittest.main() 111 | # Run just 1 test. 112 | # unittest.main(defaultTest='TestFoo.test_foo', warnings='ignore') 113 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "central.html" %} 2 | {% block content%} 3 | 4 |
5 | {% include "sidebar.html" %} 6 |
7 |
{{ title }}
8 |
9 |
10 |
11 |
12 |

{{ _('Welcome!') }}

13 |
14 |
15 | {{ _("""On the left bar you will find the categories organising the books.""") }} 16 |
17 |
18 | {{ _("""On the upper bar you will find the categories organising the books.""") }} 19 |
20 |
21 | 22 |
23 |
24 |

{{ _('This node has:') }}

25 |
26 |
27 | 57 |
58 |
59 | 60 |
61 |
62 |

63 | {{ _("""To read the books we recommend the following applications:""") }} 64 |

65 | 66 | 67 | 68 | 69 | 72 | 75 | 76 | 77 | 78 | 79 | 82 | 85 | 86 | 87 | 90 | 93 | 94 | 95 |
70 | {{ _('System') }} 71 | 73 | {{ _('Application') }} 74 |
80 | Android 81 | 83 | Cool Reader 84 |
88 | GNU/Linux, win, mac 89 | 91 | Calibre 92 |
96 |
97 |
98 |
99 |
100 |

{{ _('Run your own node:') }}

101 |
102 |
103 |

104 | {{_("""Hey! Do you like the idea?""") }} 105 |
106 | {{ _("""Running your own node is very cheap and easy: you need a router, a Raspberry PI or just a computer.""") }} 107 |
108 | {{ _("""Talk to the admin ( %(name)s ) of this node or send him/her an E-mail .""", name=admin.name, email=admin.email) }} 109 |

110 | {{ _("""If you have suggestions, ideas, complaints or anything else, you can send an E-mail to the author, his address is in the footer.""")}} 111 |

112 |
113 |
114 |
115 |
116 |
117 |
118 | 119 | {% endblock %} 120 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/connector/calibre/calibre.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim:fenc=utf-8 3 | # 4 | # Distributed under terms of the GPLv3+ license. 5 | 6 | import logging 7 | import os 8 | import sqlite3 9 | from flask_babel import gettext as _ 10 | 11 | from connector.dbprovider import ConnectorABS 12 | 13 | 14 | class Connector(ConnectorABS): 15 | """Connect to the calibre database and provides an API to it""" 16 | 17 | def __init__(self, **kwargs): 18 | # path to db 19 | self.db = kwargs.get('path', '') 20 | logging.basicConfig(level=logging.INFO) 21 | self.logger = logging.getLogger(__name__) 22 | 23 | if not os.path.isfile(self.db): 24 | self.logger.critical(_("Database not found.")) 25 | raise FileNotFoundError(_("Database not found.")) 26 | 27 | def connect(self): 28 | # connect and create the cursor 29 | self.con = sqlite3.connect(self.db) 30 | self.cursor = self.con.cursor() 31 | 32 | def desconnect(self): 33 | try: 34 | self.con.disconnect() 35 | except BaseException: 36 | pass 37 | 38 | def get_all(self): 39 | # Get the metadata of each book 40 | self.cursor.execute(""" 41 | select id, title, pubdate, path 42 | from books 43 | order by title; 44 | """) 45 | # reaturn a listf of authors 46 | ret = [] 47 | for register in self.cursor.fetchall(): 48 | ret.append({"id": register[0], 49 | "title": register[1], 50 | "publication_date": register[2], 51 | "path": register[3], 52 | }) 53 | return ret 54 | 55 | def get_book_by_name(self, name): 56 | self.cursor.execute(""" 57 | select distinct b.id, b.title, b.pubdate, b.path 58 | from books b 59 | where b.title = ? 60 | order by b.title""", (name,)) 61 | 62 | ret = [] 63 | for register in self.cursor.fetchall(): 64 | ret.append({"id": register[0], 65 | "title": register[1], 66 | "publication_date": register[2], 67 | "path": register[3], 68 | }) 69 | return ret 70 | 71 | def get_by_author(self, author): 72 | # Get the metadata of each book by author 73 | self.cursor.execute(""" 74 | select distinct b.id, b.title, b.pubdate, b.path 75 | from books b, authors a 76 | where b.author_sort like "%"||a.sort||"%" and a.name like ? 77 | order by b.title""", ("%" + author + "%",)) 78 | 79 | ret = [] 80 | 81 | for register in self.cursor.fetchall(): 82 | ret.append({"id": register[0], 83 | "title": register[1], 84 | "publication_date": register[2], 85 | "path": register[3], 86 | }) 87 | 88 | return ret 89 | 90 | def get_author_of_book(self, book_id): 91 | self.cursor.execute(""" 92 | select distinct a.name 93 | from authors a, books_authors_link bal 94 | where bal.author= a.id and bal.book = ?""", (book_id,)) 95 | 96 | ret = [] 97 | for register in self.cursor.fetchall(): 98 | ret.append(register[0]) 99 | return ret 100 | 101 | def get_tags_from_book(self, book_id): 102 | 103 | self.cursor.execute(""" 104 | select t.name 105 | from tags t, books_tags_link btl 106 | where btl.tag = t.id and btl.book = ? 107 | order by t.name""", (book_id,)) 108 | 109 | ret = [] 110 | for register in self.cursor.fetchall(): 111 | ret.append(register[0]) 112 | return ret 113 | 114 | def get_synopsis(self, book_id): 115 | 116 | self.cursor.execute(""" 117 | select c.text 118 | from comments c 119 | where c.book = ? """, (book_id,)) 120 | 121 | ret = [] 122 | for register in self.cursor.fetchall(): 123 | ret.append(register[0]) 124 | return ret 125 | 126 | def get_authors(self): 127 | self.cursor.execute(""" 128 | select name 129 | from authors 130 | order by name""") 131 | # retornamos la lista de authors 132 | ret = [] 133 | for register in self.cursor.fetchall(): 134 | ret.append(register[0]) 135 | return ret 136 | 137 | def get_books_by_serie(self, serie): 138 | self.cursor.execute(""" 139 | select distinct b.id, b.title, b.pubdate, b.path 140 | from books b, series s, books_series_link bsl 141 | where bsl.book = b.id and bsl.series = s.id and s.name = ? 142 | order by b.title""", (serie,)) 143 | 144 | # return the list of books 145 | ret = [] 146 | for register in self.cursor.fetchall(): 147 | ret.append({"id": register[0], 148 | "title": register[1], 149 | "publication_date": register[2], 150 | "path": register[3], 151 | }) 152 | return ret 153 | 154 | def obtener_series(self): 155 | self.cursor.execute(""" 156 | select s.name 157 | from series s 158 | order by s.name""") 159 | ret = [] 160 | for register in self.cursor.fetchall(): 161 | ret.append(register[0]) 162 | return ret 163 | 164 | def get_series_from_book(self, book_id): 165 | self.cursor.execute(""" 166 | select s.name 167 | from series s, books_series_link bsl 168 | where bsl.series = s.id and bsl.book = ? 169 | order by s.name""", (book_id,)) 170 | 171 | ret = [] 172 | for register in self.cursor.fetchall(): 173 | ret.append(register[0]) 174 | return ret 175 | 176 | def get_books_by_tag(self, tag): 177 | self.cursor.execute(""" 178 | select distinct b.id, b.title, b.pubdate, b.path 179 | from books b, tags t, books_tags_link btl 180 | where btl.book = b.id and btl.tag = t.id and t.name = ? 181 | order by b.title""", (tag,)) 182 | 183 | ret = [] 184 | for register in self.cursor.fetchall(): 185 | ret.append({"id": register[0], 186 | "title": register[1], 187 | "publication_date": register[2], 188 | "path": register[3], 189 | }) 190 | return ret 191 | 192 | def get_tags(self): 193 | self.cursor.execute(""" 194 | select name 195 | from tags 196 | order by name""") 197 | 198 | ret = [] 199 | for register in self.cursor.fetchall(): 200 | ret.append(register[0]) 201 | return ret 202 | 203 | def get_formats(self, book_id): 204 | """Return a list of file extension of the books in a set""" 205 | 206 | # format, file name 207 | self.cursor.execute(""" 208 | select format, name 209 | from data 210 | where book=?""", (book_id,)) 211 | 212 | ret = [] 213 | for register in self.cursor.fetchall(): 214 | ret.append(register) 215 | return ret 216 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # vim:fenc=utf-8 3 | # 4 | # 5 | # Distributed under terms of the GPLv3+ license. 6 | 7 | """ 8 | 9 | """ 10 | from connector.dbprovider import instance_connector 11 | from flask import (Flask, redirect, render_template, send_from_directory, 12 | url_for) 13 | from flask_babel import gettext as _ 14 | from flask_babel import Babel 15 | from settings import BASE_BOOK_PATH 16 | from utils.books import normalize_book 17 | from utils.urls import urldecode, urlencode 18 | 19 | app = Flask('__name__') 20 | 21 | # Set up 22 | app.config.from_object("settings") 23 | babel = Babel(app) 24 | 25 | 26 | # Filters 27 | 28 | def get_filters(): 29 | """Filters on the left bar""" 30 | filters = ( 31 | {'url': url_for('all_the_books_view'), 32 | 'name': _("Books"), 33 | 'iconclass': "fa fa-book"}, 34 | {'url': url_for('authors_view'), 35 | 'name': _("Authors"), 36 | 'iconclass': "fa fa-users"}, 37 | {'url': url_for('tags_view'), 38 | 'name': _("Categories"), 39 | 'iconclass': "fa fa-list"}, 40 | # {'url': url_for('idiomas'), 41 | # 'name': _("Langueges"), 42 | # 'fa-icon-class': "fa fa-language"}, 43 | {'url': url_for('series_view'), 44 | 'name': _("Series"), 45 | 'iconclass': "fa fa-indent"}, 46 | ) 47 | return filters 48 | 49 | 50 | def get_admin_data(): 51 | """Get Admin data form config file 52 | :returns: dicct 53 | 54 | """ 55 | admin_data = { 56 | 'name': app.config.get("ADMIN_NAME", _("Not set")), 57 | 'email': app.config.get("ADMIN_EMAIL", _("Not set")), 58 | } 59 | return admin_data 60 | 61 | 62 | def get_stats(): 63 | """ 64 | Gets stats about the amount of books, series, tags and authors 65 | :returns: dicct 66 | 67 | """ 68 | 69 | stats = {'authors': len(filter_by_author()), 70 | 'categories': len(get_tags_with_url()), 71 | 'books': len(get_books()), 72 | 'series': len(get_collections_with_url()), 73 | } 74 | 75 | return stats 76 | 77 | 78 | def filter_by_author(author=""): 79 | connector = instance_connector() 80 | connector.connect() 81 | # get books without processing 82 | books = connector.get_by_author(author) 83 | # Lets normalize the list f books 84 | books = normalize_book(books, connector) 85 | connector.desconnect() 86 | return books 87 | 88 | 89 | def filter_by_tag(tag=""): 90 | connector = instance_connector() 91 | connector.connect() 92 | # get books without processing 93 | books = connector.get_books_by_tag(tag) 94 | # Lets normalize the list f books 95 | books = normalize_book(books, connector) 96 | connector.desconnect() 97 | return books 98 | 99 | 100 | def filter_by_collection(serie=""): 101 | connector = instance_connector() 102 | connector.connect() 103 | serie = urldecode(serie) 104 | # get books without processing 105 | books = connector.get_books_by_serie(serie) 106 | # Lets normalize the list f books 107 | books = normalize_book(books, connector) 108 | connector.desconnect() 109 | return books 110 | 111 | 112 | def filter_by_book_name(book_name=""): 113 | """Filter by the name of the book""" 114 | connector = instance_connector() 115 | connector.connect() 116 | # get books without processing 117 | books = connector.get_book_by_name(book_name) 118 | # Lets normalize the list f books 119 | books = normalize_book(books, connector) 120 | connector.desconnect() 121 | return books 122 | 123 | 124 | def get_books(): 125 | """Get all books and normalize them 126 | :returns: list 127 | 128 | """ 129 | connector = instance_connector() 130 | connector.connect() 131 | # get books without processing 132 | books = connector.get_all() 133 | # Lets normalize the list f books 134 | books = normalize_book(books, connector) 135 | connector.desconnect() 136 | return books 137 | 138 | 139 | def get_collections_with_url(): 140 | """Get a list with all the series""" 141 | series = [] 142 | 143 | connector = instance_connector() 144 | connector.connect() 145 | # Get seriers without processing 146 | raw_series = connector.obtener_series() 147 | for serie in raw_series: 148 | serie_safe = urlencode(serie) 149 | url = url_for('collection_view', serie_name=serie_safe) 150 | series.append({'url': url, 'element': serie}) 151 | 152 | connector.desconnect() 153 | return series 154 | 155 | 156 | def get_tags_with_url(): 157 | """Get a list with all the tags""" 158 | tags = [] 159 | 160 | connector = instance_connector() 161 | connector.connect() 162 | # Get tags without processing 163 | tags_raw = connector.get_tags() 164 | for tag in tags_raw: 165 | tag_safe = urlencode(tag) 166 | url = url_for( 167 | 'tag_view', 168 | tag_name=tag_safe) 169 | tags.append({'url': url, 'element': tag}) 170 | 171 | connector.desconnect() 172 | return tags 173 | 174 | 175 | def get_authors_with_url(): 176 | """Get a list with all the authors""" 177 | authors = [] 178 | 179 | connector = instance_connector() 180 | connector.connect() 181 | # Get authors without processing 182 | authors_raw = connector.get_authors() 183 | for author in authors_raw: 184 | autor_safe = urlencode(author) 185 | url = url_for( 186 | 'author_view', 187 | author_name=autor_safe) 188 | authors.append({'url': url, 'element': author}) 189 | 190 | connector.desconnect() 191 | return authors 192 | 193 | 194 | def format_elements_for_template(elements): 195 | """Generate a dict with the first key of the element as key and the element as value""" 196 | 197 | first_letter_dict = {} 198 | for element in elements: 199 | # Inside element there is two items, 'url' and 'element' 200 | first_letter = element.get('element')[0].upper() 201 | if first_letter_dict.get(first_letter, None) is None: 202 | first_letter_dict[first_letter] = [] 203 | 204 | first_letter_dict[first_letter].append(element) 205 | return first_letter_dict 206 | 207 | # Views 208 | 209 | 210 | @app.route('/') 211 | def index(): 212 | return render_template('index.html', 213 | title="", 214 | general_filters=get_filters(), 215 | stats=get_stats(), 216 | admin=get_admin_data(), 217 | ) 218 | 219 | 220 | @app.route('/books/') 221 | def all_the_books_view(): 222 | """Show the books""" 223 | books = get_books() 224 | 225 | return render_template("list_of_books.html", 226 | books=books, 227 | title=_("All books:"), 228 | general_filters=get_filters() 229 | ) 230 | 231 | 232 | @app.route('/author//') 233 | def author_view(author_name): 234 | """Muestra los books de un author""" 235 | if not author_name: 236 | return redirect(url_for('authors_view')) 237 | 238 | author_name = urldecode(author_name) 239 | books = filter_by_author(author_name) 240 | 241 | return render_template("list_of_books.html", 242 | books=books, 243 | title=author_name, 244 | general_filters=get_filters() 245 | ) 246 | 247 | 248 | @app.route('/author/') 249 | def redirect_author(): 250 | return redirect(url_for('authors_view')) 251 | 252 | 253 | @app.route('/serie//') 254 | def collection_view(serie_name): 255 | """Shows books with a particular tag""" 256 | if not serie_name: 257 | return redirect(url_for('series_view')) 258 | 259 | serie_name = urldecode(serie_name) 260 | books = filter_by_collection(serie_name) 261 | 262 | return render_template("list_of_books.html", 263 | books=books, 264 | title=serie_name, 265 | general_filters=get_filters() 266 | ) 267 | 268 | 269 | @app.route('/serie/') 270 | def redirect_serie(): 271 | return redirect(url_for('series_view')) 272 | 273 | 274 | @app.route('/tag//') 275 | def tag_view(tag_name): 276 | """Shows books with a particular tag""" 277 | if not tag_name: 278 | return redirect(url_for('tags_view')) 279 | 280 | tag_name = urldecode(tag_name) 281 | books = filter_by_tag(tag_name) 282 | 283 | return render_template("list_of_books.html", 284 | books=books, 285 | title=tag_name, 286 | general_filters=get_filters(), 287 | ) 288 | 289 | 290 | @app.route('/tag/') 291 | def redirect_tag(): 292 | return redirect(url_for('tags_view')) 293 | 294 | 295 | @app.route('/book//') 296 | def book_view(book_name): 297 | """Shows a particular book""" 298 | book_name = urldecode(book_name) 299 | books = filter_by_book_name(book_name) 300 | 301 | return render_template("book.html", 302 | book=books[0], 303 | title=book_name, 304 | general_filters=get_filters() 305 | ) 306 | 307 | 308 | @app.route('/book/') 309 | def redirect_book(): 310 | return redirect(url_for('index')) 311 | 312 | 313 | @app.route('/authors/') 314 | def authors_view(): 315 | """List of authors """ 316 | authors = get_authors_with_url() 317 | authors = format_elements_for_template(authors) 318 | 319 | return render_template("list_of_entries.html", 320 | entries=authors, 321 | title=_("Authors"), 322 | general_filters=get_filters(), 323 | path='author' 324 | ) 325 | 326 | 327 | @app.route('/tags/') 328 | def tags_view(): 329 | """List of tags""" 330 | tags = get_tags_with_url() 331 | tags = format_elements_for_template(tags) 332 | 333 | return render_template("list_of_entries.html", 334 | entries=tags, 335 | title=_("Categories"), 336 | general_filters=get_filters(), 337 | path='tags' 338 | ) 339 | 340 | 341 | @app.route('/series/') 342 | def series_view(): 343 | """List of series""" 344 | series = get_collections_with_url() 345 | series = format_elements_for_template(series) 346 | 347 | return render_template("list_of_entries.html", 348 | entries=series, 349 | title=_("Series"), 350 | general_filters=get_filters(), 351 | path='series' 352 | ) 353 | 354 | 355 | @app.route('/covers/') 356 | def get_book_cover(path): 357 | safe_path = urldecode(path) 358 | return send_from_directory(BASE_BOOK_PATH, safe_path) 359 | 360 | 361 | @app.route('/file/') 362 | def get_book_download(path): 363 | safe_path = urldecode(path) 364 | return send_from_directory(BASE_BOOK_PATH, safe_path, as_attachment=True) 365 | 366 | 367 | # Allow to use this function from templates 368 | @app.context_processor 369 | def utility_processor(): 370 | return dict(urlencode=urlencode) 371 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/tests/data/biblioteca_calibre/metadata_db_prefs_backup.json: -------------------------------------------------------------------------------- 1 | { 2 | "saved_searches": {}, 3 | "user_categories": {}, 4 | "field_metadata": { 5 | "rating": { 6 | "is_category": true, 7 | "is_multiple": {}, 8 | "kind": "field", 9 | "is_custom": false, 10 | "is_csp": false, 11 | "column": "rating", 12 | "rec_index": 5, 13 | "search_terms": [ 14 | "rating" 15 | ], 16 | "link_column": "rating", 17 | "label": "rating", 18 | "is_editable": true, 19 | "datatype": "rating", 20 | "category_sort": "rating", 21 | "table": "ratings", 22 | "display": {}, 23 | "name": "Valoraci\u00f3n" 24 | }, 25 | "identifiers": { 26 | "is_category": true, 27 | "is_multiple": { 28 | "cache_to_list": ",", 29 | "ui_to_list": ",", 30 | "list_to_ui": ", " 31 | }, 32 | "kind": "field", 33 | "is_custom": false, 34 | "is_csp": true, 35 | "column": null, 36 | "rec_index": 20, 37 | "search_terms": [ 38 | "identifiers", 39 | "identifier", 40 | "isbn" 41 | ], 42 | "label": "identifiers", 43 | "is_editable": true, 44 | "datatype": "text", 45 | "table": null, 46 | "display": {}, 47 | "name": "Identificadores" 48 | }, 49 | "pubdate": { 50 | "is_category": false, 51 | "is_multiple": {}, 52 | "kind": "field", 53 | "is_custom": false, 54 | "is_csp": false, 55 | "column": null, 56 | "rec_index": 15, 57 | "search_terms": [ 58 | "pubdate" 59 | ], 60 | "label": "pubdate", 61 | "is_editable": true, 62 | "datatype": "datetime", 63 | "table": null, 64 | "display": { 65 | "date_format": "MMM yyyy" 66 | }, 67 | "name": "Publicado" 68 | }, 69 | "series": { 70 | "is_category": true, 71 | "is_multiple": {}, 72 | "kind": "field", 73 | "is_custom": false, 74 | "is_csp": false, 75 | "column": "name", 76 | "rec_index": 8, 77 | "search_terms": [ 78 | "series" 79 | ], 80 | "link_column": "series", 81 | "label": "series", 82 | "is_editable": true, 83 | "datatype": "series", 84 | "category_sort": "(title_sort(name))", 85 | "table": "series", 86 | "display": {}, 87 | "name": "Serie" 88 | }, 89 | "marked": { 90 | "is_category": false, 91 | "is_multiple": {}, 92 | "kind": "field", 93 | "is_custom": false, 94 | "is_csp": false, 95 | "column": null, 96 | "rec_index": 23, 97 | "search_terms": [ 98 | "marked" 99 | ], 100 | "label": "marked", 101 | "is_editable": true, 102 | "datatype": "text", 103 | "table": null, 104 | "display": {}, 105 | "name": null 106 | }, 107 | "path": { 108 | "is_category": false, 109 | "is_multiple": {}, 110 | "kind": "field", 111 | "is_custom": false, 112 | "is_csp": false, 113 | "column": null, 114 | "rec_index": 14, 115 | "search_terms": [], 116 | "label": "path", 117 | "is_editable": true, 118 | "datatype": "text", 119 | "table": null, 120 | "display": {}, 121 | "name": "Ruta" 122 | }, 123 | "au_map": { 124 | "is_category": false, 125 | "is_multiple": { 126 | "cache_to_list": ",", 127 | "ui_to_list": null, 128 | "list_to_ui": null 129 | }, 130 | "kind": "field", 131 | "is_custom": false, 132 | "is_csp": false, 133 | "column": null, 134 | "rec_index": 18, 135 | "search_terms": [], 136 | "label": "au_map", 137 | "is_editable": true, 138 | "datatype": "text", 139 | "table": null, 140 | "display": {}, 141 | "name": null 142 | }, 143 | "id": { 144 | "is_category": false, 145 | "is_multiple": {}, 146 | "kind": "field", 147 | "is_custom": false, 148 | "is_csp": false, 149 | "column": null, 150 | "rec_index": 0, 151 | "search_terms": [ 152 | "id" 153 | ], 154 | "label": "id", 155 | "is_editable": true, 156 | "datatype": "int", 157 | "table": null, 158 | "display": {}, 159 | "name": null 160 | }, 161 | "size": { 162 | "is_category": false, 163 | "is_multiple": {}, 164 | "kind": "field", 165 | "is_custom": false, 166 | "is_csp": false, 167 | "column": null, 168 | "rec_index": 4, 169 | "search_terms": [ 170 | "size" 171 | ], 172 | "label": "size", 173 | "is_editable": true, 174 | "datatype": "float", 175 | "table": null, 176 | "display": {}, 177 | "name": "Tama\u00f1o" 178 | }, 179 | "uuid": { 180 | "is_category": false, 181 | "is_multiple": {}, 182 | "kind": "field", 183 | "is_custom": false, 184 | "is_csp": false, 185 | "column": null, 186 | "rec_index": 16, 187 | "search_terms": [ 188 | "uuid" 189 | ], 190 | "label": "uuid", 191 | "is_editable": true, 192 | "datatype": "text", 193 | "table": null, 194 | "display": {}, 195 | "name": null 196 | }, 197 | "title": { 198 | "is_category": false, 199 | "is_multiple": {}, 200 | "kind": "field", 201 | "is_custom": false, 202 | "is_csp": false, 203 | "column": null, 204 | "rec_index": 1, 205 | "search_terms": [ 206 | "title" 207 | ], 208 | "label": "title", 209 | "is_editable": true, 210 | "datatype": "text", 211 | "table": null, 212 | "display": {}, 213 | "name": "T\u00edtulo" 214 | }, 215 | "series_sort": { 216 | "is_category": false, 217 | "is_multiple": {}, 218 | "kind": "field", 219 | "is_custom": false, 220 | "is_csp": false, 221 | "column": null, 222 | "rec_index": 24, 223 | "search_terms": [ 224 | "series_sort" 225 | ], 226 | "label": "series_sort", 227 | "is_editable": true, 228 | "datatype": "text", 229 | "table": null, 230 | "display": {}, 231 | "name": "Orden de serie" 232 | }, 233 | "comments": { 234 | "is_category": false, 235 | "is_multiple": {}, 236 | "kind": "field", 237 | "is_custom": false, 238 | "is_csp": false, 239 | "column": null, 240 | "rec_index": 7, 241 | "search_terms": [ 242 | "comments", 243 | "comment" 244 | ], 245 | "label": "comments", 246 | "is_editable": true, 247 | "datatype": "text", 248 | "table": null, 249 | "display": {}, 250 | "name": "Comentarios" 251 | }, 252 | "languages": { 253 | "is_category": true, 254 | "is_multiple": { 255 | "cache_to_list": ",", 256 | "ui_to_list": ",", 257 | "list_to_ui": ", " 258 | }, 259 | "kind": "field", 260 | "is_custom": false, 261 | "is_csp": false, 262 | "column": "lang_code", 263 | "rec_index": 21, 264 | "search_terms": [ 265 | "languages", 266 | "language" 267 | ], 268 | "link_column": "lang_code", 269 | "label": "languages", 270 | "is_editable": true, 271 | "datatype": "text", 272 | "category_sort": "lang_code", 273 | "table": "languages", 274 | "display": {}, 275 | "name": "Idiomas" 276 | }, 277 | "sort": { 278 | "is_category": false, 279 | "is_multiple": {}, 280 | "kind": "field", 281 | "is_custom": false, 282 | "is_csp": false, 283 | "column": null, 284 | "rec_index": 11, 285 | "search_terms": [ 286 | "title_sort" 287 | ], 288 | "label": "sort", 289 | "is_editable": true, 290 | "datatype": "text", 291 | "table": null, 292 | "display": {}, 293 | "name": "Orden de t\u00edtulo" 294 | }, 295 | "tags": { 296 | "is_category": true, 297 | "is_multiple": { 298 | "cache_to_list": ",", 299 | "ui_to_list": ",", 300 | "list_to_ui": ", " 301 | }, 302 | "kind": "field", 303 | "is_custom": false, 304 | "is_csp": false, 305 | "column": "name", 306 | "rec_index": 6, 307 | "search_terms": [ 308 | "tags", 309 | "tag" 310 | ], 311 | "link_column": "tag", 312 | "label": "tags", 313 | "is_editable": true, 314 | "datatype": "text", 315 | "category_sort": "name", 316 | "table": "tags", 317 | "display": {}, 318 | "name": "Etiquetas" 319 | }, 320 | "timestamp": { 321 | "is_category": false, 322 | "is_multiple": {}, 323 | "kind": "field", 324 | "is_custom": false, 325 | "is_csp": false, 326 | "column": null, 327 | "rec_index": 3, 328 | "search_terms": [ 329 | "date" 330 | ], 331 | "label": "timestamp", 332 | "is_editable": true, 333 | "datatype": "datetime", 334 | "table": null, 335 | "display": { 336 | "date_format": "dd MMM yyyy" 337 | }, 338 | "name": "Fecha" 339 | }, 340 | "last_modified": { 341 | "is_category": false, 342 | "is_multiple": {}, 343 | "kind": "field", 344 | "is_custom": false, 345 | "is_csp": false, 346 | "column": null, 347 | "rec_index": 19, 348 | "search_terms": [ 349 | "last_modified" 350 | ], 351 | "label": "last_modified", 352 | "is_editable": true, 353 | "datatype": "datetime", 354 | "table": null, 355 | "display": { 356 | "date_format": "dd MMM yyyy" 357 | }, 358 | "name": "Modificado" 359 | }, 360 | "authors": { 361 | "is_category": true, 362 | "is_multiple": { 363 | "cache_to_list": ",", 364 | "ui_to_list": "&", 365 | "list_to_ui": " & " 366 | }, 367 | "kind": "field", 368 | "is_custom": false, 369 | "is_csp": false, 370 | "column": "name", 371 | "rec_index": 2, 372 | "search_terms": [ 373 | "authors", 374 | "author" 375 | ], 376 | "link_column": "author", 377 | "label": "authors", 378 | "is_editable": true, 379 | "datatype": "text", 380 | "category_sort": "sort", 381 | "table": "authors", 382 | "display": {}, 383 | "name": "Autores" 384 | }, 385 | "news": { 386 | "is_category": true, 387 | "is_multiple": {}, 388 | "kind": "category", 389 | "is_custom": false, 390 | "is_csp": false, 391 | "column": "name", 392 | "search_terms": [], 393 | "label": "news", 394 | "is_editable": true, 395 | "datatype": null, 396 | "category_sort": "name", 397 | "table": "news", 398 | "display": {}, 399 | "name": "Noticias" 400 | }, 401 | "publisher": { 402 | "is_category": true, 403 | "is_multiple": {}, 404 | "kind": "field", 405 | "is_custom": false, 406 | "is_csp": false, 407 | "column": "name", 408 | "rec_index": 9, 409 | "search_terms": [ 410 | "publisher" 411 | ], 412 | "link_column": "publisher", 413 | "label": "publisher", 414 | "is_editable": true, 415 | "datatype": "text", 416 | "category_sort": "name", 417 | "table": "publishers", 418 | "display": {}, 419 | "name": "Editorial" 420 | }, 421 | "series_index": { 422 | "is_category": false, 423 | "is_multiple": {}, 424 | "kind": "field", 425 | "is_custom": false, 426 | "is_csp": false, 427 | "column": null, 428 | "rec_index": 10, 429 | "search_terms": [ 430 | "series_index" 431 | ], 432 | "label": "series_index", 433 | "is_editable": true, 434 | "datatype": "float", 435 | "table": null, 436 | "display": {}, 437 | "name": null 438 | }, 439 | "author_sort": { 440 | "is_category": false, 441 | "is_multiple": {}, 442 | "kind": "field", 443 | "is_custom": false, 444 | "is_csp": false, 445 | "column": null, 446 | "rec_index": 12, 447 | "search_terms": [ 448 | "author_sort" 449 | ], 450 | "label": "author_sort", 451 | "is_editable": true, 452 | "datatype": "text", 453 | "table": null, 454 | "display": {}, 455 | "name": "Orden de author" 456 | }, 457 | "cover": { 458 | "is_category": false, 459 | "is_multiple": {}, 460 | "kind": "field", 461 | "is_custom": false, 462 | "is_csp": false, 463 | "column": null, 464 | "rec_index": 17, 465 | "search_terms": [ 466 | "cover" 467 | ], 468 | "label": "cover", 469 | "is_editable": true, 470 | "datatype": "int", 471 | "table": null, 472 | "display": {}, 473 | "name": "Portada" 474 | }, 475 | "ondevice": { 476 | "is_category": false, 477 | "is_multiple": {}, 478 | "kind": "field", 479 | "is_custom": false, 480 | "is_csp": false, 481 | "column": null, 482 | "rec_index": 22, 483 | "search_terms": [ 484 | "ondevice" 485 | ], 486 | "label": "ondevice", 487 | "is_editable": true, 488 | "datatype": "text", 489 | "table": null, 490 | "display": {}, 491 | "name": "En el dispositivo" 492 | }, 493 | "formats": { 494 | "is_category": true, 495 | "is_multiple": { 496 | "cache_to_list": ",", 497 | "ui_to_list": ",", 498 | "list_to_ui": ", " 499 | }, 500 | "kind": "field", 501 | "is_custom": false, 502 | "is_csp": false, 503 | "column": null, 504 | "rec_index": 13, 505 | "search_terms": [ 506 | "formats", 507 | "format" 508 | ], 509 | "label": "formats", 510 | "is_editable": true, 511 | "datatype": "text", 512 | "table": null, 513 | "display": {}, 514 | "name": "Formatos" 515 | } 516 | }, 517 | "news_to_be_synced": [], 518 | "grouped_search_terms": {}, 519 | "tag_browser_hidden_categories": [], 520 | "library_view books view state": { 521 | "column_alignment": { 522 | "timestamp": "center", 523 | "pubdate": "center", 524 | "size": "center" 525 | }, 526 | "column_sizes": { 527 | "rating": 103, 528 | "pubdate": 97, 529 | "tags": 106, 530 | "series": 63, 531 | "timestamp": 81, 532 | "title": 196, 533 | "publisher": 88, 534 | "languages": 0, 535 | "last_modified": 0, 536 | "authors": 95, 537 | "size": 194 538 | }, 539 | "languages_injected": true, 540 | "column_positions": { 541 | "rating": 5, 542 | "pubdate": 9, 543 | "title": 1, 544 | "series": 7, 545 | "timestamp": 3, 546 | "tags": 6, 547 | "publisher": 8, 548 | "languages": 11, 549 | "last_modified": 10, 550 | "ondevice": 0, 551 | "authors": 2, 552 | "size": 4 553 | }, 554 | "sort_history": [ 555 | [ 556 | "timestamp", 557 | false 558 | ], 559 | [ 560 | "ondevice", 561 | false 562 | ], 563 | [ 564 | "title", 565 | true 566 | ], 567 | [ 568 | "timestamp", 569 | false 570 | ], 571 | [ 572 | "ondevice", 573 | false 574 | ], 575 | [ 576 | "title", 577 | true 578 | ], 579 | [ 580 | "timestamp", 581 | false 582 | ] 583 | ], 584 | "hidden_columns": [ 585 | "last_modified", 586 | "languages" 587 | ], 588 | "last_modified_injected": true 589 | }, 590 | "bools_are_tristate": true 591 | } 592 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/css/font-awesome.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | /* FONT PATH 6 | * -------------------------- */ 7 | @font-face { 8 | font-family: 'FontAwesome'; 9 | src: url('../fonts/fontawesome-webfont.eot?v=4.7.0'); 10 | src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); 11 | font-weight: normal; 12 | font-style: normal; 13 | } 14 | .fa { 15 | display: inline-block; 16 | font: normal normal normal 14px/1 FontAwesome; 17 | font-size: inherit; 18 | text-rendering: auto; 19 | -webkit-font-smoothing: antialiased; 20 | -moz-osx-font-smoothing: grayscale; 21 | } 22 | /* makes the font 33% larger relative to the icon container */ 23 | .fa-lg { 24 | font-size: 1.33333333em; 25 | line-height: 0.75em; 26 | vertical-align: -15%; 27 | } 28 | .fa-2x { 29 | font-size: 2em; 30 | } 31 | .fa-3x { 32 | font-size: 3em; 33 | } 34 | .fa-4x { 35 | font-size: 4em; 36 | } 37 | .fa-5x { 38 | font-size: 5em; 39 | } 40 | .fa-fw { 41 | width: 1.28571429em; 42 | text-align: center; 43 | } 44 | .fa-ul { 45 | padding-left: 0; 46 | margin-left: 2.14285714em; 47 | list-style-type: none; 48 | } 49 | .fa-ul > li { 50 | position: relative; 51 | } 52 | .fa-li { 53 | position: absolute; 54 | left: -2.14285714em; 55 | width: 2.14285714em; 56 | top: 0.14285714em; 57 | text-align: center; 58 | } 59 | .fa-li.fa-lg { 60 | left: -1.85714286em; 61 | } 62 | .fa-border { 63 | padding: .2em .25em .15em; 64 | border: solid 0.08em #eeeeee; 65 | border-radius: .1em; 66 | } 67 | .fa-pull-left { 68 | float: left; 69 | } 70 | .fa-pull-right { 71 | float: right; 72 | } 73 | .fa.fa-pull-left { 74 | margin-right: .3em; 75 | } 76 | .fa.fa-pull-right { 77 | margin-left: .3em; 78 | } 79 | /* Deprecated as of 4.4.0 */ 80 | .pull-right { 81 | float: right; 82 | } 83 | .pull-left { 84 | float: left; 85 | } 86 | .fa.pull-left { 87 | margin-right: .3em; 88 | } 89 | .fa.pull-right { 90 | margin-left: .3em; 91 | } 92 | .fa-spin { 93 | -webkit-animation: fa-spin 2s infinite linear; 94 | animation: fa-spin 2s infinite linear; 95 | } 96 | .fa-pulse { 97 | -webkit-animation: fa-spin 1s infinite steps(8); 98 | animation: fa-spin 1s infinite steps(8); 99 | } 100 | @-webkit-keyframes fa-spin { 101 | 0% { 102 | -webkit-transform: rotate(0deg); 103 | transform: rotate(0deg); 104 | } 105 | 100% { 106 | -webkit-transform: rotate(359deg); 107 | transform: rotate(359deg); 108 | } 109 | } 110 | @keyframes fa-spin { 111 | 0% { 112 | -webkit-transform: rotate(0deg); 113 | transform: rotate(0deg); 114 | } 115 | 100% { 116 | -webkit-transform: rotate(359deg); 117 | transform: rotate(359deg); 118 | } 119 | } 120 | .fa-rotate-90 { 121 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; 122 | -webkit-transform: rotate(90deg); 123 | -ms-transform: rotate(90deg); 124 | transform: rotate(90deg); 125 | } 126 | .fa-rotate-180 { 127 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; 128 | -webkit-transform: rotate(180deg); 129 | -ms-transform: rotate(180deg); 130 | transform: rotate(180deg); 131 | } 132 | .fa-rotate-270 { 133 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; 134 | -webkit-transform: rotate(270deg); 135 | -ms-transform: rotate(270deg); 136 | transform: rotate(270deg); 137 | } 138 | .fa-flip-horizontal { 139 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; 140 | -webkit-transform: scale(-1, 1); 141 | -ms-transform: scale(-1, 1); 142 | transform: scale(-1, 1); 143 | } 144 | .fa-flip-vertical { 145 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; 146 | -webkit-transform: scale(1, -1); 147 | -ms-transform: scale(1, -1); 148 | transform: scale(1, -1); 149 | } 150 | :root .fa-rotate-90, 151 | :root .fa-rotate-180, 152 | :root .fa-rotate-270, 153 | :root .fa-flip-horizontal, 154 | :root .fa-flip-vertical { 155 | filter: none; 156 | } 157 | .fa-stack { 158 | position: relative; 159 | display: inline-block; 160 | width: 2em; 161 | height: 2em; 162 | line-height: 2em; 163 | vertical-align: middle; 164 | } 165 | .fa-stack-1x, 166 | .fa-stack-2x { 167 | position: absolute; 168 | left: 0; 169 | width: 100%; 170 | text-align: center; 171 | } 172 | .fa-stack-1x { 173 | line-height: inherit; 174 | } 175 | .fa-stack-2x { 176 | font-size: 2em; 177 | } 178 | .fa-inverse { 179 | color: #ffffff; 180 | } 181 | /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen 182 | readers do not read off random characters that represent icons */ 183 | .fa-glass:before { 184 | content: "\f000"; 185 | } 186 | .fa-music:before { 187 | content: "\f001"; 188 | } 189 | .fa-search:before { 190 | content: "\f002"; 191 | } 192 | .fa-envelope-o:before { 193 | content: "\f003"; 194 | } 195 | .fa-heart:before { 196 | content: "\f004"; 197 | } 198 | .fa-star:before { 199 | content: "\f005"; 200 | } 201 | .fa-star-o:before { 202 | content: "\f006"; 203 | } 204 | .fa-user:before { 205 | content: "\f007"; 206 | } 207 | .fa-film:before { 208 | content: "\f008"; 209 | } 210 | .fa-th-large:before { 211 | content: "\f009"; 212 | } 213 | .fa-th:before { 214 | content: "\f00a"; 215 | } 216 | .fa-th-list:before { 217 | content: "\f00b"; 218 | } 219 | .fa-check:before { 220 | content: "\f00c"; 221 | } 222 | .fa-remove:before, 223 | .fa-close:before, 224 | .fa-times:before { 225 | content: "\f00d"; 226 | } 227 | .fa-search-plus:before { 228 | content: "\f00e"; 229 | } 230 | .fa-search-minus:before { 231 | content: "\f010"; 232 | } 233 | .fa-power-off:before { 234 | content: "\f011"; 235 | } 236 | .fa-signal:before { 237 | content: "\f012"; 238 | } 239 | .fa-gear:before, 240 | .fa-cog:before { 241 | content: "\f013"; 242 | } 243 | .fa-trash-o:before { 244 | content: "\f014"; 245 | } 246 | .fa-home:before { 247 | content: "\f015"; 248 | } 249 | .fa-file-o:before { 250 | content: "\f016"; 251 | } 252 | .fa-clock-o:before { 253 | content: "\f017"; 254 | } 255 | .fa-road:before { 256 | content: "\f018"; 257 | } 258 | .fa-download:before { 259 | content: "\f019"; 260 | } 261 | .fa-arrow-circle-o-down:before { 262 | content: "\f01a"; 263 | } 264 | .fa-arrow-circle-o-up:before { 265 | content: "\f01b"; 266 | } 267 | .fa-inbox:before { 268 | content: "\f01c"; 269 | } 270 | .fa-play-circle-o:before { 271 | content: "\f01d"; 272 | } 273 | .fa-rotate-right:before, 274 | .fa-repeat:before { 275 | content: "\f01e"; 276 | } 277 | .fa-refresh:before { 278 | content: "\f021"; 279 | } 280 | .fa-list-alt:before { 281 | content: "\f022"; 282 | } 283 | .fa-lock:before { 284 | content: "\f023"; 285 | } 286 | .fa-flag:before { 287 | content: "\f024"; 288 | } 289 | .fa-headphones:before { 290 | content: "\f025"; 291 | } 292 | .fa-volume-off:before { 293 | content: "\f026"; 294 | } 295 | .fa-volume-down:before { 296 | content: "\f027"; 297 | } 298 | .fa-volume-up:before { 299 | content: "\f028"; 300 | } 301 | .fa-qrcode:before { 302 | content: "\f029"; 303 | } 304 | .fa-barcode:before { 305 | content: "\f02a"; 306 | } 307 | .fa-tag:before { 308 | content: "\f02b"; 309 | } 310 | .fa-tags:before { 311 | content: "\f02c"; 312 | } 313 | .fa-book:before { 314 | content: "\f02d"; 315 | } 316 | .fa-bookmark:before { 317 | content: "\f02e"; 318 | } 319 | .fa-print:before { 320 | content: "\f02f"; 321 | } 322 | .fa-camera:before { 323 | content: "\f030"; 324 | } 325 | .fa-font:before { 326 | content: "\f031"; 327 | } 328 | .fa-bold:before { 329 | content: "\f032"; 330 | } 331 | .fa-italic:before { 332 | content: "\f033"; 333 | } 334 | .fa-text-height:before { 335 | content: "\f034"; 336 | } 337 | .fa-text-width:before { 338 | content: "\f035"; 339 | } 340 | .fa-align-left:before { 341 | content: "\f036"; 342 | } 343 | .fa-align-center:before { 344 | content: "\f037"; 345 | } 346 | .fa-align-right:before { 347 | content: "\f038"; 348 | } 349 | .fa-align-justify:before { 350 | content: "\f039"; 351 | } 352 | .fa-list:before { 353 | content: "\f03a"; 354 | } 355 | .fa-dedent:before, 356 | .fa-outdent:before { 357 | content: "\f03b"; 358 | } 359 | .fa-indent:before { 360 | content: "\f03c"; 361 | } 362 | .fa-video-camera:before { 363 | content: "\f03d"; 364 | } 365 | .fa-photo:before, 366 | .fa-image:before, 367 | .fa-picture-o:before { 368 | content: "\f03e"; 369 | } 370 | .fa-pencil:before { 371 | content: "\f040"; 372 | } 373 | .fa-map-marker:before { 374 | content: "\f041"; 375 | } 376 | .fa-adjust:before { 377 | content: "\f042"; 378 | } 379 | .fa-tint:before { 380 | content: "\f043"; 381 | } 382 | .fa-edit:before, 383 | .fa-pencil-square-o:before { 384 | content: "\f044"; 385 | } 386 | .fa-share-square-o:before { 387 | content: "\f045"; 388 | } 389 | .fa-check-square-o:before { 390 | content: "\f046"; 391 | } 392 | .fa-arrows:before { 393 | content: "\f047"; 394 | } 395 | .fa-step-backward:before { 396 | content: "\f048"; 397 | } 398 | .fa-fast-backward:before { 399 | content: "\f049"; 400 | } 401 | .fa-backward:before { 402 | content: "\f04a"; 403 | } 404 | .fa-play:before { 405 | content: "\f04b"; 406 | } 407 | .fa-pause:before { 408 | content: "\f04c"; 409 | } 410 | .fa-stop:before { 411 | content: "\f04d"; 412 | } 413 | .fa-forward:before { 414 | content: "\f04e"; 415 | } 416 | .fa-fast-forward:before { 417 | content: "\f050"; 418 | } 419 | .fa-step-forward:before { 420 | content: "\f051"; 421 | } 422 | .fa-eject:before { 423 | content: "\f052"; 424 | } 425 | .fa-chevron-left:before { 426 | content: "\f053"; 427 | } 428 | .fa-chevron-right:before { 429 | content: "\f054"; 430 | } 431 | .fa-plus-circle:before { 432 | content: "\f055"; 433 | } 434 | .fa-minus-circle:before { 435 | content: "\f056"; 436 | } 437 | .fa-times-circle:before { 438 | content: "\f057"; 439 | } 440 | .fa-check-circle:before { 441 | content: "\f058"; 442 | } 443 | .fa-question-circle:before { 444 | content: "\f059"; 445 | } 446 | .fa-info-circle:before { 447 | content: "\f05a"; 448 | } 449 | .fa-crosshairs:before { 450 | content: "\f05b"; 451 | } 452 | .fa-times-circle-o:before { 453 | content: "\f05c"; 454 | } 455 | .fa-check-circle-o:before { 456 | content: "\f05d"; 457 | } 458 | .fa-ban:before { 459 | content: "\f05e"; 460 | } 461 | .fa-arrow-left:before { 462 | content: "\f060"; 463 | } 464 | .fa-arrow-right:before { 465 | content: "\f061"; 466 | } 467 | .fa-arrow-up:before { 468 | content: "\f062"; 469 | } 470 | .fa-arrow-down:before { 471 | content: "\f063"; 472 | } 473 | .fa-mail-forward:before, 474 | .fa-share:before { 475 | content: "\f064"; 476 | } 477 | .fa-expand:before { 478 | content: "\f065"; 479 | } 480 | .fa-compress:before { 481 | content: "\f066"; 482 | } 483 | .fa-plus:before { 484 | content: "\f067"; 485 | } 486 | .fa-minus:before { 487 | content: "\f068"; 488 | } 489 | .fa-asterisk:before { 490 | content: "\f069"; 491 | } 492 | .fa-exclamation-circle:before { 493 | content: "\f06a"; 494 | } 495 | .fa-gift:before { 496 | content: "\f06b"; 497 | } 498 | .fa-leaf:before { 499 | content: "\f06c"; 500 | } 501 | .fa-fire:before { 502 | content: "\f06d"; 503 | } 504 | .fa-eye:before { 505 | content: "\f06e"; 506 | } 507 | .fa-eye-slash:before { 508 | content: "\f070"; 509 | } 510 | .fa-warning:before, 511 | .fa-exclamation-triangle:before { 512 | content: "\f071"; 513 | } 514 | .fa-plane:before { 515 | content: "\f072"; 516 | } 517 | .fa-calendar:before { 518 | content: "\f073"; 519 | } 520 | .fa-random:before { 521 | content: "\f074"; 522 | } 523 | .fa-comment:before { 524 | content: "\f075"; 525 | } 526 | .fa-magnet:before { 527 | content: "\f076"; 528 | } 529 | .fa-chevron-up:before { 530 | content: "\f077"; 531 | } 532 | .fa-chevron-down:before { 533 | content: "\f078"; 534 | } 535 | .fa-retweet:before { 536 | content: "\f079"; 537 | } 538 | .fa-shopping-cart:before { 539 | content: "\f07a"; 540 | } 541 | .fa-folder:before { 542 | content: "\f07b"; 543 | } 544 | .fa-folder-open:before { 545 | content: "\f07c"; 546 | } 547 | .fa-arrows-v:before { 548 | content: "\f07d"; 549 | } 550 | .fa-arrows-h:before { 551 | content: "\f07e"; 552 | } 553 | .fa-bar-chart-o:before, 554 | .fa-bar-chart:before { 555 | content: "\f080"; 556 | } 557 | .fa-twitter-square:before { 558 | content: "\f081"; 559 | } 560 | .fa-facebook-square:before { 561 | content: "\f082"; 562 | } 563 | .fa-camera-retro:before { 564 | content: "\f083"; 565 | } 566 | .fa-key:before { 567 | content: "\f084"; 568 | } 569 | .fa-gears:before, 570 | .fa-cogs:before { 571 | content: "\f085"; 572 | } 573 | .fa-comments:before { 574 | content: "\f086"; 575 | } 576 | .fa-thumbs-o-up:before { 577 | content: "\f087"; 578 | } 579 | .fa-thumbs-o-down:before { 580 | content: "\f088"; 581 | } 582 | .fa-star-half:before { 583 | content: "\f089"; 584 | } 585 | .fa-heart-o:before { 586 | content: "\f08a"; 587 | } 588 | .fa-sign-out:before { 589 | content: "\f08b"; 590 | } 591 | .fa-linkedin-square:before { 592 | content: "\f08c"; 593 | } 594 | .fa-thumb-tack:before { 595 | content: "\f08d"; 596 | } 597 | .fa-external-link:before { 598 | content: "\f08e"; 599 | } 600 | .fa-sign-in:before { 601 | content: "\f090"; 602 | } 603 | .fa-trophy:before { 604 | content: "\f091"; 605 | } 606 | .fa-github-square:before { 607 | content: "\f092"; 608 | } 609 | .fa-upload:before { 610 | content: "\f093"; 611 | } 612 | .fa-lemon-o:before { 613 | content: "\f094"; 614 | } 615 | .fa-phone:before { 616 | content: "\f095"; 617 | } 618 | .fa-square-o:before { 619 | content: "\f096"; 620 | } 621 | .fa-bookmark-o:before { 622 | content: "\f097"; 623 | } 624 | .fa-phone-square:before { 625 | content: "\f098"; 626 | } 627 | .fa-twitter:before { 628 | content: "\f099"; 629 | } 630 | .fa-facebook-f:before, 631 | .fa-facebook:before { 632 | content: "\f09a"; 633 | } 634 | .fa-github:before { 635 | content: "\f09b"; 636 | } 637 | .fa-unlock:before { 638 | content: "\f09c"; 639 | } 640 | .fa-credit-card:before { 641 | content: "\f09d"; 642 | } 643 | .fa-feed:before, 644 | .fa-rss:before { 645 | content: "\f09e"; 646 | } 647 | .fa-hdd-o:before { 648 | content: "\f0a0"; 649 | } 650 | .fa-bullhorn:before { 651 | content: "\f0a1"; 652 | } 653 | .fa-bell:before { 654 | content: "\f0f3"; 655 | } 656 | .fa-certificate:before { 657 | content: "\f0a3"; 658 | } 659 | .fa-hand-o-right:before { 660 | content: "\f0a4"; 661 | } 662 | .fa-hand-o-left:before { 663 | content: "\f0a5"; 664 | } 665 | .fa-hand-o-up:before { 666 | content: "\f0a6"; 667 | } 668 | .fa-hand-o-down:before { 669 | content: "\f0a7"; 670 | } 671 | .fa-arrow-circle-left:before { 672 | content: "\f0a8"; 673 | } 674 | .fa-arrow-circle-right:before { 675 | content: "\f0a9"; 676 | } 677 | .fa-arrow-circle-up:before { 678 | content: "\f0aa"; 679 | } 680 | .fa-arrow-circle-down:before { 681 | content: "\f0ab"; 682 | } 683 | .fa-globe:before { 684 | content: "\f0ac"; 685 | } 686 | .fa-wrench:before { 687 | content: "\f0ad"; 688 | } 689 | .fa-tasks:before { 690 | content: "\f0ae"; 691 | } 692 | .fa-filter:before { 693 | content: "\f0b0"; 694 | } 695 | .fa-briefcase:before { 696 | content: "\f0b1"; 697 | } 698 | .fa-arrows-alt:before { 699 | content: "\f0b2"; 700 | } 701 | .fa-group:before, 702 | .fa-users:before { 703 | content: "\f0c0"; 704 | } 705 | .fa-chain:before, 706 | .fa-link:before { 707 | content: "\f0c1"; 708 | } 709 | .fa-cloud:before { 710 | content: "\f0c2"; 711 | } 712 | .fa-flask:before { 713 | content: "\f0c3"; 714 | } 715 | .fa-cut:before, 716 | .fa-scissors:before { 717 | content: "\f0c4"; 718 | } 719 | .fa-copy:before, 720 | .fa-files-o:before { 721 | content: "\f0c5"; 722 | } 723 | .fa-paperclip:before { 724 | content: "\f0c6"; 725 | } 726 | .fa-save:before, 727 | .fa-floppy-o:before { 728 | content: "\f0c7"; 729 | } 730 | .fa-square:before { 731 | content: "\f0c8"; 732 | } 733 | .fa-navicon:before, 734 | .fa-reorder:before, 735 | .fa-bars:before { 736 | content: "\f0c9"; 737 | } 738 | .fa-list-ul:before { 739 | content: "\f0ca"; 740 | } 741 | .fa-list-ol:before { 742 | content: "\f0cb"; 743 | } 744 | .fa-strikethrough:before { 745 | content: "\f0cc"; 746 | } 747 | .fa-underline:before { 748 | content: "\f0cd"; 749 | } 750 | .fa-table:before { 751 | content: "\f0ce"; 752 | } 753 | .fa-magic:before { 754 | content: "\f0d0"; 755 | } 756 | .fa-truck:before { 757 | content: "\f0d1"; 758 | } 759 | .fa-pinterest:before { 760 | content: "\f0d2"; 761 | } 762 | .fa-pinterest-square:before { 763 | content: "\f0d3"; 764 | } 765 | .fa-google-plus-square:before { 766 | content: "\f0d4"; 767 | } 768 | .fa-google-plus:before { 769 | content: "\f0d5"; 770 | } 771 | .fa-money:before { 772 | content: "\f0d6"; 773 | } 774 | .fa-caret-down:before { 775 | content: "\f0d7"; 776 | } 777 | .fa-caret-up:before { 778 | content: "\f0d8"; 779 | } 780 | .fa-caret-left:before { 781 | content: "\f0d9"; 782 | } 783 | .fa-caret-right:before { 784 | content: "\f0da"; 785 | } 786 | .fa-columns:before { 787 | content: "\f0db"; 788 | } 789 | .fa-unsorted:before, 790 | .fa-sort:before { 791 | content: "\f0dc"; 792 | } 793 | .fa-sort-down:before, 794 | .fa-sort-desc:before { 795 | content: "\f0dd"; 796 | } 797 | .fa-sort-up:before, 798 | .fa-sort-asc:before { 799 | content: "\f0de"; 800 | } 801 | .fa-envelope:before { 802 | content: "\f0e0"; 803 | } 804 | .fa-linkedin:before { 805 | content: "\f0e1"; 806 | } 807 | .fa-rotate-left:before, 808 | .fa-undo:before { 809 | content: "\f0e2"; 810 | } 811 | .fa-legal:before, 812 | .fa-gavel:before { 813 | content: "\f0e3"; 814 | } 815 | .fa-dashboard:before, 816 | .fa-tachometer:before { 817 | content: "\f0e4"; 818 | } 819 | .fa-comment-o:before { 820 | content: "\f0e5"; 821 | } 822 | .fa-comments-o:before { 823 | content: "\f0e6"; 824 | } 825 | .fa-flash:before, 826 | .fa-bolt:before { 827 | content: "\f0e7"; 828 | } 829 | .fa-sitemap:before { 830 | content: "\f0e8"; 831 | } 832 | .fa-umbrella:before { 833 | content: "\f0e9"; 834 | } 835 | .fa-paste:before, 836 | .fa-clipboard:before { 837 | content: "\f0ea"; 838 | } 839 | .fa-lightbulb-o:before { 840 | content: "\f0eb"; 841 | } 842 | .fa-exchange:before { 843 | content: "\f0ec"; 844 | } 845 | .fa-cloud-download:before { 846 | content: "\f0ed"; 847 | } 848 | .fa-cloud-upload:before { 849 | content: "\f0ee"; 850 | } 851 | .fa-user-md:before { 852 | content: "\f0f0"; 853 | } 854 | .fa-stethoscope:before { 855 | content: "\f0f1"; 856 | } 857 | .fa-suitcase:before { 858 | content: "\f0f2"; 859 | } 860 | .fa-bell-o:before { 861 | content: "\f0a2"; 862 | } 863 | .fa-coffee:before { 864 | content: "\f0f4"; 865 | } 866 | .fa-cutlery:before { 867 | content: "\f0f5"; 868 | } 869 | .fa-file-text-o:before { 870 | content: "\f0f6"; 871 | } 872 | .fa-building-o:before { 873 | content: "\f0f7"; 874 | } 875 | .fa-hospital-o:before { 876 | content: "\f0f8"; 877 | } 878 | .fa-ambulance:before { 879 | content: "\f0f9"; 880 | } 881 | .fa-medkit:before { 882 | content: "\f0fa"; 883 | } 884 | .fa-fighter-jet:before { 885 | content: "\f0fb"; 886 | } 887 | .fa-beer:before { 888 | content: "\f0fc"; 889 | } 890 | .fa-h-square:before { 891 | content: "\f0fd"; 892 | } 893 | .fa-plus-square:before { 894 | content: "\f0fe"; 895 | } 896 | .fa-angle-double-left:before { 897 | content: "\f100"; 898 | } 899 | .fa-angle-double-right:before { 900 | content: "\f101"; 901 | } 902 | .fa-angle-double-up:before { 903 | content: "\f102"; 904 | } 905 | .fa-angle-double-down:before { 906 | content: "\f103"; 907 | } 908 | .fa-angle-left:before { 909 | content: "\f104"; 910 | } 911 | .fa-angle-right:before { 912 | content: "\f105"; 913 | } 914 | .fa-angle-up:before { 915 | content: "\f106"; 916 | } 917 | .fa-angle-down:before { 918 | content: "\f107"; 919 | } 920 | .fa-desktop:before { 921 | content: "\f108"; 922 | } 923 | .fa-laptop:before { 924 | content: "\f109"; 925 | } 926 | .fa-tablet:before { 927 | content: "\f10a"; 928 | } 929 | .fa-mobile-phone:before, 930 | .fa-mobile:before { 931 | content: "\f10b"; 932 | } 933 | .fa-circle-o:before { 934 | content: "\f10c"; 935 | } 936 | .fa-quote-left:before { 937 | content: "\f10d"; 938 | } 939 | .fa-quote-right:before { 940 | content: "\f10e"; 941 | } 942 | .fa-spinner:before { 943 | content: "\f110"; 944 | } 945 | .fa-circle:before { 946 | content: "\f111"; 947 | } 948 | .fa-mail-reply:before, 949 | .fa-reply:before { 950 | content: "\f112"; 951 | } 952 | .fa-github-alt:before { 953 | content: "\f113"; 954 | } 955 | .fa-folder-o:before { 956 | content: "\f114"; 957 | } 958 | .fa-folder-open-o:before { 959 | content: "\f115"; 960 | } 961 | .fa-smile-o:before { 962 | content: "\f118"; 963 | } 964 | .fa-frown-o:before { 965 | content: "\f119"; 966 | } 967 | .fa-meh-o:before { 968 | content: "\f11a"; 969 | } 970 | .fa-gamepad:before { 971 | content: "\f11b"; 972 | } 973 | .fa-keyboard-o:before { 974 | content: "\f11c"; 975 | } 976 | .fa-flag-o:before { 977 | content: "\f11d"; 978 | } 979 | .fa-flag-checkered:before { 980 | content: "\f11e"; 981 | } 982 | .fa-terminal:before { 983 | content: "\f120"; 984 | } 985 | .fa-code:before { 986 | content: "\f121"; 987 | } 988 | .fa-mail-reply-all:before, 989 | .fa-reply-all:before { 990 | content: "\f122"; 991 | } 992 | .fa-star-half-empty:before, 993 | .fa-star-half-full:before, 994 | .fa-star-half-o:before { 995 | content: "\f123"; 996 | } 997 | .fa-location-arrow:before { 998 | content: "\f124"; 999 | } 1000 | .fa-crop:before { 1001 | content: "\f125"; 1002 | } 1003 | .fa-code-fork:before { 1004 | content: "\f126"; 1005 | } 1006 | .fa-unlink:before, 1007 | .fa-chain-broken:before { 1008 | content: "\f127"; 1009 | } 1010 | .fa-question:before { 1011 | content: "\f128"; 1012 | } 1013 | .fa-info:before { 1014 | content: "\f129"; 1015 | } 1016 | .fa-exclamation:before { 1017 | content: "\f12a"; 1018 | } 1019 | .fa-superscript:before { 1020 | content: "\f12b"; 1021 | } 1022 | .fa-subscript:before { 1023 | content: "\f12c"; 1024 | } 1025 | .fa-eraser:before { 1026 | content: "\f12d"; 1027 | } 1028 | .fa-puzzle-piece:before { 1029 | content: "\f12e"; 1030 | } 1031 | .fa-microphone:before { 1032 | content: "\f130"; 1033 | } 1034 | .fa-microphone-slash:before { 1035 | content: "\f131"; 1036 | } 1037 | .fa-shield:before { 1038 | content: "\f132"; 1039 | } 1040 | .fa-calendar-o:before { 1041 | content: "\f133"; 1042 | } 1043 | .fa-fire-extinguisher:before { 1044 | content: "\f134"; 1045 | } 1046 | .fa-rocket:before { 1047 | content: "\f135"; 1048 | } 1049 | .fa-maxcdn:before { 1050 | content: "\f136"; 1051 | } 1052 | .fa-chevron-circle-left:before { 1053 | content: "\f137"; 1054 | } 1055 | .fa-chevron-circle-right:before { 1056 | content: "\f138"; 1057 | } 1058 | .fa-chevron-circle-up:before { 1059 | content: "\f139"; 1060 | } 1061 | .fa-chevron-circle-down:before { 1062 | content: "\f13a"; 1063 | } 1064 | .fa-html5:before { 1065 | content: "\f13b"; 1066 | } 1067 | .fa-css3:before { 1068 | content: "\f13c"; 1069 | } 1070 | .fa-anchor:before { 1071 | content: "\f13d"; 1072 | } 1073 | .fa-unlock-alt:before { 1074 | content: "\f13e"; 1075 | } 1076 | .fa-bullseye:before { 1077 | content: "\f140"; 1078 | } 1079 | .fa-ellipsis-h:before { 1080 | content: "\f141"; 1081 | } 1082 | .fa-ellipsis-v:before { 1083 | content: "\f142"; 1084 | } 1085 | .fa-rss-square:before { 1086 | content: "\f143"; 1087 | } 1088 | .fa-play-circle:before { 1089 | content: "\f144"; 1090 | } 1091 | .fa-ticket:before { 1092 | content: "\f145"; 1093 | } 1094 | .fa-minus-square:before { 1095 | content: "\f146"; 1096 | } 1097 | .fa-minus-square-o:before { 1098 | content: "\f147"; 1099 | } 1100 | .fa-level-up:before { 1101 | content: "\f148"; 1102 | } 1103 | .fa-level-down:before { 1104 | content: "\f149"; 1105 | } 1106 | .fa-check-square:before { 1107 | content: "\f14a"; 1108 | } 1109 | .fa-pencil-square:before { 1110 | content: "\f14b"; 1111 | } 1112 | .fa-external-link-square:before { 1113 | content: "\f14c"; 1114 | } 1115 | .fa-share-square:before { 1116 | content: "\f14d"; 1117 | } 1118 | .fa-compass:before { 1119 | content: "\f14e"; 1120 | } 1121 | .fa-toggle-down:before, 1122 | .fa-caret-square-o-down:before { 1123 | content: "\f150"; 1124 | } 1125 | .fa-toggle-up:before, 1126 | .fa-caret-square-o-up:before { 1127 | content: "\f151"; 1128 | } 1129 | .fa-toggle-right:before, 1130 | .fa-caret-square-o-right:before { 1131 | content: "\f152"; 1132 | } 1133 | .fa-euro:before, 1134 | .fa-eur:before { 1135 | content: "\f153"; 1136 | } 1137 | .fa-gbp:before { 1138 | content: "\f154"; 1139 | } 1140 | .fa-dollar:before, 1141 | .fa-usd:before { 1142 | content: "\f155"; 1143 | } 1144 | .fa-rupee:before, 1145 | .fa-inr:before { 1146 | content: "\f156"; 1147 | } 1148 | .fa-cny:before, 1149 | .fa-rmb:before, 1150 | .fa-yen:before, 1151 | .fa-jpy:before { 1152 | content: "\f157"; 1153 | } 1154 | .fa-ruble:before, 1155 | .fa-rouble:before, 1156 | .fa-rub:before { 1157 | content: "\f158"; 1158 | } 1159 | .fa-won:before, 1160 | .fa-krw:before { 1161 | content: "\f159"; 1162 | } 1163 | .fa-bitcoin:before, 1164 | .fa-btc:before { 1165 | content: "\f15a"; 1166 | } 1167 | .fa-file:before { 1168 | content: "\f15b"; 1169 | } 1170 | .fa-file-text:before { 1171 | content: "\f15c"; 1172 | } 1173 | .fa-sort-alpha-asc:before { 1174 | content: "\f15d"; 1175 | } 1176 | .fa-sort-alpha-desc:before { 1177 | content: "\f15e"; 1178 | } 1179 | .fa-sort-amount-asc:before { 1180 | content: "\f160"; 1181 | } 1182 | .fa-sort-amount-desc:before { 1183 | content: "\f161"; 1184 | } 1185 | .fa-sort-numeric-asc:before { 1186 | content: "\f162"; 1187 | } 1188 | .fa-sort-numeric-desc:before { 1189 | content: "\f163"; 1190 | } 1191 | .fa-thumbs-up:before { 1192 | content: "\f164"; 1193 | } 1194 | .fa-thumbs-down:before { 1195 | content: "\f165"; 1196 | } 1197 | .fa-youtube-square:before { 1198 | content: "\f166"; 1199 | } 1200 | .fa-youtube:before { 1201 | content: "\f167"; 1202 | } 1203 | .fa-xing:before { 1204 | content: "\f168"; 1205 | } 1206 | .fa-xing-square:before { 1207 | content: "\f169"; 1208 | } 1209 | .fa-youtube-play:before { 1210 | content: "\f16a"; 1211 | } 1212 | .fa-dropbox:before { 1213 | content: "\f16b"; 1214 | } 1215 | .fa-stack-overflow:before { 1216 | content: "\f16c"; 1217 | } 1218 | .fa-instagram:before { 1219 | content: "\f16d"; 1220 | } 1221 | .fa-flickr:before { 1222 | content: "\f16e"; 1223 | } 1224 | .fa-adn:before { 1225 | content: "\f170"; 1226 | } 1227 | .fa-bitbucket:before { 1228 | content: "\f171"; 1229 | } 1230 | .fa-bitbucket-square:before { 1231 | content: "\f172"; 1232 | } 1233 | .fa-tumblr:before { 1234 | content: "\f173"; 1235 | } 1236 | .fa-tumblr-square:before { 1237 | content: "\f174"; 1238 | } 1239 | .fa-long-arrow-down:before { 1240 | content: "\f175"; 1241 | } 1242 | .fa-long-arrow-up:before { 1243 | content: "\f176"; 1244 | } 1245 | .fa-long-arrow-left:before { 1246 | content: "\f177"; 1247 | } 1248 | .fa-long-arrow-right:before { 1249 | content: "\f178"; 1250 | } 1251 | .fa-apple:before { 1252 | content: "\f179"; 1253 | } 1254 | .fa-windows:before { 1255 | content: "\f17a"; 1256 | } 1257 | .fa-android:before { 1258 | content: "\f17b"; 1259 | } 1260 | .fa-linux:before { 1261 | content: "\f17c"; 1262 | } 1263 | .fa-dribbble:before { 1264 | content: "\f17d"; 1265 | } 1266 | .fa-skype:before { 1267 | content: "\f17e"; 1268 | } 1269 | .fa-foursquare:before { 1270 | content: "\f180"; 1271 | } 1272 | .fa-trello:before { 1273 | content: "\f181"; 1274 | } 1275 | .fa-female:before { 1276 | content: "\f182"; 1277 | } 1278 | .fa-male:before { 1279 | content: "\f183"; 1280 | } 1281 | .fa-gittip:before, 1282 | .fa-gratipay:before { 1283 | content: "\f184"; 1284 | } 1285 | .fa-sun-o:before { 1286 | content: "\f185"; 1287 | } 1288 | .fa-moon-o:before { 1289 | content: "\f186"; 1290 | } 1291 | .fa-archive:before { 1292 | content: "\f187"; 1293 | } 1294 | .fa-bug:before { 1295 | content: "\f188"; 1296 | } 1297 | .fa-vk:before { 1298 | content: "\f189"; 1299 | } 1300 | .fa-weibo:before { 1301 | content: "\f18a"; 1302 | } 1303 | .fa-renren:before { 1304 | content: "\f18b"; 1305 | } 1306 | .fa-pagelines:before { 1307 | content: "\f18c"; 1308 | } 1309 | .fa-stack-exchange:before { 1310 | content: "\f18d"; 1311 | } 1312 | .fa-arrow-circle-o-right:before { 1313 | content: "\f18e"; 1314 | } 1315 | .fa-arrow-circle-o-left:before { 1316 | content: "\f190"; 1317 | } 1318 | .fa-toggle-left:before, 1319 | .fa-caret-square-o-left:before { 1320 | content: "\f191"; 1321 | } 1322 | .fa-dot-circle-o:before { 1323 | content: "\f192"; 1324 | } 1325 | .fa-wheelchair:before { 1326 | content: "\f193"; 1327 | } 1328 | .fa-vimeo-square:before { 1329 | content: "\f194"; 1330 | } 1331 | .fa-turkish-lira:before, 1332 | .fa-try:before { 1333 | content: "\f195"; 1334 | } 1335 | .fa-plus-square-o:before { 1336 | content: "\f196"; 1337 | } 1338 | .fa-space-shuttle:before { 1339 | content: "\f197"; 1340 | } 1341 | .fa-slack:before { 1342 | content: "\f198"; 1343 | } 1344 | .fa-envelope-square:before { 1345 | content: "\f199"; 1346 | } 1347 | .fa-wordpress:before { 1348 | content: "\f19a"; 1349 | } 1350 | .fa-openid:before { 1351 | content: "\f19b"; 1352 | } 1353 | .fa-institution:before, 1354 | .fa-bank:before, 1355 | .fa-university:before { 1356 | content: "\f19c"; 1357 | } 1358 | .fa-mortar-board:before, 1359 | .fa-graduation-cap:before { 1360 | content: "\f19d"; 1361 | } 1362 | .fa-yahoo:before { 1363 | content: "\f19e"; 1364 | } 1365 | .fa-google:before { 1366 | content: "\f1a0"; 1367 | } 1368 | .fa-reddit:before { 1369 | content: "\f1a1"; 1370 | } 1371 | .fa-reddit-square:before { 1372 | content: "\f1a2"; 1373 | } 1374 | .fa-stumbleupon-circle:before { 1375 | content: "\f1a3"; 1376 | } 1377 | .fa-stumbleupon:before { 1378 | content: "\f1a4"; 1379 | } 1380 | .fa-delicious:before { 1381 | content: "\f1a5"; 1382 | } 1383 | .fa-digg:before { 1384 | content: "\f1a6"; 1385 | } 1386 | .fa-pied-piper-pp:before { 1387 | content: "\f1a7"; 1388 | } 1389 | .fa-pied-piper-alt:before { 1390 | content: "\f1a8"; 1391 | } 1392 | .fa-drupal:before { 1393 | content: "\f1a9"; 1394 | } 1395 | .fa-joomla:before { 1396 | content: "\f1aa"; 1397 | } 1398 | .fa-language:before { 1399 | content: "\f1ab"; 1400 | } 1401 | .fa-fax:before { 1402 | content: "\f1ac"; 1403 | } 1404 | .fa-building:before { 1405 | content: "\f1ad"; 1406 | } 1407 | .fa-child:before { 1408 | content: "\f1ae"; 1409 | } 1410 | .fa-paw:before { 1411 | content: "\f1b0"; 1412 | } 1413 | .fa-spoon:before { 1414 | content: "\f1b1"; 1415 | } 1416 | .fa-cube:before { 1417 | content: "\f1b2"; 1418 | } 1419 | .fa-cubes:before { 1420 | content: "\f1b3"; 1421 | } 1422 | .fa-behance:before { 1423 | content: "\f1b4"; 1424 | } 1425 | .fa-behance-square:before { 1426 | content: "\f1b5"; 1427 | } 1428 | .fa-steam:before { 1429 | content: "\f1b6"; 1430 | } 1431 | .fa-steam-square:before { 1432 | content: "\f1b7"; 1433 | } 1434 | .fa-recycle:before { 1435 | content: "\f1b8"; 1436 | } 1437 | .fa-automobile:before, 1438 | .fa-car:before { 1439 | content: "\f1b9"; 1440 | } 1441 | .fa-cab:before, 1442 | .fa-taxi:before { 1443 | content: "\f1ba"; 1444 | } 1445 | .fa-tree:before { 1446 | content: "\f1bb"; 1447 | } 1448 | .fa-spotify:before { 1449 | content: "\f1bc"; 1450 | } 1451 | .fa-deviantart:before { 1452 | content: "\f1bd"; 1453 | } 1454 | .fa-soundcloud:before { 1455 | content: "\f1be"; 1456 | } 1457 | .fa-database:before { 1458 | content: "\f1c0"; 1459 | } 1460 | .fa-file-pdf-o:before { 1461 | content: "\f1c1"; 1462 | } 1463 | .fa-file-word-o:before { 1464 | content: "\f1c2"; 1465 | } 1466 | .fa-file-excel-o:before { 1467 | content: "\f1c3"; 1468 | } 1469 | .fa-file-powerpoint-o:before { 1470 | content: "\f1c4"; 1471 | } 1472 | .fa-file-photo-o:before, 1473 | .fa-file-picture-o:before, 1474 | .fa-file-image-o:before { 1475 | content: "\f1c5"; 1476 | } 1477 | .fa-file-zip-o:before, 1478 | .fa-file-archive-o:before { 1479 | content: "\f1c6"; 1480 | } 1481 | .fa-file-sound-o:before, 1482 | .fa-file-audio-o:before { 1483 | content: "\f1c7"; 1484 | } 1485 | .fa-file-movie-o:before, 1486 | .fa-file-video-o:before { 1487 | content: "\f1c8"; 1488 | } 1489 | .fa-file-code-o:before { 1490 | content: "\f1c9"; 1491 | } 1492 | .fa-vine:before { 1493 | content: "\f1ca"; 1494 | } 1495 | .fa-codepen:before { 1496 | content: "\f1cb"; 1497 | } 1498 | .fa-jsfiddle:before { 1499 | content: "\f1cc"; 1500 | } 1501 | .fa-life-bouy:before, 1502 | .fa-life-buoy:before, 1503 | .fa-life-saver:before, 1504 | .fa-support:before, 1505 | .fa-life-ring:before { 1506 | content: "\f1cd"; 1507 | } 1508 | .fa-circle-o-notch:before { 1509 | content: "\f1ce"; 1510 | } 1511 | .fa-ra:before, 1512 | .fa-resistance:before, 1513 | .fa-rebel:before { 1514 | content: "\f1d0"; 1515 | } 1516 | .fa-ge:before, 1517 | .fa-empire:before { 1518 | content: "\f1d1"; 1519 | } 1520 | .fa-git-square:before { 1521 | content: "\f1d2"; 1522 | } 1523 | .fa-git:before { 1524 | content: "\f1d3"; 1525 | } 1526 | .fa-y-combinator-square:before, 1527 | .fa-yc-square:before, 1528 | .fa-hacker-news:before { 1529 | content: "\f1d4"; 1530 | } 1531 | .fa-tencent-weibo:before { 1532 | content: "\f1d5"; 1533 | } 1534 | .fa-qq:before { 1535 | content: "\f1d6"; 1536 | } 1537 | .fa-wechat:before, 1538 | .fa-weixin:before { 1539 | content: "\f1d7"; 1540 | } 1541 | .fa-send:before, 1542 | .fa-paper-plane:before { 1543 | content: "\f1d8"; 1544 | } 1545 | .fa-send-o:before, 1546 | .fa-paper-plane-o:before { 1547 | content: "\f1d9"; 1548 | } 1549 | .fa-history:before { 1550 | content: "\f1da"; 1551 | } 1552 | .fa-circle-thin:before { 1553 | content: "\f1db"; 1554 | } 1555 | .fa-header:before { 1556 | content: "\f1dc"; 1557 | } 1558 | .fa-paragraph:before { 1559 | content: "\f1dd"; 1560 | } 1561 | .fa-sliders:before { 1562 | content: "\f1de"; 1563 | } 1564 | .fa-share-alt:before { 1565 | content: "\f1e0"; 1566 | } 1567 | .fa-share-alt-square:before { 1568 | content: "\f1e1"; 1569 | } 1570 | .fa-bomb:before { 1571 | content: "\f1e2"; 1572 | } 1573 | .fa-soccer-ball-o:before, 1574 | .fa-futbol-o:before { 1575 | content: "\f1e3"; 1576 | } 1577 | .fa-tty:before { 1578 | content: "\f1e4"; 1579 | } 1580 | .fa-binoculars:before { 1581 | content: "\f1e5"; 1582 | } 1583 | .fa-plug:before { 1584 | content: "\f1e6"; 1585 | } 1586 | .fa-slideshare:before { 1587 | content: "\f1e7"; 1588 | } 1589 | .fa-twitch:before { 1590 | content: "\f1e8"; 1591 | } 1592 | .fa-yelp:before { 1593 | content: "\f1e9"; 1594 | } 1595 | .fa-newspaper-o:before { 1596 | content: "\f1ea"; 1597 | } 1598 | .fa-wifi:before { 1599 | content: "\f1eb"; 1600 | } 1601 | .fa-calculator:before { 1602 | content: "\f1ec"; 1603 | } 1604 | .fa-paypal:before { 1605 | content: "\f1ed"; 1606 | } 1607 | .fa-google-wallet:before { 1608 | content: "\f1ee"; 1609 | } 1610 | .fa-cc-visa:before { 1611 | content: "\f1f0"; 1612 | } 1613 | .fa-cc-mastercard:before { 1614 | content: "\f1f1"; 1615 | } 1616 | .fa-cc-discover:before { 1617 | content: "\f1f2"; 1618 | } 1619 | .fa-cc-amex:before { 1620 | content: "\f1f3"; 1621 | } 1622 | .fa-cc-paypal:before { 1623 | content: "\f1f4"; 1624 | } 1625 | .fa-cc-stripe:before { 1626 | content: "\f1f5"; 1627 | } 1628 | .fa-bell-slash:before { 1629 | content: "\f1f6"; 1630 | } 1631 | .fa-bell-slash-o:before { 1632 | content: "\f1f7"; 1633 | } 1634 | .fa-trash:before { 1635 | content: "\f1f8"; 1636 | } 1637 | .fa-copyright:before { 1638 | content: "\f1f9"; 1639 | } 1640 | .fa-at:before { 1641 | content: "\f1fa"; 1642 | } 1643 | .fa-eyedropper:before { 1644 | content: "\f1fb"; 1645 | } 1646 | .fa-paint-brush:before { 1647 | content: "\f1fc"; 1648 | } 1649 | .fa-birthday-cake:before { 1650 | content: "\f1fd"; 1651 | } 1652 | .fa-area-chart:before { 1653 | content: "\f1fe"; 1654 | } 1655 | .fa-pie-chart:before { 1656 | content: "\f200"; 1657 | } 1658 | .fa-line-chart:before { 1659 | content: "\f201"; 1660 | } 1661 | .fa-lastfm:before { 1662 | content: "\f202"; 1663 | } 1664 | .fa-lastfm-square:before { 1665 | content: "\f203"; 1666 | } 1667 | .fa-toggle-off:before { 1668 | content: "\f204"; 1669 | } 1670 | .fa-toggle-on:before { 1671 | content: "\f205"; 1672 | } 1673 | .fa-bicycle:before { 1674 | content: "\f206"; 1675 | } 1676 | .fa-bus:before { 1677 | content: "\f207"; 1678 | } 1679 | .fa-ioxhost:before { 1680 | content: "\f208"; 1681 | } 1682 | .fa-angellist:before { 1683 | content: "\f209"; 1684 | } 1685 | .fa-cc:before { 1686 | content: "\f20a"; 1687 | } 1688 | .fa-shekel:before, 1689 | .fa-sheqel:before, 1690 | .fa-ils:before { 1691 | content: "\f20b"; 1692 | } 1693 | .fa-meanpath:before { 1694 | content: "\f20c"; 1695 | } 1696 | .fa-buysellads:before { 1697 | content: "\f20d"; 1698 | } 1699 | .fa-connectdevelop:before { 1700 | content: "\f20e"; 1701 | } 1702 | .fa-dashcube:before { 1703 | content: "\f210"; 1704 | } 1705 | .fa-forumbee:before { 1706 | content: "\f211"; 1707 | } 1708 | .fa-leanpub:before { 1709 | content: "\f212"; 1710 | } 1711 | .fa-sellsy:before { 1712 | content: "\f213"; 1713 | } 1714 | .fa-shirtsinbulk:before { 1715 | content: "\f214"; 1716 | } 1717 | .fa-simplybuilt:before { 1718 | content: "\f215"; 1719 | } 1720 | .fa-skyatlas:before { 1721 | content: "\f216"; 1722 | } 1723 | .fa-cart-plus:before { 1724 | content: "\f217"; 1725 | } 1726 | .fa-cart-arrow-down:before { 1727 | content: "\f218"; 1728 | } 1729 | .fa-diamond:before { 1730 | content: "\f219"; 1731 | } 1732 | .fa-ship:before { 1733 | content: "\f21a"; 1734 | } 1735 | .fa-user-secret:before { 1736 | content: "\f21b"; 1737 | } 1738 | .fa-motorcycle:before { 1739 | content: "\f21c"; 1740 | } 1741 | .fa-street-view:before { 1742 | content: "\f21d"; 1743 | } 1744 | .fa-heartbeat:before { 1745 | content: "\f21e"; 1746 | } 1747 | .fa-venus:before { 1748 | content: "\f221"; 1749 | } 1750 | .fa-mars:before { 1751 | content: "\f222"; 1752 | } 1753 | .fa-mercury:before { 1754 | content: "\f223"; 1755 | } 1756 | .fa-intersex:before, 1757 | .fa-transgender:before { 1758 | content: "\f224"; 1759 | } 1760 | .fa-transgender-alt:before { 1761 | content: "\f225"; 1762 | } 1763 | .fa-venus-double:before { 1764 | content: "\f226"; 1765 | } 1766 | .fa-mars-double:before { 1767 | content: "\f227"; 1768 | } 1769 | .fa-venus-mars:before { 1770 | content: "\f228"; 1771 | } 1772 | .fa-mars-stroke:before { 1773 | content: "\f229"; 1774 | } 1775 | .fa-mars-stroke-v:before { 1776 | content: "\f22a"; 1777 | } 1778 | .fa-mars-stroke-h:before { 1779 | content: "\f22b"; 1780 | } 1781 | .fa-neuter:before { 1782 | content: "\f22c"; 1783 | } 1784 | .fa-genderless:before { 1785 | content: "\f22d"; 1786 | } 1787 | .fa-facebook-official:before { 1788 | content: "\f230"; 1789 | } 1790 | .fa-pinterest-p:before { 1791 | content: "\f231"; 1792 | } 1793 | .fa-whatsapp:before { 1794 | content: "\f232"; 1795 | } 1796 | .fa-server:before { 1797 | content: "\f233"; 1798 | } 1799 | .fa-user-plus:before { 1800 | content: "\f234"; 1801 | } 1802 | .fa-user-times:before { 1803 | content: "\f235"; 1804 | } 1805 | .fa-hotel:before, 1806 | .fa-bed:before { 1807 | content: "\f236"; 1808 | } 1809 | .fa-viacoin:before { 1810 | content: "\f237"; 1811 | } 1812 | .fa-train:before { 1813 | content: "\f238"; 1814 | } 1815 | .fa-subway:before { 1816 | content: "\f239"; 1817 | } 1818 | .fa-medium:before { 1819 | content: "\f23a"; 1820 | } 1821 | .fa-yc:before, 1822 | .fa-y-combinator:before { 1823 | content: "\f23b"; 1824 | } 1825 | .fa-optin-monster:before { 1826 | content: "\f23c"; 1827 | } 1828 | .fa-opencart:before { 1829 | content: "\f23d"; 1830 | } 1831 | .fa-expeditedssl:before { 1832 | content: "\f23e"; 1833 | } 1834 | .fa-battery-4:before, 1835 | .fa-battery:before, 1836 | .fa-battery-full:before { 1837 | content: "\f240"; 1838 | } 1839 | .fa-battery-3:before, 1840 | .fa-battery-three-quarters:before { 1841 | content: "\f241"; 1842 | } 1843 | .fa-battery-2:before, 1844 | .fa-battery-half:before { 1845 | content: "\f242"; 1846 | } 1847 | .fa-battery-1:before, 1848 | .fa-battery-quarter:before { 1849 | content: "\f243"; 1850 | } 1851 | .fa-battery-0:before, 1852 | .fa-battery-empty:before { 1853 | content: "\f244"; 1854 | } 1855 | .fa-mouse-pointer:before { 1856 | content: "\f245"; 1857 | } 1858 | .fa-i-cursor:before { 1859 | content: "\f246"; 1860 | } 1861 | .fa-object-group:before { 1862 | content: "\f247"; 1863 | } 1864 | .fa-object-ungroup:before { 1865 | content: "\f248"; 1866 | } 1867 | .fa-sticky-note:before { 1868 | content: "\f249"; 1869 | } 1870 | .fa-sticky-note-o:before { 1871 | content: "\f24a"; 1872 | } 1873 | .fa-cc-jcb:before { 1874 | content: "\f24b"; 1875 | } 1876 | .fa-cc-diners-club:before { 1877 | content: "\f24c"; 1878 | } 1879 | .fa-clone:before { 1880 | content: "\f24d"; 1881 | } 1882 | .fa-balance-scale:before { 1883 | content: "\f24e"; 1884 | } 1885 | .fa-hourglass-o:before { 1886 | content: "\f250"; 1887 | } 1888 | .fa-hourglass-1:before, 1889 | .fa-hourglass-start:before { 1890 | content: "\f251"; 1891 | } 1892 | .fa-hourglass-2:before, 1893 | .fa-hourglass-half:before { 1894 | content: "\f252"; 1895 | } 1896 | .fa-hourglass-3:before, 1897 | .fa-hourglass-end:before { 1898 | content: "\f253"; 1899 | } 1900 | .fa-hourglass:before { 1901 | content: "\f254"; 1902 | } 1903 | .fa-hand-grab-o:before, 1904 | .fa-hand-rock-o:before { 1905 | content: "\f255"; 1906 | } 1907 | .fa-hand-stop-o:before, 1908 | .fa-hand-paper-o:before { 1909 | content: "\f256"; 1910 | } 1911 | .fa-hand-scissors-o:before { 1912 | content: "\f257"; 1913 | } 1914 | .fa-hand-lizard-o:before { 1915 | content: "\f258"; 1916 | } 1917 | .fa-hand-spock-o:before { 1918 | content: "\f259"; 1919 | } 1920 | .fa-hand-pointer-o:before { 1921 | content: "\f25a"; 1922 | } 1923 | .fa-hand-peace-o:before { 1924 | content: "\f25b"; 1925 | } 1926 | .fa-trademark:before { 1927 | content: "\f25c"; 1928 | } 1929 | .fa-registered:before { 1930 | content: "\f25d"; 1931 | } 1932 | .fa-creative-commons:before { 1933 | content: "\f25e"; 1934 | } 1935 | .fa-gg:before { 1936 | content: "\f260"; 1937 | } 1938 | .fa-gg-circle:before { 1939 | content: "\f261"; 1940 | } 1941 | .fa-tripadvisor:before { 1942 | content: "\f262"; 1943 | } 1944 | .fa-odnoklassniki:before { 1945 | content: "\f263"; 1946 | } 1947 | .fa-odnoklassniki-square:before { 1948 | content: "\f264"; 1949 | } 1950 | .fa-get-pocket:before { 1951 | content: "\f265"; 1952 | } 1953 | .fa-wikipedia-w:before { 1954 | content: "\f266"; 1955 | } 1956 | .fa-safari:before { 1957 | content: "\f267"; 1958 | } 1959 | .fa-chrome:before { 1960 | content: "\f268"; 1961 | } 1962 | .fa-firefox:before { 1963 | content: "\f269"; 1964 | } 1965 | .fa-opera:before { 1966 | content: "\f26a"; 1967 | } 1968 | .fa-internet-explorer:before { 1969 | content: "\f26b"; 1970 | } 1971 | .fa-tv:before, 1972 | .fa-television:before { 1973 | content: "\f26c"; 1974 | } 1975 | .fa-contao:before { 1976 | content: "\f26d"; 1977 | } 1978 | .fa-500px:before { 1979 | content: "\f26e"; 1980 | } 1981 | .fa-amazon:before { 1982 | content: "\f270"; 1983 | } 1984 | .fa-calendar-plus-o:before { 1985 | content: "\f271"; 1986 | } 1987 | .fa-calendar-minus-o:before { 1988 | content: "\f272"; 1989 | } 1990 | .fa-calendar-times-o:before { 1991 | content: "\f273"; 1992 | } 1993 | .fa-calendar-check-o:before { 1994 | content: "\f274"; 1995 | } 1996 | .fa-industry:before { 1997 | content: "\f275"; 1998 | } 1999 | .fa-map-pin:before { 2000 | content: "\f276"; 2001 | } 2002 | .fa-map-signs:before { 2003 | content: "\f277"; 2004 | } 2005 | .fa-map-o:before { 2006 | content: "\f278"; 2007 | } 2008 | .fa-map:before { 2009 | content: "\f279"; 2010 | } 2011 | .fa-commenting:before { 2012 | content: "\f27a"; 2013 | } 2014 | .fa-commenting-o:before { 2015 | content: "\f27b"; 2016 | } 2017 | .fa-houzz:before { 2018 | content: "\f27c"; 2019 | } 2020 | .fa-vimeo:before { 2021 | content: "\f27d"; 2022 | } 2023 | .fa-black-tie:before { 2024 | content: "\f27e"; 2025 | } 2026 | .fa-fonticons:before { 2027 | content: "\f280"; 2028 | } 2029 | .fa-reddit-alien:before { 2030 | content: "\f281"; 2031 | } 2032 | .fa-edge:before { 2033 | content: "\f282"; 2034 | } 2035 | .fa-credit-card-alt:before { 2036 | content: "\f283"; 2037 | } 2038 | .fa-codiepie:before { 2039 | content: "\f284"; 2040 | } 2041 | .fa-modx:before { 2042 | content: "\f285"; 2043 | } 2044 | .fa-fort-awesome:before { 2045 | content: "\f286"; 2046 | } 2047 | .fa-usb:before { 2048 | content: "\f287"; 2049 | } 2050 | .fa-product-hunt:before { 2051 | content: "\f288"; 2052 | } 2053 | .fa-mixcloud:before { 2054 | content: "\f289"; 2055 | } 2056 | .fa-scribd:before { 2057 | content: "\f28a"; 2058 | } 2059 | .fa-pause-circle:before { 2060 | content: "\f28b"; 2061 | } 2062 | .fa-pause-circle-o:before { 2063 | content: "\f28c"; 2064 | } 2065 | .fa-stop-circle:before { 2066 | content: "\f28d"; 2067 | } 2068 | .fa-stop-circle-o:before { 2069 | content: "\f28e"; 2070 | } 2071 | .fa-shopping-bag:before { 2072 | content: "\f290"; 2073 | } 2074 | .fa-shopping-basket:before { 2075 | content: "\f291"; 2076 | } 2077 | .fa-hashtag:before { 2078 | content: "\f292"; 2079 | } 2080 | .fa-bluetooth:before { 2081 | content: "\f293"; 2082 | } 2083 | .fa-bluetooth-b:before { 2084 | content: "\f294"; 2085 | } 2086 | .fa-percent:before { 2087 | content: "\f295"; 2088 | } 2089 | .fa-gitlab:before { 2090 | content: "\f296"; 2091 | } 2092 | .fa-wpbeginner:before { 2093 | content: "\f297"; 2094 | } 2095 | .fa-wpforms:before { 2096 | content: "\f298"; 2097 | } 2098 | .fa-envira:before { 2099 | content: "\f299"; 2100 | } 2101 | .fa-universal-access:before { 2102 | content: "\f29a"; 2103 | } 2104 | .fa-wheelchair-alt:before { 2105 | content: "\f29b"; 2106 | } 2107 | .fa-question-circle-o:before { 2108 | content: "\f29c"; 2109 | } 2110 | .fa-blind:before { 2111 | content: "\f29d"; 2112 | } 2113 | .fa-audio-description:before { 2114 | content: "\f29e"; 2115 | } 2116 | .fa-volume-control-phone:before { 2117 | content: "\f2a0"; 2118 | } 2119 | .fa-braille:before { 2120 | content: "\f2a1"; 2121 | } 2122 | .fa-assistive-listening-systems:before { 2123 | content: "\f2a2"; 2124 | } 2125 | .fa-asl-interpreting:before, 2126 | .fa-american-sign-language-interpreting:before { 2127 | content: "\f2a3"; 2128 | } 2129 | .fa-deafness:before, 2130 | .fa-hard-of-hearing:before, 2131 | .fa-deaf:before { 2132 | content: "\f2a4"; 2133 | } 2134 | .fa-glide:before { 2135 | content: "\f2a5"; 2136 | } 2137 | .fa-glide-g:before { 2138 | content: "\f2a6"; 2139 | } 2140 | .fa-signing:before, 2141 | .fa-sign-language:before { 2142 | content: "\f2a7"; 2143 | } 2144 | .fa-low-vision:before { 2145 | content: "\f2a8"; 2146 | } 2147 | .fa-viadeo:before { 2148 | content: "\f2a9"; 2149 | } 2150 | .fa-viadeo-square:before { 2151 | content: "\f2aa"; 2152 | } 2153 | .fa-snapchat:before { 2154 | content: "\f2ab"; 2155 | } 2156 | .fa-snapchat-ghost:before { 2157 | content: "\f2ac"; 2158 | } 2159 | .fa-snapchat-square:before { 2160 | content: "\f2ad"; 2161 | } 2162 | .fa-pied-piper:before { 2163 | content: "\f2ae"; 2164 | } 2165 | .fa-first-order:before { 2166 | content: "\f2b0"; 2167 | } 2168 | .fa-yoast:before { 2169 | content: "\f2b1"; 2170 | } 2171 | .fa-themeisle:before { 2172 | content: "\f2b2"; 2173 | } 2174 | .fa-google-plus-circle:before, 2175 | .fa-google-plus-official:before { 2176 | content: "\f2b3"; 2177 | } 2178 | .fa-fa:before, 2179 | .fa-font-awesome:before { 2180 | content: "\f2b4"; 2181 | } 2182 | .fa-handshake-o:before { 2183 | content: "\f2b5"; 2184 | } 2185 | .fa-envelope-open:before { 2186 | content: "\f2b6"; 2187 | } 2188 | .fa-envelope-open-o:before { 2189 | content: "\f2b7"; 2190 | } 2191 | .fa-linode:before { 2192 | content: "\f2b8"; 2193 | } 2194 | .fa-address-book:before { 2195 | content: "\f2b9"; 2196 | } 2197 | .fa-address-book-o:before { 2198 | content: "\f2ba"; 2199 | } 2200 | .fa-vcard:before, 2201 | .fa-address-card:before { 2202 | content: "\f2bb"; 2203 | } 2204 | .fa-vcard-o:before, 2205 | .fa-address-card-o:before { 2206 | content: "\f2bc"; 2207 | } 2208 | .fa-user-circle:before { 2209 | content: "\f2bd"; 2210 | } 2211 | .fa-user-circle-o:before { 2212 | content: "\f2be"; 2213 | } 2214 | .fa-user-o:before { 2215 | content: "\f2c0"; 2216 | } 2217 | .fa-id-badge:before { 2218 | content: "\f2c1"; 2219 | } 2220 | .fa-drivers-license:before, 2221 | .fa-id-card:before { 2222 | content: "\f2c2"; 2223 | } 2224 | .fa-drivers-license-o:before, 2225 | .fa-id-card-o:before { 2226 | content: "\f2c3"; 2227 | } 2228 | .fa-quora:before { 2229 | content: "\f2c4"; 2230 | } 2231 | .fa-free-code-camp:before { 2232 | content: "\f2c5"; 2233 | } 2234 | .fa-telegram:before { 2235 | content: "\f2c6"; 2236 | } 2237 | .fa-thermometer-4:before, 2238 | .fa-thermometer:before, 2239 | .fa-thermometer-full:before { 2240 | content: "\f2c7"; 2241 | } 2242 | .fa-thermometer-3:before, 2243 | .fa-thermometer-three-quarters:before { 2244 | content: "\f2c8"; 2245 | } 2246 | .fa-thermometer-2:before, 2247 | .fa-thermometer-half:before { 2248 | content: "\f2c9"; 2249 | } 2250 | .fa-thermometer-1:before, 2251 | .fa-thermometer-quarter:before { 2252 | content: "\f2ca"; 2253 | } 2254 | .fa-thermometer-0:before, 2255 | .fa-thermometer-empty:before { 2256 | content: "\f2cb"; 2257 | } 2258 | .fa-shower:before { 2259 | content: "\f2cc"; 2260 | } 2261 | .fa-bathtub:before, 2262 | .fa-s15:before, 2263 | .fa-bath:before { 2264 | content: "\f2cd"; 2265 | } 2266 | .fa-podcast:before { 2267 | content: "\f2ce"; 2268 | } 2269 | .fa-window-maximize:before { 2270 | content: "\f2d0"; 2271 | } 2272 | .fa-window-minimize:before { 2273 | content: "\f2d1"; 2274 | } 2275 | .fa-window-restore:before { 2276 | content: "\f2d2"; 2277 | } 2278 | .fa-times-rectangle:before, 2279 | .fa-window-close:before { 2280 | content: "\f2d3"; 2281 | } 2282 | .fa-times-rectangle-o:before, 2283 | .fa-window-close-o:before { 2284 | content: "\f2d4"; 2285 | } 2286 | .fa-bandcamp:before { 2287 | content: "\f2d5"; 2288 | } 2289 | .fa-grav:before { 2290 | content: "\f2d6"; 2291 | } 2292 | .fa-etsy:before { 2293 | content: "\f2d7"; 2294 | } 2295 | .fa-imdb:before { 2296 | content: "\f2d8"; 2297 | } 2298 | .fa-ravelry:before { 2299 | content: "\f2d9"; 2300 | } 2301 | .fa-eercast:before { 2302 | content: "\f2da"; 2303 | } 2304 | .fa-microchip:before { 2305 | content: "\f2db"; 2306 | } 2307 | .fa-snowflake-o:before { 2308 | content: "\f2dc"; 2309 | } 2310 | .fa-superpowers:before { 2311 | content: "\f2dd"; 2312 | } 2313 | .fa-wpexplorer:before { 2314 | content: "\f2de"; 2315 | } 2316 | .fa-meetup:before { 2317 | content: "\f2e0"; 2318 | } 2319 | .sr-only { 2320 | position: absolute; 2321 | width: 1px; 2322 | height: 1px; 2323 | padding: 0; 2324 | margin: -1px; 2325 | overflow: hidden; 2326 | clip: rect(0, 0, 0, 0); 2327 | border: 0; 2328 | } 2329 | .sr-only-focusable:active, 2330 | .sr-only-focusable:focus { 2331 | position: static; 2332 | width: auto; 2333 | height: auto; 2334 | margin: 0; 2335 | overflow: visible; 2336 | clip: auto; 2337 | } 2338 | -------------------------------------------------------------------------------- /biblioteca_guerrilla/app/static/img/bg-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 29 | 34 | 35 | 43 | 48 | 49 | 57 | 62 | 63 | 71 | 76 | 77 | 85 | 90 | 91 | 99 | 104 | 105 | 113 | 118 | 119 | 127 | 132 | 133 | 141 | 146 | 147 | 155 | 160 | 161 | 169 | 174 | 175 | 183 | 188 | 189 | 197 | 202 | 203 | 211 | 216 | 217 | 225 | 230 | 231 | 239 | 244 | 245 | 253 | 258 | 259 | 267 | 272 | 273 | 281 | 286 | 287 | 295 | 300 | 301 | 309 | 314 | 315 | 323 | 328 | 329 | 337 | 342 | 343 | 351 | 356 | 357 | 365 | 370 | 371 | 379 | 384 | 385 | 393 | 398 | 399 | 407 | 412 | 413 | 421 | 426 | 427 | 435 | 440 | 441 | 449 | 454 | 455 | 463 | 468 | 469 | 477 | 482 | 483 | 491 | 496 | 497 | 505 | 510 | 511 | 519 | 524 | 525 | 533 | 538 | 539 | 547 | 552 | 553 | 561 | 566 | 567 | 568 | 586 | 588 | 589 | 591 | image/svg+xml 592 | 594 | 595 | 596 | 597 | 598 | 602 | 610 | 624 | 638 | 652 | bibliotecaguerrilla 678 | bibliotecaguerrilla 704 | 709 | 722 | 735 | 748 | 761 | 774 | 787 | 788 | 10 820 | 834 | 848 | bibliotecaguerrilla 875 | 880 | 888 | 896 | 910 | 924 | 938 | 939 | 948 | 951 | 959 | 973 | 987 | 1001 | 1002 | 1011 | 1016 | 1024 | 1038 | 1052 | 1066 | 1067 | 1068 | 1069 | --------------------------------------------------------------------------------