├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── manage.py ├── requirements.txt ├── tellina ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py └── website ├── __init__.py ├── admin.py ├── annotator.py ├── apps.py ├── backend_interface.py ├── cmd2html.py ├── constants.py ├── context_processor.py ├── functions.py ├── manpage_expl.json ├── models.py ├── scripts ├── __init__.py └── db_changes.py ├── static ├── css │ ├── animate.css │ ├── annotator │ │ ├── login.css │ │ └── panel.css │ ├── comment.css │ ├── developers.css │ ├── font-awesome.min.css │ ├── index.css │ ├── introjs.min.css │ ├── main.css │ ├── perfect-scrollbar.css │ ├── perfect-scrollbar.min.css │ ├── responsive-mp.css │ └── translate.css ├── font │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── html │ ├── annotator │ │ ├── base.html │ │ ├── collect_page.html │ │ ├── login.html │ │ ├── url_panel.html │ │ ├── user_panel.html │ │ ├── user_profile.html │ │ └── utility_panel.html │ └── translator │ │ ├── base.html │ │ ├── developers.html │ │ ├── index.html │ │ ├── macros.html │ │ ├── options.html │ │ ├── query_history.html │ │ └── translate.html ├── img │ ├── cli.png │ ├── clippy.svg │ ├── developers │ │ └── system_overview.png │ ├── gear.svg │ ├── gears.gif │ ├── globe.svg │ ├── glyphicons-halflings-white.png │ ├── glyphicons-halflings.png │ ├── tellina.svg │ └── tellina_avatar.svg ├── js │ ├── annotator │ │ └── main.js │ ├── clipboard.js │ ├── clipboard.min.js │ ├── comment.js │ ├── d3.v3.js │ ├── d3.v3.min.js │ ├── intro.min.js │ ├── jquery-3.1.1.js │ ├── perfect-scrollbar.jquery.js │ ├── perfect-scrollbar.jquery.min.js │ ├── perfect-scrollbar.js │ ├── perfect-scrollbar.min.js │ ├── tellina.js │ └── underscore.js └── lib │ ├── bootstrap │ ├── config.json │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ ├── bootstrap-dialog.js │ │ ├── bootstrap-modal.js │ │ ├── bootstrap.js │ │ └── bootstrap.min.js │ ├── font-awesome-4.7.0 2 │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.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.scss │ ├── google-plus.themes │ └── google-plus.css │ ├── hljs.themes │ ├── agate.css │ ├── bash.js │ ├── color-brewer.css │ ├── dracula.css │ ├── github-gist.css │ ├── hljs-9.8.0.min.js │ ├── solarized-light.css │ ├── tomorrow.css │ └── zenburn.css │ ├── jquery-ui-1.12.1.custom │ ├── AUTHORS.txt │ ├── LICENSE.txt │ ├── external │ │ └── jquery │ │ │ └── jquery.js │ ├── images │ │ ├── ui-icons_444444_256x240.png │ │ ├── ui-icons_555555_256x240.png │ │ ├── ui-icons_777620_256x240.png │ │ ├── ui-icons_777777_256x240.png │ │ ├── ui-icons_cc0000_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── index.html │ ├── jquery-ui.css │ ├── jquery-ui.js │ ├── jquery-ui.min.css │ ├── jquery-ui.min.js │ ├── jquery-ui.structure.css │ ├── jquery-ui.structure.min.css │ ├── jquery-ui.theme.css │ ├── jquery-ui.theme.min.css │ └── package.json │ └── jquery.upvote │ ├── images │ ├── sprites-meta-stackoverflow.png │ ├── sprites-programmers.png │ ├── sprites-serverfault.png │ ├── sprites-stackoverflow.png │ ├── sprites-superuser.png │ └── sprites-unix.png │ ├── jquery.upvote.css │ └── jquery.upvote.js ├── utils.py └── views.py /.gitignore: -------------------------------------------------------------------------------- 1 | website/migrations 2 | website/config.py 3 | 4 | # LaTeX junk 5 | *.aux 6 | *.log 7 | *.bbl 8 | *.blg 9 | *.fdb_latexmk 10 | *.fls 11 | *.pdf 12 | *.synctex.gz 13 | *.out 14 | *.dvi 15 | 16 | # uncompressed StackOverflow data 17 | *.sqlite 18 | 19 | # IDE junk 20 | *.sublime-* 21 | 22 | # Python 23 | *.pyc 24 | 25 | # Java 26 | *.class 27 | 28 | # moses files 29 | *.final 30 | *.vcb 31 | 32 | # auto-generated files 33 | parsetab.py 34 | /man-parser/out 35 | 36 | # Shell scripts 37 | *.sh 38 | 39 | # Database file 40 | *.db 41 | *.txt 42 | *.sqlite3 43 | 44 | # Misc 45 | MANIFEST 46 | .DS_Store 47 | *.csv 48 | *.key 49 | eval.* 50 | temp*.txt 51 | *dump*.txt 52 | spell.txt 53 | manual.eval.results* 54 | *beam_search.eval 55 | beam_search*eval* 56 | *.swp 57 | *.swo 58 | *.debug 59 | /paper 60 | website/data/ 61 | website/scripts/export_pairs.py 62 | tools/spellcheck/*.txt 63 | 64 | # IDE-specific stuff: 65 | __pycache__ 66 | .idea 67 | *.iml 68 | site_config.py 69 | 70 | # Intellij project 71 | parsers/out/production/* 72 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tellina_learning_module"] 2 | path = tellina_learning_module 3 | url = https://github.com/TellinaTool/tellina_learning_module 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This Makefile wraps commands used to set up the learning module and 2 | # start the Tellina server. 3 | 4 | LR_MODULE=tellina_learning_module 5 | 6 | submodule: 7 | # Update learning submodule 8 | git submodule update --remote 9 | # Set up data files used in the learning module 10 | tar xf $(LR_MODULE)/data/bash/vocab.tar.xz --directory $(LR_MODULE)/data/bash/ 11 | # tar xf $(LR_MODULE)/data/bash.final/vocab.tar.xz --directory $(LR_MODULE)/data/bash.final/ 12 | # Set up nlp tools 13 | tar xf $(LR_MODULE)/nlp_tools/spellcheck/most_common.tar.xz --directory $(LR_MODULE)/nlp_tools/spellcheck/ 14 | 15 | db: 16 | # Setup database tables 17 | python3 manage.py makemigrations website 18 | python3 manage.py migrate 19 | 20 | run: 21 | # Set CUDAPATH 22 | # source ~/.profile 23 | # Set PYTHONPATH 24 | export PYTHONPATH=`pwd` 25 | # Run server 26 | python3 manage.py runserver 0.0.0.0:8000 --insecure 27 | 28 | clean: 29 | # Destroy database and migrations 30 | find . -type d -name "__pycache__" | xargs rm -r 31 | rm -rf website/migrations 32 | # rm -rf db.sqlite3 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tellina 2 | 3 | Tellina uses natural language processing (NLP) to translate an English sentence, such as "Find text file in the current folder", into a bash command, such as `find . -name "*.txt"`. 4 | 5 | You can try it now at http://tellina.rocks . 6 | Or, you can install it locally; this document tells you how. 7 | 8 | ## Installation 9 | 10 | ### Install Tensorflow 11 | Tellina uses Tensorflow 2.0. 12 | 13 | Follow the instructions on the [Tensorflow website](https://www.tensorflow.org/get_started/get_started). The simplest way is to install using [`pip3`](https://www.tensorflow.org/install/). 14 | 15 | ### Install other dependencies: 16 | 17 | ``` 18 | pip3 install -r requirements.txt 19 | ``` 20 | 21 | ### Set up tellina_learning_module submodule: 22 | 23 | ``` 24 | git submodule update --init --remote 25 | git submodule foreach git pull origin master 26 | make submodule 27 | ``` 28 | To update the tellina_learning_module in the future, run: 29 | ``` 30 | make submodule 31 | ``` 32 | 33 | ### Set up databases: 34 | 35 | ``` 36 | make db 37 | ``` 38 | 39 | ### Run webapp: 40 | 41 | ``` 42 | make run 43 | ``` 44 | 45 | To experiment with the translation model locally, make sure to set following control variables correctly. 46 | 47 | ### Control variables: 48 | 49 | ``` 50 | WEBSITE_DEVELOP (website/views.py) 51 | 52 | - True, start the web server without importing the Tensorflow translation module (no server start delay, suggested setting when testing peripheral website functions) 53 | - False (default), start the web server and translate new queries (5-10 secs server start delay due to Tensorflow graph building) 54 | 55 | CACHE_TRANSLATIONS (website/views.py) 56 | 57 | - True, cache translation results for natural language queries that were seen 58 | - False (default), run translation model on every query, regardless of whether it has been seen or not 59 | 60 | CPU_ONLY (website/backend_interface.py) 61 | 62 | - True (default), run Tellina on CPU 63 | - False, run Tellina on GPU if and only if the host machine has GPU installed 64 | ``` 65 | Visit http://127.0.0.1:8000 in your browser. 66 | 67 | ## Citation 68 | 69 | If you used Tellina in your work, please cite 70 | ``` 71 | @techreport{LinWPVZE2017:TR, 72 | author = {Xi Victoria Lin and Chenglong Wang and Deric Pang and Kevin Vu and Luke Zettlemoyer and Michael D. Ernst}, 73 | title = {Program synthesis from natural language using recurrent neural networks}, 74 | institution = {University of Washington Department of Computer Science and Engineering}, 75 | number = {UW-CSE-17-03-01}, 76 | address = {Seattle, WA, USA}, 77 | month = mar, 78 | year = {2017} 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /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", "tellina.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django>=1.10.8 2 | nltk==3.6.6 3 | matplotlib==1.5.3 4 | tqdm==4.9.0 5 | requests==2.31.0 6 | -------------------------------------------------------------------------------- /tellina/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/tellina/__init__.py -------------------------------------------------------------------------------- /tellina/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for tellina project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/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/1.10/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '*zca^nlaejb32n)5@cevdlsb@g3ea4in=x_k1x9we788v&6k5r' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = ['kirin.cs.washington.edu', '127.0.0.1', '205.175.118.26', 29 | '69.91.132.97'] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'website.apps.TranslatorConfig', 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | ] 43 | 44 | MIDDLEWARE = [ 45 | 'django.middleware.security.SecurityMiddleware', 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.common.CommonMiddleware', 48 | 'django.middleware.csrf.CsrfViewMiddleware', 49 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ] 53 | 54 | ROOT_URLCONF = 'tellina.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [os.path.join(BASE_DIR, 'website/static/html/')], 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 | 73 | WSGI_APPLICATION = 'tellina.wsgi.application' 74 | 75 | 76 | # Database 77 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 78 | 79 | DATABASES = { 80 | 'default': { 81 | 'ENGINE': 'django.db.backends.sqlite3', 82 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 83 | } 84 | } 85 | 86 | 87 | # Password validation 88 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 89 | 90 | AUTH_PASSWORD_VALIDATORS = [ 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 102 | }, 103 | ] 104 | 105 | 106 | # Internationalization 107 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 108 | 109 | LANGUAGE_CODE = 'en-us' 110 | 111 | TIME_ZONE = 'UTC' 112 | 113 | USE_I18N = True 114 | 115 | USE_L10N = True 116 | 117 | USE_TZ = True 118 | 119 | 120 | # Static files (CSS, JavaScript, Images) 121 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 122 | 123 | STATIC_URL = '/static/' 124 | 125 | STATICFILES_DIRS = [ 126 | BASE_DIR + "/website/static/", 127 | ] 128 | -------------------------------------------------------------------------------- /tellina/urls.py: -------------------------------------------------------------------------------- 1 | """django_project URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.10/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: url(r'^$', 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: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | from django.http import HttpResponse 19 | 20 | from website import annotator, cmd2html, views 21 | 22 | urlpatterns = [ 23 | url(r'^$', views.index), 24 | url(r'^index$', views.index), 25 | url(r'^translate$', views.translate), 26 | url(r'^load_example_requests_with_translations', views.example_requests_with_translations), 27 | url(r'^load_latest_requests_with_translations', views.latest_requests_with_translations), 28 | url(r'^developers$', views.developers), 29 | 30 | url(r'^remember_ip_address$', views.remember_ip_address), 31 | url(r'^vote$', views.vote), 32 | 33 | url(r'^explain_cmd$', cmd2html.explain_cmd), 34 | 35 | url(r'^login$', annotator.login), 36 | url(r'^register_user', annotator.register_user), 37 | url(r'^user_login$', annotator.user_login), 38 | url(r'^logout$', annotator.user_logout), 39 | 40 | url(r'^url_panel$', annotator.url_panel), 41 | url(r'^utility_panel$', annotator.utility_panel), 42 | 43 | url(r'^collect_page$', annotator.collect_page), 44 | url(r'^previous_url$', annotator.previous_url), 45 | url(r'^next_url$', annotator.next_url), 46 | url(r'^submit_annotation$', annotator.submit_annotation), 47 | url(r'^submit_edit$', annotator.submit_edit), 48 | url(r'^delete_annotation$', annotator.delete_annotation), 49 | url(r'^mark_duplicate$', annotator.mark_duplicate), 50 | url(r'^mark_wrong$', annotator.mark_wrong), 51 | url(r'^mark_i_dont_know', annotator.mark_i_dont_know), 52 | url(r'^update_progress$', annotator.update_progress), 53 | 54 | url(r'^accept_update', annotator.accept_update), 55 | url(r'^retract_update', annotator.retract_update), 56 | url(r'^submit_annotation_update', annotator.submit_annotation_update), 57 | url(r'^get_relevant_updates', annotator.get_relevant_updates), 58 | url(r'^get_update_status', annotator.get_update_status), 59 | url(r'^get_url_stats', annotator.get_url_stats), 60 | url(r'^get_utility_stats', annotator.get_utility_stats), 61 | url(r'^get_utility_num_notifications', annotator.get_utility_num_notifications), 62 | url(r'^get_url_num_notifications', annotator.get_url_num_notifications), 63 | url(r'^reject_update', annotator.reject_update), 64 | 65 | url(r'user_panel', annotator.user_panel), 66 | url(r'user_profile', annotator.user_profile), 67 | url(r'update_user_time_logged', annotator.update_user_time_logged), 68 | 69 | url(r'^robots.txt$', lambda r: HttpResponse("User-agent: *\nDisallow: /", mimetype="text/plain")), 70 | 71 | url(r'^admin', admin.site.urls) 72 | ] 73 | -------------------------------------------------------------------------------- /tellina/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_project 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/1.10/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", "tellina.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /website/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/__init__.py -------------------------------------------------------------------------------- /website/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Annotation, AnnotationUpdate, Command, CommandAdmin, NLRequest, \ 4 | Translation, URL, URLTag, User, UserAdmin 5 | 6 | admin.site.register(Command, CommandAdmin) 7 | 8 | admin.site.register(URL) 9 | admin.site.register(User, UserAdmin) 10 | admin.site.register(NLRequest) 11 | admin.site.register(Translation) 12 | admin.site.register(Annotation) 13 | admin.site.register(AnnotationUpdate) 14 | admin.site.register(URLTag) 15 | -------------------------------------------------------------------------------- /website/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | class TranslatorConfig(AppConfig): # Our app config class 4 | name = 'website' 5 | -------------------------------------------------------------------------------- /website/backend_interface.py: -------------------------------------------------------------------------------- 1 | """ 2 | Interface to the neural translation model. 3 | """ 4 | import tensorflow as tf 5 | tf.compat.v1.disable_eager_execution() 6 | 7 | import os 8 | import sys 9 | 10 | learning_module_dir = os.path.join(os.path.dirname(__file__), "..", 11 | "tellina_learning_module") 12 | sys.path.append(learning_module_dir) 13 | 14 | from website.utils import NUM_TRANSLATIONS 15 | from encoder_decoder import data_utils 16 | from encoder_decoder import decode_tools 17 | from encoder_decoder import parse_args 18 | from encoder_decoder import translate 19 | 20 | CPU_ONLY=True 21 | if CPU_ONLY: 22 | os.environ["CUDA_VISIBLE_DEVICES"] = "-1" 23 | else: 24 | os.environ["CUDA_VISIBLE_DEVICES"] = "2" 25 | 26 | # initialize FLAGS by parsing a dummy argument list 27 | tf.compat.v1.flags.FLAGS(sys.argv[:1]) 28 | FLAGS = tf.compat.v1.flags.FLAGS 29 | 30 | FLAGS.demo = True 31 | FLAGS.fill_argument_slots = False 32 | FLAGS.num_nn_slot_filling = 5 33 | 34 | FLAGS.encoder_topology = 'birnn' 35 | 36 | FLAGS.sc_token_dim = 200 37 | FLAGS.batch_size = 128 38 | FLAGS.num_layers = 1 39 | FLAGS.learning_rate = 0.0001 40 | FLAGS.sc_input_keep = 0.6 41 | FLAGS.sc_output_keep = 0.6 42 | FLAGS.tg_input_keep = 0.6 43 | FLAGS.tg_output_keep = 0.6 44 | 45 | FLAGS.tg_token_use_attention = True 46 | FLAGS.tg_token_attn_fun = 'non-linear' 47 | FLAGS.attention_input_keep = 0.6 48 | FLAGS.attention_output_keep = 0.6 49 | FLAGS.beta = 0.0 50 | 51 | FLAGS.token_decoding_algorithm = 'beam_search' 52 | FLAGS.beam_size = 100 53 | FLAGS.alpha = 1 54 | 55 | FLAGS.min_vocab_frequency = 4 56 | FLAGS.normalized = False 57 | FLAGS.channel = 'partial.token' 58 | FLAGS.use_copy = True 59 | FLAGS.copy_fun = 'copynet' 60 | 61 | FLAGS.dataset = 'bash' 62 | FLAGS.data_dir = os.path.join(learning_module_dir, "data", FLAGS.dataset) 63 | FLAGS.model_root_dir = os.path.join(learning_module_dir, "model", "seq2seq") 64 | 65 | # Data-dependent parameters 66 | FLAGS.max_sc_length = 42 67 | FLAGS.max_tg_length = 57 68 | FLAGS.sc_vocab_size = 1324 69 | FLAGS.tg_vocab_size = 1219 70 | FLAGS.max_sc_token_size = 100 71 | FLAGS.max_tg_token_size = 100 72 | buckets = [(13, 57), (18, 57), (42, 57)] 73 | 74 | # Create tensorflow session 75 | sess = tf.compat.v1.Session(config=tf.compat.v1.ConfigProto(allow_soft_placement=True, 76 | log_device_placement=FLAGS.log_device_placement)) 77 | 78 | # create model and load nerual model parameters. 79 | model = translate.define_model(sess, forward_only=True, buckets=buckets) 80 | print('loading models from {}'.format(FLAGS.model_dir)) 81 | 82 | vocabs = data_utils.load_vocabulary(FLAGS) 83 | 84 | if FLAGS.fill_argument_slots: 85 | # Create slot filling classifier 86 | model_param_dir = os.path.join(FLAGS.model_dir, 'train.mappings.X.Y.npz') 87 | train_X, train_Y = data_utils.load_slot_filling_data(model_param_dir) 88 | slot_filling_classifier = classifiers.KNearestNeighborModel( 89 | FLAGS.num_nn_slot_filling, train_X, train_Y) 90 | print('Slot filling classifier parameters loaded.') 91 | else: 92 | slot_filling_classifier = None 93 | 94 | def translate_fun(sentence, slot_filling_classifier=slot_filling_classifier): 95 | print('translating |{}|'.format(sentence)) 96 | list_of_translations = decode_tools.translate_fun( 97 | sentence, sess, model, vocabs, FLAGS, slot_filling_classifier) 98 | return list_of_translations 99 | -------------------------------------------------------------------------------- /website/cmd2html.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | 5 | from django.http import HttpResponse 6 | sys.path.append(os.path.join(os.path.dirname(__file__),"..", "tellina_learning_module")) 7 | from bashlint import data_tools 8 | 9 | ## load the manpage expl file, note that the root should be before tellina 10 | with open(os.path.join('website', 'manpage_expl.json'), encoding='UTF-8') as data_file: 11 | manpage_json = json.loads(data_file.read()) 12 | 13 | def explain_cmd(request): 14 | """ This is the responser for flag explanation: 15 | it takes in a request consist of a tuple (cmd_head, flag_name, node_kind) and returns the explanation of the flag. 16 | Arguments: 17 | request { 18 | cmd_head: the command to query 19 | flag_name: the flag to query 20 | node_kind: the type of span that the query is issued from 21 | } 22 | Returns: 23 | returns the manpage explanation of the cmd_head/flag_name 24 | """ 25 | 26 | if request.method == 'POST': 27 | cmd_head = request.POST.get('cmd_head') 28 | flag_name = request.POST.get('flag_name') 29 | node_kind = request.POST.get('node_kind') 30 | else: 31 | cmd_head = request.GET.get('cmd_head') 32 | flag_name = request.GET.get('flag_name') 33 | node_kind = request.GET.get('node_kind') 34 | 35 | if cmd_head: 36 | # retrieve the explanation of the command 37 | for cmd_obj in manpage_json: 38 | if cmd_head in cmd_obj["aliases"]: 39 | #cmd_expl = "Aliases:" + " ".join(cmd_obj["aliases"]) + "\n\n" + cmd_obj["description"] 40 | 41 | # note that we use "None" due to the serialized field is of string type 42 | if flag_name != "None": 43 | # in this case, our goal is to explain a command 44 | flag_expl_list = [] 45 | for option_desc in cmd_obj["optionDesc"]: 46 | if flag_name == option_desc["name"].split()[0]: 47 | flag_expl_list.append(option_desc["description"]) 48 | if flag_expl_list: 49 | return HttpResponse("".join(flag_expl_list)) 50 | else: 51 | return HttpResponse("") 52 | 53 | # if the flag is not provided, or we cannot find the flag 54 | if node_kind == "argument": 55 | return HttpResponse(cmd_obj["rawSynopsis"]) 56 | elif node_kind == "utility": 57 | return HttpResponse(cmd_obj["description"]) 58 | 59 | # in this case, either the thead is not provided or the head cannot be retrieved 60 | return HttpResponse("") 61 | 62 | def cmd2html(cmd_str): 63 | """ A wrapper for the function ast2html (see below) that takes in a cmd string 64 | and translate into a html string with highlinghting. 65 | """ 66 | return " ".join(ast2html(data_tools.bash_parser(cmd_str))) 67 | 68 | def tokens2html(cmd_str): 69 | """ A wrapper for the function ast2html (see below) that takes in a cmd string 70 | and translate into a html string with highlinghting. 71 | """ 72 | return " ".join(ast2html(cmd_str)) 73 | 74 | def ast2html(node): 75 | 76 | """ Translate a bash AST from tellina_learning_module/bashlint/nast.py into html code, 77 | with proper syntax highlighting. 78 | Argument: 79 | node: an ast returned from tellina_learning_module.data_tools.bash_parser(cmd_str) 80 | Returns: 81 | a html string that can be embedded into your browser with appropriate syntax highlighting 82 | """ 83 | 84 | dominator = retrieve_dominators(node) 85 | 86 | # the documation of the span 87 | span_doc = "dominate_cmd=\"" + (str(dominator[0]) if dominator[0] else "None") \ 88 | + "\" dominate_flag=\"" + (str(dominator[1]) if dominator[1] else "None") \ 89 | + "\" node_kind=\"" + node.kind + "\""; 90 | 91 | html_spans = [] 92 | 93 | # switching among node kinds for the generation of different spans 94 | if node.kind == "root": 95 | for child in node.children: 96 | html_spans.extend(ast2html(child)) 97 | elif node.kind == "pipeline": 98 | is_first = True 99 | for child in node.children: 100 | if is_first: 101 | is_first = False 102 | else: 103 | html_spans.append("|") 104 | html_spans.extend(ast2html(child)) 105 | elif node.kind == "utility": 106 | span = "" + node.value + "" 107 | html_spans.append(span) 108 | for child in node.children: 109 | html_spans.extend(ast2html(child)) 110 | elif node.kind == "flag": 111 | # note there are two corner cases of flags: 112 | # -exec::; and -exec::+ since they have different endings 113 | if node.value == "-exec::;" or node.value == "-exec::+": 114 | head_span = "" + "-exec" + "" 115 | else: 116 | head_span = "" + node.value + "" 117 | html_spans.append(head_span) 118 | for child in node.children: 119 | html_spans.extend(ast2html(child)) 120 | if node.value == "-exec::;": 121 | html_spans.append("\\;") 122 | elif node.value == "-exec::+": 123 | html_spans.append("+"); 124 | elif node.kind == "argument" and node.arg_type != "ReservedWord": 125 | span = "" + node.value + "" 126 | html_spans.append(span) 127 | for child in node.children: 128 | html_spans.extend(ast2html(child)) 129 | elif node.kind == "bracket": 130 | html_spans.append("\\(") 131 | for child in node.children: 132 | html_spans.extend(ast2html(child)) 133 | html_spans.append("\\)") 134 | elif node.kind in ["binarylogicop", "unarylogicop", "redirect"]: 135 | span = "" + node.value + "" 136 | html_spans.append(span) 137 | elif node.kind in ["commandsubstitution", "processsubstitution"]: 138 | html_spans.append(node.value) 139 | html_spans.append("(") 140 | for child in node.children: 141 | html_spans.extend(ast2html(child)) 142 | html_spans.append(")") 143 | else: 144 | html_spans.append(node.value) 145 | 146 | return html_spans 147 | 148 | def retrieve_dominators(node): 149 | """ Given a node, retrieve its dominator, 150 | i.e., its utility and/or its dominate flag 151 | """ 152 | dominate_headcmd = None 153 | dominate_flag = None 154 | 155 | current_node = node 156 | 157 | while True: 158 | if current_node and current_node.kind == "flag": 159 | if not dominate_flag: 160 | dominate_flag = current_node.value 161 | # this is resulted from a corner case by Victoria, 162 | # for -exec::; -exec::+ and potentially others 163 | if "::" in dominate_flag: 164 | dominate_flag = dominate_flag[0: dominate_flag.index("::")] 165 | elif current_node and current_node.kind == "utility": 166 | dominate_headcmd = current_node.value 167 | return (dominate_headcmd, dominate_flag) 168 | 169 | # we have already find dominate_headcmd or we have reached root 170 | if current_node and (not current_node.parent): 171 | return (dominate_headcmd, dominate_flag) 172 | elif current_node: 173 | current_node = current_node.parent 174 | 175 | if dominate_headcmd is None: 176 | return ('', '') 177 | return (dominate_headcmd, dominate_flag) 178 | 179 | def test(): 180 | cmd_str_list = [ 181 | "find Path -iname Regex -exec grep -i -l Regex {} \;", 182 | "find Path -type f -iname Regex | xargs -I {} grep -i -l Regex {}", 183 | "find Path \( -name Regex-01 -or -name Regex-02 \) -print", 184 | "find Path -not -name Regex", 185 | "find . \( -mtime 10d -or -atime Timespan -or -atime Timespan -or -atime Timespan -or -atime Timespan \) -print", 186 | "find Documents \( -name \"*.py\" -o -name \"*.html\" \)" 187 | ]; 188 | for cmd_str in cmd_str_list: 189 | print(cmd2html(cmd_str)) 190 | 191 | if __name__ == '__main__': 192 | test() 193 | -------------------------------------------------------------------------------- /website/constants.py: -------------------------------------------------------------------------------- 1 | INVALID_ANNOTATION_TAGS = { 2 | 'NA', 3 | 'ERROR', 4 | 'DUPLICATE', 5 | 'WRONG', 6 | 'I DON\'T KNOW' 7 | } 8 | 9 | WHITE_LIST = { 10 | 'find', 11 | 'xargs' 12 | } 13 | -------------------------------------------------------------------------------- /website/context_processor.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | def debug(context): 4 | return {'DEBUG': settings.DEBUG} 5 | -------------------------------------------------------------------------------- /website/functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Standard python package file with syntax comaptible with python3.5 and above. 3 | """ 4 | 5 | import collections 6 | import inspect 7 | 8 | from functools import partial, wraps 9 | 10 | 11 | def first(coll): # rewrite to use frozen dict 12 | """Return the first item in a dictionary, list, or tuple.""" 13 | if not coll: 14 | return None 15 | try: 16 | return dict((coll.items()[0],)) 17 | except AttributeError: 18 | return coll[0] 19 | 20 | 21 | def last(coll): # rewrite to use frozen dict 22 | """Return the last item in a dictionary, list, or tuple.""" 23 | try: 24 | return dict((coll.items()[-1],)) 25 | except AttributeError: 26 | return coll[-1] 27 | 28 | 29 | def rest(coll): # rewrite to use frozen dict 30 | """Return the remaining items in a dictionary, list, or tuple.""" 31 | try: 32 | return dict(coll.items()[1:]) 33 | except AttributeError: 34 | return coll[1:] 35 | 36 | 37 | def none(*args, **kwargs): 38 | return None 39 | 40 | 41 | identity = lambda x: x 42 | 43 | 44 | def is_seq(x): 45 | """Return True if x is iterable.""" 46 | return (not hasattr(x, "strip") and 47 | hasattr(x, "__getitem__") or 48 | hasattr(x, "__iter__")) 49 | 50 | 51 | def fmap(f, coll): 52 | """Apply a function to each item in a dictionary, list, or tuple.""" 53 | try: 54 | return {k: f(v) for k, v in coll.iteritems()} 55 | except AttributeError: 56 | return tuple(f(v) for v in coll) 57 | 58 | 59 | def walk(inner, outer, data): 60 | """Traverse an arbitrary data structure and apply a function to each node.""" 61 | def process_node(inner, k, v): 62 | if not isinstance(v, collections.Iterable) or isinstance(v, basestring): 63 | return inner(k, v) 64 | if isinstance(v, collections.Sequence): 65 | rows = tuple(walk(inner, identity, row) for row in v) 66 | rv = tuple(filter(lambda row: row, rows)) 67 | else: 68 | rv = walk(inner, identity, v) 69 | return (k, rv) if rv else None 70 | if isinstance(data, collections.Sequence): 71 | return outer(tuple(map(lambda x: walk(inner, identity, x), data))) 72 | nodes = tuple(map(lambda kv: process_node(inner, kv[0], kv[1]), 73 | data.iteritems())) 74 | return outer(dict(filter(lambda node: node is not None, nodes))) 75 | 76 | 77 | def cons(x, seq): 78 | """Return a tuple where x is the first element and seq is the rest.""" 79 | return (x,) + tuple(seq) 80 | 81 | 82 | def thread(x, form): 83 | if isinstance(form, tuple): 84 | f, args = first(form), rest(form) 85 | return f(x, *args) 86 | return form(x) 87 | 88 | 89 | def threadfirst(x, form, *more): 90 | """Thread the expression through the forms.""" 91 | if not more: 92 | return thread(x, form) 93 | return thread_first(*cons(thread(x, form), more)) 94 | 95 | 96 | def compose(*funcs): 97 | def compose2(f, g): 98 | if not callable(f): 99 | foo = partial(*f) 100 | else: 101 | foo = f 102 | if not callable(g): 103 | bar = partial(*g) 104 | else: 105 | bar = g 106 | return lambda x: foo(bar(x)) 107 | return reduce(compose2, reversed(funcs)) 108 | 109 | 110 | def threadlast(x, *funcs): 111 | return compose(*funcs)(x) 112 | 113 | 114 | def thread_first(x, form, *more): 115 | return threadfirst(x, form, *more) 116 | 117 | 118 | def thread_last(x, *funcs): 119 | return threadlast(x, *funcs) 120 | 121 | 122 | def memoize(f): 123 | """Return a memoized version of a function.""" 124 | cache = {} 125 | 126 | @wraps(f) 127 | def wrapper(*args): 128 | if args in cache: 129 | return cache[args] 130 | rv = f(*args) 131 | cache[args] = rv 132 | return rv 133 | return wrapper 134 | 135 | 136 | def frozendict(*keyvals): 137 | """Return an immutable dictionary""" 138 | return frozenset(keyvals) 139 | 140 | 141 | def zipdict(keys, vals): 142 | """Return an immutable dictionary with keys mapped to corresponding 143 | values""" 144 | return frozendict(*zip(keys, vals)) 145 | 146 | 147 | def get(fdict, key, default=None): 148 | """Return the value mapped to a key, default or None if key not present""" 149 | if fdict is None: 150 | return default 151 | try: 152 | return dict(fdict)[key] 153 | except KeyError: 154 | return default 155 | 156 | 157 | def contains(fdict, key): 158 | return key in dict(fdict) 159 | 160 | 161 | def find(fdict, key): 162 | try: 163 | return (key, dict(fdict)[key]) 164 | except KeyError: 165 | return None 166 | 167 | 168 | def keys(fdict): 169 | return tuple(dict(fdict).keys()) 170 | 171 | 172 | def vals(fdict): 173 | return tuple(dict(fdict).values()) 174 | 175 | 176 | def merge(*fdicts): 177 | """Merge two or more frozen dictionaries.""" 178 | def items(fdict): 179 | return tuple(dict(fdict).items()) 180 | if len(fdicts) == 2: 181 | return dict(items(first(fdicts)) + items(last(fdicts))) 182 | return merge(first(fdicts), apply(merge, rest(fdicts))) 183 | 184 | 185 | def walk_replace(smap, data): 186 | def replace_at(k, v): 187 | if k in smap: 188 | return (smap[k], v) 189 | return (k, v) 190 | 191 | def process_node(k, v): 192 | if not isinstance(v, collections.Iterable) or isinstance(v, basestring): 193 | return replace_at(k, v) 194 | if isinstance(v, collections.Sequence): 195 | rows = () 196 | for row in v: 197 | if isinstance(row, basestring): 198 | rows += (row,) 199 | else: 200 | rows += (walk_replace(smap, row),) 201 | rv = tuple(filter(lambda row: row, rows)) 202 | else: 203 | rv = walk_replace(smap, v) 204 | return replace_at(k, rv) if rv else None 205 | 206 | if isinstance(data, collections.Sequence): 207 | return tuple(map(lambda x: walk_replace(smap, x), data)) 208 | try: 209 | nodes = tuple(map(lambda kv: process_node(kv[0], kv[1]), data.iteritems())) 210 | return dict(filter(lambda node: node is not None, nodes)) 211 | except AttributeError: 212 | return data 213 | 214 | 215 | def union(*sets): 216 | return first(sets).union(*rest(sets)) 217 | 218 | 219 | def intersection(x, y): 220 | return tuple(set(x).intersection(y)) 221 | 222 | 223 | def dict_invert(dict): 224 | return {v: k for (k, v) in dict.iteritems()} 225 | 226 | 227 | def flatten(dict): 228 | return reduce(merge, [{k: last(item) for k in first(item)} 229 | for item in dict.items()]) 230 | 231 | 232 | # not tested with frozen dicts, just regular ones 233 | def assoc(fdict, key, val, *kvs): 234 | keyvals = (key, val) + kvs 235 | return merge(fdict, dict(zip(keyvals[0::2], keyvals[1::2]))) 236 | 237 | 238 | # not tested with frozen dicts, just regular ones 239 | def dissoc(fdict, key, *ks): 240 | keys = (key,) + ks 241 | return {k: v for k, v in fdict.iteritems() if k not in keys} 242 | 243 | 244 | def hash_map(*keyvals): 245 | i = iter(keyvals) 246 | return dict(zip(i, i)) 247 | 248 | 249 | def format(fmt, *args, **kwargs): 250 | if kwargs: 251 | return fmt.format(**kwargs) 252 | else: 253 | return fmt.format(*args) 254 | 255 | 256 | def select_keys(fdict, keys): 257 | return {k: fdict[k] for k in keys if k in fdict} 258 | 259 | 260 | def destructure(f): 261 | @wraps(f) 262 | def wrapper(*args, **kwargs): 263 | params = select_keys(first(args), inspect.getargspec(f).args) 264 | return f(**(merge(kwargs, params))) 265 | return wrapper 266 | -------------------------------------------------------------------------------- /website/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.db import models 3 | from django.utils import timezone 4 | 5 | import datetime 6 | 7 | class NL(models.Model): 8 | """ 9 | Natural language command. 10 | """ 11 | str = models.TextField(primary_key=True) 12 | 13 | class Command(models.Model): 14 | """ 15 | Command line. 16 | """ 17 | str = models.TextField(primary_key=True) 18 | template = models.TextField(default='') 19 | language = models.TextField(default='bash') 20 | tags = models.ManyToManyField('Tag') 21 | 22 | class CommandAdmin(admin.ModelAdmin): 23 | fields = ['str', 'language'] 24 | list_display = ['get_str'] 25 | 26 | def get_str(self, obj): 27 | return '\n'.join(obj.str) 28 | 29 | class Tag(models.Model): 30 | """ 31 | Tag. 32 | """ 33 | str = models.TextField(primary_key=True) 34 | commands = models.ManyToManyField('Command') 35 | annotations = models.ManyToManyField('Annotation') 36 | 37 | class URL(models.Model): 38 | """ 39 | URL. 40 | 41 | :member str: url address. 42 | :member html_content: snapshot of the URL content at the time of annotation. 43 | :member commands: commands in the URL (automatically extracted) 44 | :member tags: tags of the URL (assigned based on user annotations) 45 | """ 46 | str = models.TextField(primary_key=True) 47 | html_content = models.TextField(default='') 48 | commands = models.ManyToManyField('Command') 49 | tags = models.ManyToManyField('Tag') 50 | 51 | class URLTag(models.Model): 52 | """ 53 | Each record stores a (url, tag) pair. 54 | """ 55 | url = models.ForeignKey(URL, on_delete=models.CASCADE) 56 | tag = models.TextField() 57 | 58 | class User(models.Model): 59 | """ 60 | Each record stores the information of a user. 61 | 62 | :member is_annotator: the annotator is responsible for collecting new data 63 | pairs 64 | :member is_judger: the judger is responsible for judging if a command pair 65 | is correct and add modifications and comments. 66 | """ 67 | access_code = models.TextField(default='') 68 | ip_address = models.TextField(default='') 69 | first_name = models.TextField(default='anonymous') 70 | last_name = models.TextField(default='anonymous') 71 | organization = models.TextField(default='--') 72 | city = models.TextField(default='--') 73 | region = models.TextField(default='--') 74 | country = models.TextField(default='--') 75 | is_annotator = models.BooleanField(default=False) 76 | is_judger = models.BooleanField(default=False) 77 | time_logged = models.FloatField(null=True, blank=True) 78 | 79 | class UserAdmin(admin.ModelAdmin): 80 | fields = ['first_name', 'last_name', 'is_annotator', 'is_judger'] 81 | list_display = ['get_full_name'] 82 | 83 | def get_full_name(self, obj): 84 | return '\n'.join(obj.first_name + obj.last_name) 85 | 86 | 87 | class Annotation(models.Model): 88 | """ 89 | Each record is a natural language <-> code translation annotated by a 90 | programmer. 91 | """ 92 | url = models.ForeignKey(URL, on_delete=models.CASCADE) 93 | nl = models.ForeignKey(NL, on_delete=models.CASCADE) 94 | cmd = models.ForeignKey(Command, on_delete=models.CASCADE) 95 | annotator = models.ForeignKey(User, on_delete=models.CASCADE) 96 | submission_time = models.DateTimeField(default=timezone.now) 97 | 98 | 99 | class AnnotationProgress(models.Model): 100 | """ 101 | Each record stores a user's annotation progress on a particular URL. 102 | """ 103 | url = models.ForeignKey(URL, on_delete=models.CASCADE) 104 | tag = models.ForeignKey(Tag, null=True, on_delete=models.CASCADE) 105 | annotator = models.ForeignKey(User, on_delete=models.CASCADE) 106 | status = models.TextField() 107 | 108 | 109 | class Comment(models.Model): 110 | """ 111 | Each record is a commend submitted by a user (either an annotator or a 112 | judger) to an annotation. 113 | """ 114 | user = models.ForeignKey(User, on_delete=models.CASCADE) 115 | reply = models.ForeignKey('self', null=True, on_delete=models.CASCADE) 116 | str = models.TextField() 117 | submission_time = models.DateTimeField(default=timezone.now) 118 | 119 | 120 | class AnnotationUpdate(models.Model): 121 | """ 122 | Each record is an update of an annotation submitted by a judger. 123 | """ 124 | annotation = models.ForeignKey(Annotation, on_delete=models.CASCADE) 125 | judger = models.ForeignKey(User, on_delete=models.CASCADE) 126 | update_str = models.TextField() 127 | update_type = models.TextField(default='nl') 128 | comment = models.ForeignKey(Comment, on_delete=models.CASCADE) 129 | submission_time = models.DateTimeField(default=timezone.now) 130 | status = models.TextField(default='open') 131 | 132 | 133 | class Notification(models.Model): 134 | """ 135 | Each record is a certain type of message issued from one annotator to 136 | another. 137 | """ 138 | sender = models.ForeignKey(User, related_name='notification_sender', 139 | on_delete=models.CASCADE) 140 | receiver = models.ForeignKey(User, related_name='notification_receiver', 141 | on_delete=models.CASCADE) 142 | type = models.TextField(default='comment') 143 | annotation_update = models.ForeignKey('AnnotationUpdate', null=True, 144 | on_delete=models.CASCADE) 145 | comment = models.ForeignKey('Comment', null=True, on_delete=models.CASCADE) 146 | url = models.ForeignKey('URL', on_delete=models.CASCADE) 147 | creation_time = models.DateTimeField(default=timezone.now) 148 | status = models.TextField(default='issued') 149 | 150 | 151 | class Translation(models.Model): 152 | """ 153 | Each record is a natural language -> code translation generated by the 154 | learning module in the backend. 155 | 156 | :member request: the natural language request issued by the user 157 | :member pred_cmd: the predicted command generated by the learning module 158 | :member score: the translation score of the predicted command 159 | :member num_upvotes: number of upvotes this translation has received 160 | :member num_downvotes: number of downvotes this translation has received 161 | :member num_stars: number of stars this translation has received 162 | """ 163 | nl = models.ForeignKey(NL, on_delete=models.CASCADE) 164 | pred_cmd = models.ForeignKey(Command, on_delete=models.CASCADE) 165 | score = models.FloatField() 166 | num_upvotes = models.PositiveIntegerField(default=0) 167 | num_downvotes = models.PositiveIntegerField(default=0) 168 | num_stars = models.PositiveIntegerField(default=0) 169 | 170 | def __str__(self): 171 | return "{}\n{}".format(self.request, self.pred_cmd) 172 | 173 | def inc_num_upvotes(self): 174 | self.num_upvotes += 1 175 | 176 | def dec_num_upvotes(self): 177 | self.num_upvotes -= 1 178 | 179 | def inc_num_downvotes(self): 180 | self.num_downvotes += 1 181 | 182 | def dec_num_downvotes(self): 183 | self.num_downvotes -= 1 184 | 185 | def inc_num_stars(self): 186 | self.num_stars += 1 187 | 188 | def dec_num_stars(self): 189 | self.num_stars -= 1 190 | 191 | @property 192 | def num_votes(self): 193 | return self.num_upvotes - self.num_downvotes 194 | 195 | 196 | class NLRequest(models.Model): 197 | """ 198 | Each record stores the IP address associated with a natural language 199 | request. 200 | :member request: a natural language request 201 | :member user: the user who submitted the request 202 | :member submission_time: the time when the request is submitted 203 | """ 204 | nl = models.ForeignKey(NL, on_delete=models.CASCADE) 205 | submission_time = models.DateTimeField(default=timezone.now) 206 | user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) 207 | 208 | 209 | class Vote(models.Model): 210 | """ 211 | Each record stores the voting actions to a translation results issued by a 212 | specific IP address. 213 | """ 214 | translation = models.ForeignKey(Translation, on_delete=models.CASCADE) 215 | ip_address = models.TextField(default='') 216 | upvoted = models.BooleanField(default=False) 217 | downvoted = models.BooleanField(default=False) 218 | starred = models.BooleanField(default=False) 219 | # user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) 220 | -------------------------------------------------------------------------------- /website/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/scripts/__init__.py -------------------------------------------------------------------------------- /website/scripts/db_changes.py: -------------------------------------------------------------------------------- 1 | import html 2 | import os, sys 3 | import pickle 4 | import re 5 | import sqlite3 6 | 7 | from website.models import Annotation, AnnotationUpdate, Command, \ 8 | Notification, URL, URLTag 9 | from website.utils import get_tag, get_command, get_url 10 | 11 | learning_module_dir = os.path.join(os.path.dirname(__file__), '..', '..', 12 | "tellina_learning_module") 13 | sys.path.append(learning_module_dir) 14 | 15 | from bashlint import data_tools 16 | 17 | CODE_REGEX = re.compile(r"
([^<]+\n[^<]*)<\/code><\/pre>")
 18 | 
 19 | 
 20 | def extract_code(text):
 21 |     for match in CODE_REGEX.findall(text):
 22 |         if match.strip():
 23 |             yield html.unescape(match.replace("
", "\n")) 24 | 25 | def extract_oneliners_from_code(code_block): 26 | for cmd in code_block.splitlines(): 27 | if cmd.startswith('$ '): 28 | cmd = cmd[2:] 29 | if cmd.startswith('# '): 30 | cmd = cmd[2:] 31 | comment = re.search(r'\s+#\s+', cmd) 32 | if comment: 33 | old_cmd = cmd 34 | cmd = cmd[:comment.start()] 35 | print('Remove comment: {} -> {}'.format(old_cmd, cmd)) 36 | cmd = cmd.strip() 37 | 38 | # discard code block opening line 39 | if cmd and not cmd[-1] in ['{', '[', '(']: 40 | yield cmd 41 | 42 | def load_urls(input_file_path): 43 | with open(input_file_path, 'rb') as f: 44 | urls_by_utility = pickle.load(f) 45 | 46 | for utility in urls_by_utility: 47 | for url in urls_by_utility[utility]: 48 | if not URLTag.objects.filter(url__str=url, tag=utility): 49 | URLTag.objects.create(url=get_url(url), tag=utility) 50 | print("Add {}, {}".format(url, utility)) 51 | 52 | def load_commands_in_url(stackoverflow_dump_path): 53 | url_prefix = 'https://stackoverflow.com/questions/' 54 | with sqlite3.connect(stackoverflow_dump_path, 55 | detect_types=sqlite3.PARSE_DECLTYPES) as db: 56 | for url in URL.objects.all(): 57 | # url = URL.objects.get(str='https://stackoverflow.com/questions/127669') 58 | url.commands.clear() 59 | print(url.str) 60 | for answer_body, in db.cursor().execute(""" 61 | SELECT answers.Body FROM answers 62 | WHERE answers.ParentId = ?""", (url.str[len(url_prefix):],)): 63 | url.html_content = answer_body 64 | for code_block in extract_code(url.html_content): 65 | for cmd in extract_oneliners_from_code(code_block): 66 | ast = data_tools.bash_parser(cmd) 67 | if ast: 68 | command = get_command(cmd) 69 | print('extracted: {}'.format(cmd)) 70 | url.commands.add(command) 71 | url.save() 72 | 73 | def populate_command_tags(): 74 | for cmd in Command.objects.all(): 75 | if len(cmd.str) > 600: 76 | cmd.delete() 77 | else: 78 | cmd.tags.clear() 79 | print(cmd.str) 80 | ast = data_tools.bash_parser(cmd.str) 81 | for utility in data_tools.get_utilities(ast): 82 | print(utility) 83 | cmd.tags.add(get_tag(utility)) 84 | cmd.save() 85 | 86 | def populate_command_template(): 87 | for cmd in Command.objects.all(): 88 | if len(cmd.str) > 600: 89 | cmd.delete() 90 | else: 91 | ast = data_tools.bash_parser(cmd.str) 92 | template = data_tools.ast2template(ast, loose_constraints=True) 93 | cmd.template = template 94 | cmd.save() 95 | 96 | def populate_tag_commands(): 97 | for tag in Tag.objects.all(): 98 | tag.commands.clear() 99 | for url_tag in URLTag.objects.all(): 100 | print(url_tag.url.str) 101 | tag = get_tag(url_tag.tag) 102 | for cmd in url_tag.url.commands.all(): 103 | if tag in cmd.tags.all(): 104 | tag.commands.add(cmd) 105 | tag.save() 106 | 107 | def populate_url_tags(): 108 | for url in URL.objects.all(): 109 | for annotation in Annotation.objects.filter(url=url): 110 | for tag in annotation.cmd.tags.all(): 111 | url.tags.add(tag) 112 | 113 | def populate_tag_annotations(): 114 | for annotation in Annotation.objects.all(): 115 | for tag in annotation.cmd.tags.all(): 116 | tag.annotations.add(annotation) 117 | 118 | def create_notifications(): 119 | for annotation_update in AnnotationUpdate.objects.all(): 120 | annotation = annotation_update.annotation 121 | Notification.objects.create(sender=annotation_update.judger, 122 | receiver=annotation.annotator, type='annotation_update', 123 | annotation_update=annotation_update, url=annotation.url) 124 | 125 | if __name__ == '__main__': 126 | load_urls() 127 | -------------------------------------------------------------------------------- /website/static/css/annotator/login.css: -------------------------------------------------------------------------------- 1 | .body-panel { 2 | padding-top: 90px; 3 | } 4 | .panel-login { 5 | border-color: #ccc; 6 | -webkit-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2); 7 | -moz-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2); 8 | box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2); 9 | } 10 | .panel-login>.panel-heading { 11 | color: #00415d; 12 | background-color: #fff; 13 | border-color: #fff; 14 | text-align:center; 15 | } 16 | .panel-login>.panel-heading a{ 17 | text-decoration: none; 18 | color: #666; 19 | font-weight: bold; 20 | font-size: 15px; 21 | -webkit-transition: all 0.1s linear; 22 | -moz-transition: all 0.1s linear; 23 | transition: all 0.1s linear; 24 | } 25 | .panel-login>.panel-heading a.active{ 26 | color: #029f5b; 27 | font-size: 18px; 28 | } 29 | .panel-login>.panel-heading hr{ 30 | margin-top: 10px; 31 | margin-bottom: 0px; 32 | clear: both; 33 | border: 0; 34 | height: 1px; 35 | background-image: -webkit-linear-gradient(left,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.15),rgba(0, 0, 0, 0)); 36 | background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0)); 37 | background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0)); 38 | background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0)); 39 | } 40 | .panel-login input[type="text"],.panel-login input[type="email"],.panel-login input[type="password"] { 41 | height: 45px; 42 | border: 1px solid #ddd; 43 | font-size: 16px; 44 | -webkit-transition: all 0.1s linear; 45 | -moz-transition: all 0.1s linear; 46 | transition: all 0.1s linear; 47 | } 48 | .panel-login input:hover, 49 | .panel-login input:focus { 50 | outline:none; 51 | -webkit-box-shadow: none; 52 | -moz-box-shadow: none; 53 | box-shadow: none; 54 | border-color: #ccc; 55 | } 56 | .btn-login { 57 | background-color: #59B2E0; 58 | outline: none; 59 | color: #fff; 60 | font-size: 14px; 61 | height: auto; 62 | font-weight: normal; 63 | padding: 14px 0; 64 | text-transform: uppercase; 65 | border-color: #59B2E6; 66 | } 67 | .btn-login:hover, 68 | .btn-login:focus { 69 | color: #fff; 70 | background-color: #53A3CD; 71 | border-color: #53A3CD; 72 | } 73 | .forgot-password { 74 | text-decoration: underline; 75 | color: #888; 76 | } 77 | .forgot-password:hover, 78 | .forgot-password:focus { 79 | text-decoration: underline; 80 | color: #666; 81 | } 82 | 83 | .btn-register { 84 | background-color: #1CB94E; 85 | outline: none; 86 | color: #fff; 87 | font-size: 14px; 88 | height: auto; 89 | font-weight: normal; 90 | padding: 14px 0; 91 | text-transform: uppercase; 92 | border-color: #1CB94A; 93 | } 94 | .btn-register:hover, 95 | .btn-register:focus { 96 | color: #fff; 97 | background-color: #1CA347; 98 | border-color: #1CA347; 99 | } 100 | -------------------------------------------------------------------------------- /website/static/css/annotator/panel.css: -------------------------------------------------------------------------------- 1 | .body-panel { 2 | padding-top: 90px; 3 | } 4 | 5 | .url-content-panel { 6 | overflow: hidden; 7 | } 8 | 9 | .url-content-data { 10 | width: 100%; 11 | } 12 | 13 | .url-panel > h1 { 14 | text-align: left; 15 | font-size: 16px; 16 | font-weight: 300; 17 | } 18 | 19 | .collect-panel { 20 | overflow: show; 21 | } 22 | 23 | .collect-panel > h1 { 24 | text-align: left; 25 | font-size: 16px; 26 | font-weight: 300; 27 | overflow: hidden; 28 | } 29 | 30 | .collect-box { 31 | padding-top: 20px; 32 | } 33 | 34 | .annotation-box { 35 | padding-top: 20px; 36 | } 37 | 38 | .command-submission { 39 | background: #F0F0F0; 40 | } 41 | 42 | .annotate-utility-self-completed { 43 | background-color: #73C6B6; 44 | border: 1px; 45 | /* border-style: dotted; 46 | box-shadow: 6px 6px 3px #888888; */ 47 | } 48 | 49 | .annotate-utility-completed { 50 | background-color: #73C6B6; 51 | } 52 | 53 | .annotate-utility-self-in-progress { 54 | background-color: #D0ECE7; 55 | border: 1px; 56 | /* border-style: dotted; 57 | box-shadow: 6px 6px 3px #888888; */ 58 | } 59 | 60 | .annotate-utility-in-progress { 61 | background-color: #D0ECE7; 62 | } 63 | 64 | .url-num-notifications { 65 | color: #4B0082; 66 | background-color: #E6E6FA; 67 | } 68 | 69 | /* --- Facebook style notification badge --- */ 70 | 71 | /* Make the badge float in the top right corner of the button */ 72 | .missing_command_badge { 73 | background-color: #FFA500; 74 | border-radius: 2px; 75 | color: white; 76 | 77 | padding: 1px 3px; 78 | font-size: 10px; 79 | 80 | position: absolute; /* Position the badge within the relatively positioned button */ 81 | top: 0px; 82 | left: 0px; 83 | } 84 | 85 | .notification_badge { 86 | background-color: #fa3e3e; 87 | border-radius: 2px; 88 | color: white; 89 | 90 | padding: 1px 3px; 91 | font-size: 10px; 92 | 93 | position: absolute; /* Position the badge within the relatively positioned button */ 94 | top: 0; 95 | right: 0px; 96 | } 97 | -------------------------------------------------------------------------------- /website/static/css/comment.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Oscuro: #283035 3 | * Azul: #03658c 4 | * Detalle: #c7cacb 5 | * Fondo: #dee1e3 6 | ----------------------------------*/ 7 | 8 | /* body { 9 | font-family: 'Roboto', Arial, Helvetica, Sans-serif, Verdana; 10 | background: #dee1e3; 11 | } */ 12 | 13 | /** ==================== 14 | * Lista de Comentarios 15 | =======================*/ 16 | 17 | ul { 18 | list-style:none; 19 | }​ 20 | 21 | .comments-container h1 { 22 | font-size: 36px; 23 | color: #283035; 24 | font-weight: 400; 25 | } 26 | 27 | .comments-container h1 a { 28 | font-size: 18px; 29 | font-weight: 700; 30 | } 31 | 32 | .comments-list { 33 | position: relative; 34 | } 35 | 36 | /** 37 | * Lineas / Detalles 38 | -----------------------*/ 39 | /* .comments-list:before { 40 | content: ''; 41 | width: 2px; 42 | height: 100%; 43 | background: #c7cacb; 44 | position: absolute; 45 | left: 32px; 46 | top: 0; 47 | } */ 48 | 49 | /* .comments-list:after { 50 | content: ''; 51 | position: absolute; 52 | background: #c7cacb; 53 | bottom: 0; 54 | left: 27px; 55 | width: 7px; 56 | height: 7px; 57 | border: 3px solid #dee1e3; 58 | -webkit-border-radius: 50%; 59 | -moz-border-radius: 50%; 60 | border-radius: 50%; 61 | } */ 62 | 63 | /* .reply-list:before, .reply-list:after {display: none;} 64 | .reply-list li:before { 65 | content: ''; 66 | width: 60px; 67 | height: 2px; 68 | background: #c7cacb; 69 | position: absolute; 70 | top: 25px; 71 | left: -55px; 72 | } */ 73 | 74 | 75 | .comments-list li { 76 | margin-bottom: 15px; 77 | display: block; 78 | position: relative; 79 | } 80 | 81 | .comments-list li:after { 82 | content: ''; 83 | display: block; 84 | clear: both; 85 | height: 0; 86 | width: 0; 87 | } 88 | 89 | .reply-list { 90 | clear: both; 91 | } 92 | /** 93 | * Avatar 94 | ---------------------------*/ 95 | .comments-list .comment-avatar { 96 | width: 65px; 97 | height: 65px; 98 | position: relative; 99 | z-index: 99; 100 | float: left; 101 | border: 3px solid #FFF; 102 | -webkit-border-radius: 4px; 103 | -moz-border-radius: 4px; 104 | border-radius: 4px; 105 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); 106 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.2); 107 | box-shadow: 0 1px 2px rgba(0,0,0,0.2); 108 | overflow: hidden; 109 | } 110 | 111 | .comments-list .comment-avatar img { 112 | width: 100%; 113 | height: 100%; 114 | } 115 | 116 | .reply-list .comment-avatar { 117 | width: 50px; 118 | height: 50px; 119 | } 120 | 121 | .comment-main-level:after { 122 | content: ''; 123 | width: 0; 124 | height: 0; 125 | display: block; 126 | clear: both; 127 | } 128 | 129 | /** 130 | * Caja del Comentario 131 | ---------------------------*/ 132 | .comments-list .comment-box { 133 | width: 100%; 134 | float: left; 135 | position: relative; 136 | } 137 | 138 | /* .comments-list .comment-box:before, .comments-list .comment-box:after { 139 | content: ''; 140 | height: 0; 141 | width: 0; 142 | position: absolute; 143 | display: block; 144 | border-width: 10px 12px 10px 0; 145 | border-style: solid; 146 | border-color: transparent #FCFCFC; 147 | top: 8px; 148 | left: 0px; 149 | } */ 150 | 151 | /* .comments-list .comment-box:before { 152 | border-width: 11px 13px 11px 0; 153 | border-color: transparent rgba(0,0,0,0.05); 154 | left: -12px; 155 | } */ 156 | 157 | .comment-box .comment-head { 158 | background: #FCFCFC; 159 | padding: 20px 12px 0px 12px; 160 | overflow: hidden; 161 | -webkit-border-radius: 4px 4px 0 0; 162 | -moz-border-radius: 4px 4px 0 0; 163 | border-radius: 4px 4px 0 0; 164 | } 165 | 166 | .comment-box .comment-head i { 167 | float: right; 168 | position: relative; 169 | color: #A6A6A6; 170 | cursor: pointer; 171 | -webkit-transition: color 0.3s ease; 172 | -o-transition: color 0.3s ease; 173 | transition: color 0.3s ease; 174 | } 175 | 176 | .comment-box .comment-head i:hover { 177 | color: #03658c; 178 | } 179 | 180 | .comment-box .submission-time { 181 | color: rgb(153, 153, 153); 182 | font-size: 12px; 183 | font-weight: 400; 184 | } 185 | 186 | .comment-box .comment-name { 187 | color: #283035; 188 | font-size: 14px; 189 | font-weight: 700; 190 | float: left; 191 | margin-right: 10px; 192 | } 193 | 194 | .comment-box .comment-name a { 195 | color: #283035; 196 | } 197 | 198 | .comment-box .comment-head span { 199 | float: left; 200 | color: #999; 201 | font-size: 13px; 202 | position: relative; 203 | top: 1px; 204 | } 205 | 206 | .comment-box .update-content { 207 | background: #D6EAF8; 208 | color: #2E86C1; 209 | margin: 12px 12px 0px 12px; 210 | } 211 | 212 | .comment-box .comment-content { 213 | background: #FFF; 214 | padding: 12px 12px 0px 12px; 215 | font-size: 15px; 216 | color: #595959; 217 | -webkit-border-radius: 0 0 4px 4px; 218 | -moz-border-radius: 0 0 4px 4px; 219 | border-radius: 0 0 4px 4px; 220 | } 221 | 222 | .comment-box .comment-name.by-author, .comment-box .comment-name.by-author a {color: #03658c;} 223 | .comment-box .comment-name.by-author:after { 224 | content: 'author'; 225 | background: #03658c; 226 | color: #FFF; 227 | font-size: 12px; 228 | padding: 3px 5px; 229 | font-weight: 700; 230 | margin-left: 10px; 231 | -webkit-border-radius: 3px; 232 | -moz-border-radius: 3px; 233 | border-radius: 3px; 234 | } 235 | 236 | // .comment-box .comment-name.by-judger, .comment-box .comment-name.by-judger a {color: #28B463} 237 | .comment-box .comment-name.by-judger:after { 238 | content: 'modification-request'; 239 | background: #28B463; 240 | color: #FFF; 241 | font-size: 12px; 242 | padding: 3px 5px; 243 | font-weight: 700; 244 | margin-left: 10px; 245 | -webkit-border-radius: 3px; 246 | -moz-border-radius: 3px; 247 | border-radius: 3px; 248 | } 249 | 250 | /** ===================== 251 | * Responsive 252 | ========================*/ 253 | @media only screen and (max-width: 766px) { 254 | .comments-container { 255 | width: 480px; 256 | } 257 | 258 | .comments-list .comment-box { 259 | width: 390px; 260 | } 261 | 262 | .reply-list .comment-box { 263 | width: 320px; 264 | } 265 | } -------------------------------------------------------------------------------- /website/static/css/developers.css: -------------------------------------------------------------------------------- 1 | .project-description { 2 | font:18px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | font-weight:300; 4 | color:#333; 5 | font-size: 18px; 6 | padding-top: 64px 7 | } 8 | 9 | .project-description h3 { 10 | margin-top: 30px; 11 | } 12 | 13 | .project-description h4 { 14 | margin-top: 20px; 15 | margin-bottom: 20px; 16 | font-style: bold; 17 | font-weight: 600; 18 | color:#777; 19 | } 20 | 21 | @media (max-width: 980px) { 22 | .project-description { 23 | padding-top: 100px; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /website/static/css/index.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | min-height: 100%; 5 | } 6 | 7 | .body-panel { 8 | padding-top: 72px; 9 | padding-left: 40px; 10 | padding-right: 40px; 11 | } 12 | 13 | .instruction-panel { 14 | /* background-color: #e2edff; */ 15 | background-color: #f9fbff; 16 | color: rgb(72, 72, 72); 17 | font-size: 16px; 18 | font-weight: 300; 19 | } 20 | 21 | .instruction-panel > h1 { 22 | text-align: left; 23 | font-size: 20px; 24 | font-weight: 400; 25 | margin: 12px 0 0 0; 26 | } 27 | 28 | .instruction-panel > h2 { 29 | text-align: left; 30 | line-height: 1.4; 31 | font-size: 16px; 32 | font-weight: 300; 33 | /* color: #43a047; */ 34 | color: #163f8e; 35 | } 36 | 37 | .instruction-panel > ul > li{ 38 | list-style-type:none; 39 | margin: 12px 0; 40 | } 41 | 42 | .instruction-panel > ul > li > ul > li{ 43 | margin-left: -20px; 44 | } 45 | 46 | .instruction-panel > ul > li:before{ 47 | content: "\e013"; 48 | font-family: 'Glyphicons Halflings'; 49 | font-size: 12px; 50 | float: left; 51 | margin-top: 4px; 52 | margin-left: -30px; 53 | color: rgb(72, 72, 72); 54 | } 55 | 56 | .panel-command { 57 | text-align: left; 58 | font-size: 20px; 59 | } 60 | 61 | .footer{ 62 | text-align: left; 63 | line-height: 16px; 64 | color: rgb(108, 108, 108); 65 | } 66 | 67 | .fadeInUp { 68 | -webkit-animation-duration: 1s; 69 | } 70 | 71 | .btn-tag { 72 | border-radius:1px; 73 | background-color: #e2edff; 74 | color: #5a6b87; 75 | } 76 | 77 | .btn-top-k { 78 | border-radius:1px; 79 | background-color: #e5e3e1; 80 | color: #76716e; 81 | margin-right: 20px; 82 | float: right; 83 | } 84 | 85 | @media (max-width: 980px) { 86 | .body-panel { 87 | padding-top: 160px; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /website/static/css/introjs.min.css: -------------------------------------------------------------------------------- 1 | .introjs-overlay{position:absolute;box-sizing:content-box;z-index:999999;background-color:#000;opacity:0;background:-moz-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));background:-webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#66000000',endColorstr='#e6000000',GradientType=1)";-ms-filter:"alpha(opacity=50)";filter:alpha(opacity=50);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-fixParent{z-index:auto!important;opacity:1.0!important;-webkit-transform:none!important;-moz-transform:none!important;-ms-transform:none!important;-o-transform:none!important;transform:none!important}.introjs-showElement,tr.introjs-showElement>td,tr.introjs-showElement>th{z-index:9999999!important}.introjs-disableInteraction{z-index:99999999!important;position:absolute;background-color:white;opacity:0;filter:alpha(opacity=0)}.introjs-relativePosition,tr.introjs-showElement>td,tr.introjs-showElement>th{position:relative}.introjs-helperLayer{box-sizing:content-box;position:absolute;z-index:9999998;background-color:#FFF;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-tooltipReferenceLayer{box-sizing:content-box;position:absolute;visibility:hidden;z-index:10000000;background-color:transparent;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperLayer *,.introjs-helperLayer *:before,.introjs-helperLayer *:after{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;-o-box-sizing:content-box;box-sizing:content-box}.introjs-helperNumberLayer{box-sizing:content-box;position:absolute;visibility:visible;top:-16px;left:-16px;z-index:9999999999!important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:bold;color:white;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid white;border-radius:50%;filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019', endColorstr='#cf0404', GradientType=0)";filter:"progid:DXImageTransform.Microsoft.Shadow(direction=135, strength=2, color=ff0000)";box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid white;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-right{top:-10px;right:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-middle{top:-10px;left:50%;margin-left:-5px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.right{right:-10px;top:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.right-bottom{bottom:10px;right:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.bottom{bottom:-10px;border-top-color:white;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left{left:-10px;top:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left-bottom{left:-10px;bottom:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-tooltip{box-sizing:content-box;position:absolute;visibility:visible;padding:10px;background-color:white;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right;white-space:nowrap}.introjs-button{box-sizing:content-box;position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;*display:inline;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:focus,.introjs-button:active{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{box-sizing:content-box;margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:0}.introjs-prevbutton.introjs-fullbutton{border:1px solid #d4d4d4;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-nextbutton.introjs-fullbutton{-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em}.introjs-disabled,.introjs-disabled:hover,.introjs-disabled:focus{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none}.introjs-hidden{display:none}.introjs-bullets{text-align:center}.introjs-bullets ul{box-sizing:content-box;clear:both;margin:15px auto 0;padding:0;display:inline-block}.introjs-bullets ul li{box-sizing:content-box;list-style:none;float:left;margin:0 2px}.introjs-bullets ul li a{box-sizing:content-box;display:block;width:6px;height:6px;background:#ccc;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-decoration:none;cursor:pointer}.introjs-bullets ul li a:hover{background:#999}.introjs-bullets ul li a.active{background:#999}.introjs-progress{box-sizing:content-box;overflow:hidden;height:10px;margin:10px 0 5px 0;border-radius:4px;background-color:#ecf0f1}.introjs-progressbar{box-sizing:content-box;float:left;width:0;height:100%;font-size:10px;line-height:10px;text-align:center;background-color:#08c}.introjsFloatingElement{position:absolute;height:0;width:0;left:50%;top:50%}.introjs-fixedTooltip{position:fixed}.introjs-hint{box-sizing:content-box;position:absolute;background:transparent;width:20px;height:15px;cursor:pointer}.introjs-hint:focus{border:0;outline:0}.introjs-hidehint{display:none}.introjs-fixedhint{position:fixed}.introjs-hint:hover>.introjs-hint-pulse{border:5px solid rgba(60,60,60,0.57)}.introjs-hint-pulse{box-sizing:content-box;width:10px;height:10px;border:5px solid rgba(60,60,60,0.27);-webkit-border-radius:30px;-moz-border-radius:30px;border-radius:30px;background-color:rgba(136,136,136,0.24);z-index:10;position:absolute;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-ms-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out}.introjs-hint-no-anim .introjs-hint-dot{-webkit-animation:none;-moz-animation:none;animation:none}.introjs-hint-dot{box-sizing:content-box;border:10px solid rgba(146,146,146,0.36);background:transparent;-webkit-border-radius:60px;-moz-border-radius:60px;border-radius:60px;height:50px;width:50px;-webkit-animation:introjspulse 3s ease-out;-moz-animation:introjspulse 3s ease-out;animation:introjspulse 3s ease-out;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;animation-iteration-count:infinite;position:absolute;top:-25px;left:-25px;z-index:1;opacity:0}@-moz-keyframes introjspulse{0%{-moz-transform:scale(0);opacity:.0}25%{-moz-transform:scale(0);opacity:.1}50%{-moz-transform:scale(0.1);opacity:.3}75%{-moz-transform:scale(0.5);opacity:.5}100%{-moz-transform:scale(1);opacity:.0}}@-webkit-keyframes introjspulse{0%{-webkit-transform:scale(0);opacity:.0}25%{-webkit-transform:scale(0);opacity:.1}50%{-webkit-transform:scale(0.1);opacity:.3}75%{-webkit-transform:scale(0.5);opacity:.5}100%{-webkit-transform:scale(1);opacity:.0}} -------------------------------------------------------------------------------- /website/static/css/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | overflow-y: scroll; 3 | } 4 | 5 | body { 6 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif; 7 | text-align: center; 8 | padding-bottom: 20px; 9 | } 10 | 11 | p { 12 | text-align:left; 13 | } 14 | 15 | li { 16 | text-align: left; 17 | } 18 | 19 | /* Start by setting display:none to make this hidden. 20 | Then we position it in relation to the viewport window 21 | with position:fixed. Width, height, top and left speak 22 | for themselves. Background we set to 80% white with 23 | our animation centered, and no-repeating */ 24 | .modal { 25 | display: none; 26 | position: fixed; 27 | z-index: 1000; 28 | top: 0; 29 | left: 0; 30 | height: 100%; 31 | width: 100%; 32 | background: rgba( 255, 255, 255, .8 ) 33 | url('/static/img/gears.gif') 34 | 50% 50% 35 | no-repeat; 36 | } 37 | 38 | /* When the body has the loading class, we turn 39 | the scrollbar off with overflow:hidden */ 40 | body.loading { 41 | overflow: hidden; 42 | } 43 | 44 | /* Anytime the body has the loading class, our 45 | modal element will be visible */ 46 | body.loading .modal { 47 | display: block; 48 | } 49 | 50 | /* Change the height of the nav bar */ 51 | .navbar-nav > li > a { 52 | padding-top:10px !important; padding-bottom:10px !important; 53 | } 54 | 55 | .navbar {min-height:32px !important} 56 | 57 | /*.command { 58 | font-family: Monaco, Menlo, Consolas, monospace; 59 | font-size: 18px; 60 | text-align: center; 61 | }*/ 62 | 63 | .program-text { 64 | font-weight: bold; 65 | } 66 | 67 | #command-wrapper { 68 | z-index: 3; 69 | } 70 | 71 | #command-wrapper.affix { 72 | position: fixed; 73 | top: 0; 74 | left: 0; 75 | width: 100%; 76 | height: 20px; 77 | background-color: white; 78 | padding-top: 10px; 79 | padding-bottom: 70px; 80 | box-shadow: 0 0 15px 5px #ffffff; 81 | } 82 | 83 | #about { 84 | text-align: justify; 85 | width: 700px; 86 | margin: 0 auto; 87 | } 88 | 89 | #canvas { 90 | position: absolute; 91 | z-index: 1; 92 | width: 100%; 93 | left: 0; 94 | pointer-events: none; 95 | } 96 | 97 | #help { 98 | z-index: 2; 99 | } 100 | 101 | .tiny-push { 102 | height: 10px; 103 | } 104 | 105 | .small-push { 106 | height: 20px; 107 | } 108 | 109 | .push { 110 | height: 40px; 111 | } 112 | 113 | .taggernooption { 114 | background-color: #f8c7c7; 115 | } 116 | 117 | .taggeroption { 118 | background-color: #caf8c7; 119 | } 120 | 121 | .taggercurrent { 122 | border-color: red; 123 | border-width: 2px; 124 | } 125 | 126 | .dropdown-menu { 127 | font-size: 14px; 128 | } 129 | 130 | .oneliner-index h4 { 131 | font-family: "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 132 | margin-left: 20px; 133 | } 134 | 135 | .explanation { 136 | margin-left: 20px; 137 | } 138 | 139 | .explanation h4 { 140 | font-family: "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 141 | } 142 | 143 | /* .oneliner .line { 144 | background: #eee; 145 | font-size: 16px; 146 | font-family: Consolas,monaco,monospace 147 | } 148 | 149 | .oneliner .line .add-on { 150 | color: #253; 151 | padding-right: .5em; 152 | font-weight: bold; 153 | } */ 154 | 155 | .index { 156 | font-size: 20px; 157 | } 158 | 159 | .center-block { 160 | display: block; 161 | margin-right: auto; 162 | margin-left: auto; 163 | } 164 | 165 | .well { 166 | background: white; 167 | height:auto; 168 | } 169 | 170 | .translate-menu { 171 | left: 120px; 172 | } 173 | 174 | .top-search-container { 175 | padding-top: 6px; 176 | } 177 | 178 | .input-group .nl-request { 179 | width: 100%; 180 | border-radius: 6px; 181 | } 182 | 183 | #top-search { 184 | -webkit-transition: all .5s ease; 185 | -moz-transition: all .5s ease; 186 | transition: all .5s ease; 187 | position: relative; 188 | left: 0; 189 | } 190 | 191 | /* #top-search:focus { 192 | border-color: #7DCEA0; 193 | -moz-box-shadow: 0 0 8px rgba(125, 125, 206, 0.6); 194 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(125, 125, 206, 0.6); 195 | outline: 0 none; 196 | } */ 197 | 198 | #prevnext { 199 | text-align: center; 200 | padding-top: 10px; 201 | } 202 | 203 | #prevnext li:not(:first-child), #prevnext span:not(:first-child) { 204 | cursor: pointer; 205 | } 206 | 207 | .help-box { 208 | background-color: white; 209 | } 210 | 211 | .help-synopsis { 212 | background-color: #f5f5f5; 213 | } 214 | 215 | .popover-content { 216 | font-size: 12px; 217 | text-align: justify; 218 | } 219 | 220 | .popover { 221 | font-weight: normal; 222 | max-width: 450px; 223 | } 224 | 225 | .btn-search{ 226 | background: white; 227 | box-shadow: none; 228 | outline: 0; 229 | } 230 | 231 | .btn-search:hover{ 232 | background: rgba(250, 215, 160, 1); 233 | #box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 6px rgba(250, 215, 160, 0.75); 234 | } 235 | 236 | /* -- navigation bar -- */ 237 | 238 | .navbar-default { 239 | background: none; 240 | border-color: transparent; 241 | margin-bottom: 0; 242 | text-align: center; 243 | } 244 | 245 | .navbar-default .navbar-nav > li > a { 246 | font-size: 15px; 247 | font-family: 'Source Sans Pro', sans-serif; 248 | font-weight: 200; 249 | color: #666; 250 | padding: 5px 15px; 251 | } 252 | 253 | .navbar-default .navbar-nav > li > a:hover { 254 | color: #f48e5c; 255 | } 256 | 257 | .navbar-nav { 258 | float: right; 259 | display: inline-block; 260 | } 261 | 262 | .logo > a { 263 | font-size: 24px; 264 | font-family: 'Source Sans Pro', sans-serif; 265 | font-weight: 200; 266 | color: #666; 267 | padding: 5px 15px; 268 | } 269 | 270 | .logo > a:hover { 271 | color: #f48e5c; 272 | text-decoration: none; 273 | } 274 | 275 | .main-website-header { 276 | position: fixed; 277 | width: 100%; 278 | -webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 279 | -moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 280 | -ms-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 281 | -o-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 282 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 283 | background: rgba(255, 255, 255, 0.96); 284 | z-index: 999; 285 | padding: 12px 0 8px 0 286 | } 287 | 288 | .fixed-in-scroll { 289 | position:fixed; 290 | top:0; 291 | left:0; 292 | } 293 | -------------------------------------------------------------------------------- /website/static/css/perfect-scrollbar.css: -------------------------------------------------------------------------------- 1 | /* perfect-scrollbar v0.6.14 */ 2 | .ps-container { 3 | -ms-touch-action: auto; 4 | touch-action: auto; 5 | overflow: hidden !important; 6 | -ms-overflow-style: none; } 7 | @supports (-ms-overflow-style: none) { 8 | .ps-container { 9 | overflow: auto !important; } } 10 | @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { 11 | .ps-container { 12 | overflow: auto !important; } } 13 | .ps-container.ps-active-x > .ps-scrollbar-x-rail, 14 | .ps-container.ps-active-y > .ps-scrollbar-y-rail { 15 | display: block; 16 | background-color: transparent; } 17 | .ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { 18 | background-color: #eee; 19 | opacity: 0.9; } 20 | .ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x { 21 | background-color: #999; 22 | height: 11px; } 23 | .ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail { 24 | background-color: #eee; 25 | opacity: 0.9; } 26 | .ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y { 27 | background-color: #999; 28 | width: 11px; } 29 | .ps-container > .ps-scrollbar-x-rail { 30 | display: none; 31 | position: absolute; 32 | /* please don't change 'position' */ 33 | opacity: 0; 34 | -webkit-transition: background-color .2s linear, opacity .2s linear; 35 | -o-transition: background-color .2s linear, opacity .2s linear; 36 | -moz-transition: background-color .2s linear, opacity .2s linear; 37 | transition: background-color .2s linear, opacity .2s linear; 38 | bottom: 0px; 39 | /* there must be 'bottom' for ps-scrollbar-x-rail */ 40 | height: 15px; } 41 | .ps-container > .ps-scrollbar-x-rail > .ps-scrollbar-x { 42 | position: absolute; 43 | /* please don't change 'position' */ 44 | background-color: #aaa; 45 | -webkit-border-radius: 6px; 46 | -moz-border-radius: 6px; 47 | border-radius: 6px; 48 | -webkit-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out; 49 | transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out; 50 | -o-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out; 51 | -moz-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out; 52 | transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out; 53 | transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out; 54 | bottom: 2px; 55 | /* there must be 'bottom' for ps-scrollbar-x */ 56 | height: 6px; } 57 | .ps-container > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x, .ps-container > .ps-scrollbar-x-rail:active > .ps-scrollbar-x { 58 | height: 11px; } 59 | .ps-container > .ps-scrollbar-y-rail { 60 | display: none; 61 | position: absolute; 62 | /* please don't change 'position' */ 63 | opacity: 0; 64 | -webkit-transition: background-color .2s linear, opacity .2s linear; 65 | -o-transition: background-color .2s linear, opacity .2s linear; 66 | -moz-transition: background-color .2s linear, opacity .2s linear; 67 | transition: background-color .2s linear, opacity .2s linear; 68 | right: 0; 69 | /* there must be 'right' for ps-scrollbar-y-rail */ 70 | width: 15px; } 71 | .ps-container > .ps-scrollbar-y-rail > .ps-scrollbar-y { 72 | position: absolute; 73 | /* please don't change 'position' */ 74 | background-color: #aaa; 75 | -webkit-border-radius: 6px; 76 | -moz-border-radius: 6px; 77 | border-radius: 6px; 78 | -webkit-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out; 79 | transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out; 80 | -o-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out; 81 | -moz-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out; 82 | transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out; 83 | transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out; 84 | right: 2px; 85 | /* there must be 'right' for ps-scrollbar-y */ 86 | width: 6px; } 87 | .ps-container > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y, .ps-container > .ps-scrollbar-y-rail:active > .ps-scrollbar-y { 88 | width: 11px; } 89 | .ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { 90 | background-color: #eee; 91 | opacity: 0.9; } 92 | .ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x { 93 | background-color: #999; 94 | height: 11px; } 95 | .ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail { 96 | background-color: #eee; 97 | opacity: 0.9; } 98 | .ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y { 99 | background-color: #999; 100 | width: 11px; } 101 | .ps-container:hover > .ps-scrollbar-x-rail, 102 | .ps-container:hover > .ps-scrollbar-y-rail { 103 | opacity: 0.6; } 104 | .ps-container:hover > .ps-scrollbar-x-rail:hover { 105 | background-color: #eee; 106 | opacity: 0.9; } 107 | .ps-container:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x { 108 | background-color: #999; } 109 | .ps-container:hover > .ps-scrollbar-y-rail:hover { 110 | background-color: #eee; 111 | opacity: 0.9; } 112 | .ps-container:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y { 113 | background-color: #999; } 114 | -------------------------------------------------------------------------------- /website/static/css/perfect-scrollbar.min.css: -------------------------------------------------------------------------------- 1 | /* perfect-scrollbar v0.6.14 */ 2 | .ps-container{-ms-touch-action:auto;touch-action:auto;overflow:hidden !important;-ms-overflow-style:none}@supports (-ms-overflow-style: none){.ps-container{overflow:auto !important}}@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none){.ps-container{overflow:auto !important}}.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block;background-color:transparent}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;bottom:0px;height:15px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;bottom:2px;height:6px}.ps-container>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x,.ps-container>.ps-scrollbar-x-rail:active>.ps-scrollbar-x{height:11px}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;right:0;width:15px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;right:2px;width:6px}.ps-container>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y,.ps-container>.ps-scrollbar-y-rail:active>.ps-scrollbar-y{width:11px}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:.6}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999} 3 | -------------------------------------------------------------------------------- /website/static/css/translate.css: -------------------------------------------------------------------------------- 1 | .translate-panel { 2 | text-align: left; 3 | padding: 72px 12px 0 12px; 4 | } 5 | 6 | .btn-copy{ 7 | border:0px solid transparent; 8 | } 9 | 10 | .btn-expl{ 11 | border:0px solid transparent; 12 | } 13 | 14 | .btn-copy:hover, 15 | .btn-copy:focus, 16 | .btn-copy:active { 17 | background-color: rgb(255, 255, 255); 18 | color: #f48e5c 19 | } 20 | 21 | .btn-expl:hover, 22 | .btn-expl:focus, 23 | .btn-expl:active { 24 | background-color: rgb(255, 255, 255); 25 | color: #f48e5c 26 | } 27 | 28 | .cmd-result { 29 | table-layout:fixed; 30 | width: 100%; 31 | } 32 | 33 | .tooltip-inner { 34 | max-width: 100%; 35 | } 36 | 37 | .tooltip-inner > .cmd-expl { 38 | font-family: "Lucida Console", Monaco, monospace; 39 | text-align: left; 40 | white-space: pre 41 | } 42 | 43 | .code { 44 | font-family: "Lucida Console", Monaco, monospace; 45 | } 46 | 47 | @media (max-width: 980px) { 48 | .translate-panel { 49 | padding-top: 140px; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /website/static/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/font/FontAwesome.otf -------------------------------------------------------------------------------- /website/static/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /website/static/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /website/static/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /website/static/html/annotator/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Collecting Command - NL Pairs 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% block head %}{% endblock %} 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 | 27 |
28 | {% block navbar %}{% endblock %} 29 |
30 |
31 |
32 | 33 | {% block body %}{% endblock %} 34 | 35 | 36 | 37 | 38 | 39 | 40 | {% block other-js %}{% endblock %} 41 | 42 | 43 | -------------------------------------------------------------------------------- /website/static/html/annotator/login.html: -------------------------------------------------------------------------------- 1 | {% extends "annotator/base.html" %} 2 | {% block head %} 3 | 4 | {% endblock %} 5 | 6 | {% block body %} 7 |
8 |
9 |
10 | 70 |
71 |
72 |
73 | {% endblock %} 74 | 75 | {% block other-js %} 76 | 77 | 78 | 79 | 161 | {% endblock %} -------------------------------------------------------------------------------- /website/static/html/annotator/url_panel.html: -------------------------------------------------------------------------------- 1 | {% extends "annotator/base.html" %} 2 | {% block head %} 3 | 4 | {% endblock %} 5 | 6 | {% block body %} 7 | {% block navbar %} 8 | 29 | {% endblock %} 30 | 31 |
32 |
33 |

URLs that contain the utility {{utility}}

34 |
35 | Collect the data from the following URLs, including the ones tagged with 36 |
37 | {% if url_list %} 38 |
    39 | {% for url, status in url_list %} 40 |
  • 41 | {{url.str}} 42 | {% if status == 'completed' %} 43 | 44 | {% else %} 45 | {% if status == 'in-progress' %} 46 | 47 | {% elif status == 'others-in-progress' %} 48 | 49 | {% endif %} 50 | {% endif %} 51 |
  • 52 | {% endfor %} 53 |
54 | {% endif %} 55 |
56 |
57 | {% endblock %} 58 | 59 | {% block other-js %} 60 | 61 | 62 | 109 | {% endblock %} 110 | -------------------------------------------------------------------------------- /website/static/html/annotator/user_panel.html: -------------------------------------------------------------------------------- 1 | {% extends "annotator/base.html" %} 2 | {% block head %} 3 | 4 | {% endblock %} 5 | 6 | {% block body %} 7 | {% block navbar %} 8 | 27 | {% endblock %} 28 |
29 |
30 |
31 | {% if annotator_list %} 32 | {% for annotator in annotator_list %} 33 |

{{annotator.name}}

34 |

Time logged: h m

35 | {{annotator.num_annotations}} annotations, {{annotator.num_annotations_per_hour}} pairs/hr 36 |

More details...

37 |
38 | {% endfor %} 39 | {% endif %} 40 | {% if total_num_annotations %} 41 | {{total_num_annotations}} annotations in total 42 |

More details...

43 | {% endif %} 44 |
45 |
46 |
47 | {% endblock %} 48 | 49 | {% block other-js %} 50 | 51 | 52 | 100 | {% endblock %} 101 | -------------------------------------------------------------------------------- /website/static/html/annotator/user_profile.html: -------------------------------------------------------------------------------- 1 | {% extends "annotator/base.html" %} 2 | {% block head %} 3 | 4 | {% endblock %} 5 | 6 | {% block body %} 7 | {% block navbar %} 8 | 27 | {% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | {% endblock %} 35 | 36 | {% block other-js %} 37 | 38 | 39 | 43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /website/static/html/annotator/utility_panel.html: -------------------------------------------------------------------------------- 1 | {% extends "annotator/base.html" %} 2 | {% block head %} 3 | 4 | {% endblock %} 5 | 6 | {% block body %} 7 | {% block navbar %} 8 | 27 | {% endblock %} 28 |
29 |
30 |
31 | {% if utility_groups %} 32 | {% for utility_group1, utility_group2 in utility_groups %} 33 | {% for utility, completion_ratio, completion_ratio_by_user in utility_group1 %} 34 |
35 | {% if completion_ratio == -1 %} 36 | 37 | {% elif completion_ratio_by_user > 0.5 %} 38 | 39 | {% elif completion_ratio_by_user > 0 %} 40 | 41 | {% elif completion_ratio > 0.5 %} 42 | 43 | {% elif completion_ratio > 0 %} 44 | 45 | {% else %} 46 | 47 | {% endif %} 48 |
49 | {% endfor %} 50 |
51 |
52 | {% for utility, completion_ratio, completion_ratio_by_user in utility_group2 %} 53 |
54 | {% if completion_ratio == -1 %} 55 | 56 | {% elif completion_ratio_by_user > 0.5 %} 57 | 58 | {% elif completion_ratio_by_user > 0 %} 59 | 60 | {% elif completion_ratio > 0.5 %} 61 | 62 | {% elif completion_ratio > 0 %} 63 | 64 | {% else %} 65 | 66 | {% endif %} 67 |
68 | {% endfor %} 69 |
70 | {% endfor %} 71 | {% endif %} 72 |
73 | 78 |
79 |
80 | {% endblock %} 81 | 82 | {% block other-js %} 83 | 84 | 140 | {% endblock %} 141 | -------------------------------------------------------------------------------- /website/static/html/translator/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tellina - a natural language to command translation tool 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% block head %}{% endblock %} 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 |
33 |
34 |
35 |
36 |
37 | Project Logo 38 |
39 |
40 |
41 | 42 | 45 | 46 | 47 | 48 | 51 | 52 |
53 |
54 |
55 | {% block navbar %}{% endblock %} 56 |
57 |
58 |
59 | 60 | {% block body %}{% endblock %} 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 107 | {% block other-js %}{% endblock %} 108 | 109 | 110 | -------------------------------------------------------------------------------- /website/static/html/translator/developers.html: -------------------------------------------------------------------------------- 1 | {% extends "translator/base.html" %} 2 | {% block head %} 3 | 4 | 5 | {% endblock %} 6 | 7 | {% block body %} 8 |
9 |
10 |
11 |
12 |

About Tellina

13 |
14 | Star 15 | Fork 16 | Issue 17 | 18 |
19 |

Tellina automatically translates the natural language commands of end-user programmers into a programming language. Currently Tellina supports Bash as its target language.

20 |

Source Code & Data

21 |

The source code for this website and the machine learning model & data is available on Github.

22 | 23 |

Publications

24 |

The following papers describe the research work and technical details of Tellina.

25 |

If you use Tellina in your work, please cite the relevant paper(s) accordingly.

26 |
27 |
28 | Program Synthesis from Natural Language 29 | Using Recurrent Neural Networks. UW-CSE-TR. 2017 30 |
31 | Keywords: stage-wise translation, user study 32 |
@techreport{LinWPVZE2017:TR, 
33 |   author = {Xi Victoria Lin and Chenglong Wang and Deric Pang and Kevin Vu and Luke Zettlemoyer and Michael D. Ernst}, 
34 |   title = {Program synthesis from natural language using recurrent neural networks}, 
35 |   institution = {University of Washington Department of Computer Science and Engineering}, 
36 |   number = {UW-CSE-17-03-01}, 
37 |   address = {Seattle, WA, USA}, 
38 |   month = mar, 
39 |   year = {2017} 
40 | }
41 |
42 | 43 |
44 | NL2Bash: A Corpus and Semantic Parser for Natural Language Interface to the Linux Operating System. LREC 2018. 45 |
46 | Keywords: end-to-end translation, CopyNet, sub-token, 100 Bash utilities, dataset 47 |
@inproceedings{LinWZE2018:NL2Bash, 
48 |   author = {Xi Victoria Lin and Chenglong Wang and Luke Zettlemoyer and Michael D. Ernst}, 
49 |   title = {NL2Bash: A Corpus and Semantic Parser for Natural Language Interface to the Linux Operating System}, 
50 |   booktitle = {Proceedings of the Eleventh International Conference on Language Resources
51 |                and Evaluation {LREC} 2018, Miyazaki (Japan), 7-12 May, 2018.},
52 |   year = {2018} 
53 | }
54 | 55 |
56 |
57 |

Team

58 | Tellina is written by Victoria Lin, with help from Chenglong Wang and Deric Pang.
Research advisors: Michael D. Ernst and Luke Zettlemoyer. 59 |
60 | * We thank the Bash programmers who worked with us on data collection. You brought Tellina to life! 61 |
62 |
63 | 64 |
65 | {% endblock %} 66 | 67 | {% block other-js %}{% endblock %} 68 | -------------------------------------------------------------------------------- /website/static/html/translator/macros.html: -------------------------------------------------------------------------------- 1 | {% macro outputcommand(mp, suggestions) -%} 2 | {% if suggestions|length == 0 %} 3 | {{ mp.program|e }} 4 | {% else %} 5 | 6 | 7 | {{ mp.program|e }} 8 | 15 | 16 | {% endif %} 17 | {% if mp.synopsis %}- {{ mp.synopsis|e }}{% endif %} 18 | {%- endmacro %} 19 | 20 | {%- macro outputcommandexplain(d) -%} 21 | {% if d.suggestions|length == 0 -%} 22 | {{ d.match|safe }} 23 | {%- else -%} 24 | 25 | 26 | 27 | {{ d.match|safe }} 28 | 35 | 36 | 37 | {%- endif %} 38 | {%- endmacro %} 39 | 40 | {%- macro spanclasses(d) -%} 41 | class="{{ d.commandclass }}"{% if d.helpclass %} helpref="{{ d.helpclass }}"{% endif %} 42 | {%- endmacro %} 43 | 44 | {%- macro examplebullet(cmd) -%} 45 |
  • {{ cmd|e }}
  • 46 | {%- endmacro %} 47 | -------------------------------------------------------------------------------- /website/static/html/translator/options.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% set t = mp.program|e %} 3 | {% if mp.synopsis %} 4 | {% set t = mp.program|e + ' - ' + mp.synopsis|e %} 5 | {% endif %} 6 | {% block title %} - {{ t }}{% endblock %} 7 | {% block content %} 8 |
    9 |
    10 |
    11 | {% import 'macros.html' as macros %} 12 | {{ macros.outputcommand(mp, suggestions) }} 13 |
    14 |
    15 |
    16 | 17 | 18 | {% for desc in mp.options -%} 19 | 20 | 23 | 24 | {%- endfor %} 25 | 26 |
    21 |
    {{ desc|safe }}
    22 |
    27 |
    28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /website/static/html/translator/query_history.html: -------------------------------------------------------------------------------- 1 | {% extends "translator/base.html" %} 2 | {% block head %} 3 | 6 | 7 | {% endblock %} 8 | {% block body %} 9 | {% if latest_request_list %} 10 |
    11 |
    Recently Asked
    12 |
      13 | {% for request, org, city, region, country in latest_request_list %} 14 |
    • 15 | {{request.request_str}} by anonymous from {{org}}, {{city}}, {{region}}, {{country}} 16 |
    • 17 | {% endfor %} 18 |
    19 |
    20 | {% endif %} 21 | {% endblock %} -------------------------------------------------------------------------------- /website/static/img/cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/img/cli.png -------------------------------------------------------------------------------- /website/static/img/clippy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/static/img/developers/system_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/img/developers/system_overview.png -------------------------------------------------------------------------------- /website/static/img/gear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/static/img/gears.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/img/gears.gif -------------------------------------------------------------------------------- /website/static/img/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /website/static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /website/static/img/tellina.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/static/img/tellina_avatar.svg: -------------------------------------------------------------------------------- 1 | bot2_openLayer 1 -------------------------------------------------------------------------------- /website/static/js/annotator/main.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $('.logout').click(function() { 3 | $.get(`logout`, function(data) { 4 | if (data.status == 'LOGOUT_SUCCESS') { 5 | window.location.replace(`login`); 6 | } 7 | }); 8 | }) 9 | }) -------------------------------------------------------------------------------- /website/static/js/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /* clipboard.js v1.5.15 2 | * https://zenorocha.github.io/clipboard.js 3 | * 4 | * Licensed MIT © Zeno Rocha 5 | */ 6 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Clipboard=e()}}(function(){var e,t,n;return function e(t,n,i){function o(a,c){if(!n[a]){if(!t[a]){var l="function"==typeof require&&require;if(!c&&l)return l(a,!0);if(r)return r(a,!0);var s=new Error("Cannot find module '"+a+"'");throw s.code="MODULE_NOT_FOUND",s}var u=n[a]={exports:{}};t[a][0].call(u.exports,function(e){var n=t[a][1][e];return o(n?n:e)},u,u.exports,e,t,n,i)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function e(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function e(){var t=this,n="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=document.body.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[n?"right":"left"]="-9999px";var i=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.addEventListener("focus",window.scrollTo(0,i)),this.fakeElem.style.top=i+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function e(){this.fakeHandler&&(document.body.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function e(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function e(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function e(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function e(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function e(){this.removeFake()}},{key:"action",set:function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function e(){return this._action}},{key:"target",set:function e(t){if(void 0!==t){if(!t||"object"!==("undefined"==typeof t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function e(){return this._target}}]),e}();e.exports=c})},{select:5}],8:[function(t,n,i){!function(o,r){if("function"==typeof e&&e.amd)e(["module","./clipboard-action","tiny-emitter","good-listener"],r);else if("undefined"!=typeof i)r(n,t("./clipboard-action"),t("tiny-emitter"),t("good-listener"));else{var a={exports:{}};r(a,o.clipboardAction,o.tinyEmitter,o.goodListener),o.clipboard=a.exports}}(this,function(e,t,n,i){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function c(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}var s=o(t),u=o(n),f=o(i),d=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText}},{key:"listenClick",value:function e(t){var n=this;this.listener=(0,f.default)(t,"click",function(e){return n.onClick(e)})}},{key:"onClick",value:function e(t){var n=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new s.default({action:this.action(n),target:this.target(n),text:this.text(n),trigger:n,emitter:this})}},{key:"defaultAction",value:function e(t){return l("action",t)}},{key:"defaultTarget",value:function e(t){var n=l("target",t);if(n)return document.querySelector(n)}},{key:"defaultText",value:function e(t){return l("text",t)}},{key:"destroy",value:function e(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}]),t}(u.default);e.exports=h})},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)}); 7 | -------------------------------------------------------------------------------- /website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/font-awesome-4.7.0 2/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/font-awesome-4.7.0 2/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/font-awesome-4.7.0 2/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 | -------------------------------------------------------------------------------- /website/static/lib/google-plus.themes/google-plus.css: -------------------------------------------------------------------------------- 1 | .panel-google-plus { 2 | position: relative; 3 | font-family: 'Source Sans Pro', sans-serif; 4 | border-radius: 5px; 5 | border: 1px solid rgb(216, 216, 216); 6 | box-shadow: 0 1px 6px rgba(0, 0, 0, 0.175); 7 | } 8 | .panel-google-plus > .dropdown { 9 | position: absolute; 10 | top: 5px; 11 | right: 15px; 12 | } 13 | .panel-google-plus > .dropdown > span > span { 14 | font-size: 10px; 15 | } 16 | .panel-google-plus > .dropdown > .dropdown-menu { 17 | left: initial; 18 | right: 0px; 19 | border-radius: 2px; 20 | } 21 | .panel-google-plus > .panel-google-plus-tags { 22 | position: absolute; 23 | top: 35px; 24 | right: -3px; 25 | } 26 | .panel-google-plus > .panel-google-plus-tags > ul { 27 | list-style: none; 28 | padding: 0px; 29 | margin: 0px; 30 | } 31 | .panel-google-plus > .panel-google-plus-tags > ul:hover { 32 | box-shadow: 0px 0px 3px rgb(0, 0, 0); 33 | box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.25); 34 | } 35 | .panel-google-plus > .panel-google-plus-tags > ul > li { 36 | display: block; 37 | right: 0px; 38 | width: 0px; 39 | padding: 5px 0px 5px 0px; 40 | background-color: rgb(245, 245, 245); 41 | font-size: 12px; 42 | overflow: hidden; 43 | } 44 | .panel-google-plus > .panel-google-plus-tags > ul > li::after { 45 | content:""; 46 | position: absolute; 47 | top: 0px; 48 | right: 0px; 49 | height: 100%; 50 | border-right: 3px solid rgb(66, 127, 237); 51 | } 52 | .panel-google-plus > .panel-google-plus-tags > ul:hover > li, 53 | .panel-google-plus > .panel-google-plus-tags > ul > li:first-child { 54 | padding: 5px 15px 5px 10px; 55 | width: auto; 56 | cursor: pointer; 57 | margin-left: auto; 58 | } 59 | .panel-google-plus > .panel-google-plus-tags > ul:hover > li { 60 | background-color: rgb(255, 255, 255); 61 | } 62 | .panel-google-plus > .panel-google-plus-tags > ul > li:hover { 63 | background-color: rgb(66, 127, 237); 64 | color: rgb(255, 255, 255); 65 | } 66 | .panel-google-plus > .panel-request, 67 | .panel-google-plus > .panel-footer { 68 | background-color: rgb(255, 255, 255); 69 | border-width: 0px; 70 | } 71 | .panel-google-plus > .panel-request { 72 | text-align: left; 73 | margin-left: 20px; 74 | margin-top: 20px; 75 | padding-bottom: 5px; 76 | } 77 | .panel-google-plus > .panel-request > img { 78 | margin-right: 15px; 79 | } 80 | .panel-google-plus > .panel-request > .nl-request { 81 | color: rgb(96, 96, 96); 82 | margin: 0px; 83 | font-size: 16px; 84 | font-weight: 400; 85 | } 86 | .panel-google-plus > .panel-request > .post-time, 87 | .panel-google-plus > .panel-request > .post-location { 88 | color: rgb(153, 153, 153); 89 | font-size: 12px; 90 | font-weight: 400; 91 | } 92 | .panel-google-plus > .panel-body { 93 | padding-top: 5px; 94 | font-size: 13px; 95 | } 96 | .panel-google-plus > .panel-body > .panel-google-plus-image { 97 | display: block; 98 | text-align: center; 99 | background-color: rgb(245, 245, 245); 100 | border: 1px solid rgb(217, 217, 217); 101 | } 102 | .panel-google-plus > .panel-body > .panel-google-plus-image > img { 103 | max-width: 100%; 104 | } 105 | 106 | .panel-google-plus > .panel-footer { 107 | padding-top: 0px; 108 | font-size: 14px; 109 | font-weight: 700; 110 | min-height: 40px; 111 | } 112 | .panel-google-plus > .panel-footer > .btn { 113 | float: right; 114 | margin-right: 8px; 115 | } 116 | .panel-google-plus > .panel-footer > .input-placeholder { 117 | display: block; 118 | margin-left: 98px; 119 | color: rgb(153, 153, 153); 120 | font-size: 12px; 121 | font-weight: 400; 122 | padding: 8px 6px 7px; 123 | border: 1px solid rgb(217, 217, 217); 124 | border-radius: 2px; 125 | box-shadow: rgba(0, 0, 0, 0.0470588) 0px 1px 0px 0px; 126 | } 127 | .panel-google-plus.panel-google-plus-show-comment > .panel-footer > .input-placeholder { 128 | display: none; 129 | } 130 | .panel-google-plus > .panel-google-plus-comment { 131 | display: none; 132 | padding: 10px 20px 15px; 133 | border-top: 1px solid rgb(229, 229, 229); 134 | background-color: rgb(245, 245, 245); 135 | } 136 | .panel-google-plus.panel-google-plus-show-comment > .panel-google-plus-comment { 137 | display: block; 138 | } 139 | /*.panel-google-plus > .panel-google-plus-comment > img { 140 | float: left; 141 | }*/ 142 | .panel-google-plus > .panel-google-plus-comment > .panel-google-plus-textarea { 143 | float: right; 144 | width: calc(100% - 56px); 145 | } 146 | .panel-google-plus > .panel-google-plus-comment > .panel-google-plus-textarea > textarea { 147 | display: block; 148 | /*margin-left: 60px; 149 | width: calc(100% - 56px);*/ 150 | width: 100%; 151 | background-color: rgb(255, 255, 255); 152 | border: 1px solid rgb(217, 217, 217); 153 | box-shadow: rgba(0, 0, 0, 0.0470588) 0px 1px 0px 0px; 154 | resize: vertical; 155 | } 156 | .panel-google-plus > .panel-google-plus-comment > .panel-google-plus-textarea > .btn { 157 | margin-top: 10px; 158 | margin-right: 8px; 159 | width: 100%; 160 | } 161 | @media (min-width: 992px) { 162 | .panel-google-plus > .panel-google-plus-comment > .panel-google-plus-textarea > .btn { 163 | width: auto; 164 | } 165 | } 166 | 167 | .panel-google-plus .btn-default { 168 | border: 0px solid rgb(217, 217, 217); 169 | } 170 | .panel-google-plus .btn-default:hover, 171 | .panel-google-plus .btn-default:focus, 172 | .panel-google-plus .btn-default:active { 173 | background-color: rgb(255, 255, 255); 174 | /* border-color: rgb(0, 0, 0); */ 175 | color: #f48e5c 176 | } 177 | 178 | -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/agate.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Agate by Taufik Nurrohman 3 | * ---------------------------------------------------- 4 | * 5 | * #ade5fc 6 | * #a2fca2 7 | * #c6b4f0 8 | * #d36363 9 | * #fcc28c 10 | * #fc9b9b 11 | * #ffa 12 | * #fff 13 | * #333 14 | * #62c8f3 15 | * #888 16 | * 17 | */.hljs{display:block;overflow-x:auto;padding:0.5em;background:#333;color:white}.hljs-name,.hljs-strong{font-weight:bold}.hljs-code,.hljs-emphasis{font-style:italic}.hljs-tag{color:#62c8f3}.hljs-variable,.hljs-template-variable,.hljs-selector-id,.hljs-selector-class{color:#ade5fc}.hljs-string,.hljs-bullet{color:#a2fca2}.hljs-type,.hljs-title,.hljs-section,.hljs-attribute,.hljs-quote,.hljs-built_in,.hljs-builtin-name{color:#ffa}.hljs-number,.hljs-symbol,.hljs-bullet{color:#d36363}.hljs-keyword,.hljs-selector-tag,.hljs-literal{color:#fcc28c}.hljs-comment,.hljs-deletion,.hljs-code{color:#888}.hljs-regexp,.hljs-link{color:#c6b4f0}.hljs-meta{color:#fc9b9b}.hljs-deletion{background-color:#fc9b9b;color:#333}.hljs-addition{background-color:#a2fca2;color:#333}.hljs a{color:inherit}.hljs a:focus,.hljs a:hover{color:inherit;text-decoration:underline} -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/bash.js: -------------------------------------------------------------------------------- 1 | hljs.registerLanguage("bash", function(e) { 2 | var t = { 3 | cN: "variable", 4 | v: [{ 5 | b: /\$[\w\d#@][\w\d_]*/ 6 | }, { 7 | b: /\$\{(.*?)}/ 8 | }] 9 | }, 10 | s = { 11 | cN: "string", 12 | b: /"/, 13 | e: /"/, 14 | c: [e.BE, t, { 15 | cN: "variable", 16 | b: /\$\(/, 17 | e: /\)/, 18 | c: [e.BE] 19 | }] 20 | }, 21 | a = { 22 | cN: "string", 23 | b: /'/, 24 | e: /'/ 25 | }; 26 | return { 27 | aliases: ["sh", "zsh"], 28 | l: /-?[a-zA-Z0-9\.\(\)\!\\;\{\}_+-]+/, 29 | k: { 30 | keyword: "if then else elif fi for while in do done case esac function" 31 | + " -true" 32 | + " -false" 33 | + " -Bmin" 34 | + " -Bnewer" 35 | + " -Btime" 36 | + " -atime" 37 | + " -acl" 38 | + " -amin" 39 | + " -anewer" 40 | + " -cmin" 41 | + " -cnewer" 42 | + " -ctime" 43 | + " -d" 44 | + " -depth" 45 | + " -depth" 46 | + " -empty" 47 | + " -executable" 48 | + " -fstype" 49 | + " -gid" 50 | + " -group" 51 | + " -ignore_readdir_race" 52 | + " -ilname" 53 | + " -ilname" 54 | + " -iname" 55 | + " -inum" 56 | + " -ipath" 57 | + " -iregex" 58 | + " -iwholename" 59 | + " -links" 60 | + " -lname" 61 | + " -ls" 62 | + " -maxdepth" 63 | + " -mindepth" 64 | + " -mmin" 65 | + " -mnewer" 66 | + " -mount" 67 | + " -mtime" 68 | + " -name" 69 | + " -newer" 70 | + " -newerXY" 71 | + " -nogroup" 72 | + " -noignore_readdir_race" 73 | + " -noleaf" 74 | + " -nouser" 75 | + " -path" 76 | + " -perm" 77 | + " -print" 78 | + " -regex" 79 | + " -samefile" 80 | + " -size" 81 | + " -type" 82 | + " -uid" 83 | + " -user" 84 | + " -wholename" 85 | + " -xattr" 86 | + " -xattrname" 87 | + " -xi" 88 | + " -daystart" 89 | + " -xtype" 90 | + " -a" 91 | + " -b" 92 | + " -c" 93 | + " -d" 94 | + " -e" 95 | + " -f" 96 | + " -g" 97 | + " -h" 98 | + " -i" 99 | + " -j" 100 | + " -k" 101 | + " -l" 102 | + " -m" 103 | + " -n" 104 | + " -o" 105 | + " -p" 106 | + " -q" 107 | + " -r" 108 | + " -s" 109 | + " -t" 110 | + " -u" 111 | + " -v" 112 | + " -w" 113 | + " -x" 114 | + " -y" 115 | + " -z" 116 | + " -A" 117 | + " -B" 118 | + " -C" 119 | + " -D" 120 | + " -E" 121 | + " -F" 122 | + " -G" 123 | + " -H" 124 | + " -I" 125 | + " -J" 126 | + " -K" 127 | + " -L" 128 | + " -M" 129 | + " -N" 130 | + " -O" 131 | + " -P" 132 | + " -Q" 133 | + " -R" 134 | + " -S" 135 | + " -T" 136 | + " -U" 137 | + " -V" 138 | + " -W" 139 | + " -X" 140 | + " -Y" 141 | + " -Z" 142 | + " -1" 143 | + " -2" 144 | + " -3" 145 | + " -4" 146 | + " -5" 147 | + " -6" 148 | + " -7" 149 | + " -8" 150 | + " -9" 151 | + " -0", 152 | literal: "true false", 153 | built_in: "break cd continue eval exec exit export find getopts grep hash pwd readonly" 154 | + " return shift test times trap umask unset alias bind builtin caller command" 155 | + " declare echo enable help let local logout mapfile printf read readarray" 156 | + " source type typeset ulimit unalias set shopt autoload bg bindkey bye cap" 157 | + " chdir clone comparguments compcall compctl compdescribe compfiles compgroups" 158 | + " compquote comptags comptry compvalues dirs disable disown echotc echoti" 159 | + " emulate fc fg float functions getcap getln history integer jobs kill limit" 160 | + " log noglob popd print pushd pushln rehash sched setcap setopt stat suspend" 161 | + " ttyctl unfunction unhash unlimit unsetopt vared wait whence where which" 162 | + " zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket" 163 | + " zstyle ztcp rm sort head tail tar cp smv ls chmod chown chgrp wc xargs", 164 | operators: "\! \\\! -not -and -or", 165 | actions: "-detele -exec -execdir -fls -fprint -fprint0 -fprintf -ls -ok -okdir -print" 166 | + " -print0 -printf -prune -quit", 167 | special_symbols: "\\\( \\\) \\; \+", 168 | semantic_types: "File-01 File-02 File-03 File-04 File-05 File-06" 169 | + " Directory-01 Directory-02 Directory-03 Directory-04 Directory-05 Directory-06" 170 | + " Path-01 Path-02 Path-03 Path-04 Path-05 Path-06" 171 | + " Number-01 Number-02 Number-03 Number-04 Number-05 Number-06" 172 | + " Size-01 Size-02 Size-03 Size-04 Size-05 Size-06" 173 | + " Timespan-01 Timespan-02 Timespan-03 Timespan-04 Timespan-05 Timespan-06" 174 | + " Regex-01 Regex-02 Regex-03 Regex-04 Regex-05 Regex-06" 175 | + " DateTime-01 DateTime-02 DateTime-03 DateTime-04 DateTime-05 DateTime-06" 176 | + " Permission-01 Permission-02 Permission-03 Permission-04 Permission-05 Permission-06" 177 | + " Username-01 Username-02 Username-03 Username-04 Username-05 Username-06" 178 | + " Groupname-01 Groupname-02 Groupname-03 Groupname-04 Groupname-05 Groupname-06" 179 | + " File Directory Path Number Size Timespan Regex DateTime Type Option" 180 | + " Permission Username Groupname Prog" 181 | }, 182 | c: [{ 183 | cN: "meta", 184 | b: /^#![^\n]+sh\s*$/, 185 | r: 10 186 | }, { 187 | cN: "function", 188 | b: /\w[\w\d_]*\s*\(\s*\)\s*\{/, 189 | rB: !0, 190 | c: [e.inherit(e.TM, { 191 | b: /\w[\w\d_]*/ 192 | })], 193 | r: 0 194 | }, e.HCM, s, a, t] 195 | } 196 | }); 197 | -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/color-brewer.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff}.hljs,.hljs-subst{color:#000}.hljs-string,.hljs-meta,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-addition{color:#756bb1}.hljs-comment,.hljs-quote{color:#636363}.hljs-number,.hljs-regexp,.hljs-literal,.hljs-bullet,.hljs-link{color:#31a354}.hljs-deletion,.hljs-variable{color:#88f}.hljs-keyword,.hljs-selector-tag,.hljs-title,.hljs-section,.hljs-built_in,.hljs-doctag,.hljs-type,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-strong{color:#3182bd}.hljs-emphasis{font-style:italic}.hljs-attribute{color:#e6550d} -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/dracula.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#282a36}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-section,.hljs-link{color:#8be9fd}.hljs-function .hljs-keyword{color:#ff79c6}.hljs,.hljs-subst{color:#f8f8f2}.hljs-string,.hljs-title,.hljs-name,.hljs-type,.hljs-attribute,.hljs-symbol,.hljs-bullet,.hljs-addition,.hljs-variable,.hljs-template-tag,.hljs-template-variable{color:#f1fa8c}.hljs-comment,.hljs-quote,.hljs-deletion,.hljs-meta{color:#6272a4}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-title,.hljs-section,.hljs-doctag,.hljs-type,.hljs-name,.hljs-strong{font-weight:bold}.hljs-emphasis{font-style:italic} -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/github-gist.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;background:white;padding:0.5em;color:#333333;overflow-x:auto}.hljs-comment,.hljs-meta{color:#969896}.hljs-string,.hljs-variable,.hljs-template-variable,.hljs-strong,.hljs-emphasis,.hljs-quote{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-literal,.hljs-symbol,.hljs-bullet,.hljs-attribute{color:#0086b3}.hljs-section,.hljs-name{color:#63a35c}.hljs-tag{color:#333333}.hljs-title,.hljs-attr,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:#795da3}.hljs-addition{color:#55a532;background-color:#eaffea}.hljs-deletion{color:#bd2c00;background-color:#ffecec}.hljs-link{text-decoration:underline} -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/solarized-light.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#fdf6e3;color:#657b83}.hljs-comment,.hljs-quote{color:#93a1a1}.hljs-keyword,.hljs-selector-tag,.hljs-addition{color:#859900}.hljs-number,.hljs-string,.hljs-meta .hljs-meta-string,.hljs-literal,.hljs-doctag,.hljs-regexp{color:#2aa198}.hljs-title,.hljs-section,.hljs-name,.hljs-selector-id,.hljs-selector-class{color:#268bd2}.hljs-attribute,.hljs-attr,.hljs-variable,.hljs-template-variable,.hljs-class .hljs-title,.hljs-type{color:#b58900}.hljs-symbol,.hljs-bullet,.hljs-subst,.hljs-meta,.hljs-meta .hljs-keyword,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-link{color:#cb4b16}.hljs-built_in,.hljs-deletion{color:#dc322f}.hljs-formula{background:#eee8d5}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/tomorrow.css: -------------------------------------------------------------------------------- 1 | .hljs-comment, 2 | .hljs-quote { 3 | color: #8e908c 4 | } 5 | 6 | .hljs-variable, 7 | .hljs-template-variable, 8 | .hljs-tag, 9 | .hljs-name, 10 | .hljs-selector-id, 11 | .hljs-selector-class, 12 | .hljs-regexp, 13 | .hljs-deletion { 14 | color: #c82829 15 | } 16 | 17 | /* bash utilities */ 18 | .hljs-number, 19 | .hljs-built_in, 20 | .hljs-builtin-name, 21 | .hljs-literal, 22 | .hljs-type, 23 | .hljs-params, 24 | .hljs-meta, 25 | .hljs-link{ 26 | color: #f5871f 27 | } 28 | .hljs-special_symbols{ 29 | color: #66cccc 30 | } 31 | 32 | /* bash operators */ 33 | .hljs-operators { 34 | color: #ff4c4c 35 | } 36 | 37 | .hljs-string, 38 | .hljs-attribute { 39 | color: #718c00 40 | } 41 | 42 | /* bash actions */ 43 | .hljs-actions, 44 | .hljs-symbol, 45 | .hljs-bullet, 46 | .hljs-addition { 47 | color: #4271ae 48 | } 49 | 50 | .hljs-title, 51 | .hljs-section { 52 | color: #eab700 53 | } 54 | 55 | /* bash tests */ 56 | .hljs-keyword, 57 | .hljs-selector-tag { 58 | color: #8959a8 59 | } 60 | 61 | /* holes */ 62 | .hljs-semantic_types { 63 | text-decoration: underline; 64 | } 65 | 66 | .hljs { 67 | display: block; 68 | overflow-x: auto; 69 | background: #f8f8f8; 70 | color: #4d4d4c; 71 | padding: 0.5em; 72 | font-size: 12px; 73 | } 74 | 75 | .hljs-emphasis { 76 | font-style: italic 77 | } 78 | 79 | .hljs-strong { 80 | font-weight: bold 81 | } 82 | -------------------------------------------------------------------------------- /website/static/lib/hljs.themes/zenburn.css: -------------------------------------------------------------------------------- 1 | .hljs { 2 | display: block; 3 | overflow-x: auto; 4 | padding: 0.5em; 5 | background: #3f3f3f; 6 | color: #dcdcdc; 7 | font-size: 14px 8 | } 9 | .hljs-keyword, 10 | .hljs-selector-tag, 11 | .hljs-tag { 12 | color: #e3ceab 13 | } 14 | .hljs-template-tag { 15 | color: #dcdcdc 16 | } 17 | .hljs-number { 18 | color: #8cd0d3 19 | } 20 | .hljs-variable, 21 | .hljs-template-variable, 22 | .hljs-attribute { 23 | color: #efdcbc 24 | } 25 | .hljs-literal { 26 | color: #efefaf 27 | } 28 | .hljs-subst { 29 | color: #8f8f8f 30 | } 31 | .hljs-title, 32 | .hljs-name, 33 | .hljs-selector-id, 34 | .hljs-selector-class, 35 | .hljs-section, 36 | .hljs-type { 37 | color: #efef8f 38 | } 39 | .hljs-symbol, 40 | .hljs-bullet, 41 | .hljs-link { 42 | color: #dca3a3 43 | } 44 | .hljs-deletion, 45 | .hljs-string, 46 | .hljs-built_in, 47 | .hljs-builtin-name { 48 | color: #cc9393 49 | } 50 | .hljs-addition, 51 | .hljs-comment, 52 | .hljs-quote, 53 | .hljs-meta { 54 | color: #7f9f7f 55 | } 56 | .hljs-emphasis { 57 | font-style: italic 58 | } 59 | .hljs-strong { 60 | font-weight: bold 61 | } -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery-ui 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | Copyright and related rights for sample code are waived via CC0. Sample 34 | code is defined as all source code contained within the demos directory. 35 | 36 | CC0: http://creativecommons.org/publicdomain/zero/1.0/ 37 | 38 | ==== 39 | 40 | All files located in the node_modules and external directories are 41 | externally maintained libraries used by this software which have their 42 | own licenses; we recommend you read them, as their terms may differ from 43 | the terms above. 44 | -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery-ui-1.12.1.custom/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /website/static/lib/jquery-ui-1.12.1.custom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-ui", 3 | "title": "jQuery UI", 4 | "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", 5 | "version": "1.12.1", 6 | "homepage": "http://jqueryui.com", 7 | "author": { 8 | "name": "jQuery Foundation and other contributors", 9 | "url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt" 10 | }, 11 | "main": "ui/widget.js", 12 | "maintainers": [ 13 | { 14 | "name": "Scott González", 15 | "email": "scott.gonzalez@gmail.com", 16 | "url": "http://scottgonzalez.com" 17 | }, 18 | { 19 | "name": "Jörn Zaefferer", 20 | "email": "joern.zaefferer@gmail.com", 21 | "url": "http://bassistance.de" 22 | }, 23 | { 24 | "name": "Mike Sherov", 25 | "email": "mike.sherov@gmail.com", 26 | "url": "http://mike.sherov.com" 27 | }, 28 | { 29 | "name": "TJ VanToll", 30 | "email": "tj.vantoll@gmail.com", 31 | "url": "http://tjvantoll.com" 32 | }, 33 | { 34 | "name": "Felix Nagel", 35 | "email": "info@felixnagel.com", 36 | "url": "http://www.felixnagel.com" 37 | }, 38 | { 39 | "name": "Alex Schmitz", 40 | "email": "arschmitz@gmail.com", 41 | "url": "https://github.com/arschmitz" 42 | } 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git://github.com/jquery/jquery-ui.git" 47 | }, 48 | "bugs": "https://bugs.jqueryui.com/", 49 | "license": "MIT", 50 | "scripts": { 51 | "test": "grunt" 52 | }, 53 | "dependencies": {}, 54 | "devDependencies": { 55 | "commitplease": "2.3.0", 56 | "grunt": "0.4.5", 57 | "grunt-bowercopy": "1.2.4", 58 | "grunt-cli": "0.1.13", 59 | "grunt-compare-size": "0.4.0", 60 | "grunt-contrib-concat": "0.5.1", 61 | "grunt-contrib-csslint": "0.5.0", 62 | "grunt-contrib-jshint": "0.12.0", 63 | "grunt-contrib-qunit": "1.0.1", 64 | "grunt-contrib-requirejs": "0.4.4", 65 | "grunt-contrib-uglify": "0.11.1", 66 | "grunt-git-authors": "3.1.0", 67 | "grunt-html": "6.0.0", 68 | "grunt-jscs": "2.1.0", 69 | "load-grunt-tasks": "3.4.0", 70 | "rimraf": "2.5.1", 71 | "testswarm": "1.1.0" 72 | }, 73 | "keywords": [] 74 | } 75 | -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/images/sprites-meta-stackoverflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery.upvote/images/sprites-meta-stackoverflow.png -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/images/sprites-programmers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery.upvote/images/sprites-programmers.png -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/images/sprites-serverfault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery.upvote/images/sprites-serverfault.png -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/images/sprites-stackoverflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery.upvote/images/sprites-stackoverflow.png -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/images/sprites-superuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery.upvote/images/sprites-superuser.png -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/images/sprites-unix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TellinaTool/tellina/61f1398eb3c2adaad32660d9185d646ff3fcd857/website/static/lib/jquery.upvote/images/sprites-unix.png -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/jquery.upvote.css: -------------------------------------------------------------------------------- 1 | div.upvote { 2 | text-align: center; 3 | } 4 | 5 | div.upvote a.upvote-enabled { 6 | cursor: pointer; 7 | } 8 | 9 | div.upvote a { 10 | color: transparent; 11 | background-image: url('images/sprites-stackoverflow.png?v=1'); 12 | background-repeat: no-repeat; 13 | overflow: hidden; 14 | display: block; 15 | margin: 0 auto; 16 | width: 41px; 17 | height: 25px; 18 | } 19 | 20 | div.upvote span.count { 21 | display: block; 22 | font-size: 24px; 23 | font-family: Arial, Liberation, Sans, DejaVu Sans, sans-serif; 24 | color: #555; 25 | text-align: center; 26 | line-height: 1; 27 | } 28 | 29 | div.upvote a.upvote { 30 | background-position: 0px -265px; 31 | } 32 | 33 | div.upvote a.upvote.upvote-on { 34 | background-position: 0px -230px; 35 | } 36 | 37 | div.upvote a.downvote { 38 | background-position: 0px -300px; 39 | } 40 | 41 | div.upvote a.downvote.downvote-on { 42 | background-position: 0px -330px; 43 | } 44 | 45 | div.upvote a.star { 46 | width: 33px; 47 | height: 31px; 48 | background-position: 0px -150px; 49 | } 50 | 51 | div.upvote a.star.star-on { 52 | background-position: 0px -190px; 53 | } 54 | 55 | div.upvote-serverfault a { 56 | background-image: url('images/sprites-serverfault.png?v=1'); 57 | } 58 | 59 | div.upvote-meta-stackoverflow a { 60 | background-image: url('images/sprites-meta-stackoverflow.png?v=1'); 61 | } 62 | 63 | div.upvote-superuser a { 64 | background-image: url('images/sprites-superuser.png?v=1'); 65 | } 66 | 67 | div.upvote-unix a { 68 | background-image: url('images/sprites-unix.png?v=1'); 69 | width: 42px; 70 | height: 27px; 71 | } 72 | 73 | div.upvote-unix a.upvote { 74 | background-position: 0px -237px; 75 | } 76 | 77 | div.upvote-unix a.upvote.upvote-on { 78 | background-position: 0px -198px; 79 | } 80 | 81 | div.upvote-unix a.downvote { 82 | background-position: 0px -281px; 83 | } 84 | 85 | div.upvote-unix a.downvote.downvote-on { 86 | background-position: 0px -319px; 87 | } 88 | 89 | div.upvote-unix a.star { 90 | width: 42px; 91 | height: 30px; 92 | background-position: 0px -126px; 93 | } 94 | 95 | div.upvote-unix a.star.star-on { 96 | background-position: 0px -164px; 97 | } 98 | 99 | div.upvote-unix span.count { 100 | color: #333; 101 | line-height: 15px; 102 | padding: 9px 0; 103 | font-family: "DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter",monospace; 104 | text-shadow: 1px 1px 0 #ffffff; 105 | font-weight: bold; 106 | margin: 0; 107 | border: 0; 108 | vertical-align: baseline; 109 | } 110 | 111 | div.upvote-programmers a { 112 | background-image: url('images/sprites-programmers.png?v=1'); 113 | width: 42px; 114 | height: 20px; 115 | } 116 | 117 | div.upvote-programmers a.upvote { 118 | background-position: 5px -248px; 119 | } 120 | 121 | div.upvote-programmers a.upvote.upvote-on { 122 | background-position: 5px -211px; 123 | } 124 | 125 | div.upvote-programmers a.downvote { 126 | background-position: 5px -282px; 127 | } 128 | 129 | div.upvote-programmers a.downvote.downvote-on { 130 | background-position: 5px -320px; 131 | } 132 | 133 | div.upvote-programmers a.star { 134 | width: 42px; 135 | height: 30px; 136 | background-position: 6px -128px; 137 | } 138 | 139 | div.upvote-programmers a.star.star-on { 140 | background-position: 6px -166px; 141 | } 142 | 143 | div.upvote-programmers span.count { 144 | color: #333; 145 | line-height: 15px; 146 | padding: 5px 0 7px; 147 | font-size: 20px; 148 | font-weight: bold; 149 | font-family: Tahoma,Geneva,Arial,sans-serif; 150 | } -------------------------------------------------------------------------------- /website/static/lib/jquery.upvote/jquery.upvote.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Upvote - a voting plugin 3 | * ------------------------------------------------------------------ 4 | * 5 | * jQuery Upvote is a plugin that generates a voting widget like 6 | * the one used on Stack Exchange sites. 7 | * 8 | * Licensed under Creative Commons Attribution 3.0 Unported 9 | * http://creativecommons.org/licenses/by/3.0/ 10 | * 11 | * @version 1.0.2 12 | * @since 2013.06.19 13 | * @author Janos Gyerik 14 | * @homepage https://janosgyerik.github.io/jquery-upvote 15 | * @twitter twitter.com/janosgyerik 16 | * 17 | * ------------------------------------------------------------------ 18 | * 19 | *
    20 | * 21 | * 22 | * 23 | * 24 | *
    25 | * 26 | * $('#topic').upvote(); 27 | * $('#topic').upvote({count: 5, upvoted: true}); 28 | * 29 | */ 30 | 31 | ;(function($) { 32 | "use strict"; 33 | var namespace = 'upvote'; 34 | var dot_namespace = '.' + namespace; 35 | var upvote_css = 'upvote'; 36 | var dot_upvote_css = '.' + upvote_css; 37 | var upvoted_css = 'upvote-on'; 38 | var dot_upvoted_css = '.' + upvoted_css; 39 | var downvote_css = 'downvote'; 40 | var dot_downvote_css = '.' + downvote_css; 41 | var downvoted_css = 'downvote-on'; 42 | var dot_downvoted_css = '.' + downvoted_css; 43 | var star_css = 'star'; 44 | var dot_star_css = '.' + star_css; 45 | var starred_css = 'star-on'; 46 | var dot_starred_css = '.' + starred_css; 47 | var count_css = 'count'; 48 | var dot_count_css = '.' + count_css; 49 | var enabled_css = 'upvote-enabled'; 50 | 51 | function init(dom, options) { 52 | return dom.each(function() { 53 | var jqdom = $(this); 54 | methods.destroy(jqdom); 55 | 56 | var count = parseInt(jqdom.find(dot_count_css).text(), 10); 57 | count = isNaN(count) ? 0 : count; 58 | var initial = { 59 | id: jqdom.attr('data-id'), 60 | count: count, 61 | upvoted: jqdom.find(dot_upvoted_css).length, 62 | downvoted: jqdom.find(dot_downvoted_css).length, 63 | starred: jqdom.find(dot_starred_css).length, 64 | callback: function() {} 65 | }; 66 | 67 | var data = $.extend(initial, options); 68 | if (data.upvoted && data.downvoted) { 69 | data.downvoted = false; 70 | } 71 | 72 | jqdom.data(namespace, data); 73 | render(jqdom); 74 | setupUI(jqdom); 75 | }); 76 | } 77 | 78 | function setupUI(jqdom) { 79 | jqdom.find(dot_upvote_css).addClass(enabled_css); 80 | jqdom.find(dot_downvote_css).addClass(enabled_css); 81 | jqdom.find(dot_star_css).addClass(enabled_css); 82 | jqdom.find(dot_upvote_css).on('click.' + namespace, function() { 83 | jqdom.upvote('upvote'); 84 | }); 85 | jqdom.find('.downvote').on('click.' + namespace, function() { 86 | jqdom.upvote('downvote'); 87 | }); 88 | jqdom.find('.star').on('click.' + namespace, function() { 89 | jqdom.upvote('star'); 90 | }); 91 | } 92 | 93 | function _click_upvote(jqdom) { 94 | jqdom.find(dot_upvote_css).click(); 95 | } 96 | 97 | function _click_downvote(jqdom) { 98 | jqdom.find(dot_downvote_css).click(); 99 | } 100 | 101 | function _click_star(jqdom) { 102 | jqdom.find(dot_star_css).click(); 103 | } 104 | 105 | function render(jqdom) { 106 | var data = jqdom.data(namespace); 107 | jqdom.find(dot_count_css).text(data.count); 108 | if (data.upvoted) { 109 | jqdom.find(dot_upvote_css).addClass(upvoted_css); 110 | jqdom.find(dot_downvote_css).removeClass(downvoted_css); 111 | } else if (data.downvoted) { 112 | jqdom.find(dot_upvote_css).removeClass(upvoted_css); 113 | jqdom.find(dot_downvote_css).addClass(downvoted_css); 114 | } else { 115 | jqdom.find(dot_upvote_css).removeClass(upvoted_css); 116 | jqdom.find(dot_downvote_css).removeClass(downvoted_css); 117 | } 118 | if (data.starred) { 119 | jqdom.find(dot_star_css).addClass(starred_css); 120 | } else { 121 | jqdom.find(dot_star_css).removeClass(starred_css); 122 | } 123 | } 124 | 125 | function callback(jqdom) { 126 | var data = jqdom.data(namespace); 127 | data.callback(data); 128 | } 129 | 130 | function upvote(jqdom) { 131 | var data = jqdom.data(namespace); 132 | if (data.upvoted) { 133 | data.upvoted = false; 134 | --data.count; 135 | } else { 136 | data.upvoted = true; 137 | ++data.count; 138 | if (data.downvoted) { 139 | data.downvoted = false; 140 | ++data.count; 141 | } 142 | } 143 | render(jqdom); 144 | callback(jqdom); 145 | return jqdom; 146 | } 147 | 148 | function downvote(jqdom) { 149 | var data = jqdom.data(namespace); 150 | if (data.downvoted) { 151 | data.downvoted = false; 152 | ++data.count; 153 | } else { 154 | data.downvoted = true; 155 | --data.count; 156 | if (data.upvoted) { 157 | data.upvoted = false; 158 | --data.count; 159 | } 160 | } 161 | render(jqdom); 162 | callback(jqdom); 163 | return jqdom; 164 | } 165 | 166 | function star(jqdom) { 167 | var data = jqdom.data(namespace); 168 | data.starred = ! data.starred; 169 | render(jqdom); 170 | callback(jqdom); 171 | return jqdom; 172 | } 173 | 174 | function count(jqdom) { 175 | return jqdom.data(namespace).count; 176 | } 177 | 178 | function upvoted(jqdom) { 179 | return jqdom.data(namespace).upvoted; 180 | } 181 | 182 | function downvoted(jqdom) { 183 | return jqdom.data(namespace).downvoted; 184 | } 185 | 186 | function starred(jqdom) { 187 | return jqdom.data(namespace).starred; 188 | } 189 | 190 | var methods = { 191 | init: init, 192 | count: count, 193 | upvote: upvote, 194 | upvoted: upvoted, 195 | downvote: downvote, 196 | downvoted: downvoted, 197 | starred: starred, 198 | star: star, 199 | _click_upvote: _click_upvote, 200 | _click_downvote: _click_downvote, 201 | _click_star: _click_star, 202 | destroy: destroy 203 | }; 204 | 205 | function destroy(jqdom) { 206 | return jqdom.each(function() { 207 | $(window).unbind(dot_namespace); 208 | $(this).removeClass(enabled_css); 209 | $(this).removeData(namespace); 210 | }); 211 | } 212 | 213 | $.fn.upvote = function(method) { 214 | var args; 215 | if (methods[method]) { 216 | args = Array.prototype.slice.call(arguments, 1); 217 | args.unshift(this); 218 | return methods[method].apply(this, args); 219 | } 220 | if (typeof method === 'object' || ! method) { 221 | args = Array.prototype.slice.call(arguments); 222 | args.unshift(this); 223 | return methods.init.apply(this, args); 224 | } 225 | $.error('Method ' + method + ' does not exist on jQuery.upvote'); 226 | }; 227 | })(jQuery); 228 | -------------------------------------------------------------------------------- /website/utils.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import socket 3 | import ssl 4 | import time 5 | import urllib 6 | 7 | from django.core.exceptions import ObjectDoesNotExist 8 | from django.http import JsonResponse 9 | from website.models import NL, Command, Tag, URL 10 | 11 | sys.path.append(os.path.join( 12 | os.path.dirname(__file__), "..", "tellina_learning_module")) 13 | 14 | from bashlint import data_tools 15 | 16 | 17 | # Number of translations to show 18 | NUM_TRANSLATIONS = 20 19 | 20 | 21 | def extract_html(url): 22 | hypothes_prefix = "https://via.hypothes.is/" 23 | try: 24 | time.sleep(0.1) 25 | html = urllib.request.urlopen(hypothes_prefix + url, timeout=2) 26 | except urllib.error.URLError: 27 | print("Error: extract_text_from_url() urllib2.URLError") 28 | # return "", randomstr(180) 29 | return None, None 30 | except socket.timeout: 31 | print("Error: extract_text_from_url() socket.timeout") 32 | # return "", randomstr(180) 33 | return None, None 34 | except ssl.SSLError: 35 | print("Error: extract_text_from_url() ssl.SSLError") 36 | # return "", randomstr(180) 37 | return None, None 38 | return html.read() 39 | 40 | def get_nl(nl_str): 41 | nl, _ = NL.objects.get_or_create(str=nl_str.strip()) 42 | return nl 43 | 44 | def get_command(command_str): 45 | command_str=command_str.strip() 46 | if Command.objects.filter(str=command_str).exists(): 47 | cmd = Command.objects.get(str=command_str) 48 | else: 49 | cmd = Command.objects.create(str=command_str) 50 | ast = data_tools.bash_parser(command_str) 51 | for utility in data_tools.get_utilities(ast): 52 | cmd.tags.add(get_tag(utility)) 53 | template = data_tools.ast2template( 54 | ast, loose_constraints=True) 55 | cmd.template = template 56 | cmd.save() 57 | return cmd 58 | 59 | def get_tag(tag_str): 60 | tag, _ = Tag.objects.get_or_create(str=tag_str.strip()) 61 | return tag 62 | 63 | def get_url(url_str): 64 | url_str = url_str.strip() 65 | try: 66 | url = URL.objects.get(str=url_str) 67 | except ObjectDoesNotExist: 68 | html = extract_html(url_str) 69 | if html is None: 70 | url = URL.objects.create(str=url_str) 71 | else: 72 | url = URL.objects.create(str=url_str, html_content=html) 73 | return url 74 | 75 | def json_response(d={}, status='SUCCESS'): 76 | d.update({'status': status}) 77 | resp = JsonResponse(d) 78 | return resp 79 | --------------------------------------------------------------------------------