├── .gitignore ├── LICENSE ├── README.md ├── classifier ├── README.md ├── baseline.ipynb ├── itos_ru.pkl ├── itos_uk.pkl ├── ru_annotation.csv ├── ru_test_set.jl ├── training.ipynb ├── uk_annotation.csv └── uk_test_set.jl ├── cls_tool ├── README.md ├── cls_tool │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py ├── news │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── forms.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── requirements.txt ├── static │ ├── admin │ │ ├── css │ │ │ ├── autocomplete.css │ │ │ ├── base.css │ │ │ ├── changelists.css │ │ │ ├── dashboard.css │ │ │ ├── fonts.css │ │ │ ├── forms.css │ │ │ ├── login.css │ │ │ ├── responsive.css │ │ │ ├── responsive_rtl.css │ │ │ ├── rtl.css │ │ │ ├── vendor │ │ │ │ └── select2 │ │ │ │ │ ├── LICENSE-SELECT2.md │ │ │ │ │ ├── select2.css │ │ │ │ │ └── select2.min.css │ │ │ └── widgets.css │ │ ├── fonts │ │ │ ├── LICENSE.txt │ │ │ ├── README.txt │ │ │ ├── Roboto-Bold-webfont.woff │ │ │ ├── Roboto-Light-webfont.woff │ │ │ └── Roboto-Regular-webfont.woff │ │ ├── img │ │ │ ├── LICENSE │ │ │ ├── README.txt │ │ │ ├── calendar-icons.svg │ │ │ ├── gis │ │ │ │ ├── move_vertex_off.svg │ │ │ │ └── move_vertex_on.svg │ │ │ ├── icon-addlink.svg │ │ │ ├── icon-alert.svg │ │ │ ├── icon-calendar.svg │ │ │ ├── icon-changelink.svg │ │ │ ├── icon-clock.svg │ │ │ ├── icon-deletelink.svg │ │ │ ├── icon-no.svg │ │ │ ├── icon-unknown-alt.svg │ │ │ ├── icon-unknown.svg │ │ │ ├── icon-yes.svg │ │ │ ├── inline-delete.svg │ │ │ ├── search.svg │ │ │ ├── selector-icons.svg │ │ │ ├── sorting-icons.svg │ │ │ ├── tooltag-add.svg │ │ │ └── tooltag-arrowright.svg │ │ └── js │ │ │ ├── SelectBox.js │ │ │ ├── SelectFilter2.js │ │ │ ├── actions.js │ │ │ ├── actions.min.js │ │ │ ├── admin │ │ │ ├── DateTimeShortcuts.js │ │ │ └── RelatedObjectLookups.js │ │ │ ├── autocomplete.js │ │ │ ├── calendar.js │ │ │ ├── cancel.js │ │ │ ├── change_form.js │ │ │ ├── collapse.js │ │ │ ├── collapse.min.js │ │ │ ├── core.js │ │ │ ├── inlines.js │ │ │ ├── inlines.min.js │ │ │ ├── jquery.init.js │ │ │ ├── popup_response.js │ │ │ ├── prepopulate.js │ │ │ ├── prepopulate.min.js │ │ │ ├── prepopulate_init.js │ │ │ ├── timeparse.js │ │ │ ├── urlify.js │ │ │ └── vendor │ │ │ ├── jquery │ │ │ ├── LICENSE-JQUERY.txt │ │ │ ├── jquery.js │ │ │ └── jquery.min.js │ │ │ ├── select2 │ │ │ ├── LICENSE-SELECT2.md │ │ │ ├── i18n │ │ │ │ ├── ar.js │ │ │ │ ├── az.js │ │ │ │ ├── bg.js │ │ │ │ ├── ca.js │ │ │ │ ├── cs.js │ │ │ │ ├── da.js │ │ │ │ ├── de.js │ │ │ │ ├── el.js │ │ │ │ ├── en.js │ │ │ │ ├── es.js │ │ │ │ ├── et.js │ │ │ │ ├── eu.js │ │ │ │ ├── fa.js │ │ │ │ ├── fi.js │ │ │ │ ├── fr.js │ │ │ │ ├── gl.js │ │ │ │ ├── he.js │ │ │ │ ├── hi.js │ │ │ │ ├── hr.js │ │ │ │ ├── hu.js │ │ │ │ ├── id.js │ │ │ │ ├── is.js │ │ │ │ ├── it.js │ │ │ │ ├── ja.js │ │ │ │ ├── km.js │ │ │ │ ├── ko.js │ │ │ │ ├── lt.js │ │ │ │ ├── lv.js │ │ │ │ ├── mk.js │ │ │ │ ├── ms.js │ │ │ │ ├── nb.js │ │ │ │ ├── nl.js │ │ │ │ ├── pl.js │ │ │ │ ├── pt-BR.js │ │ │ │ ├── pt.js │ │ │ │ ├── ro.js │ │ │ │ ├── ru.js │ │ │ │ ├── sk.js │ │ │ │ ├── sr-Cyrl.js │ │ │ │ ├── sr.js │ │ │ │ ├── sv.js │ │ │ │ ├── th.js │ │ │ │ ├── tr.js │ │ │ │ ├── uk.js │ │ │ │ ├── vi.js │ │ │ │ ├── zh-CN.js │ │ │ │ └── zh-TW.js │ │ │ ├── select2.full.js │ │ │ └── select2.full.min.js │ │ │ └── xregexp │ │ │ ├── LICENSE-XREGEXP.txt │ │ │ ├── xregexp.js │ │ │ └── xregexp.min.js │ ├── classify_js.js │ ├── favicon.ico │ ├── libs │ │ ├── bootstrap-4.0.0-beta.2-dist │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── bootstrap.min.css.map │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── bootstrap.min.js.map │ │ ├── font-awesome-4.7.0 │ │ │ ├── HELP-US-OUT.txt │ │ │ ├── css │ │ │ │ ├── font-awesome.css │ │ │ │ ├── font-awesome.min.css │ │ │ │ ├── mixins.css │ │ │ │ └── variables.css │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ ├── less │ │ │ │ ├── animated.less │ │ │ │ ├── bordered-pulled.less │ │ │ │ ├── core.less │ │ │ │ ├── fixed-width.less │ │ │ │ ├── font-awesome.less │ │ │ │ ├── icons.less │ │ │ │ ├── larger.less │ │ │ │ ├── list.less │ │ │ │ ├── mixins.less │ │ │ │ ├── path.less │ │ │ │ ├── rotated-flipped.less │ │ │ │ ├── screen-reader.less │ │ │ │ ├── stacked.less │ │ │ │ └── variables.less │ │ │ └── scss │ │ │ │ ├── _animated.scss │ │ │ │ ├── _bordered-pulled.scss │ │ │ │ ├── _core.scss │ │ │ │ ├── _fixed-width.scss │ │ │ │ ├── _icons.scss │ │ │ │ ├── _larger.scss │ │ │ │ ├── _list.scss │ │ │ │ ├── _mixins.scss │ │ │ │ ├── _path.scss │ │ │ │ ├── _rotated-flipped.scss │ │ │ │ ├── _screen-reader.scss │ │ │ │ ├── _stacked.scss │ │ │ │ ├── _variables.scss │ │ │ │ ├── font-awesome.css │ │ │ │ ├── font-awesome.css.map │ │ │ │ └── font-awesome.scss │ │ ├── jquery3.2.1.js │ │ └── popper.js │ ├── styles.css │ ├── styles.css.map │ └── styles.scss └── templates │ ├── classifier.html │ ├── edit_done.html │ ├── list_done.html │ ├── registration │ └── login.html │ └── sceleton.html ├── data_collection ├── README.md ├── crawl_htmls │ ├── crawl_htmls │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-36.pyc │ │ │ ├── items.cpython-36.pyc │ │ │ ├── middlewares.cpython-36.pyc │ │ │ ├── pipelines.cpython-36.pyc │ │ │ └── settings.cpython-36.pyc │ │ ├── items.py │ │ ├── middlewares.py │ │ ├── pipelines.py │ │ ├── settings.py │ │ └── spiders │ │ │ ├── __init__.py │ │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-36.pyc │ │ │ ├── ra_htmls.cpython-36.pyc │ │ │ └── test.cpython-36.pyc │ │ │ └── ra_htmls.py │ ├── psql_engine.txt │ └── scrapy.cfg ├── load_fb.py ├── load_rss.py ├── my_fb.json ├── package.json └── ra_server.js ├── data_processing ├── README.md ├── classify_tech_tags.pkl ├── dvect_tech_tags.pkl ├── itos_ru.pkl ├── itos_uk.pkl ├── langdetect.py └── tokenize_and_numericalize.ipynb ├── img ├── performance.png ├── roc_ru.png ├── roc_uk.png └── temp ├── psql_engine.txt └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.bz2 2 | *.csv 3 | *.jl 4 | *.h5 5 | *.log 6 | -------------------------------------------------------------------------------- /classifier/README.md: -------------------------------------------------------------------------------- 1 | ## Scripts, models and data to traine language model-based classifier of manipulations in news. 2 | Based on [fast.ai](https://github.com/fastai/fastai) library, version 0.7.0. 3 | 4 | * `training.ipynb` - notebook with classifier of relevant-irrelevant articles, and multilabel classifier of manipulative texts, both in Ukrainian and Russian 5 | * `itos_.pkl` - token dictionaries 6 | * `ru/`, `uk/` - folders with fastai models. Put models in \/models - links to pretrained LM and classifiers: 7 | 8 | * [Wikipedia language model for Russian, forward LSTM](http://texty.org.ua/d/2018/share/mnews/fwd_ru_lm.zip) 9 | * [Wikipedia language model for Ukrainian, forward LSTM](http://texty.org.ua/d/2018/share/mnews/fwd_uk_lm.zip) 10 | * [Finetuned on news corpus Wikipedia language model for Russian](http://texty.org.ua/d/2018/share/mnews/fwd_ru_finetuned_lm.zip) 11 | * [Finetuned on news corpus Wikipedia language model for Ukrainian](http://texty.org.ua/d/2018/share/mnews/fwd_uk_finetuned_lm.zip) 12 | * [Finetuned on news corpus Wikipedia language model for Russian, encoder only](http://texty.org.ua/d/2018/share/mnews/fwd_ru_finetuned_lm_enc.zip) 13 | * [Finetuned on news corpus Wikipedia language model for Ukrainian, encoder only](http://texty.org.ua/d/2018/share/mnews/fwd_uk_finetuned_lm_enc.zip) 14 | * [Classifier of relevant news in Russian](http://texty.org.ua/d/2018/share/mnews/ru_is_other_cls.zip) 15 | * [Classifier of relevant news in Ukrainian](http://texty.org.ua/d/2018/share/mnews/uk_is_other_cls.zip) 16 | * [Classifier of types of manipulation for Russian](http://texty.org.ua/d/2018/share/mnews/ru_arg_emo_cls.zip) 17 | * [Classifier of types of manipulation for Ukrainian](http://texty.org.ua/d/2018/share/mnews/uk_emo_arg_cls.zip) 18 | 19 | 20 | * `_test_set.jl` - more thoroughly annotated random sets of news in Russian and Ukraininan, that were not involved in training. 21 | -------------------------------------------------------------------------------- /classifier/itos_ru.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/classifier/itos_ru.pkl -------------------------------------------------------------------------------- /classifier/itos_uk.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/classifier/itos_uk.pkl -------------------------------------------------------------------------------- /cls_tool/README.md: -------------------------------------------------------------------------------- 1 | ## Django project to set up annotation tool 2 | 3 | Usage of annotation tool requires basic knowledge of Django.
4 | 5 | To initialize the project create an environment, install `requirements.txt`, execute `python manage.py makemigrations`, and then `python manage.py migrate`. This will create sqlite3 database for your annotator. In case you want to use another database type, edit settings according to django docs.
6 | To use the tool you need to [create superuser](https://docs.djangoproject.com/en/2.0/intro/tutorial02/#creating-an-admin-user) and add possible labels for texts with django admin.
7 | You can upload data for annotation via django shell or using [django migration](https://simpleisbetterthancomplex.com/tutorial/2017/09/26/how-to-create-django-data-migrations.html) (the proper way). In any case consider using [`bulk_create`](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#bulk-create) for speed. To download annotated data use `python manage.py dumpdata mydata.json`.
8 | 9 | ### Models in django project 10 | 11 | ##### Article 12 | The main object - article for annotation. It is required to have `html_id`, text or readability html - `ra_summary`, a title - `ra_title`, and be associated with particular annotator from `django.contrib.auth.models.User` - `bee`. 13 | 14 | ##### Classified 15 | Types for article. This model has one-to-one relations with `Article` and many-to-many relations with `FakeType` (not the best model name). All annotated `Article`s are stored in `Classified` 16 | 17 | ##### FakeType 18 | Model for types of manipulation or whatever else your annotation is about. Each one has label and long description 19 | 20 | ##### Feedback 21 | Comments for articles. Each feedback has one-to-one relation with `Article`. -------------------------------------------------------------------------------- /cls_tool/cls_tool/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/cls_tool/__init__.py -------------------------------------------------------------------------------- /cls_tool/cls_tool/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for cls_tool project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '&)xa=6=xni^)vgv=$ix6s74kqmz^3m90kxzby0%-8=3z@qr3d=' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = ['localhost', '0.0.0.0'] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'news', 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'cls_tool.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': ['./templates', 59 | ], 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | WSGI_APPLICATION = 'cls_tool.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/2.1/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 'default': { 80 | 'ENGINE': 'django.db.backends.sqlite3', 81 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 82 | } 83 | } 84 | 85 | 86 | # Password validation 87 | # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators 88 | 89 | AUTH_PASSWORD_VALIDATORS = [ 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 92 | }, 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 101 | }, 102 | ] 103 | 104 | 105 | # Internationalization 106 | # https://docs.djangoproject.com/en/2.1/topics/i18n/ 107 | 108 | LANGUAGE_CODE = 'en-us' 109 | 110 | TIME_ZONE = 'UTC' 111 | 112 | USE_I18N = True 113 | 114 | USE_L10N = True 115 | 116 | USE_TZ = True 117 | 118 | 119 | # Static files (CSS, JavaScript, Images) 120 | # https://docs.djangoproject.com/en/2.1/howto/static-files/ 121 | 122 | STATIC_URL = '/static/' 123 | STATICFILES_DIRS = [ 124 | os.path.join(BASE_DIR, "static"), 125 | ] 126 | 127 | LOGIN_REDIRECT_URL = '/classifier/' 128 | -------------------------------------------------------------------------------- /cls_tool/cls_tool/urls.py: -------------------------------------------------------------------------------- 1 | """imi_cls URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 18 | from django.urls import path, include 19 | from django.contrib.auth import views as auth_views 20 | 21 | urlpatterns = [ 22 | path(r'admin/', admin.site.urls), 23 | path(r'', auth_views.LoginView.as_view(), name='login'), 24 | path(r'classifier/', include(('news.urls', 'news'), namespace='newsurls')), 25 | ] 26 | 27 | urlpatterns += staticfiles_urlpatterns() -------------------------------------------------------------------------------- /cls_tool/cls_tool/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for cls_tool project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cls_tool.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /cls_tool/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cls_tool.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /cls_tool/news/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/news/__init__.py -------------------------------------------------------------------------------- /cls_tool/news/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | class ArticleAdmin(admin.ModelAdmin): 5 | list_filter = ['bee'] 6 | search_fields = ['real_url', 'ra_title'] 7 | 8 | class ClassifiedAdmin(admin.ModelAdmin): 9 | list_filter = ['article__bee', 'types'] 10 | search_fields = ['article__real_url', 'article__ra_title'] 11 | 12 | class Ner_entityAdmin(admin.ModelAdmin): 13 | list_filter = ['entity_type', 'article__bee'] 14 | search_fields = ['article__real_url', 'article__ra_title'] 15 | 16 | admin.site.register(models.Article, ArticleAdmin) 17 | admin.site.register(models.Classified, ClassifiedAdmin) 18 | admin.site.register(models.FakeType) 19 | admin.site.register(models.Feedback) -------------------------------------------------------------------------------- /cls_tool/news/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NewsConfig(AppConfig): 5 | name = 'news' 6 | -------------------------------------------------------------------------------- /cls_tool/news/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from . import models 3 | 4 | class NewClassify(forms.ModelForm): 5 | class Meta: 6 | model = models.Classified 7 | fields = ['types', 'article'] 8 | 9 | def __init__(self, *args, **kwargs): 10 | super(NewClassify, self).__init__(*args, **kwargs) 11 | self.fields['types'].widget = forms.widgets.CheckboxSelectMultiple() 12 | self.fields['types'].queryset = models.FakeType.objects.all() 13 | self.fields['article'].widget = forms.widgets.HiddenInput() 14 | self.fields['article'].required = True 15 | 16 | 17 | class FeedbackForm(forms.ModelForm): 18 | class Meta: 19 | model = models.Feedback 20 | fields = ['article', 'comment'] 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(FeedbackForm, self).__init__(*args, **kwargs) 24 | self.fields['article'].widget = forms.widgets.HiddenInput() 25 | self.fields['article'].required = True 26 | -------------------------------------------------------------------------------- /cls_tool/news/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/news/migrations/__init__.py -------------------------------------------------------------------------------- /cls_tool/news/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | class FakeType(models.Model): 5 | label = models.CharField(max_length=255) 6 | description = models.TextField(null=True) 7 | id = models.IntegerField(primary_key=True) 8 | 9 | def __str__(self): 10 | return self.label 11 | 12 | class Meta: 13 | ordering = ('id', ) 14 | 15 | class Article(models.Model): 16 | html_id = models.IntegerField(primary_key=True) 17 | real_url = models.TextField(null=True) 18 | ra_summary = models.TextField(null=True) 19 | ra_title = models.TextField(null=True) 20 | loaded_unix = models.PositiveIntegerField() 21 | bee = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) 22 | 23 | def __str__(self): 24 | return '#{id}: {title}'.format(id=self.html_id, title=self.ra_title) 25 | 26 | class Classified(models.Model): 27 | types = models.ManyToManyField(FakeType) 28 | article = models.ForeignKey(Article, on_delete=models.PROTECT) 29 | classified_at = models.DateTimeField(auto_now=True) 30 | 31 | def __str__(self): 32 | return f'#{self.article.html_id} by {self.article.bee}: {self.article.ra_title}' 33 | class Meta: 34 | verbose_name_plural = 'Classified' 35 | 36 | 37 | class Feedback(models.Model): 38 | article = models.ForeignKey(Article, on_delete=models.PROTECT) 39 | written_at = models.DateTimeField(auto_now=True) 40 | comment = models.TextField() 41 | 42 | def __str__(self): 43 | return f'{self.article.bee} for "{self.article.ra_title}" at {self.written_at}' -------------------------------------------------------------------------------- /cls_tool/news/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /cls_tool/news/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path(r'done/', views.edit, name='list_done'), 6 | path(r'edit//', views.edit_done, name='edit_done'), 7 | path(r'ajax/feedback/', views.feedback, name='feedback'), 8 | path(r'', views.classify, name='classify'), 9 | ] -------------------------------------------------------------------------------- /cls_tool/news/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from . import models, forms 3 | from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage 4 | from django.contrib.auth.decorators import login_required 5 | from django.http import HttpResponseRedirect, JsonResponse 6 | from django.forms.models import model_to_dict 7 | 8 | 9 | @login_required 10 | def classify(request): 11 | if request.method == 'POST': 12 | form = forms.NewClassify(request.POST) 13 | if form.is_valid(): 14 | form.save() 15 | return HttpResponseRedirect('/classifier/') 16 | 17 | else: 18 | explanations = ';;'.join([t.description for t in models.FakeType.objects.all()]) 19 | classified_new = models.Article.objects.filter(bee=request.user 20 | ).exclude(html_id__in=models.Classified.objects.all( 21 | ).values('article') 22 | ).order_by('?' 23 | ).first() 24 | form = forms.NewClassify(initial={'article': classified_new}) 25 | feedback = forms.FeedbackForm(initial={'article': classified_new}) 26 | done_counter = models.Classified.objects.filter(article__bee=request.user).count() 27 | 28 | return render(request, 'classifier.html', {'cls_new': classified_new, 29 | 'form': form, 30 | 'type_explanations': explanations, 31 | 'feedback': feedback, 32 | 'done_counter': done_counter, 33 | }) 34 | 35 | 36 | @login_required 37 | def edit(request): 38 | selected_type = request.GET.get('type') 39 | 40 | print(request.GET.get('types')) 41 | types = models.FakeType.objects.all() 42 | if not selected_type or selected_type == 'all': 43 | classified_before = models.Classified.objects.filter(article__bee=request.user 44 | ).order_by('-classified_at') 45 | else: 46 | classified_before = models.Classified.objects.filter(article__bee=request.user 47 | ).filter(types__label=selected_type 48 | ).order_by('-classified_at') 49 | paginator = Paginator(classified_before, 15) 50 | 51 | page = request.GET.get('page') 52 | try: 53 | done = paginator.page(page) 54 | except PageNotAnInteger: 55 | # If page is not an integer, deliver first page. 56 | done = paginator.page(1) 57 | except EmptyPage: 58 | # If page is out of range (e.g. 9999), deliver last page of results. 59 | done = paginator.page(paginator.num_pages) 60 | 61 | return render(request, 'list_done.html', {'done': done, 62 | 'types': types, 63 | 'selected_type': selected_type}) 64 | 65 | 66 | @login_required 67 | def edit_done(request, pk): 68 | article = models.Classified.objects.get(article__html_id=pk) 69 | if request.method == 'POST': 70 | form = forms.NewClassify(request.POST, instance=article) 71 | if form.is_valid(): 72 | form.save() 73 | return HttpResponseRedirect('/classifier/done/') 74 | else: 75 | explanations = ';;'.join([t.description for t in models.FakeType.objects.all()]) 76 | 77 | feedback = forms.FeedbackForm(initial={'article': article.article}) 78 | form = forms.NewClassify(instance=article, data=model_to_dict(article)) 79 | 80 | return render(request, 'edit_done.html', {'form': form, 81 | 'cls_article': article, 82 | 'type_explanations': explanations, 83 | 'feedback': feedback, 84 | }) 85 | 86 | 87 | @login_required 88 | def feedback(request): 89 | if request.method == 'POST': 90 | feedback = forms.FeedbackForm(request.POST) 91 | if feedback.is_valid(): 92 | feedback.save() 93 | return JsonResponse({'ok': True}) 94 | -------------------------------------------------------------------------------- /cls_tool/requirements.txt: -------------------------------------------------------------------------------- 1 | Django>=2.1.5 2 | pytz==2018.7 3 | -------------------------------------------------------------------------------- /cls_tool/static/admin/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* DASHBOARD */ 2 | 3 | .dashboard .module table th { 4 | width: 100%; 5 | } 6 | 7 | .dashboard .module table td { 8 | white-space: nowrap; 9 | } 10 | 11 | .dashboard .module table td a { 12 | display: block; 13 | padding-right: .6em; 14 | } 15 | 16 | /* RECENT ACTIONS MODULE */ 17 | 18 | .module ul.actionlist { 19 | margin-left: 0; 20 | } 21 | 22 | ul.actionlist li { 23 | list-style-type: none; 24 | overflow: hidden; 25 | text-overflow: ellipsis; 26 | -o-text-overflow: ellipsis; 27 | } 28 | -------------------------------------------------------------------------------- /cls_tool/static/admin/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | src: url('../fonts/Roboto-Bold-webfont.woff'); 4 | font-weight: 700; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'Roboto'; 10 | src: url('../fonts/Roboto-Regular-webfont.woff'); 11 | font-weight: 400; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Roboto'; 17 | src: url('../fonts/Roboto-Light-webfont.woff'); 18 | font-weight: 300; 19 | font-style: normal; 20 | } 21 | -------------------------------------------------------------------------------- /cls_tool/static/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | body.login { 4 | background: #f8f8f8; 5 | } 6 | 7 | .login #header { 8 | height: auto; 9 | padding: 5px 16px; 10 | } 11 | 12 | .login #header h1 { 13 | font-size: 18px; 14 | } 15 | 16 | .login #header h1 a { 17 | color: #fff; 18 | } 19 | 20 | .login #content { 21 | padding: 20px 20px 0; 22 | } 23 | 24 | .login #container { 25 | background: #fff; 26 | border: 1px solid #eaeaea; 27 | border-radius: 4px; 28 | overflow: hidden; 29 | width: 28em; 30 | min-width: 300px; 31 | margin: 100px auto; 32 | } 33 | 34 | .login #content-main { 35 | width: 100%; 36 | } 37 | 38 | .login .form-row { 39 | padding: 4px 0; 40 | float: left; 41 | width: 100%; 42 | border-bottom: none; 43 | } 44 | 45 | .login .form-row label { 46 | padding-right: 0.5em; 47 | line-height: 2em; 48 | font-size: 1em; 49 | clear: both; 50 | color: #333; 51 | } 52 | 53 | .login .form-row #id_username, .login .form-row #id_password { 54 | clear: both; 55 | padding: 8px; 56 | width: 100%; 57 | -webkit-box-sizing: border-box; 58 | -moz-box-sizing: border-box; 59 | box-sizing: border-box; 60 | } 61 | 62 | .login span.help { 63 | font-size: 10px; 64 | display: block; 65 | } 66 | 67 | .login .submit-row { 68 | clear: both; 69 | padding: 1em 0 0 9.4em; 70 | margin: 0; 71 | border: none; 72 | background: none; 73 | text-align: left; 74 | } 75 | 76 | .login .password-reset-link { 77 | text-align: center; 78 | } 79 | -------------------------------------------------------------------------------- /cls_tool/static/admin/css/responsive_rtl.css: -------------------------------------------------------------------------------- 1 | /* TABLETS */ 2 | 3 | @media (max-width: 1024px) { 4 | [dir="rtl"] .colMS { 5 | margin-right: 0; 6 | } 7 | 8 | [dir="rtl"] #user-tools { 9 | text-align: right; 10 | } 11 | 12 | [dir="rtl"] #changelist .actions label { 13 | padding-left: 10px; 14 | padding-right: 0; 15 | } 16 | 17 | [dir="rtl"] #changelist .actions select { 18 | margin-left: 0; 19 | margin-right: 15px; 20 | } 21 | 22 | [dir="rtl"] .change-list .filtered .results, 23 | [dir="rtl"] .change-list .filtered .paginator, 24 | [dir="rtl"] .filtered #toolbar, 25 | [dir="rtl"] .filtered div.xfull, 26 | [dir="rtl"] .filtered .actions { 27 | margin-right: 0; 28 | margin-left: 230px; 29 | } 30 | 31 | [dir="rtl"] .inline-group ul.tools a.add, 32 | [dir="rtl"] .inline-group div.add-row a, 33 | [dir="rtl"] .inline-group .tabular tr.add-row td a { 34 | padding: 8px 26px 8px 10px; 35 | background-position: calc(100% - 8px) 9px; 36 | } 37 | 38 | [dir="rtl"] .related-widget-wrapper-link + .selector { 39 | margin-right: 0; 40 | margin-left: 15px; 41 | } 42 | 43 | [dir="rtl"] .selector .selector-filter label { 44 | margin-right: 0; 45 | margin-left: 8px; 46 | } 47 | 48 | [dir="rtl"] .object-tools li { 49 | float: right; 50 | } 51 | 52 | [dir="rtl"] .object-tools li + li { 53 | margin-left: 0; 54 | margin-right: 15px; 55 | } 56 | 57 | [dir="rtl"] .dashboard .module table td a { 58 | padding-left: 0; 59 | padding-right: 16px; 60 | } 61 | } 62 | 63 | /* MOBILE */ 64 | 65 | @media (max-width: 767px) { 66 | [dir="rtl"] .change-list .filtered .results, 67 | [dir="rtl"] .change-list .filtered .paginator, 68 | [dir="rtl"] .filtered #toolbar, 69 | [dir="rtl"] .filtered div.xfull, 70 | [dir="rtl"] .filtered .actions { 71 | margin-left: 0; 72 | } 73 | 74 | [dir="rtl"] .aligned .add-another, 75 | [dir="rtl"] .aligned .related-lookup, 76 | [dir="rtl"] .aligned .datetimeshortcuts { 77 | margin-left: 0; 78 | margin-right: 15px; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /cls_tool/static/admin/css/rtl.css: -------------------------------------------------------------------------------- 1 | body { 2 | direction: rtl; 3 | } 4 | 5 | /* LOGIN */ 6 | 7 | .login .form-row { 8 | float: right; 9 | } 10 | 11 | .login .form-row label { 12 | float: right; 13 | padding-left: 0.5em; 14 | padding-right: 0; 15 | text-align: left; 16 | } 17 | 18 | .login .submit-row { 19 | clear: both; 20 | padding: 1em 9.4em 0 0; 21 | } 22 | 23 | /* GLOBAL */ 24 | 25 | th { 26 | text-align: right; 27 | } 28 | 29 | .module h2, .module caption { 30 | text-align: right; 31 | } 32 | 33 | .module ul, .module ol { 34 | margin-left: 0; 35 | margin-right: 1.5em; 36 | } 37 | 38 | .addlink, .changelink { 39 | padding-left: 0; 40 | padding-right: 16px; 41 | background-position: 100% 1px; 42 | } 43 | 44 | .deletelink { 45 | padding-left: 0; 46 | padding-right: 16px; 47 | background-position: 100% 1px; 48 | } 49 | 50 | .object-tools { 51 | float: left; 52 | } 53 | 54 | thead th:first-child, 55 | tfoot td:first-child { 56 | border-left: none; 57 | } 58 | 59 | /* LAYOUT */ 60 | 61 | #user-tools { 62 | right: auto; 63 | left: 0; 64 | text-align: left; 65 | } 66 | 67 | div.breadcrumbs { 68 | text-align: right; 69 | } 70 | 71 | #content-main { 72 | float: right; 73 | } 74 | 75 | #content-related { 76 | float: left; 77 | margin-left: -300px; 78 | margin-right: auto; 79 | } 80 | 81 | .colMS { 82 | margin-left: 300px; 83 | margin-right: 0; 84 | } 85 | 86 | /* SORTABLE TABLES */ 87 | 88 | table thead th.sorted .sortoptions { 89 | float: left; 90 | } 91 | 92 | thead th.sorted .text { 93 | padding-right: 0; 94 | padding-left: 42px; 95 | } 96 | 97 | /* dashboard styles */ 98 | 99 | .dashboard .module table td a { 100 | padding-left: .6em; 101 | padding-right: 16px; 102 | } 103 | 104 | /* changelists styles */ 105 | 106 | .change-list .filtered table { 107 | border-left: none; 108 | border-right: 0px none; 109 | } 110 | 111 | #changelist-filter { 112 | right: auto; 113 | left: 0; 114 | border-left: none; 115 | border-right: none; 116 | } 117 | 118 | .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { 119 | margin-right: 0; 120 | margin-left: 280px; 121 | } 122 | 123 | #changelist-filter li.selected { 124 | border-left: none; 125 | padding-left: 10px; 126 | margin-left: 0; 127 | border-right: 5px solid #eaeaea; 128 | padding-right: 10px; 129 | margin-right: -15px; 130 | } 131 | 132 | .filtered .actions { 133 | margin-left: 280px; 134 | margin-right: 0; 135 | } 136 | 137 | #changelist table tbody td:first-child, #changelist table tbody th:first-child { 138 | border-right: none; 139 | border-left: none; 140 | } 141 | 142 | /* FORMS */ 143 | 144 | .aligned label { 145 | padding: 0 0 3px 1em; 146 | float: right; 147 | } 148 | 149 | .submit-row { 150 | text-align: left 151 | } 152 | 153 | .submit-row p.deletelink-box { 154 | float: right; 155 | } 156 | 157 | .submit-row input.default { 158 | margin-left: 0; 159 | } 160 | 161 | .vDateField, .vTimeField { 162 | margin-left: 2px; 163 | } 164 | 165 | .aligned .form-row input { 166 | margin-left: 5px; 167 | } 168 | 169 | form .aligned p.help, form .aligned div.help { 170 | clear: right; 171 | } 172 | 173 | form ul.inline li { 174 | float: right; 175 | padding-right: 0; 176 | padding-left: 7px; 177 | } 178 | 179 | input[type=submit].default, .submit-row input.default { 180 | float: left; 181 | } 182 | 183 | fieldset .field-box { 184 | float: right; 185 | margin-left: 20px; 186 | margin-right: 0; 187 | } 188 | 189 | .errorlist li { 190 | background-position: 100% 12px; 191 | padding: 0; 192 | } 193 | 194 | .errornote { 195 | background-position: 100% 12px; 196 | padding: 10px 12px; 197 | } 198 | 199 | /* WIDGETS */ 200 | 201 | .calendarnav-previous { 202 | top: 0; 203 | left: auto; 204 | right: 10px; 205 | } 206 | 207 | .calendarnav-next { 208 | top: 0; 209 | right: auto; 210 | left: 10px; 211 | } 212 | 213 | .calendar caption, .calendarbox h2 { 214 | text-align: center; 215 | } 216 | 217 | .selector { 218 | float: right; 219 | } 220 | 221 | .selector .selector-filter { 222 | text-align: right; 223 | } 224 | 225 | .inline-deletelink { 226 | float: left; 227 | } 228 | 229 | form .form-row p.datetime { 230 | overflow: hidden; 231 | } 232 | 233 | .related-widget-wrapper { 234 | float: right; 235 | } 236 | 237 | /* MISC */ 238 | 239 | .inline-related h2, .inline-group h2 { 240 | text-align: right 241 | } 242 | 243 | .inline-related h3 span.delete { 244 | padding-right: 20px; 245 | padding-left: inherit; 246 | left: 10px; 247 | right: inherit; 248 | float:left; 249 | } 250 | 251 | .inline-related h3 span.delete label { 252 | margin-left: inherit; 253 | margin-right: 2px; 254 | } 255 | 256 | /* IE7 specific bug fixes */ 257 | 258 | div.colM { 259 | position: relative; 260 | } 261 | 262 | .submit-row input { 263 | float: left; 264 | } 265 | -------------------------------------------------------------------------------- /cls_tool/static/admin/css/vendor/select2/LICENSE-SELECT2.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2015 Kevin Brown, Igor Vaynberg, and Select2 contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cls_tool/static/admin/fonts/README.txt: -------------------------------------------------------------------------------- 1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto 2 | Weights used in this project: Light (300), Regular (400), Bold (700) 3 | -------------------------------------------------------------------------------- /cls_tool/static/admin/fonts/Roboto-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/admin/fonts/Roboto-Bold-webfont.woff -------------------------------------------------------------------------------- /cls_tool/static/admin/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/admin/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /cls_tool/static/admin/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/admin/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /cls_tool/static/admin/img/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Code Charm Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/README.txt: -------------------------------------------------------------------------------- 1 | All icons are taken from Font Awesome (http://fontawesome.io/) project. 2 | The Font Awesome font is licensed under the SIL OFL 1.1: 3 | - http://scripts.sil.org/OFL 4 | 5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG 6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license 7 | in current folder). 8 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/selector-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/sorting-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/SelectBox.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | var SelectBox = { 4 | cache: {}, 5 | init: function(id) { 6 | var box = document.getElementById(id); 7 | var node; 8 | SelectBox.cache[id] = []; 9 | var cache = SelectBox.cache[id]; 10 | var boxOptions = box.options; 11 | var boxOptionsLength = boxOptions.length; 12 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 13 | node = boxOptions[i]; 14 | cache.push({value: node.value, text: node.text, displayed: 1}); 15 | } 16 | }, 17 | redisplay: function(id) { 18 | // Repopulate HTML select box from cache 19 | var box = document.getElementById(id); 20 | var node; 21 | $(box).empty(); // clear all options 22 | var new_options = box.outerHTML.slice(0, -9); // grab just the opening tag 23 | var cache = SelectBox.cache[id]; 24 | for (var i = 0, j = cache.length; i < j; i++) { 25 | node = cache[i]; 26 | if (node.displayed) { 27 | var new_option = new Option(node.text, node.value, false, false); 28 | // Shows a tooltip when hovering over the option 29 | new_option.setAttribute("title", node.text); 30 | new_options += new_option.outerHTML; 31 | } 32 | } 33 | new_options += ''; 34 | box.outerHTML = new_options; 35 | }, 36 | filter: function(id, text) { 37 | // Redisplay the HTML select box, displaying only the choices containing ALL 38 | // the words in text. (It's an AND search.) 39 | var tokens = text.toLowerCase().split(/\s+/); 40 | var node, token; 41 | var cache = SelectBox.cache[id]; 42 | for (var i = 0, j = cache.length; i < j; i++) { 43 | node = cache[i]; 44 | node.displayed = 1; 45 | var node_text = node.text.toLowerCase(); 46 | var numTokens = tokens.length; 47 | for (var k = 0; k < numTokens; k++) { 48 | token = tokens[k]; 49 | if (node_text.indexOf(token) === -1) { 50 | node.displayed = 0; 51 | break; // Once the first token isn't found we're done 52 | } 53 | } 54 | } 55 | SelectBox.redisplay(id); 56 | }, 57 | delete_from_cache: function(id, value) { 58 | var node, delete_index = null; 59 | var cache = SelectBox.cache[id]; 60 | for (var i = 0, j = cache.length; i < j; i++) { 61 | node = cache[i]; 62 | if (node.value === value) { 63 | delete_index = i; 64 | break; 65 | } 66 | } 67 | cache.splice(delete_index, 1); 68 | }, 69 | add_to_cache: function(id, option) { 70 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); 71 | }, 72 | cache_contains: function(id, value) { 73 | // Check if an item is contained in the cache 74 | var node; 75 | var cache = SelectBox.cache[id]; 76 | for (var i = 0, j = cache.length; i < j; i++) { 77 | node = cache[i]; 78 | if (node.value === value) { 79 | return true; 80 | } 81 | } 82 | return false; 83 | }, 84 | move: function(from, to) { 85 | var from_box = document.getElementById(from); 86 | var option; 87 | var boxOptions = from_box.options; 88 | var boxOptionsLength = boxOptions.length; 89 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 90 | option = boxOptions[i]; 91 | var option_value = option.value; 92 | if (option.selected && SelectBox.cache_contains(from, option_value)) { 93 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 94 | SelectBox.delete_from_cache(from, option_value); 95 | } 96 | } 97 | SelectBox.redisplay(from); 98 | SelectBox.redisplay(to); 99 | }, 100 | move_all: function(from, to) { 101 | var from_box = document.getElementById(from); 102 | var option; 103 | var boxOptions = from_box.options; 104 | var boxOptionsLength = boxOptions.length; 105 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 106 | option = boxOptions[i]; 107 | var option_value = option.value; 108 | if (SelectBox.cache_contains(from, option_value)) { 109 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 110 | SelectBox.delete_from_cache(from, option_value); 111 | } 112 | } 113 | SelectBox.redisplay(from); 114 | SelectBox.redisplay(to); 115 | }, 116 | sort: function(id) { 117 | SelectBox.cache[id].sort(function(a, b) { 118 | a = a.text.toLowerCase(); 119 | b = b.text.toLowerCase(); 120 | try { 121 | if (a > b) { 122 | return 1; 123 | } 124 | if (a < b) { 125 | return -1; 126 | } 127 | } 128 | catch (e) { 129 | // silently fail on IE 'unknown' exception 130 | } 131 | return 0; 132 | } ); 133 | }, 134 | select_all: function(id) { 135 | var box = document.getElementById(id); 136 | var boxOptions = box.options; 137 | var boxOptionsLength = boxOptions.length; 138 | for (var i = 0; i < boxOptionsLength; i++) { 139 | boxOptions[i].selected = 'selected'; 140 | } 141 | } 142 | }; 143 | window.SelectBox = SelectBox; 144 | })(django.jQuery); 145 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/actions.min.js: -------------------------------------------------------------------------------- 1 | (function(a){var f;a.fn.actions=function(e){var b=a.extend({},a.fn.actions.defaults,e),g=a(this),k=!1,l=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()},m=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},n=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},p=function(){n(); 2 | a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)},q=function(c){c?l():n();a(g).prop("checked",c).parent().parent().toggleClass(b.selectedClass,c)},h=function(){var c=a(g).filter(":checked").length,d=a(".action-counter").data("actionsIcnt");a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:d},!0));a(b.allToggle).prop("checked",function(){var a;c===g.length?(a=!0,l()):(a=!1,p());return a})};a(b.counterContainer).show(); 3 | a(this).filter(":checked").each(function(c){a(this).parent().parent().toggleClass(b.selectedClass);h();1===a(b.acrossInput).val()&&m()});a(b.allToggle).show().click(function(){q(a(this).prop("checked"));h()});a("a",b.acrossQuestions).click(function(c){c.preventDefault();a(b.acrossInput).val(1);m()});a("a",b.acrossClears).click(function(c){c.preventDefault();a(b.allToggle).prop("checked",!1);p();q(0);h()});f=null;a(g).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(f&& 4 | a.data(f)!==a.data(d)&&!0===c.shiftKey){var e=!1;a(f).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(g).each(function(){if(a.data(this)===a.data(f)||a.data(this)===a.data(d))e=e?!1:!0;e&&a(this).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);f=d;h()});a("form#changelist-form table#result_list tr").on("change","td:gt(0) :input",function(){k=!0});a('form#changelist-form button[name="index"]').click(function(a){if(k)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))}); 5 | a('form#changelist-form input[name="_save"]').click(function(c){var d=!1;a("select option:selected",b.actionContainer).each(function(){a(this).val()&&(d=!0)});if(d)return k?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})}; 6 | a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"};a(document).ready(function(){var e=a("tr input.action-select");0' + gettext("Show") + 11 | ')'); 12 | } 13 | }); 14 | // Add toggle to anchor tag 15 | $("fieldset.collapse a.collapse-toggle").click(function(ev) { 16 | if ($(this).closest("fieldset").hasClass("collapsed")) { 17 | // Show 18 | $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]); 19 | } else { 20 | // Hide 21 | $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]); 22 | } 23 | return false; 24 | }); 25 | }); 26 | })(django.jQuery); 27 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/collapse.min.js: -------------------------------------------------------------------------------- 1 | var $jscomp={scope:{},findInternal:function(a,c,b){a instanceof String&&(a=String(a));for(var d=a.length,e=0;e'+gettext("Show")+")")});a("fieldset.collapse a.collapse-toggle").click(function(c){a(this).closest("fieldset").hasClass("collapsed")?a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]):a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", 5 | [a(this).attr("id")]);return!1})})})(django.jQuery); 6 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/inlines.min.js: -------------------------------------------------------------------------------- 1 | var $jscomp={scope:{},findInternal:function(b,c,a){b instanceof String&&(b=String(b));for(var d=b.length,e=0;e'+a.addText+""),k=c.find("tr:last a")):(d.filter(":last").after('"),k=d.filter(":last").next().find("a")));k.click(function(c){c.preventDefault();c=b("#"+a.prefix+"-empty"); 6 | var d=c.clone(!0);d.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);d.is("tr")?d.children(":last").append('"):d.is("ul")||d.is("ol")?d.append('
  • '+a.deleteText+"
  • "):d.children(":first").append(''+a.deleteText+"");d.find("*").each(function(){e(this,a.prefix,f.val())});d.insertBefore(b(c)); 7 | b(f).val(parseInt(f.val(),10)+1);l+=1;""!==h.val()&&0>=h.val()-f.val()&&k.parent().hide();d.find("a."+a.deleteCssClass).click(function(c){c.preventDefault();d.remove();--l;a.removed&&a.removed(d);b(document).trigger("formset:removed",[d,a.prefix]);c=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(c.length);(""===h.val()||0 tr").tabularFormset(a.options)}})})})(django.jQuery); 14 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/jquery.init.js: -------------------------------------------------------------------------------- 1 | /*global django:true, jQuery:false*/ 2 | /* Puts the included jQuery into our own namespace using noConflict and passing 3 | * it 'true'. This ensures that the included jQuery doesn't pollute the global 4 | * namespace (i.e. this preserves pre-existing values for both window.$ and 5 | * window.jQuery). 6 | */ 7 | var django = django || {}; 8 | django.jQuery = jQuery.noConflict(true); 9 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/popup_response.js: -------------------------------------------------------------------------------- 1 | /*global opener */ 2 | (function() { 3 | 'use strict'; 4 | var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); 5 | switch(initData.action) { 6 | case 'change': 7 | opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); 8 | break; 9 | case 'delete': 10 | opener.dismissDeleteRelatedObjectPopup(window, initData.value); 11 | break; 12 | default: 13 | opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); 14 | break; 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/prepopulate.js: -------------------------------------------------------------------------------- 1 | /*global URLify*/ 2 | (function($) { 3 | 'use strict'; 4 | $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { 5 | /* 6 | Depends on urlify.js 7 | Populates a selected field with the values of the dependent fields, 8 | URLifies and shortens the string. 9 | dependencies - array of dependent fields ids 10 | maxLength - maximum length of the URLify'd string 11 | allowUnicode - Unicode support of the URLify'd string 12 | */ 13 | return this.each(function() { 14 | var prepopulatedField = $(this); 15 | 16 | var populate = function() { 17 | // Bail if the field's value has been changed by the user 18 | if (prepopulatedField.data('_changed')) { 19 | return; 20 | } 21 | 22 | var values = []; 23 | $.each(dependencies, function(i, field) { 24 | field = $(field); 25 | if (field.val().length > 0) { 26 | values.push(field.val()); 27 | } 28 | }); 29 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 30 | }; 31 | 32 | prepopulatedField.data('_changed', false); 33 | prepopulatedField.change(function() { 34 | prepopulatedField.data('_changed', true); 35 | }); 36 | 37 | if (!prepopulatedField.val()) { 38 | $(dependencies.join(',')).keyup(populate).change(populate).focus(populate); 39 | } 40 | }); 41 | }; 42 | })(django.jQuery); 43 | -------------------------------------------------------------------------------- /cls_tool/static/admin/js/prepopulate.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.prepopulate=function(e,f,g){return this.each(function(){var a=c(this),b=function(){if(!a.data("_changed")){var b=[];c.each(e,function(a,d){d=c(d);01&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/el.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Παρακαλώ διαγράψτε "+t+" χαρακτήρ";return t==1&&(n+="α"),t!=1&&(n+="ες"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Παρακαλώ συμπληρώστε "+t+" ή περισσότερους χαρακτήρες";return n},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(e){var t="Μπορείτε να επιλέξετε μόνο "+e.maximum+" επιλογ";return e.maximum==1&&(t+="ή"),e.maximum!=1&&(t+="ές"),t},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها می‌توانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק ";return t===1?n+="תו אחד":n+=t+" תווים",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס ";return t===1?n+="תו אחד":n+=t+" תווים",n+=" או יותר",n},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור עד ";return e.maximum===1?t+="פריט אחד":t+=e.maximum+" פריטים",t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/ja.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" 文字を削除してください";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="少なくとも "+t+" 文字を入力してください";return n},loadingMore:function(){return"読み込み中…"},maximumSelected:function(e){var t=e.maximum+" 件しか選択できません";return t},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/km.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="សូមលុបចេញ "+t+" អក្សរ";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="សូមបញ្ចូល"+t+" អក្សរ រឺ ច្រើនជាងនេះ";return n},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(e){var t="អ្នកអាចជ្រើសរើសបានតែ "+e.maximum+" ជម្រើសប៉ុណ្ណោះ";return t},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%10===1&&(e%100<11||e%100>19)?t:e%10>=2&&e%10<=9&&(e%100<11||e%100>19)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"į","ius","ių"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"į","ius","ių"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ą","us","ų"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/ms.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Sila hapuskan "+t+" aksara"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Sila masukkan "+t+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(e){return"Anda hanya boleh memilih "+e.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t=e.maximum==1?"kan":"kunnen",n="Er "+t+" maar "+e.maximum+" item";return e.maximum!=1&&(n+="s"),n+=" worden geselecteerd",n},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maximum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return t!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți "+t+"sau mai multe caractere";return n},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",e.maximum!==1&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/sr-Cyrl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr-Cyrl",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Обришите "+n+" симбол";return r+=e(n,"","а","а"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Укуцајте бар још "+n+" симбол";return r+=e(n,"","а","а"),r},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(t){var n="Можете изабрати само "+t.maximum+" ставк";return n+=e(t.maximum,"у","е","и"),n},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+' ký tự"';return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/select2/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /cls_tool/static/admin/js/vendor/xregexp/LICENSE-XREGEXP.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2007-2012 Steven Levithan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cls_tool/static/classify_js.js: -------------------------------------------------------------------------------- 1 | // Disable all links in fulltext 2 | 3 | String.prototype.trunc = function(n){ 4 | return (this.length > n) ? this.substr(0, n-1) + '...' : this; 5 | }; 6 | 7 | // Buttons-checkbox 8 | $('div.faketype input').change(function() { 9 | 10 | $(this).closest('label') 11 | .toggleClass('btn-dark') 12 | .toggleClass('btn-outline-dark'); 13 | 14 | }); 15 | 16 | $("#article_text *").each(function(i) { $(this).removeAttr('class').removeAttr('id').removeAttr('style'); }); 17 | 18 | // Keyboard checking 19 | const keycodes = { 20 | '49': {'faketype': '1'}, 21 | '50': {'faketype': '2'}, 22 | '51': {'faketype': '3'}, 23 | '52': {'faketype': '4'}, 24 | '53': {'faketype': '5'}, 25 | '54': {'faketype': '6'}, 26 | '55': {'faketype': '7'}, 27 | '56': {'faketype': '8'}, 28 | '97': {'faketype': '1'}, 29 | '98': {'faketype': '2'}, 30 | '99': {'faketype': '3'}, 31 | '100': {'faketype': '4'}, 32 | '101': {'faketype': '5'}, 33 | '102': {'faketype': '6'}, 34 | '103': {'faketype': '7'}, 35 | '104': {'faketype': '8'} 36 | }; 37 | 38 | var keys = {}; 39 | 40 | $('body').keydown(function (e) { 41 | if ( document.URL.indexOf('classifier') > -1 && 42 | e.which !== 40 && e.which !== 38 && 43 | e.which !== 33 && e.which !== 34 && 44 | e.which !== 35 && e.which !== 36 && 45 | e.which !== 17 && e.which !== 70 && 46 | (!$('#feedback_modal').is(':visible')) ) { 47 | e.preventDefault(); 48 | var keycode = e.which; 49 | keys[keycode] = true; 50 | if ( keys[16] && keys[37] ) { 51 | $('.fa-clock-o').click(); 52 | } 53 | 54 | if ( keys[16] && keys[39] ) { 55 | $('.fa-angle-right.fa-3x').click(); 56 | } 57 | 58 | var keypressed = keycode.toString(); 59 | 60 | if ( keycodes[keypressed] ) { 61 | if ( keys[16] ) { 62 | $('#id_types_' + keycodes[keypressed].faketype) 63 | .closest('label') 64 | .contextmenu(); 65 | } else { 66 | $('#id_types_' + keycodes[keypressed].faketype) 67 | .closest('label') 68 | .click(); 69 | } 70 | } 71 | 72 | if ( keycode === 13 ) { 73 | if ( $('#explanation_modal').is(':visible') ) { 74 | $('button[data-dismiss="modal"]').click(); 75 | 76 | } else if ( $('#ner_tagger').is(':visible') ) { 77 | $('#submit_ner').click(); 78 | 79 | } else { 80 | $('#submit_form').click(); 81 | } 82 | } 83 | 84 | if ( $('#ner_tagger').is(':visible') ) { 85 | if ( keys[16] ) { 86 | if ( keys[80] ) { 87 | $('input[value="P"]') 88 | .parent() 89 | .click(); 90 | $('#submit_ner').click(); 91 | } 92 | if ( keys[76] ) { 93 | $('input[value="L"]') 94 | .parent() 95 | .click(); 96 | $('#submit_ner').click(); 97 | } 98 | if ( keys[79] ) { 99 | $('input[value="O"]') 100 | .parent() 101 | .click(); 102 | $('#submit_ner').click(); 103 | } 104 | if ( keys[68] ) { 105 | $('input[value="none"]') 106 | .parent() 107 | .click(); 108 | $('#submit_ner').click(); 109 | } 110 | } 111 | } 112 | } 113 | }); 114 | 115 | $('body').keyup(function (e) { 116 | if ( document.URL.indexOf('classifier') > -1 && e.which !== 40 && e.which !== 38 ) { 117 | e.preventDefault(); 118 | delete keys[e.which]; 119 | } 120 | }); 121 | 122 | $(document).ready(function() { 123 | 124 | $('#article_text img').remove(); 125 | 126 | var $links = $('#article_text a:not([data-toggle="popover"])'); 127 | 128 | $links.each(function () { 129 | var $this = $(this); 130 | if ( $this.attr('href') ) { 131 | $this.attr('target', '') 132 | .attr('data-toggle', 'popover') 133 | .attr('data-trigger', 'focus') 134 | .attr('data-placement', 'top') 135 | .attr('title', 'Перейти за лінком') 136 | .attr('data-content', 137 | ''+ 140 | $this.attr('href').trunc(50) + 141 | '') 142 | .attr('data-html', 'true') 143 | .attr('href', '#') 144 | .click(function (e) { 145 | e.preventDefault(); 146 | }) 147 | .popover(); 148 | 149 | } else { 150 | $this.contents().unwrap(); 151 | } 152 | }); 153 | 154 | var explanations = $('#form-div').data('explanations').split(';;'); 155 | $('.modal_button').contextmenu(function(e) { 156 | e.preventDefault(); 157 | var targetModal = $(this).data('target'); 158 | var buttonIndex = + $(this).find('input').attr('value') - 1; 159 | $('#explanation_modal_label').text( $(e.currentTarget).data('title') ); 160 | $('#explanation_modal_description').text( explanations[buttonIndex] ); 161 | $(targetModal).modal("show"); 162 | 163 | }); 164 | 165 | $('#feedback_button').click(function (e) { 166 | $( $(this).data('target') ).modal("show"); 167 | }); 168 | 169 | $('#options form').submit(function (e) { 170 | if ( $(e.target).find('div.faketype .btn-dark').length < 1 ) { 171 | e.preventDefault(); 172 | } 173 | }); 174 | 175 | }); 176 | -------------------------------------------------------------------------------- /cls_tool/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/favicon.ico -------------------------------------------------------------------------------- /cls_tool/static/libs/bootstrap-4.0.0-beta.2-dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -ms-text-size-adjust: 100%; 19 | -ms-overflow-style: scrollbar; 20 | -webkit-tap-highlight-color: transparent; 21 | } 22 | 23 | @-ms-viewport { 24 | width: device-width; 25 | } 26 | 27 | article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { 28 | display: block; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 34 | font-size: 1rem; 35 | font-weight: 400; 36 | line-height: 1.5; 37 | color: #212529; 38 | text-align: left; 39 | background-color: #fff; 40 | } 41 | 42 | [tabindex="-1"]:focus { 43 | outline: none !important; 44 | } 45 | 46 | hr { 47 | box-sizing: content-box; 48 | height: 0; 49 | overflow: visible; 50 | } 51 | 52 | h1, h2, h3, h4, h5, h6 { 53 | margin-top: 0; 54 | margin-bottom: 0.5rem; 55 | } 56 | 57 | p { 58 | margin-top: 0; 59 | margin-bottom: 1rem; 60 | } 61 | 62 | abbr[title], 63 | abbr[data-original-title] { 64 | text-decoration: underline; 65 | -webkit-text-decoration: underline dotted; 66 | text-decoration: underline dotted; 67 | cursor: help; 68 | border-bottom: 0; 69 | } 70 | 71 | address { 72 | margin-bottom: 1rem; 73 | font-style: normal; 74 | line-height: inherit; 75 | } 76 | 77 | ol, 78 | ul, 79 | dl { 80 | margin-top: 0; 81 | margin-bottom: 1rem; 82 | } 83 | 84 | ol ol, 85 | ul ul, 86 | ol ul, 87 | ul ol { 88 | margin-bottom: 0; 89 | } 90 | 91 | dt { 92 | font-weight: 700; 93 | } 94 | 95 | dd { 96 | margin-bottom: .5rem; 97 | margin-left: 0; 98 | } 99 | 100 | blockquote { 101 | margin: 0 0 1rem; 102 | } 103 | 104 | dfn { 105 | font-style: italic; 106 | } 107 | 108 | b, 109 | strong { 110 | font-weight: bolder; 111 | } 112 | 113 | small { 114 | font-size: 80%; 115 | } 116 | 117 | sub, 118 | sup { 119 | position: relative; 120 | font-size: 75%; 121 | line-height: 0; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -.25em; 127 | } 128 | 129 | sup { 130 | top: -.5em; 131 | } 132 | 133 | a { 134 | color: #007bff; 135 | text-decoration: none; 136 | background-color: transparent; 137 | -webkit-text-decoration-skip: objects; 138 | } 139 | 140 | a:hover { 141 | color: #0056b3; 142 | text-decoration: underline; 143 | } 144 | 145 | a:not([href]):not([tabindex]) { 146 | color: inherit; 147 | text-decoration: none; 148 | } 149 | 150 | a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover { 151 | color: inherit; 152 | text-decoration: none; 153 | } 154 | 155 | a:not([href]):not([tabindex]):focus { 156 | outline: 0; 157 | } 158 | 159 | pre, 160 | code, 161 | kbd, 162 | samp { 163 | font-family: monospace, monospace; 164 | font-size: 1em; 165 | } 166 | 167 | pre { 168 | margin-top: 0; 169 | margin-bottom: 1rem; 170 | overflow: auto; 171 | -ms-overflow-style: scrollbar; 172 | } 173 | 174 | figure { 175 | margin: 0 0 1rem; 176 | } 177 | 178 | img { 179 | vertical-align: middle; 180 | border-style: none; 181 | } 182 | 183 | svg:not(:root) { 184 | overflow: hidden; 185 | } 186 | 187 | a, 188 | area, 189 | button, 190 | [role="button"], 191 | input:not([type="range"]), 192 | label, 193 | select, 194 | summary, 195 | textarea { 196 | -ms-touch-action: manipulation; 197 | touch-action: manipulation; 198 | } 199 | 200 | table { 201 | border-collapse: collapse; 202 | } 203 | 204 | caption { 205 | padding-top: 0.75rem; 206 | padding-bottom: 0.75rem; 207 | color: #868e96; 208 | text-align: left; 209 | caption-side: bottom; 210 | } 211 | 212 | th { 213 | text-align: inherit; 214 | } 215 | 216 | label { 217 | display: inline-block; 218 | margin-bottom: .5rem; 219 | } 220 | 221 | button { 222 | border-radius: 0; 223 | } 224 | 225 | button:focus { 226 | outline: 1px dotted; 227 | outline: 5px auto -webkit-focus-ring-color; 228 | } 229 | 230 | input, 231 | button, 232 | select, 233 | optgroup, 234 | textarea { 235 | margin: 0; 236 | font-family: inherit; 237 | font-size: inherit; 238 | line-height: inherit; 239 | } 240 | 241 | button, 242 | input { 243 | overflow: visible; 244 | } 245 | 246 | button, 247 | select { 248 | text-transform: none; 249 | } 250 | 251 | button, 252 | html [type="button"], 253 | [type="reset"], 254 | [type="submit"] { 255 | -webkit-appearance: button; 256 | } 257 | 258 | button::-moz-focus-inner, 259 | [type="button"]::-moz-focus-inner, 260 | [type="reset"]::-moz-focus-inner, 261 | [type="submit"]::-moz-focus-inner { 262 | padding: 0; 263 | border-style: none; 264 | } 265 | 266 | input[type="radio"], 267 | input[type="checkbox"] { 268 | box-sizing: border-box; 269 | padding: 0; 270 | } 271 | 272 | input[type="date"], 273 | input[type="time"], 274 | input[type="datetime-local"], 275 | input[type="month"] { 276 | -webkit-appearance: listbox; 277 | } 278 | 279 | textarea { 280 | overflow: auto; 281 | resize: vertical; 282 | } 283 | 284 | fieldset { 285 | min-width: 0; 286 | padding: 0; 287 | margin: 0; 288 | border: 0; 289 | } 290 | 291 | legend { 292 | display: block; 293 | width: 100%; 294 | max-width: 100%; 295 | padding: 0; 296 | margin-bottom: .5rem; 297 | font-size: 1.5rem; 298 | line-height: inherit; 299 | color: inherit; 300 | white-space: normal; 301 | } 302 | 303 | progress { 304 | vertical-align: baseline; 305 | } 306 | 307 | [type="number"]::-webkit-inner-spin-button, 308 | [type="number"]::-webkit-outer-spin-button { 309 | height: auto; 310 | } 311 | 312 | [type="search"] { 313 | outline-offset: -2px; 314 | -webkit-appearance: none; 315 | } 316 | 317 | [type="search"]::-webkit-search-cancel-button, 318 | [type="search"]::-webkit-search-decoration { 319 | -webkit-appearance: none; 320 | } 321 | 322 | ::-webkit-file-upload-button { 323 | font: inherit; 324 | -webkit-appearance: button; 325 | } 326 | 327 | output { 328 | display: inline-block; 329 | } 330 | 331 | summary { 332 | display: list-item; 333 | } 334 | 335 | template { 336 | display: none; 337 | } 338 | 339 | [hidden] { 340 | display: none !important; 341 | } 342 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /cls_tool/static/libs/bootstrap-4.0.0-beta.2-dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com) 3 | * Copyright 2011-2017 The Bootstrap Authors 4 | * Copyright 2011-2017 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/HELP-US-OUT.txt: -------------------------------------------------------------------------------- 1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, 2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, 3 | comprehensive icon sets or copy and paste your own. 4 | 5 | Please. Check it out. 6 | 7 | -Dave Gandy 8 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/css/mixins.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/css/mixins.css -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/css/variables.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/css/variables.css -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/cls_tool/static/libs/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/font-awesome.less: -------------------------------------------------------------------------------- 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 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /cls_tool/static/libs/font-awesome-4.7.0/scss/font-awesome.scss: -------------------------------------------------------------------------------- 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 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /cls_tool/static/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #0e0e0e; } 3 | 4 | div.footer { 5 | background-color: #e6cbfb !important; } 6 | 7 | h1 { 8 | font-size: 2rem; 9 | font-weight: bold; } 10 | 11 | i { 12 | color: #430971; } 13 | 14 | .link { 15 | color: #430971; } 16 | 17 | .link:hover { 18 | color: #FFA121; } 19 | 20 | input.faketype { 21 | opacity: 0; 22 | height: 0; 23 | width: 0; 24 | margin: 0; 25 | padding: 0; 26 | display: none; } 27 | 28 | div.faketype label { 29 | white-space: normal; 30 | width: 100%; } 31 | 32 | img { 33 | max-width: 100%; } 34 | 35 | input[type="submit"] { 36 | color: #0e0e0e; } 37 | 38 | #ner_tagger { 39 | position: absolute; 40 | z-index: 100000; 41 | display: none; 42 | background-color: #ffffff; 43 | -webkit-box-shadow: 0px 0px 25px 3px #c384f5; 44 | -moz-box-shadow: 0px 0px 25px 3px #c384f5; 45 | box-shadow: 0px 0px 25px 3px #c384f5; 46 | padding: 5px; 47 | border-radius: 4px; } 48 | 49 | nerperson { 50 | background-color: #ffb865; 51 | cursor: pointer; } 52 | 53 | nerlocation { 54 | background-color: #afdc61; 55 | cursor: pointer; } 56 | 57 | nerorganisation { 58 | background-color: #a3d0dc; 59 | cursor: pointer; } 60 | 61 | [data-issource="true"] { 62 | border: 1.5px solid #430971; } 63 | 64 | /*# sourceMappingURL=styles.css.map */ 65 | -------------------------------------------------------------------------------- /cls_tool/static/styles.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAKA,IAAK;EACH,KAAK,EALG,OAAO;;AAQjB,UAAW;EACT,gBAAgB,EAAE,kBAAmC;;AAGvD,EAAG;EACD,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,IAAI;;AAGnB,CAAE;EACA,KAAK,EAjBG,OAAO;;AAoBjB,KAAM;EACJ,KAAK,EArBG,OAAO;;AAwBjB,WAAY;EACV,KAAK,EAxBK,OAAO;;AA2BnB,cAAe;EACb,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;EACT,KAAK,EAAE,CAAC;EACR,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,OAAO,EAAE,IAAI;;AAGf,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,KAAK,EAAE,IAAI;;AAGb,GAAI;EACF,SAAS,EAAE,IAAI;;AAGjB,oBAAqB;EACnB,KAAK,EAhDG,OAAO;;AAmDjB,WAAY;EACV,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,MAAM;EACf,OAAO,EAAE,IAAI;EACb,gBAAgB,EAxDV,OAAO;EAyDb,kBAAkB,EAAE,wBAAyC;EAC7D,eAAe,EAAE,wBAAyC;EAC1D,UAAU,EAAE,wBAAyC;EACrD,OAAO,EAAE,GAAG;EACZ,aAAa,EAAE,GAAG;;AAGpB,SAAU;EACR,gBAAgB,EAAE,OAAO;EACzB,MAAM,EAAE,OAAO;;AAGjB,WAAY;EACV,gBAAgB,EAAE,OAAO;EACzB,MAAM,EAAE,OAAO;;AAGjB,eAAgB;EACd,gBAAgB,EAAE,OAAO;EACzB,MAAM,EAAE,OAAO;;AAGjB,sBAAuB;EACrB,MAAM,EAAE,mBAAoB", 4 | "sources": ["styles.scss"], 5 | "names": [], 6 | "file": "styles.css" 7 | } 8 | -------------------------------------------------------------------------------- /cls_tool/static/styles.scss: -------------------------------------------------------------------------------- 1 | $bgcol: #ffffff; 2 | $fontcol: #0e0e0e; 3 | $linkcol: #430971; 4 | $selectcol: #FFA121; 5 | 6 | body { 7 | color: $fontcol; 8 | } 9 | 10 | div.footer { 11 | background-color: lighten( $linkcol, 65% ) !important; 12 | } 13 | 14 | h1 { 15 | font-size: 2rem; 16 | font-weight: bold; 17 | } 18 | 19 | i { 20 | color: $linkcol; 21 | } 22 | 23 | .link { 24 | color: $linkcol; 25 | } 26 | 27 | .link:hover { 28 | color: $selectcol; 29 | } 30 | 31 | input.faketype { 32 | opacity: 0; 33 | height: 0; 34 | width: 0; 35 | margin: 0; 36 | padding: 0; 37 | display: none; 38 | } 39 | 40 | div.faketype label { 41 | white-space: normal; 42 | width: 100%; 43 | } 44 | 45 | img { 46 | max-width: 100%; 47 | } 48 | 49 | input[type="submit"] { 50 | color: $fontcol; 51 | } 52 | 53 | #ner_tagger { 54 | position: absolute; 55 | z-index: 100000; 56 | display: none; 57 | background-color: $bgcol; 58 | -webkit-box-shadow: 0px 0px 25px 3px lighten( $linkcol, 50% ); 59 | -moz-box-shadow: 0px 0px 25px 3px lighten( $linkcol, 50% ); 60 | box-shadow: 0px 0px 25px 3px lighten( $linkcol, 50% ); 61 | padding: 5px; 62 | border-radius: 4px; 63 | } 64 | 65 | nerperson { 66 | background-color: #ffb865; 67 | cursor: pointer; 68 | } 69 | 70 | nerlocation { 71 | background-color: #afdc61; 72 | cursor: pointer; 73 | } 74 | 75 | nerorganisation { 76 | background-color: #a3d0dc; 77 | cursor: pointer; 78 | } 79 | 80 | [data-issource="true"] { 81 | border: 1.5px solid $linkcol; 82 | } -------------------------------------------------------------------------------- /cls_tool/templates/classifier.html: -------------------------------------------------------------------------------- 1 | {% extends "sceleton.html" %} 2 | 3 | {% load static from staticfiles %} 4 | 5 | {% block content %} 6 |
    7 |
    8 |
    9 | {% url 'newsurls:list_done' as done_url %} 10 | 11 | 12 | 13 |
    14 |
    15 |

    #{{ cls_new.html_id }}: {{ cls_new.ra_title }}

    16 |
    17 |
    18 | 19 | 20 | 21 |
    22 |

    {{ form.article }}

    23 |
    24 |
    25 |
    26 | 27 |
    28 |
    29 | {% autoescape off %} {{ cls_new.ra_summary }} {% endautoescape %} 30 |
    31 |
    32 | 33 |
    34 |
    35 | {% csrf_token %} 36 | 37 | {% for f, l in form.fields.types.choices %} 38 | 39 |
    40 | 45 |
    46 | 47 | {% endfor %} 48 | 49 |
    50 | 53 |
    54 | 55 |
    56 | 57 |
    58 | 59 |
    60 |
    61 |
    62 |
    63 | 64 | 78 |
    79 | 80 | 81 | 99 | 100 | 101 | 129 | 130 | 145 | 146 | 147 | {% endblock content %} -------------------------------------------------------------------------------- /cls_tool/templates/list_done.html: -------------------------------------------------------------------------------- 1 | {% extends "sceleton.html" %} 2 | 3 | {% block content %} 4 | 5 |
    6 |
    7 |
    8 | 9 | 10 | 11 |
    12 |
    13 |

    Останні класифіковані тексти

    14 |
    15 |
    16 |
    17 |
    18 |
    19 | 31 |
    32 |
    33 | 34 |
    35 |
    36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
    45 |
    46 | 47 |
    48 | 49 |
    50 | 64 |
    65 | 66 | 89 |
    90 |
    91 | 92 | 104 | 105 | {% endblock %} -------------------------------------------------------------------------------- /cls_tool/templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "sceleton.html" %} 2 | 3 | {% block content %} 4 |
    5 |
    6 | {% if form.errors %} 7 |
    8 | 11 |
    12 | {% endif %} 13 | 14 | {% if next %} 15 | {% if user.is_authenticated %} 16 |
    17 |
    18 |

    Your account doesn't have access to this page. To proceed, 19 | please login with an account that has access.

    20 |
    21 |
    22 | {% else %} 23 |
    24 |
    25 |

    Please login to see this page.

    26 |
    27 |
    28 | {% endif %} 29 | {% endif %} 30 | 31 |
    32 |
    33 | {% csrf_token %} 34 | 35 |
    Логін
    36 |
    {{ form.username }}
    37 | 38 |
    Пароль
    39 |
    {{ form.password }}
    40 | 41 |
    42 | 43 | 44 |
    45 |
    46 |
    47 | 48 | 49 |
    50 | {% endblock %} -------------------------------------------------------------------------------- /cls_tool/templates/sceleton.html: -------------------------------------------------------------------------------- 1 | {% load static from staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 | Texty Classifier 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% block content %} 21 | {% endblock content %} 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /data_collection/README.md: -------------------------------------------------------------------------------- 1 | ## Data collection scripts 2 | 3 | * `crawl_htmls` - scrapy project to download articles' text and write readability html to database. If website is blocked - uses Tor and Polipo proxy 4 | * `load_fb.py` - script to download facebook feed of a page, and store all the links in postgres. Requires facebook app, put your credentials in [`my_fb.json`](my_fb.json) 5 | * `load_rss.py` - uses `feedparser` library to crawl RSS feeds of selected websites. Needs rewriting - on `scrapy`, and to handle blocked websites 6 | * `sites_ids.csv` - list of all sites, its feeds and fb pages 7 | * `ra_server.js` - express.js simple Node app. Listens to port 3000 and returns readability html. [Readability](https://github.com/mozilla/readability) is from Mozilla. Run it before launching `crawl_htmls`. To install dependencies - use `npm install` in this folder. `node ra_server.js` will launch it on port 3000 8 | * [`../psql_engine.txt`](../psql_engine.txt) - Postgresql credentials example to use in data collection and preprocessing scripts in case you also want to store data in postgres 9 | -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/__init__.py -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/__pycache__/items.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/__pycache__/items.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/__pycache__/middlewares.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/__pycache__/middlewares.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/__pycache__/pipelines.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/__pycache__/pipelines.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/__pycache__/settings.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/__pycache__/settings.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/items.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Define here the models for your scraped items 4 | # 5 | # See documentation in: 6 | # https://doc.scrapy.org/en/latest/topics/items.html 7 | 8 | import scrapy 9 | 10 | class RaResult(scrapy.Item): 11 | # define the fields for your item here like: 12 | link = scrapy.Field() 13 | real_url = scrapy.Field() 14 | ra_title = scrapy.Field() 15 | ra_summary = scrapy.Field() 16 | rss_id = scrapy.Field() 17 | fbfeeds_id = scrapy.Field() 18 | page_links = scrapy.Field() 19 | pass -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/middlewares.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Define here the models for your spider middleware 4 | # 5 | # See documentation in: 6 | # https://doc.scrapy.org/en/latest/topics/spider-middleware.html 7 | 8 | from scrapy import signals 9 | 10 | 11 | class CrawlHtmlsSpiderMiddleware(object): 12 | # Not all methods need to be defined. If a method is not defined, 13 | # scrapy acts as if the spider middleware does not modify the 14 | # passed objects. 15 | 16 | @classmethod 17 | def from_crawler(cls, crawler): 18 | # This method is used by Scrapy to create your spiders. 19 | s = cls() 20 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) 21 | return s 22 | 23 | def process_spider_input(self, response, spider): 24 | # Called for each response that goes through the spider 25 | # middleware and into the spider. 26 | 27 | # Should return None or raise an exception. 28 | return None 29 | 30 | def process_spider_output(self, response, result, spider): 31 | # Called with the results returned from the Spider, after 32 | # it has processed the response. 33 | 34 | # Must return an iterable of Request, dict or Item objects. 35 | for i in result: 36 | yield i 37 | 38 | def process_spider_exception(self, response, exception, spider): 39 | # Called when a spider or process_spider_input() method 40 | # (from other spider middleware) raises an exception. 41 | 42 | # Should return either None or an iterable of Response, dict 43 | # or Item objects. 44 | pass 45 | 46 | def process_start_requests(self, start_requests, spider): 47 | # Called with the start requests of the spider, and works 48 | # similarly to the process_spider_output() method, except 49 | # that it doesn’t have a response associated. 50 | 51 | # Must return only requests (not items). 52 | for r in start_requests: 53 | yield r 54 | 55 | def spider_opened(self, spider): 56 | spider.logger.info('Spider opened: %s' % spider.name) 57 | 58 | 59 | class CrawlHtmlsDownloaderMiddleware(object): 60 | # Not all methods need to be defined. If a method is not defined, 61 | # scrapy acts as if the downloader middleware does not modify the 62 | # passed objects. 63 | 64 | @classmethod 65 | def from_crawler(cls, crawler): 66 | # This method is used by Scrapy to create your spiders. 67 | s = cls() 68 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) 69 | return s 70 | 71 | def process_request(self, request, spider): 72 | # Called for each request that goes through the downloader 73 | # middleware. 74 | 75 | # Must either: 76 | # - return None: continue processing this request 77 | # - or return a Response object 78 | # - or return a Request object 79 | # - or raise IgnoreRequest: process_exception() methods of 80 | # installed downloader middleware will be called 81 | 82 | # request.meta['proxy'] = 'http://127.0.0.1:8123' 83 | return None 84 | 85 | def process_response(self, request, response, spider): 86 | # Called with the response returned from the downloader. 87 | 88 | # Must either; 89 | # - return a Response object 90 | # - return a Request object 91 | # - or raise IgnoreRequest 92 | return response 93 | 94 | def process_exception(self, request, exception, spider): 95 | # Called when a download handler or a process_request() 96 | # (from other downloader middleware) raises an exception. 97 | 98 | # Must either: 99 | # - return None: continue processing this exception 100 | # - return a Response object: stops process_exception() chain 101 | # - return a Request object: stops process_exception() chain 102 | pass 103 | 104 | def spider_opened(self, spider): 105 | spider.logger.info('Spider opened: %s' % spider.name) 106 | 107 | 108 | -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/pipelines.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Define your item pipelines here 4 | # 5 | # Don't forget to add your pipeline to the ITEM_PIPELINES setting 6 | # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html 7 | 8 | from sqlalchemy import create_engine 9 | import pdb 10 | 11 | 12 | class RaItemPipeline(object): 13 | 14 | def process_item(self, item, spider): 15 | q = f'''INSERT INTO htmls(link, real_url, ra_title, ra_summary, rss_id, fbfeeds_id, loaded_unix) 16 | VALUES ('{item['link'].replace("'", "''").replace('%', '%%')}', 17 | '{item['real_url'].replace("'", "''").replace('%', '%%')}', 18 | '{item['ra_title'].replace("'", "''").replace('%', '%%')}', 19 | '{item['ra_summary'].replace("'", "''").replace('%', '%%')}', 20 | {item['rss_id']}, 21 | {item['fbfeeds_id']}, 22 | extract(epoch from current_timestamp)::int 23 | ); 24 | ''' 25 | # q = f'''update htmls set 26 | # real_url = '{item['real_url'].replace("'", "''").replace('%', '%%')}', 27 | # ra_title = '{item['ra_title'].replace("'", "''").replace('%', '%%')}', 28 | # ra_summary = '{item['ra_summary'].replace("'", "''").replace('%', '%%')}', 29 | # rss_id = {item['rss_id']}, 30 | # fbfeeds_id = {item['fbfeeds_id']}, 31 | # loaded_unix = extract(epoch from current_timestamp)::int 32 | 33 | # where link = '{item['link'].replace("'", "''").replace('%', '%%').replace('ru.hromadske.ua', 'hromadske.ua')}'; 34 | # ''' 35 | spider.psql.execute(q) 36 | spider.psql.execute(f'''insert into plinks values ( 37 | '{item['link'].replace("'", "''").replace('%', '%%')}', 38 | ARRAY{item['page_links']}::text[] 39 | ) 40 | on conflict (link) do nothing; 41 | ''') 42 | spider.logger.info(f"wrote {item['link']}") 43 | return item 44 | -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Scrapy settings for crawl_htmls project 4 | # 5 | # For simplicity, this file contains only settings considered important or 6 | # commonly used. You can find more settings consulting the documentation: 7 | # 8 | # https://doc.scrapy.org/en/latest/topics/settings.html 9 | # https://doc.scrapy.org/en/latest/topics/downloader-middleware.html 10 | # https://doc.scrapy.org/en/latest/topics/spider-middleware.html 11 | 12 | BOT_NAME = 'crawl_htmls' 13 | LOG_FILE = 'ra_htmls.log' 14 | 15 | SPIDER_MODULES = ['crawl_htmls.spiders'] 16 | NEWSPIDER_MODULE = 'crawl_htmls.spiders' 17 | 18 | 19 | # Crawl responsibly by identifying yourself (and your website) on the user-agent 20 | USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0' 21 | 22 | # Obey robots.txt rules 23 | ROBOTSTXT_OBEY = False 24 | 25 | # Configure maximum concurrent requests performed by Scrapy (default: 16) 26 | CONCURRENT_REQUESTS = 500 27 | 28 | # Configure a delay for requests for the same website (default: 0) 29 | # See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay 30 | # See also autothrottle settings and docs 31 | #DOWNLOAD_DELAY = 3 32 | # The download delay setting will honor only one of: 33 | CONCURRENT_REQUESTS_PER_DOMAIN = 7 34 | #CONCURRENT_REQUESTS_PER_IP = 16 35 | 36 | # Disable cookies (enabled by default) 37 | COOKIES_ENABLED = False 38 | 39 | # Disable Telnet Console (enabled by default) 40 | #TELNETCONSOLE_ENABLED = False 41 | 42 | # Override the default request headers: 43 | #DEFAULT_REQUEST_HEADERS = { 44 | # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 45 | # 'Accept-Language': 'en', 46 | #} 47 | 48 | # Enable or disable spider middlewares 49 | # See https://doc.scrapy.org/en/latest/topics/spider-middleware.html 50 | #SPIDER_MIDDLEWARES = { 51 | # 'crawl_htmls.middlewares.CrawlHtmlsSpiderMiddleware': 543, 52 | #} 53 | 54 | # Enable or disable downloader middlewares 55 | # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html 56 | DOWNLOADER_MIDDLEWARES = { 57 | 'crawl_htmls.middlewares.CrawlHtmlsDownloaderMiddleware': 543, 58 | } 59 | 60 | # Enable or disable extensions 61 | # See https://doc.scrapy.org/en/latest/topics/extensions.html 62 | #EXTENSIONS = { 63 | # 'scrapy.extensions.telnet.TelnetConsole': None, 64 | #} 65 | 66 | # Configure item pipelines 67 | # See https://doc.scrapy.org/en/latest/topics/item-pipeline.html 68 | ITEM_PIPELINES = { 69 | 'crawl_htmls.pipelines.RaItemPipeline': 300, 70 | } 71 | 72 | # Enable and configure the AutoThrottle extension (disabled by default) 73 | # See https://doc.scrapy.org/en/latest/topics/autothrottle.html 74 | #AUTOTHROTTLE_ENABLED = True 75 | # The initial download delay 76 | #AUTOTHROTTLE_START_DELAY = 5 77 | # The maximum download delay to be set in case of high latencies 78 | #AUTOTHROTTLE_MAX_DELAY = 60 79 | # The average number of requests Scrapy should be sending in parallel to 80 | # each remote server 81 | #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 82 | # Enable showing throttling stats for every response received: 83 | #AUTOTHROTTLE_DEBUG = False 84 | 85 | # Enable and configure HTTP caching (disabled by default) 86 | # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings 87 | #HTTPCACHE_ENABLED = True 88 | #HTTPCACHE_EXPIRATION_SECS = 0 89 | #HTTPCACHE_DIR = 'httpcache' 90 | #HTTPCACHE_IGNORE_HTTP_CODES = [] 91 | #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' 92 | -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/spiders/__init__.py: -------------------------------------------------------------------------------- 1 | # This package will contain the spiders of your Scrapy project 2 | # 3 | # Please refer to the documentation for information on how to create and manage 4 | # your spiders. 5 | -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/spiders/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/spiders/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/spiders/__pycache__/ra_htmls.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/spiders/__pycache__/ra_htmls.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/spiders/__pycache__/test.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_collection/crawl_htmls/crawl_htmls/spiders/__pycache__/test.cpython-36.pyc -------------------------------------------------------------------------------- /data_collection/crawl_htmls/crawl_htmls/spiders/ra_htmls.py: -------------------------------------------------------------------------------- 1 | import scrapy, re, pdb, pandas as pd, requests 2 | from urllib.parse import urlparse 3 | from bs4 import BeautifulSoup 4 | from sqlalchemy import create_engine 5 | from crawl_htmls.items import RaResult 6 | from urllib.parse import urlparse 7 | 8 | with open('psql_engine.txt') as f: 9 | psql = create_engine(f.read()) 10 | 11 | unix_offset = (pd.to_datetime('now') - pd.DateOffset(days=30)).replace(hour=0, minute=0, second=0).value // 10**9 12 | 13 | q = f''' 14 | SELECT * FROM 15 | (SELECT fbfeeds.link, fbfeeds.fbfeeds_id FROM fbfeeds 16 | LEFT JOIN htmls ON (fbfeeds.link = htmls.link) 17 | WHERE htmls.link ISNULL AND fbfeeds.unix_time > {unix_offset} 18 | ) AS fb 19 | FULL OUTER JOIN 20 | (SELECT rss.link, rss.rss_id FROM rss 21 | LEFT JOIN htmls ON (rss.link = htmls.link) 22 | WHERE htmls.link ISNULL AND rss.published_parsed > {unix_offset} 23 | ) AS r 24 | ON (r.link = fb.link); 25 | ''' 26 | raw = pd.read_sql(q, psql) 27 | 28 | raw.columns = ['link', 'fbfeeds_id', 'link1', 'rss_id'] 29 | raw.link = raw.link.fillna(raw.link1) 30 | del(raw['link1']) 31 | raw = raw.sample(frac=1) 32 | 33 | # raw = pd.read_sql(f''' 34 | # select distinct link, fbfeeds_id, rss_id from htmls 35 | # where (link ~~ '%%hromadske.ua%%' and is_other isnull) 36 | # or link ~~ '%%alternatio.org%%'; 37 | # ''', psql) 38 | 39 | 40 | class SitesCrawler(scrapy.Spider): 41 | name = 'ra_htmls' 42 | psql = psql 43 | 44 | custom_settings = { 45 | 'CONCURRENT_ITEMS': 300, 46 | 'URLLENGTH_LIMIT': 10000, 47 | } 48 | 49 | def start_requests(self): 50 | urls = raw.sample(frac=1).values 51 | 52 | blocked = ['tvzvezda.ru', 'tk-union.tv', 'novorossiatv.com', 'ria.ru', 53 | 'sputniknews.com', 'rian.com.ua', 'news-front.info', 54 | 'armiyadnr.su', 'lug-info.com', 'dnr-live.ru', 'dnr-pravda.ru', 55 | 'republic-tv.ru', 'dan-news.info'] 56 | 57 | for link, fbfeeds_id, rss_id in urls: 58 | domain = urlparse(link).netloc 59 | if domain == 'hromadske.ua': 60 | link = link.replace('hromadske.ua', 'ru.hromadske.ua') 61 | if domain in blocked: 62 | yield scrapy.Request(link, callback=self.parse, 63 | meta={'link':link, 'fbfeeds_id': fbfeeds_id, 'rss_id': rss_id, 'proxy': 'http://localhost:8123',}) 64 | else: 65 | yield scrapy.Request(link, callback=self.parse, 66 | meta={'link':link, 'fbfeeds_id': fbfeeds_id, 'rss_id': rss_id,}) 67 | 68 | def parse(self, r): 69 | 70 | link = r.meta['link'] 71 | domain = urlparse(link).netloc 72 | page_links = filter(lambda a: 'http' in a, 73 | r.xpath('//a/@href').extract()) 74 | page_links = map(lambda a: urlparse(a).netloc.replace('www.', ' '), page_links) 75 | page_links = list(set(filter(lambda a: a != domain, page_links))) 76 | if 'alternatio.org' in link or 'hromadske.ua' in link: 77 | soup = BeautifulSoup(r.body.decode('utf8', 'ignore'), 'lxml') 78 | else: 79 | soup = BeautifulSoup(r.body, 'lxml') 80 | [t.extract() for t in soup.find_all() 81 | if len(t.text.strip()) == 0 82 | or t.name in ['img', 'iframe', 'script', 'link', 'footer', 'meta'] 83 | or re.search('nav|p[io]dval|footer|copyright|re[ck]lam', str(list(t.attrs.values()))) 84 | ] 85 | try: 86 | d = requests.post('http://localhost:3000', 87 | data={'raw_html': str(soup)} 88 | ).json() 89 | assert len(d['title']) > 0 90 | except Exception as err: 91 | self.logger.info(f'Failed {r.url}') 92 | pass 93 | 94 | item = RaResult() 95 | item['link'] = r.meta['link'] 96 | item['real_url'] = r.url 97 | item['ra_title'] = d['title'] 98 | item['ra_summary'] = re.sub('\s+', ' ', d['content']) 99 | item['rss_id'] = r.meta['rss_id'] if pd.notnull(r.meta['rss_id']) else 'null' 100 | item['fbfeeds_id'] = r.meta['fbfeeds_id'] if pd.notnull(r.meta['fbfeeds_id']) else 'null' 101 | item['page_links'] = page_links 102 | 103 | yield item -------------------------------------------------------------------------------- /data_collection/crawl_htmls/psql_engine.txt: -------------------------------------------------------------------------------- 1 | postgresql+psycopg2://username:password@111.222.0.333:5432/dbname -------------------------------------------------------------------------------- /data_collection/crawl_htmls/scrapy.cfg: -------------------------------------------------------------------------------- 1 | # Automatically created by: scrapy startproject 2 | # 3 | # For more information about the [deploy] section see: 4 | # https://scrapyd.readthedocs.io/en/latest/deploy.html 5 | 6 | [settings] 7 | default = crawl_htmls.settings 8 | 9 | [deploy] 10 | #url = http://localhost:6800/ 11 | project = crawl_htmls 12 | -------------------------------------------------------------------------------- /data_collection/load_fb.py: -------------------------------------------------------------------------------- 1 | import requests, re, codecs, json 2 | import pandas as pd 3 | from sqlalchemy import create_engine 4 | from time import sleep 5 | 6 | start = pd.to_datetime('now', utc=True).tz_convert('Europe/Kiev') 7 | 8 | with open('../psql_engine.txt', 'r') as f: 9 | psql = create_engine(f.read()) 10 | 11 | def fb_token(): 12 | ''' 13 | loads credentials from local file and returns requested FB access token 14 | ''' 15 | with open('my_fb.json') as f: 16 | auth_credentials = json.load(f) 17 | 18 | fb_auth_url = '''https://graph.facebook.com/v2.10/oauth/access_token?client_id={appid}&client_secret={appsecret}&grant_type=client_credentials''' 19 | token = requests.get(fb_auth_url.format(appid=auth_credentials['appid'], 20 | appsecret=auth_credentials['appsecret'])).json()['access_token'] 21 | return(token) 22 | 23 | token = '&access_token=' + fb_token() 24 | 25 | sites = pd.read_csv('sites_ids.csv') 26 | fbsites = sites.loc[pd.notnull(sites.fb_id), ].copy() 27 | fbsites.fb_id = fbsites.fb_id.str.strip('"') 28 | 29 | fb_feed_url = 'https://graph.facebook.com/v2.10/{id}?fields=feed.fields(caption, id, created_time, link, name, description){token}' 30 | 31 | def get_link(url): 32 | for _ in range(5): 33 | try: 34 | return requests.get(url) 35 | except Exception as err: 36 | print('Connection error: ', err) 37 | sleep(5) 38 | 39 | def get_fbfeed(url): 40 | ''' 41 | loads feeds as list of dict 42 | ''' 43 | response = get_link(url).json() 44 | 45 | if not 'feed' in response: 46 | return None, None 47 | response = response['feed'] 48 | if not 'data' in response: 49 | return None, None 50 | feed_df = pd.DataFrame(response['data']) 51 | feed_df.created_time = pd.to_datetime(feed_df.created_time) 52 | return feed_df, response.get('paging', {}).get('next', None) 53 | 54 | aff_fb_feeds = [] 55 | for i, site in fbsites.iterrows(): 56 | feed_url = fb_feed_url.format(id=site['fb_id'], token=token) 57 | feed_df, next_page = get_fbfeed(feed_url) 58 | if not isinstance(feed_df, pd.core.frame.DataFrame): 59 | continue 60 | while (pd.to_datetime('now') - min(feed_df.created_time)) < pd.Timedelta('1 day') and next_page != None: 61 | more_posts, next_page = get_fbfeed(next_page) 62 | feed_df = pd.concat([feed_df, more_posts]) 63 | aff_fb_feeds.append(feed_df) 64 | sleep(3) 65 | 66 | allposts = pd.concat(aff_fb_feeds) 67 | allposts = allposts.reset_index(drop=True) 68 | allposts.created_time = pd.to_datetime(allposts.created_time, utc=True).apply( 69 | lambda t: t.tz_convert('Europe/Kiev')) 70 | allposts['unix_time'] = allposts.created_time.apply(lambda x: x.value // 10**9) 71 | allposts.created_time = allposts.created_time.astype(str) 72 | allposts['grid'] = None 73 | allposts['postid'] = None 74 | allposts.loc[:, ['grid', 'postid']] = allposts.id.str.split('_').values.tolist() 75 | del(allposts['id']) 76 | allposts = allposts.loc[pd.notnull(allposts.link), ] 77 | allposts = allposts.loc[~allposts.link.str.contains('https://www.facebook.com|youtu.*be'), ] 78 | 79 | allposts.link = allposts.link.apply( 80 | lambda l: get_link(l).url.replace('%', '%%') 81 | if 'bit.ly' in l or 'goo.gl' in l 82 | else l.replace('%', '%%')) 83 | 84 | allposts.to_sql('fbfeeds', psql, index=False, if_exists='append') 85 | 86 | endtime = pd.to_datetime('now', utc=True).tz_convert('Europe/Kiev') 87 | 88 | print('{dt} loaded fb feeds in {timing}'.format(dt=endtime, timing=str(endtime-start))) -------------------------------------------------------------------------------- /data_collection/load_rss.py: -------------------------------------------------------------------------------- 1 | import codecs, feedparser, re, os, pickle 2 | import pandas as pd 3 | from sqlalchemy import create_engine 4 | from time import sleep 5 | from dateparser import parse as parsedate 6 | from bs4 import BeautifulSoup 7 | 8 | os.chdir('./propaganda/') 9 | 10 | now = pd.to_datetime('now', utc=True).tz_convert('Europe/Kiev') 11 | 12 | with open('psql_engine.txt', 'r') as f: 13 | engine = create_engine(f.read()) 14 | 15 | sites = pd.read_csv('sites_ids.csv') 16 | 17 | replace_dates = [('нояб.*|листоп.*', 'November'), 18 | ('дек.*|груд.', 'December'), 19 | ('січ.*|янв.*', 'January'), 20 | ('фев.*|лют.*', 'February'), 21 | ('мар.*|берез.*', 'March'), 22 | ('апр.*|квіт.*', 'April'), 23 | ('ма[йя].*|трав.*', 'May'), 24 | ('июн.*|черв.*', 'June'), 25 | ('июл.*|лип.?н.*', 'July'), 26 | ('авг.*|серп.?.*', 'August')] 27 | 28 | now = pd.to_datetime('now', utc=True).tz_convert('Europe/Kiev') 29 | 30 | 31 | def get_date(date): 32 | ''' 33 | parses dates from strange 34 | ''' 35 | if pd.isnull(date): 36 | return 37 | 38 | parsed = parsedate(date) 39 | 40 | if parsed: 41 | if parsed.year < 2017: 42 | return 43 | 44 | parsed = pd.to_datetime(parsed) 45 | else: 46 | for repl in replace_dates: 47 | date = re.sub(repl[0], repl[1], date) 48 | parsed = pd.to_datetime(parsedate(date)) 49 | if not parsed: 50 | return now 51 | 52 | if parsed.tz: 53 | if now.tz_convert(parsed.tz) < parsed: 54 | parsed = parsed.tz_localize(None).tz_localize('Europe/Kiev') 55 | else: 56 | parsed = parsed.tz_localize('Europe/Kiev') 57 | 58 | parsed = parsed.tz_convert('Europe/Kiev') 59 | 60 | if parsed > (now - pd.DateOffset(days=1)) and parsed <= now: 61 | return parsed 62 | 63 | 64 | feed_dfs = [] 65 | for i, site in sites.loc[pd.notnull(sites.rss),].iterrows(): 66 | for i in range(5): 67 | feed = feedparser.parse(site['rss']) 68 | df = pd.DataFrame(feed.entries) 69 | if len(df.columns) > 0: 70 | break 71 | else: 72 | if i == 4: 73 | print('\tProblem while loading feed for {}'.format(site['rss'])) 74 | if i < 4: 75 | sleep(5) 76 | if len(df.columns) < 1 or len(df) < 1: 77 | continue 78 | 79 | df['site'] = site['source'] 80 | if not 'published' in df.columns: 81 | df['published'] = now 82 | df['published_parsed'] = now.tz_convert('UTC').value // 10 ** 9 83 | else: 84 | df.published = df.published.apply(get_date) 85 | df = df.loc[pd.notnull(df.published),] 86 | df.published_parsed = df.published.apply(lambda x: x.tz_convert('UTC').value // 10 ** 9) 87 | 88 | df['site'] = site['source'] 89 | site_links = pd.read_sql("SELECT link FROM rss WHERE site = '{source}' AND published_parsed > {yesterday};".format( 90 | source=site['source'], yesterday=((now - pd.DateOffset(days=1)).value // 10**9) 91 | ), engine).link.tolist() 92 | df = df.reindex(columns=['site', 'link', 'published', 'published_parsed', 'title', 'summary', 'tags']) 93 | df = df.loc[~df.link.isin(site_links), ] 94 | if len(df) > 0: 95 | feed_dfs.append(df) 96 | 97 | allfeeds = pd.concat(feed_dfs) 98 | 99 | deltags = codecs.open('deltags.txt', 'r', encoding='utf-8').readlines() 100 | deltags = list(map(lambda s: re.sub('[\-\s+]', ' ', s.strip().lower()), deltags)) 101 | deltags = '|'.join(deltags) 102 | 103 | allfeeds = allfeeds.loc[~allfeeds.tags.astype('str').str.lower().str.contains(deltags), ] 104 | 105 | allfeeds.loc[pd.notnull(allfeeds.tags), 'tags'] = allfeeds.loc[pd.notnull(allfeeds.tags), 'tags'].apply( 106 | lambda tags: '[{}]'.format(', '.join(list(map(lambda tag: tag.term ,tags))))) 107 | 108 | def remove_html(html): 109 | ''' 110 | Removes all html tags and specific symbols as " from text 111 | ''' 112 | return BeautifulSoup('{}'.format(html), 'html.parser').body.get_text(separator=' ') 113 | 114 | allfeeds.title = allfeeds.title.apply(remove_html) 115 | allfeeds.summary = allfeeds.summary.apply(remove_html) 116 | 117 | allfeeds.published = allfeeds.published.apply(lambda t: t.tz_localize(None)) 118 | 119 | try: 120 | allfeeds.to_sql('rss', engine, index=False, if_exists='append') 121 | except ValueError: 122 | with open('ValueErrorSQL.pkl', 'wb') as f: 123 | pickle.dump(allfeeds, f) 124 | print('{} Inadequate time zones, quiting\n'.format(now)) 125 | quit() 126 | 127 | timing = pd.to_datetime('now', utc=True).tz_convert('Europe/Kiev') - now 128 | 129 | print(now, 'loaded feeds in {}\n'.format(str(timing))) -------------------------------------------------------------------------------- /data_collection/my_fb.json: -------------------------------------------------------------------------------- 1 | {"appid": "123456789", 2 | "appsecret": "my_app_secret_from_fb"} 3 | -------------------------------------------------------------------------------- /data_collection/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "readability_server", 3 | "version": "1.0.0", 4 | "description": "Small express.js app to process raw htmls with Mozilla Readability ", 5 | "main": "ra_server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "readability", 11 | "express" 12 | ], 13 | "author": "Nadiia Romanenko", 14 | "license": "MIT", 15 | "dependencies": { 16 | "body-parser": "^1.18.3", 17 | "express": "^4.16.4", 18 | "jsdom": "^13.0.0", 19 | "readability": "git+https://github.com/mozilla/readability.git" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data_collection/ra_server.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const app = express() 3 | 4 | var bodyParser = require('body-parser'); 5 | 6 | var readability = require('readability'); 7 | const jsdom = require('jsdom'); 8 | const { JSDOM } = jsdom; 9 | 10 | app.use(bodyParser.json({ limit:'100MB', type:'application/json'})); 11 | app.use(bodyParser.urlencoded({ limit:'100MB', extended: true })); 12 | 13 | app.post('/', function( req, res ) { 14 | var doc = new JSDOM( req.body.raw_html ); 15 | 16 | var article = new readability(doc.window.document).parse(); 17 | if ( article == null ) { 18 | var resp = { 19 | title: '', 20 | content: '' 21 | }; 22 | console.log( "Can't process it :((" ); 23 | } else { 24 | var resp = { 25 | title: article.title, 26 | content: article.content 27 | }; 28 | console.log( article.title ); 29 | } 30 | 31 | res.send( JSON.stringify(resp) ); 32 | }) 33 | 34 | app.listen(3000, () => console.log('Readability node server is ready! Default port - 3000')) -------------------------------------------------------------------------------- /data_processing/README.md: -------------------------------------------------------------------------------- 1 | ## Data preprocessing 2 | This folder contains a notebook to turn readability html into tokenized text, and then to numerical ids for classifier. 3 | 4 | Notebook is written either for Postgresql database with all htmls (commented code), or for `../htmls_sample.jl.bz2` sample of 100k articles. Final output - sequence of token ids at each article - is an input to LM classifier 5 | 6 | `itos.pkl` - token dictionaries, composed during fine-tuning of language model. A list of up to 60k most common words with minimum frequency 15. 7 | `classify_tech_tags.pkl` - scikit-learn LogisticRegressionClassifier to detect technical html elements, such as datetime, "read also" paragraps, social media buttons etc. 8 | 9 | `langdetect.py` - simple script to detect language with `cld2` or python `langid`. 10 | -------------------------------------------------------------------------------- /data_processing/classify_tech_tags.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_processing/classify_tech_tags.pkl -------------------------------------------------------------------------------- /data_processing/dvect_tech_tags.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_processing/dvect_tech_tags.pkl -------------------------------------------------------------------------------- /data_processing/itos_ru.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_processing/itos_ru.pkl -------------------------------------------------------------------------------- /data_processing/itos_uk.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/data_processing/itos_uk.pkl -------------------------------------------------------------------------------- /data_processing/langdetect.py: -------------------------------------------------------------------------------- 1 | import pandas as pd, pycld2 as cld2, re, langid 2 | from sqlalchemy import create_engine 3 | from bs4 import BeautifulSoup 4 | 5 | from tqdm import tqdm 6 | 7 | langid.set_languages(['ru','uk','en']) 8 | 9 | with open('../psql_engine.txt') as f: 10 | psql = create_engine(f.read()) 11 | 12 | def get_lang(text): 13 | rel, _, matches = cld2.detect(text) 14 | if not rel: 15 | return 16 | matches = list(filter(lambda m: m[1] in ['ru', 'uk', 'en'], matches)) 17 | if len(matches) == 0: 18 | return langid.classify(text)[0] 19 | return matches[0][1] 20 | 21 | chunks = pd.read_sql('''SELECT html_id, ra_summary FROM htmls 22 | WHERE lang isnull and ra_summary notnull; 23 | ''', psql, chunksize=20000) 24 | 25 | for df in tqdm(chunks): 26 | df['text'] = df.ra_summary.apply(lambda s: re.sub('\s+', ' ', BeautifulSoup(s, 'lxml').get_text()).strip()) 27 | df['text'] = df.text.apply(lambda t: ''.join([ch for ch in t if ch.isprintable()])) 28 | df['lang'] = df.text.apply(get_lang) 29 | vals = ',\n'.join([f"({html_id}, '{lang}')" for html_id, lang 30 | in df.loc[pd.notnull(df.lang)].reindex(['html_id', 'lang'], axis=1).values]) 31 | psql.execute(f''' 32 | update htmls as t set 33 | lang = c.lang 34 | from (values 35 | {vals} 36 | ) as c(html_id, lang) 37 | where c.html_id = t.html_id; 38 | ''') -------------------------------------------------------------------------------- /img/performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/img/performance.png -------------------------------------------------------------------------------- /img/roc_ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/img/roc_ru.png -------------------------------------------------------------------------------- /img/roc_uk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/texty/manipulative_news_methodology/1a7ae1ecd78224c3edd08f21a4bdd00f036b4eb1/img/roc_uk.png -------------------------------------------------------------------------------- /img/temp: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /psql_engine.txt: -------------------------------------------------------------------------------- 1 | postgresql+psycopg2://username:password@111.222.0.333:5432/dbname -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | feedparser 2 | nltk 3 | tokenize_uk 4 | readability-lxml 5 | sqlalchemy 6 | psycopg2 7 | psycopg2-binary 8 | requests 9 | scrapy --------------------------------------------------------------------------------