Showing preview only (7,018K chars total). Download the full file or copy to clipboard to get everything.
Repository: kootenpv/TwitterQA
Branch: master
Commit: 733bb025d4f6
Files: 71
Total size: 39.7 MB
Directory structure:
gitextract_kes89e0b/
├── .gitignore
├── LICENSE
├── README.md
├── chatbot/
│ ├── __init__.py
│ ├── chatbot.py
│ ├── cornelldata.py
│ ├── model.py
│ ├── textdata.py
│ ├── trainner.py
│ ├── twitter_generate_data_pickle.py
│ ├── twitter_get_access_token.py
│ └── twitter_qa.py
├── chatbot_website/
│ ├── .gitignore
│ ├── chatbot_interface/
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── chatbotmanager.py
│ │ ├── consumer.py
│ │ ├── migrations/
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── routing.py
│ │ ├── static/
│ │ │ ├── LICENSE.txt
│ │ │ ├── README.txt
│ │ │ ├── assets/
│ │ │ │ ├── css/
│ │ │ │ │ ├── ie8.css
│ │ │ │ │ ├── ie9.css
│ │ │ │ │ ├── main.css
│ │ │ │ │ └── noscript.css
│ │ │ │ ├── fonts/
│ │ │ │ │ └── FontAwesome.otf
│ │ │ │ ├── js/
│ │ │ │ │ ├── PIE.htc
│ │ │ │ │ └── html5shiv.js
│ │ │ │ └── sass/
│ │ │ │ ├── base/
│ │ │ │ │ ├── _page.scss
│ │ │ │ │ └── _typography.scss
│ │ │ │ ├── components/
│ │ │ │ │ ├── _button.scss
│ │ │ │ │ ├── _form.scss
│ │ │ │ │ ├── _icon.scss
│ │ │ │ │ └── _list.scss
│ │ │ │ ├── ie8.scss
│ │ │ │ ├── ie9.scss
│ │ │ │ ├── layout/
│ │ │ │ │ ├── _footer.scss
│ │ │ │ │ ├── _main.scss
│ │ │ │ │ └── _wrapper.scss
│ │ │ │ ├── libs/
│ │ │ │ │ ├── _functions.scss
│ │ │ │ │ ├── _mixins.scss
│ │ │ │ │ ├── _skel.scss
│ │ │ │ │ └── _vars.scss
│ │ │ │ ├── main.scss
│ │ │ │ └── noscript.scss
│ │ │ └── js/
│ │ │ ├── chat.js
│ │ │ └── reconnecting-websocket.js
│ │ ├── templates/
│ │ │ └── index.html
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── chatbot_website/
│ │ ├── __init__.py
│ │ ├── asgi.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── logs/
│ │ └── .gitignore
│ └── manage.py
├── data/
│ ├── cornell/
│ │ ├── README.txt
│ │ ├── movie_conversations.txt
│ │ └── movie_lines.txt
│ ├── samples/
│ │ └── .gitignore
│ ├── test/
│ │ └── samples.txt
│ └── tweets/
│ └── README.md
├── main.py
├── requirements.txt
├── save/
│ └── .gitignore
├── setup_server.sh
└── testsuite.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# PyCharm files
.idea/
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
# twitter cred
chatbot/credentials.json
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Deep Twitter Q&A
## Introduction
Have you ever wanted to know how someone special would reply on Twitter? Train a model on their twitter data.
This repository has adapted [Conchylicultor/DeepQA](https://github.com/Conchylicultor/DeepQA) to specifically ONLY work with tweets.
Note that by default scraping Twitter and using their API will only yield you a maximum of 3200 tweets; most likely less.
Twitter data will be collected by using the Twitter API. More specifically, all the answers of the person of interest in respond to questions is what the model will be trained on.
If there are companies out there who would like to have a custom QA application, feel free to contact me.
## Usage
Fill in twitter credentials in `chatbot/credentials.json`.
Then you can run:
python main.py --twitter_name gvanrossum
to build a model after the BDFL.
... 20 minutes later ...
Run
python main.py --twitter_name gvanrossum --test interactive
to have an interactive QA session with Guido.
## Example
Question asked after having trained on default settings:
Q: which editor do you use ?
A: emacs of course !
## Twitter data
You can see the collected twitter data at:
data/tweets/<username>-answers.txt
data/tweets/<username>-questions.txt
## Installation (quoting Conchylicultor)
The program requires the following dependencies (easy to install using pip):
* python 3.5
* tensorflow (tested with v0.9.0 and v0.11.0)
* numpy
* CUDA (for using gpu, see TensorFlow [installation page](https://www.tensorflow.org/versions/master/get_started/os_setup.html#optional-install-cuda-gpus-on-linux) for more details)
* nltk (natural language toolkit for tokenized the sentences)
* tqdm (for the nice progression bars)
## Further instructions
You're advised to experiment with the possible paramters to make it a better model.
Have a look at the [original repo](https://github.com/Conchylicultor/DeepQA) for more information.
================================================
FILE: chatbot/__init__.py
================================================
__all__ = ["chatbot"]
================================================
FILE: chatbot/chatbot.py
================================================
#!/usr/bin/env python3
# Copyright 2015 Conchylicultor. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
Main script. See README.md for more information
Use python 3
"""
import argparse # Command line parsing
import configparser # Saving the models parameters
import datetime # Chronometer
import os # Files management
from tqdm import tqdm # Progress bar
import tensorflow as tf
from chatbot.textdata import TextData
from chatbot.model import Model
class Chatbot:
"""
Main class which launch the training or testing mode
"""
class TestMode:
""" Simple structure representing the different testing modes
"""
ALL = 'all'
INTERACTIVE = 'interactive' # The user can write his own questions
DAEMON = 'daemon' # The chatbot runs on background and can regularly be called to predict something
def __init__(self):
"""
"""
# Model/dataset parameters
self.args = None
# Task specific object
self.textData = None # Dataset
self.model = None # Sequence to sequence model
# Tensorflow utilities for convenience saving/logging
self.writer = None
self.saver = None
self.modelDir = '' # Where the model is saved
self.globStep = 0 # Represent the number of iteration for the current model
# TensorFlow main session (we keep track for the daemon)
self.sess = None
# Filename and directories constants
self.MODEL_DIR_BASE = 'save/model'
self.MODEL_NAME_BASE = 'model'
self.MODEL_EXT = '.ckpt'
self.CONFIG_FILENAME = 'params.ini'
self.CONFIG_VERSION = '0.2'
self.TEST_IN_NAME = 'data/test/samples.txt'
self.TEST_OUT_SUFFIX = '_predictions.txt'
self.SENTENCES_PREFIX = ['Q: ', 'A: ']
@staticmethod
def parseArgs(args):
"""
Parse the arguments from the given command line
Args:
args (list<str>): List of arguments to parse. If None, the default sys.argv will be parsed
"""
parser = argparse.ArgumentParser()
# Global options
globalArgs = parser.add_argument_group('Global options')
globalArgs.add_argument('--test',
nargs='?',
choices=[Chatbot.TestMode.ALL,
Chatbot.TestMode.INTERACTIVE, Chatbot.TestMode.DAEMON],
const=Chatbot.TestMode.ALL, default=None,
help='if present, launch the program try to answer all sentences from data/test/ with'
' the defined model(s), in interactive mode, the user can wrote his own sentences,'
' use daemon mode to integrate the chatbot in another program')
globalArgs.add_argument('--createDataset', action='store_true',
help='if present, the program will only generate the dataset from the corpus (no training/testing)')
globalArgs.add_argument('--playDataset', type=int, nargs='?', const=10, default=None,
help='if set, the program will randomly play some samples(can be use conjointly with createDataset if this is the only action you want to perform)')
globalArgs.add_argument('--reset', action='store_true',
help='use this if you want to ignore the previous model present on the model directory (Warning: the model will be destroyed with all the folder content)')
globalArgs.add_argument('--verbose', action='store_true',
help='When testing, will plot the outputs at the same time they are computed')
# TODO: Add an option to delimit the max size
globalArgs.add_argument('--keepAll', action='store_true',
help='If this option is set, all saved model will be keep (Warning: make sure you have enough free disk space or increase saveEvery)')
globalArgs.add_argument('--modelTag', type=str, default=None,
help='tag to differentiate which model to store/load')
globalArgs.add_argument('--rootDir', type=str, default=None,
help='folder where to look for the models and data')
globalArgs.add_argument('--watsonMode', action='store_true',
help='Inverse the questions and answer when training (the network try to guess the question)')
globalArgs.add_argument('--device', type=str, default=None,
help='\'gpu\' or \'cpu\' (Warning: make sure you have enough free RAM), allow to choose on which hardware run the model')
globalArgs.add_argument('--seed', type=int, default=None,
help='random seed for replication')
# Dataset options
datasetArgs = parser.add_argument_group('Dataset options')
datasetArgs.add_argument('--twitter_name', type=str, required=True,
help='Name of twitter account to download/use data from')
datasetArgs.add_argument('--max_tweets', type=int, default=3200,
help='Number of tweets to use at most')
datasetArgs.add_argument('--corpus', type=str, default='cornell',
help='corpus on which extract the dataset. Only one corpus available right now (Cornell)')
# The samples are computed from the corpus if it does not exist already.
# There are saved in \'data/samples/\'
datasetArgs.add_argument('--datasetTag', type=str, default=None,
help='add a tag to the dataset (file where to load the vocabulary and the precomputed samples, not the original corpus). Useful to manage multiple versions')
datasetArgs.add_argument('--ratioDataset', type=float, default=1.0,
help='ratio of dataset used to avoid using the whole dataset') # Not implemented, useless ?
datasetArgs.add_argument('--maxLength', type=int, default=10,
help='maximum length of the sentence (for input and output), define number of maximum step of the RNN')
# Network options (Warning: if modifying something here, also make the
# change on save/loadParams() )
nnArgs = parser.add_argument_group('Network options', 'architecture related option')
nnArgs.add_argument('--hiddenSize', type=int, default=256,
help='number of hidden units in each RNN cell')
nnArgs.add_argument('--numLayers', type=int, default=2, help='number of rnn layers')
nnArgs.add_argument('--embeddingSize', type=int, default=32,
help='embedding size of the word representation')
# Training options
trainingArgs = parser.add_argument_group('Training options')
trainingArgs.add_argument('--numEpochs', type=int, default=30,
help='maximum number of epochs to run')
trainingArgs.add_argument('--saveEvery', type=int, default=1000,
help='nb of mini-batch step before creating a model checkpoint')
trainingArgs.add_argument('--batchSize', type=int, default=10, help='mini-batch size')
trainingArgs.add_argument('--learningRate', type=float,
default=0.001, help='Learning rate')
return parser.parse_args(args)
def main(self, args=None):
"""
Launch the training and/or the interactive mode
"""
print('Welcome to DeepQA v0.1 !')
print()
print('TensorFlow detected: v{}'.format(tf.__version__))
# General initialisation
self.args = self.parseArgs(args)
if not self.args.rootDir:
self.args.rootDir = os.getcwd() # Use the current working directory
# tf.logging.set_verbosity(tf.logging.INFO) # DEBUG, INFO, WARN (default), ERROR, or FATAL
self.loadModelParams() # Update the self.modelDir and self.globStep, for now, not used when loading Model (but need to be called before _getSummaryName)
self.textData = TextData(self.args)
# TODO: Add a mode where we can force the input of the decoder // Try to visualize the predictions for
# each word of the vocabulary / decoder input
# TODO: For now, the model are trained for a specific dataset (because of the maxLength which define the
# vocabulary). Add a compatibility mode which allow to launch a model trained on a different vocabulary (
# remap the word2id/id2word variables).
if self.args.createDataset:
print('Dataset created! Thanks for using this program')
return # No need to go further
with tf.device(self.getDevice()):
self.model = Model(self.args, self.textData)
# Saver/summaries
self.writer = tf.train.SummaryWriter(self._getSummaryName())
self.saver = tf.train.Saver(max_to_keep=200) # Arbitrary limit ?
# TODO: Fixed seed (WARNING: If dataset shuffling, make sure to do that after saving the
# dataset, otherwise, all which cames after the shuffling won't be replicable when
# reloading the dataset). How to restore the seed after loading ??
# Also fix seed for random.shuffle (does it works globally for all files ?)
# Running session
self.sess = tf.Session() # TODO: Replace all sess by self.sess (not necessary a good idea) ?
print('Initialize variables...')
self.sess.run(tf.initialize_all_variables())
# Reload the model eventually (if it exist.), on testing mode, the models
# are not loaded here (but in predictTestset)
if self.args.test != Chatbot.TestMode.ALL:
self.managePreviousModel(self.sess)
if self.args.test:
# TODO: For testing, add a mode where instead taking the most likely output after the <go> token,
# takes the second or third so it generates new sentences for the same input. Difficult to implement,
# probably have to modify the TensorFlow source code
if self.args.test == Chatbot.TestMode.INTERACTIVE:
self.mainTestInteractive(self.sess)
elif self.args.test == Chatbot.TestMode.ALL:
print('Start predicting...')
self.predictTestset(self.sess)
print('All predictions done')
elif self.args.test == Chatbot.TestMode.DAEMON:
print('Daemon mode, running in background...')
else:
raise RuntimeError('Unknown test mode: {}'.format(
self.args.test)) # Should never happen
else:
self.mainTrain(self.sess)
if self.args.test != Chatbot.TestMode.DAEMON:
self.sess.close()
print("The End! Thanks for using this program")
def mainTrain(self, sess):
""" Training loop
Args:
sess: The current running session
"""
# Specific training dependent loading
self.textData.makeLighter(self.args.ratioDataset) # Limit the number of training samples
# Define the summary operator (Warning: Won't appear on the tensorboard graph)
mergedSummaries = tf.merge_all_summaries()
if self.globStep == 0: # Not restoring from previous run
self.writer.add_graph(sess.graph) # First time only
# If restoring a model, restore the progression bar ? and current batch ?
print('Start training (press Ctrl+C to save and exit)...')
try: # If the user exit while training, we still try to save the model
for e in range(self.args.numEpochs):
print()
print("----- Epoch {}/{} ; (lr={}) -----".format(e +
1, self.args.numEpochs, self.args.learningRate))
batches = self.textData.getBatches()
# TODO: Also update learning parameters eventually
tic = datetime.datetime.now()
for nextBatch in tqdm(batches, desc="Training"):
# Training pass
ops, feedDict = self.model.step(nextBatch)
assert len(ops) == 2 # training, loss
_, loss, summary = sess.run(ops + (mergedSummaries,), feedDict)
self.writer.add_summary(summary, self.globStep)
self.globStep += 1
# Checkpoint
if self.globStep % self.args.saveEvery == 0:
self._saveSession(sess)
toc = datetime.datetime.now()
# Warning: Will overflow if an epoch takes more than 24 hours, and the
# output isn't really nicer
print("Epoch finished in {}".format(toc - tic))
except (KeyboardInterrupt, SystemExit): # If the user press Ctrl+C while testing progress
print('Interruption detected, exiting the program...')
self._saveSession(sess) # Ultimate saving before complete exit
def predictTestset(self, sess):
""" Try predicting the sentences from the samples.txt file.
The sentences are saved on the modelDir under the same name
Args:
sess: The current running session
"""
# Loading the file to predict
with open(os.path.join(self.args.rootDir, self.TEST_IN_NAME), 'r') as f:
lines = f.readlines()
modelList = self._getModelList()
if not modelList:
print('Warning: No model found in \'{}\'. Please train a model before trying to predict'.format(
self.modelDir))
return
# Predicting for each model present in modelDir
for modelName in sorted(modelList): # TODO: Natural sorting
print('Restoring previous model from {}'.format(modelName))
self.saver.restore(sess, modelName)
print('Testing...')
# We remove the model extension and add the prediction suffix
saveName = modelName[:-len(self.MODEL_EXT)] + self.TEST_OUT_SUFFIX
with open(saveName, 'w') as f:
nbIgnored = 0
for line in tqdm(lines, desc='Sentences'):
question = line[:-1] # Remove the endl character
answer = self.singlePredict(question)
if not answer:
nbIgnored += 1
continue # Back to the beginning, try again
predString = '{x[0]}{0}\n{x[1]}{1}\n\n'.format(
question, self.textData.sequence2str(answer, clean=True), x=self.SENTENCES_PREFIX)
if self.args.verbose:
tqdm.write(predString)
f.write(predString)
print('Prediction finished, {}/{} sentences ignored (too long)'.format(nbIgnored, len(lines)))
def mainTestInteractive(self, sess):
""" Try predicting the sentences that the user will enter in the console
Args:
sess: The current running session
"""
# TODO: If verbose mode, also show similar sentences from the training set with the same words (include in mainTest also)
# TODO: Also show the top 10 most likely predictions for each predicted output (when verbose mode)
# TODO: Log the questions asked for latter re-use (merge with test/samples.txt)
print('Testing: Launch interactive mode:')
print('')
print('Welcome to the interactive mode, here you can ask to Deep Q&A the sentence you want. Don\'t have high '
'expectation. Type \'exit\' or just press ENTER to quit the program. Have fun.')
while True:
question = input(self.SENTENCES_PREFIX[0])
if question == '' or question == 'exit':
break
questionSeq = [] # Will be contain the question as seen by the encoder
answer = self.singlePredict(question, questionSeq)
if not answer:
print('Warning: sentence too long, sorry. Maybe try a simpler sentence.')
continue # Back to the beginning, try again
print('{}{}'.format(self.SENTENCES_PREFIX[
1], self.textData.sequence2str(answer, clean=True)))
if self.args.verbose:
print(self.textData.batchSeq2str(questionSeq, clean=True, reverse=True))
print(self.textData.sequence2str(answer))
print()
def singlePredict(self, question, questionSeq=None):
""" Predict the sentence
Args:
question (str): the raw input sentence
questionSeq (List<int>): output argument. If given will contain the input batch sequence
Return:
list <int>: the word ids corresponding to the answer
"""
# Create the input batch
batch = self.textData.sentence2enco(question)
if not batch:
return None
if questionSeq is not None: # If the caller want to have the real input
questionSeq.extend(batch.encoderSeqs)
# Run the model
ops, feedDict = self.model.step(batch)
output = self.sess.run(ops[0], feedDict) # TODO: Summarize the output too (histogram, ...)
answer = self.textData.deco2sentence(output)
return answer
def daemonPredict(self, sentence):
""" Return the answer to a given sentence (same as singlePredict() but with additional cleaning)
Args:
sentence (str): the raw input sentence
Return:
str: the human readable sentence
"""
return self.textData.sequence2str(
self.singlePredict(sentence),
clean=True
)
def daemonClose(self):
""" A utility function to close the daemon when finish
"""
print('Exiting the daemon mode...')
self.sess.close()
print('Daemon closed.')
def managePreviousModel(self, sess):
""" Restore or reset the model, depending of the parameters
If the destination directory already contains some file, it will handle the conflict as following:
* If --reset is set, all present files will be removed (warning: no confirmation is asked) and the training
restart from scratch (globStep & cie reinitialized)
* Otherwise, it will depend of the directory content. If the directory contains:
* No model files (only summary logs): works as a reset (restart from scratch)
* Other model files, but modelName not found (surely keepAll option changed): raise error, the user should
decide by himself what to do
* The right model file (eventually some other): no problem, simply resume the training
In any case, the directory will exist as it has been created by the summary writer
Args:
sess: The current running session
"""
print('WARNING: ', end='')
modelName = self._getModelName()
if os.listdir(self.modelDir):
if self.args.reset:
print('Reset: Destroying previous model at {}'.format(self.modelDir))
# Analysing directory content
elif os.path.exists(modelName): # Restore the model
print('Restoring previous model from {}'.format(modelName))
# Will crash when --reset is not activated and the model has not been saved yet
self.saver.restore(sess, modelName)
print('Model restored.')
elif self._getModelList():
print('Conflict with previous models.')
raise RuntimeError(
'Some models are already present in \'{}\'. You should check them first (or re-try with the keepAll flag)'.format(self.modelDir))
else: # No other model to conflict with (probably summary files)
print('No previous model found, but some files found at {}. Cleaning...'.format(
self.modelDir)) # Warning: No confirmation asked
self.args.reset = True
if self.args.reset:
fileList = [os.path.join(self.modelDir, f) for f in os.listdir(self.modelDir)]
for f in fileList:
print('Removing {}'.format(f))
os.remove(f)
else:
print('No previous model found, starting from clean directory: {}'.format(self.modelDir))
def _saveSession(self, sess):
""" Save the model parameters and the variables
Args:
sess: the current session
"""
tqdm.write('Checkpoint reached: saving model (don\'t stop the run)...')
self.saveModelParams()
# TODO: Put a limit size (ex: 3GB for the modelDir)
self.saver.save(sess, self._getModelName())
tqdm.write('Model saved.')
def _getModelList(self):
""" Return the list of the model files inside the model directory
"""
return [os.path.join(self.modelDir, f) for f in os.listdir(self.modelDir) if f.endswith(self.MODEL_EXT)]
def loadModelParams(self):
""" Load the some values associated with the current model, like the current globStep value
For now, this function does not need to be called before loading the model (no parameters restored). However,
the modelDir name will be initialized here so it is required to call this function before managePreviousModel(),
_getModelName() or _getSummaryName()
Warning: if you modify this function, make sure the changes mirror saveModelParams, also check if the parameters
should be reset in managePreviousModel
"""
# Compute the current model path
self.modelDir = os.path.join(
self.args.rootDir, self.MODEL_DIR_BASE, self.args.twitter_name)
if self.args.modelTag:
self.modelDir += '-' + self.args.modelTag
# If there is a previous model, restore some parameters
configName = os.path.join(self.modelDir, self.CONFIG_FILENAME)
if not self.args.reset and not self.args.createDataset and os.path.exists(configName):
# Loading
config = configparser.ConfigParser()
config.read(configName)
# Check the version
currentVersion = config['General'].get('version')
if currentVersion != self.CONFIG_VERSION:
raise UserWarning('Present configuration version {0} does not match {1}. You can try manual changes on \'{2}\''.format(
currentVersion, self.CONFIG_VERSION, configName))
# Restoring the the parameters
self.globStep = config['General'].getint('globStep')
# We need to restore the model length because of the textData associated
# and the vocabulary size (TODO: Compatibility mode between different
# maxLength)
self.args.maxLength = config['General'].getint('maxLength')
self.args.watsonMode = config['General'].getboolean('watsonMode')
#self.args.datasetTag = config['General'].get('datasetTag')
self.args.hiddenSize = config['Network'].getint('hiddenSize')
self.args.numLayers = config['Network'].getint('numLayers')
self.args.embeddingSize = config['Network'].getint('embeddingSize')
# No restoring for training params, batch size or other non model dependent parameters
# Show the restored params
print()
print('Warning: Restoring parameters:')
print('globStep: {}'.format(self.globStep))
print('maxLength: {}'.format(self.args.maxLength))
print('watsonMode: {}'.format(self.args.watsonMode))
print('hiddenSize: {}'.format(self.args.hiddenSize))
print('numLayers: {}'.format(self.args.numLayers))
print('embeddingSize: {}'.format(self.args.embeddingSize))
print()
# For now, not arbitrary independent maxLength between encoder and decoder
self.args.maxLengthEnco = self.args.maxLength
self.args.maxLengthDeco = self.args.maxLength + 2
if self.args.watsonMode:
self.SENTENCES_PREFIX.reverse()
def saveModelParams(self):
""" Save the params of the model, like the current globStep value
Warning: if you modify this function, make sure the changes mirror loadModelParams
"""
config = configparser.ConfigParser()
config['General'] = {}
config['General']['version'] = self.CONFIG_VERSION
config['General']['globStep'] = str(self.globStep)
config['General']['maxLength'] = str(self.args.maxLength)
config['General']['watsonMode'] = str(self.args.watsonMode)
config['Network'] = {}
config['Network']['hiddenSize'] = str(self.args.hiddenSize)
config['Network']['numLayers'] = str(self.args.numLayers)
config['Network']['embeddingSize'] = str(self.args.embeddingSize)
# Keep track of the learning params (but without restoring them)
config['Training (won\'t be restored)'] = {}
config['Training (won\'t be restored)']['learningRate'] = str(self.args.learningRate)
config['Training (won\'t be restored)']['batchSize'] = str(self.args.batchSize)
with open(os.path.join(self.modelDir, self.CONFIG_FILENAME), 'w') as configFile:
config.write(configFile)
def _getSummaryName(self):
""" Parse the argument to decide were to save the summary, at the same place that the model
The folder could already contain logs if we restore the training, those will be merged
Return:
str: The path and name of the summary
"""
return self.modelDir
def _getModelName(self):
""" Parse the argument to decide were to save/load the model
This function is called at each checkpoint and the first time the model is load. If keepAll option is set, the
globStep value will be included in the name.
Return:
str: The path and name were the model need to be saved
"""
modelName = os.path.join(self.modelDir, self.MODEL_NAME_BASE)
if self.args.keepAll: # We do not erase the previously saved model by including the current step on the name
modelName += '-' + str(self.globStep)
return modelName + self.MODEL_EXT
def getDevice(self):
""" Parse the argument to decide on which device run the model
Return:
str: The name of the device on which run the program
"""
if self.args.device == 'cpu':
return '/cpu:0'
elif self.args.device == 'gpu':
return '/gpu:0'
elif self.args.device is None: # No specified device (default)
return None
else:
print('Warning: Error in the device name: {}, use the default device'.format(self.args.device))
return None
================================================
FILE: chatbot/cornelldata.py
================================================
#!/usr/bin/env python3
# Copyright 2015 Conchylicultor. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
Load the cornell movie dialog corpus.
Available from here:
http://www.cs.cornell.edu/~cristian/Cornell_Movie-Dialogs_Corpus.html
"""
class CornellData:
"""
"""
def __init__(self, dirName):
"""
Args:
dirName (string): directory where to load the corpus
"""
self.lines = {}
self.conversations = []
MOVIE_LINES_FIELDS = ["lineID","characterID","movieID","character","text"]
MOVIE_CONVERSATIONS_FIELDS = ["character1ID","character2ID","movieID","utteranceIDs"]
self.lines = self.loadLines(dirName + "movie_lines.txt", MOVIE_LINES_FIELDS)
self.conversations = self.loadConversations(dirName + "movie_conversations.txt", MOVIE_CONVERSATIONS_FIELDS)
# TODO: Cleaner program (merge copy-paste) !!
def loadLines(self, fileName, fields):
"""
Args:
fileName (str): file to load
field (set<str>): fields to extract
Return:
dict<dict<str>>: the extracted fields for each line
"""
lines = {}
with open(fileName, 'r', encoding='iso-8859-1') as f: # TODO: Solve Iso encoding pb !
for line in f:
values = line.split(" +++$+++ ")
# Extract fields
lineObj = {}
for i, field in enumerate(fields):
lineObj[field] = values[i]
lines[lineObj['lineID']] = lineObj
return lines
def loadConversations(self, fileName, fields):
"""
Args:
fileName (str): file to load
field (set<str>): fields to extract
Return:
dict<dict<str>>: the extracted fields for each line
"""
conversations = []
with open(fileName, 'r', encoding='iso-8859-1') as f: # TODO: Solve Iso encoding pb !
for line in f:
values = line.split(" +++$+++ ")
# Extract fields
convObj = {}
for i, field in enumerate(fields):
convObj[field] = values[i]
lineIds = convObj["utteranceIDs"][2:-3].split("', '")
#print(convObj["utteranceIDs"])
#for lineId in lineIds:
#print(lineId, end=' ')
#print()
# Reassemble lines
convObj["lines"] = []
for lineId in lineIds:
convObj["lines"].append(self.lines[lineId])
conversations.append(convObj)
return conversations
def getConversations(self):
return self.conversations
================================================
FILE: chatbot/model.py
================================================
#!/usr/bin/env python3
# Copyright 2015 Conchylicultor. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
Model to predict the next sentence given an input sequence
"""
import tensorflow as tf
from chatbot.textdata import Batch
class Model:
"""
Implementation of a seq2seq model.
Achitecture:
2 LTSM layers
"""
def __init__(self, args, textData):
"""
Args:
args: parametters of the model
textData: the dataset object
"""
print("Model creation...")
self.textData = textData # Keep a reference on the dataset
self.args = args # Keep track of the parameters of the model
# Placeholders
self.encoderInputs = None
self.decoderInputs = None # Same that decoderTarget plus the <go>
self.decoderTargets = None
self.decoderWeights = None # Adjust the learning to the target sentence size
# Main operators
self.lossFct = None
self.optOp = None
self.outputs = None # Outputs of the network, list of probability for each words
# Construct the graphs
self.buildNetwork()
def buildNetwork(self):
""" Create the computational graph
"""
# TODO: Create name_scopes (for better graph visualisation)
# TODO: Use buckets (better perfs)
# Creation of the rnn cell
with tf.variable_scope("chatbot_cell"): # TODO: How to make this appear on the graph ?
encoDecoCell = tf.nn.rnn_cell.BasicLSTMCell(
self.args.hiddenSize, state_is_tuple=True) # Or GRUCell, LSTMCell(args.hiddenSize)
# encoDecoCell = tf.nn.rnn_cell.DropoutWrapper(encoDecoCell,
# input_keep_prob=1.0, output_keep_prob=1.0) # TODO: Custom values
# (WARNING: No dropout when testing !!!)
encoDecoCell = tf.nn.rnn_cell.MultiRNNCell(
[encoDecoCell] * self.args.numLayers, state_is_tuple=True)
# Network input (placeholders)
with tf.name_scope('placeholder_encoder'):
self.encoderInputs = [tf.placeholder(tf.int32, [None, ]) for _ in range(
self.args.maxLengthEnco)] # Batch size * sequence length * input dim
with tf.name_scope('placeholder_decoder'):
self.decoderInputs = [tf.placeholder(tf.int32, [None, ], name='inputs') for _ in range(
self.args.maxLengthDeco)] # Same sentence length for input and output (Right ?)
self.decoderTargets = [tf.placeholder(
tf.int32, [None, ], name='targets') for _ in range(self.args.maxLengthDeco)]
self.decoderWeights = [tf.placeholder(
tf.float32, [None, ], name='weights') for _ in range(self.args.maxLengthDeco)]
# Define the network
# Here we use an embedding model, it takes integer as input and convert them into word vector for
# better word representation
decoderOutputs, states = tf.nn.seq2seq.embedding_attention_seq2seq(
self.encoderInputs, # List<[batch=?, inputDim=1]>, list of size args.maxLength
self.decoderInputs, # For training, we force the correct output (feed_previous=False)
encoDecoCell,
self.textData.getVocabularySize(),
self.textData.getVocabularySize(), # Both encoder and decoder have the same number of class
embedding_size=self.args.embeddingSize, # Dimension of each word
output_projection=None, # Eventually
# When we test (self.args.test), we use previous output as next input (feed_previous)
feed_previous=bool(self.args.test)
)
# For testing only
if self.args.test:
self.outputs = decoderOutputs
# TODO: Attach a summary to visualize the output
# For training only
else:
# Finally, we define the loss function
self.lossFct = tf.nn.seq2seq.sequence_loss(
decoderOutputs, self.decoderTargets, self.decoderWeights, self.textData.getVocabularySize())
tf.scalar_summary('loss', self.lossFct) # Keep track of the cost
# Initialize the optimizer
opt = tf.train.AdamOptimizer(
learning_rate=self.args.learningRate,
beta1=0.9,
beta2=0.999,
epsilon=1e-08
)
self.optOp = opt.minimize(self.lossFct)
def step(self, batch):
""" Forward/training step operation.
Does not perform run on itself but just return the operators to do so. Those have then to be run
Args:
batch (Batch): Input data on testing mode, input and target on output mode
Return:
(ops), dict: A tuple of the (training, loss) operators or (outputs,) in testing mode with the associated feed dictionary
"""
# Feed the dictionary
feedDict = {}
ops = None
if not self.args.test: # Training
for i in range(self.args.maxLengthEnco):
feedDict[self.encoderInputs[i]] = batch.encoderSeqs[i]
for i in range(self.args.maxLengthDeco):
feedDict[self.decoderInputs[i]] = batch.decoderSeqs[i]
feedDict[self.decoderTargets[i]] = batch.targetSeqs[i]
feedDict[self.decoderWeights[i]] = batch.weights[i]
ops = (self.optOp, self.lossFct)
else: # Testing (batchSize == 1)
for i in range(self.args.maxLengthEnco):
feedDict[self.encoderInputs[i]] = batch.encoderSeqs[i]
feedDict[self.decoderInputs[0]] = [self.textData.goToken]
ops = (self.outputs,)
# Return one pass operator
return ops, feedDict
================================================
FILE: chatbot/textdata.py
================================================
#!/usr/bin/env python3
# Copyright 2015 Conchylicultor. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
Loads the dialogue corpus, builds the vocabulary
"""
import numpy as np
import nltk # For tokenize
from tqdm import tqdm # Progress bar
import pickle # Saving the data
import math # For float comparison
import os # Checking file existance
import random
from chatbot.twitter_generate_data_pickle import get_data
class Batch:
"""Struct containing batches info
"""
def __init__(self):
self.encoderSeqs = []
self.decoderSeqs = []
self.targetSeqs = []
self.weights = []
class TextData:
"""Dataset class
Warning: No vocabulary limit
"""
def __init__(self, args):
"""Load all conversations
Args:
args: parameters of the model
"""
# Model parameters
self.args = args
# Path variables
self.corpusDir = os.path.join(self.args.rootDir, 'data/cornell/')
self.samplesDir = os.path.join(self.args.rootDir, 'data/samples/')
self.twitter_name = self.args.twitter_name
self.samplesName = self._constructName()
self.max_tweets = self.args.max_tweets
self.padToken = -1 # Padding
self.goToken = -1 # Start of sequence
self.eosToken = -1 # End of sequence
self.unknownToken = -1 # Word dropped from vocabulary
self.trainingSamples = [] # 2d array containing each question and his answer [[input,target]]
self.word2id = {}
self.id2word = {} # For a rapid conversion
self.loadCorpus(self.samplesDir)
# Plot some stats:
print('Loaded: {} words, {} QA'.format(len(self.word2id), len(self.trainingSamples)))
if self.args.playDataset:
self.playDataset()
def _constructName(self):
"""Return the name of the dataset that the program should use with the current parameters.
Computer from the base name, the given tag (self.args.datasetTag) and the sentence length
"""
baseName = self.twitter_name + '-dataset'
if self.args.datasetTag:
baseName += '-' + self.args.datasetTag
return baseName + '-' + str(self.args.maxLength) + '.pkl'
def makeLighter(self, ratioDataset):
"""Only keep a small fraction of the dataset, given by the ratio
"""
pass
def shuffle(self):
"""Shuffle the training samples
"""
print("Shuffling the dataset...")
random.shuffle(self.trainingSamples)
def _createBatch(self, samples):
"""Create a single batch from the list of sample. The batch size is automatically defined by the number of
samples given.
The inputs should already be inverted. The target should already have <go> and <eos>
Warning: This function should not make direct calls to args.batchSize !!!
Args:
samples (list<Obj>): a list of samples, each sample being on the form [input, target]
Return:
Batch: a batch object en
"""
batch = Batch()
batchSize = len(samples)
# Create the batch tensor
for i in range(batchSize):
# Unpack the sample
sample = samples[i]
if not self.args.test and self.args.watsonMode: # Watson mode: invert question and answer
sample = list(reversed(sample))
# Reverse inputs (and not outputs), little trick as defined on the
# original seq2seq paper
batch.encoderSeqs.append(list(reversed(sample[0])))
# Add the <go> and <eos> tokens
batch.decoderSeqs.append([self.goToken] + sample[1] + [self.eosToken])
# Same as decoder, but shifted to the left (ignore the <go>)
batch.targetSeqs.append(batch.decoderSeqs[-1][1:])
# Long sentences should have been filtered during the dataset creation
assert len(batch.encoderSeqs[i]) <= self.args.maxLengthEnco
assert len(batch.decoderSeqs[i]) <= self.args.maxLengthDeco
# Add padding & define weight
batch.encoderSeqs[i] = [self.padToken] * (self.args.maxLengthEnco - len(
batch.encoderSeqs[i])) + batch.encoderSeqs[i] # Left padding for the input
batch.weights.append([1.0] * len(batch.targetSeqs[i]) + [0.0] *
(self.args.maxLengthDeco - len(batch.targetSeqs[i])))
batch.decoderSeqs[i] = batch.decoderSeqs[i] + [self.padToken] * \
(self.args.maxLengthDeco - len(batch.decoderSeqs[i]))
batch.targetSeqs[i] = batch.targetSeqs[i] + [self.padToken] * \
(self.args.maxLengthDeco - len(batch.targetSeqs[i]))
# Simple hack to reshape the batch
encoderSeqsT = [] # Corrected orientation
for i in range(self.args.maxLengthEnco):
encoderSeqT = []
for j in range(batchSize):
encoderSeqT.append(batch.encoderSeqs[j][i])
encoderSeqsT.append(encoderSeqT)
batch.encoderSeqs = encoderSeqsT
decoderSeqsT = []
targetSeqsT = []
weightsT = []
for i in range(self.args.maxLengthDeco):
decoderSeqT = []
targetSeqT = []
weightT = []
for j in range(batchSize):
decoderSeqT.append(batch.decoderSeqs[j][i])
targetSeqT.append(batch.targetSeqs[j][i])
weightT.append(batch.weights[j][i])
decoderSeqsT.append(decoderSeqT)
targetSeqsT.append(targetSeqT)
weightsT.append(weightT)
batch.decoderSeqs = decoderSeqsT
batch.targetSeqs = targetSeqsT
batch.weights = weightsT
# # Debug
# self.printBatch(batch) # Input inverted, padding should be correct
# print(self.sequence2str(samples[0][0]))
# print(self.sequence2str(samples[0][1])) # Check we did not modified the original sample
return batch
def getBatches(self):
"""Prepare the batches for the current epoch
Return:
list<Batch>: Get a list of the batches for the next epoch
"""
self.shuffle()
batches = []
def genNextSamples():
""" Generator over the mini-batch training samples
"""
for i in range(0, self.getSampleSize(), self.args.batchSize):
yield self.trainingSamples[i:min(i + self.args.batchSize, self.getSampleSize())]
for samples in genNextSamples():
batch = self._createBatch(samples)
batches.append(batch)
return batches
def getSampleSize(self):
"""Return the size of the dataset
Return:
int: Number of training samples
"""
return len(self.trainingSamples)
def getVocabularySize(self):
"""Return the number of words present in the dataset
Return:
int: Number of word on the loader corpus
"""
return len(self.word2id)
def loadCorpus(self, dirName):
"""Load/create the conversations data
Args:
dirName (str): The directory where to load/save the model
"""
get_data(self.twitter_name, self.args.maxLength, self.max_tweets)
self.loadDataset(dirName)
assert self.padToken == 0
def saveDataset(self, dirName):
"""Save samples to file
Args:
dirName (str): The directory where to load/save the model
"""
with open(os.path.join(dirName, self.samplesName), 'wb') as handle:
data = { # Warning: If adding something here, also modifying loadDataset
"word2id": self.word2id,
"id2word": self.id2word,
"trainingSamples": self.trainingSamples
}
pickle.dump(data, handle, -1) # Using the highest protocol available
def loadDataset(self, dirName):
"""Load samples from file
Args:
dirName (str): The directory where to load the model
"""
with open(os.path.join(dirName, self.samplesName), 'rb') as handle:
# Warning: If adding something here, also modifying saveDataset
data = pickle.load(handle)
self.word2id = data["word2id"]
self.id2word = data["id2word"]
self.trainingSamples = data["trainingSamples"]
self.padToken = self.word2id["<pad>"]
self.goToken = self.word2id["<go>"]
self.eosToken = self.word2id["<eos>"]
self.unknownToken = self.word2id["<unknown>"] # Restore special words
def createCorpus(self, conversations):
"""Extract all data from the given vocabulary
"""
# Add standard tokens
self.padToken = self.getWordId("<pad>") # Padding (Warning: first things to add > id=0 !!)
self.goToken = self.getWordId("<go>") # Start of sequence
self.eosToken = self.getWordId("<eos>") # End of sequence
self.unknownToken = self.getWordId("<unknown>") # Word dropped from vocabulary
# Preprocessing data
for conversation in tqdm(conversations, desc="Extract conversations"):
self.extractConversation(conversation)
# The dataset will be saved in the same order it has been extracted
def extractConversation(self, conversation):
"""Extract the sample lines from the conversations
Args:
conversation (Obj): a convesation object containing the lines to extract
"""
# Iterate over all the lines of the conversation
# We ignore the last line (no answer for it)
for i in range(len(conversation["lines"]) - 1):
inputLine = conversation["lines"][i]
targetLine = conversation["lines"][i + 1]
inputWords = self.extractText(inputLine["text"])
targetWords = self.extractText(targetLine["text"], True)
if inputWords and targetWords: # Filter wrong samples (if one of the list is empty)
self.trainingSamples.append([inputWords, targetWords])
def extractText(self, line, isTarget=False):
"""Extract the words from a sample lines
Args:
line (str): a line containing the text to extract
isTarget (bool): Define the question on the answer
Return:
list<int>: the list of the word ids of the sentence
"""
words = []
# Extract sentences
sentencesToken = nltk.sent_tokenize(line)
# We add sentence by sentence until we reach the maximum length
for i in range(len(sentencesToken)):
# If question: we only keep the last sentences
# If answer: we only keep the first sentences
if not isTarget:
i = len(sentencesToken) - 1 - i
tokens = nltk.word_tokenize(sentencesToken[i])
# If the total length is not too big, we still can add one more sentence
if len(words) + len(tokens) <= self.args.maxLength:
tempWords = []
for token in tokens:
# Create the vocabulary and the training sentences
tempWords.append(self.getWordId(token))
if isTarget:
words = words + tempWords
else:
words = tempWords + words
else:
break # We reach the max length already
return words
def getWordId(self, word, create=True):
"""Get the id of the word (and add it to the dictionary if not existing). If the word does not exist and
create is set to False, the function will return the unknownToken value
Args:
word (str): word to add
create (Bool): if True and the word does not exist already, the world will be added
Return:
int: the id of the word created
"""
# Should we Keep only words with more than one occurrence ?
word = word.lower() # Ignore case
# Get the id if the word already exist
wordId = self.word2id.get(word, -1)
# If not, we create a new entry
if wordId == -1:
if create:
wordId = len(self.word2id)
self.word2id[word] = wordId
self.id2word[wordId] = word
else:
wordId = self.unknownToken
return wordId
def printBatch(self, batch):
"""Print a complete batch, useful for debugging
Args:
batch (Batch): a batch object
"""
print('----- Print batch -----')
for i in range(len(batch.encoderSeqs[0])): # Batch size
print('Encoder: {}'.format(self.batchSeq2str(batch.encoderSeqs, seqId=i)))
print('Decoder: {}'.format(self.batchSeq2str(batch.decoderSeqs, seqId=i)))
print('Targets: {}'.format(self.batchSeq2str(batch.targetSeqs, seqId=i)))
print('Weights: {}'.format(
' '.join([str(weight) for weight in [batchWeight[i] for batchWeight in batch.weights]])))
def sequence2str(self, sequence, clean=False, reverse=False):
"""Convert a list of integer into a human readable string
Args:
sequence (list<int>): the sentence to print
clean (Bool): if set, remove the <go>, <pad> and <eos> tokens
reverse (Bool): for the input, option to restore the standard order
Return:
str: the sentence
"""
if not sequence:
return ''
if not clean:
return ' '.join([self.id2word[idx] for idx in sequence])
sentence = []
for wordId in sequence:
if wordId == self.eosToken: # End of generated sentence
break
elif wordId != self.padToken and wordId != self.goToken:
sentence.append(self.id2word[wordId])
if reverse: # Reverse means input so no <eos> (otherwise pb with previous early stop)
sentence.reverse()
return ' '.join(sentence)
def batchSeq2str(self, batchSeq, seqId=0, **kwargs):
"""Convert a list of integer into a human readable string.
The difference between the previous function is that on a batch object, the values have been reorganized as
batch instead of sentence.
Args:
batchSeq (list<list<int>>): the sentence(s) to print
seqId (int): the position of the sequence inside the batch
kwargs: the formatting options( See sequence2str() )
Return:
str: the sentence
"""
sequence = []
for i in range(len(batchSeq)): # Sequence length
sequence.append(batchSeq[i][seqId])
return self.sequence2str(sequence, **kwargs)
def sentence2enco(self, sentence):
"""Encode a sequence and return a batch as an input for the model
Return:
Batch: a batch object containing the sentence, or none if something went wrong
"""
if sentence == '':
return None
# First step: Divide the sentence in token
tokens = nltk.word_tokenize(sentence)
if len(tokens) > self.args.maxLength:
return None
# Second step: Convert the token in word ids
wordIds = []
for token in tokens:
# Create the vocabulary and the training sentences
wordIds.append(self.getWordId(token, create=False))
# Third step: creating the batch (add padding, reverse)
batch = self._createBatch([[wordIds, []]]) # Mono batch, no target output
return batch
def deco2sentence(self, decoderOutputs):
"""Decode the output of the decoder and return a human friendly sentence
decoderOutputs (list<np.array>):
"""
sequence = []
# Choose the words with the highest prediction score
for out in decoderOutputs:
sequence.append(np.argmax(out)) # Adding each predicted word ids
return sequence # We return the raw sentence. Let the caller do some cleaning eventually
def playDataset(self):
"""Print a random dialogue from the dataset
"""
print('Randomly play samples:')
for i in range(self.args.playDataset):
idSample = random.randint(0, len(self.trainingSamples))
print('Q: {}'.format(self.sequence2str(self.trainingSamples[idSample][0])))
print('A: {}'.format(self.sequence2str(self.trainingSamples[idSample][1])))
print()
pass
================================================
FILE: chatbot/trainner.py
================================================
#!/usr/bin/env python3
# Copyright 2015 Conchylicultor. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
Train the program by launching it with random parametters
"""
from tqdm import tqdm
import os
def main():
"""
Launch the training with different parametters
"""
# TODO: define:
# step+noize
# log scale instead of uniform
# Define parametter: [min, max]
dictParams = {
"batchSize": [int, [1, 3]]
"learningRate": [float, [1, 3]]
}
# Training multiple times with different parametters
for i in range(10):
# Generate the command line arguments
trainingArgs = ""
for keyArg, valueArg in dictParams:
value = str(random(valueArg[0], max=valueArg[1]))
trainingArgs += " --" + keyArg + " " + value
# Launch the program
os.run("main.py" + trainingArgs)
# TODO: Save params/results ? or already inside training args ?
if __name__ == "__main__":
main()
================================================
FILE: chatbot/twitter_generate_data_pickle.py
================================================
import os
import pickle
from chatbot.twitter_qa import store_question_answers
def genset(questions, answers, maxLength):
words = set()
questions = [x.split()[-maxLength:] for x in questions]
answers = [x.split()[:maxLength] for x in answers]
for x in questions:
words.update(x)
for x in answers:
words.update(x)
words = sorted(words)
word2id = {x: num + 4 for num, x in enumerate(words)}
id2word = {num + 4: x for num, x in enumerate(words)}
specials = ['<pad>', '<go>', '<eos>', '<unknown>']
id2word.update({num: x for num, x in enumerate(specials)})
word2id.update({x: num for num, x in enumerate(specials)})
trainingSamples = []
for q, a in zip(questions, answers):
trainingSamples.append([[word2id[x] for x in q],
[word2id[x] for x in a]])
return {"trainingSamples": trainingSamples,
"id2word": id2word,
"word2id": word2id}
def load_qa(username, max_tweets, overwrite):
d = "data/tweets/" if os.path.isdir("data/tweets") else "../data/tweets/"
d += "{}-{}.txt"
if overwrite:
questions, answers = store_question_answers(username, max_tweets)
else:
try:
with open(d.format(username, "questions")) as f:
questions = [x for x in f.read().split("\n")]
print("Loaded", d.format(username, "questions"))
with open(d.format(username, "answers")) as f:
answers = [x for x in f.read().split("\n")]
print("Loaded", d.format(username, "answers"))
except FileNotFoundError:
print("QA files not found, downloading.")
questions, answers = store_question_answers(username, max_tweets)
return questions, answers
def get_data(username, maxLength=35, max_tweets=3200, overwrite=False):
sample_path = "data/samples/" if os.path.isdir("data/samples") else "../data/samples/"
path = os.path.join(sample_path + "{}-dataset-{}.pkl".format(username, maxLength))
if not overwrite and os.path.isfile(path):
print("Using existing pickle", path)
else:
questions, answers = load_qa(username, max_tweets, overwrite)
data = genset(questions, answers, maxLength)
with open(path, "wb") as f:
pickle.dump(data, f)
msg = "Saved model. {} unique words found. {} QA pairs created."
print(msg.format(len(data['id2word']), len(questions)))
================================================
FILE: chatbot/twitter_get_access_token.py
================================================
#!/usr/bin/env python
#
# Copyright 2007-2013 The Python-Twitter Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
from requests_oauthlib import OAuth1Session
import webbrowser
REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token'
ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token'
AUTHORIZATION_URL = 'https://api.twitter.com/oauth/authorize'
SIGNIN_URL = 'https://api.twitter.com/oauth/authenticate'
def get_access_token(consumer_key, consumer_secret):
oauth_client = OAuth1Session(consumer_key, client_secret=consumer_secret, callback_uri='oob')
print('\nRequesting temp token from Twitter...\n')
try:
resp = oauth_client.fetch_request_token(REQUEST_TOKEN_URL)
except ValueError as e:
raise 'Invalid response from Twitter requesting temp token: {0}'.format(e)
url = oauth_client.authorization_url(AUTHORIZATION_URL)
print('I will try to start a browser to visit the following Twitter page '
'if a browser will not start, copy the URL to your browser '
'and retrieve the pincode to be used '
'in the next step to obtaining an Authentication Token: \n'
'\n\t{0}'.format(url))
webbrowser.open(url)
pincode = input('\nEnter your pincode? ')
print('\nGenerating and signing request for an access token...\n')
oauth_client = OAuth1Session(consumer_key, client_secret=consumer_secret,
resource_owner_key=resp.get('oauth_token'),
resource_owner_secret=resp.get('oauth_token_secret'),
verifier=pincode)
try:
resp = oauth_client.fetch_access_token(ACCESS_TOKEN_URL)
except ValueError as e:
raise 'Invalid response from Twitter requesting temp token: {0}'.format(e)
print('''Your tokens/keys are as follows:
consumer_key = {ck}
consumer_secret = {cs}
access_token_key = {atk}
access_token_secret = {ats}'''.format(
ck=consumer_key,
cs=consumer_secret,
atk=resp.get('oauth_token'),
ats=resp.get('oauth_token_secret')))
def main():
consumer_key = input('Enter your consumer key: ')
consumer_secret = input('Enter your consumer secret: ')
get_access_token(consumer_key, consumer_secret)
if __name__ == "__main__":
main()
================================================
FILE: chatbot/twitter_qa.py
================================================
import json
import os
import re
import itertools
from TwitterAPI import TwitterAPI
with open("chatbot/credentials.json") as f:
credentials = json.load(f)
api = TwitterAPI(**credentials)
def get_tweets(screen_name, max_tweets=None):
show = api.request("users/show", {"screen_name": screen_name}).json()
max_tweets = max_tweets or show.get("statuses_count")
max_tweets = min(max_tweets, 3200)
print("Gathering {} tweets. Through API, 3200 is max possible".format(max_tweets))
user_tweets = []
query_params = {"screen_name": screen_name, "max_id": None, "count": 200}
last_seen = True
print("Gathering tweets for", screen_name)
while True:
try:
r = api.request("statuses/user_timeline", query_params)
timeline_tweets = r.json()
if timeline_tweets[-1]['id'] == last_seen:
break
last_seen = timeline_tweets[-1]['id']
user_tweets.extend(timeline_tweets)
query_params['max_id'] = timeline_tweets[-1]['id']
print("latest ID", query_params['max_id'],
"number of new tweets", len(timeline_tweets))
except Exception as e:
print("ERROR", e)
if len(user_tweets) >= max_tweets:
break
seen = set()
tweets = []
for x in user_tweets:
if x['id'] not in seen:
tweets.append(x)
seen.add(x['id'])
return tweets
def find_questions_for_tweets(tweets):
origins = {tweet['in_reply_to_status_id']: tweet
for tweet in tweets if tweet.get('in_reply_to_status_id')}
origin_gen = (x for x in origins)
questions = []
answers = []
print("Getting original tweets to which <user> replied")
while True:
orig = list(itertools.islice(origin_gen, 100))
if not orig:
break
id_query = ",".join([str(x) for x in orig])
orig_tweets = api.request("statuses/lookup", {"id": id_query}).json()
for ot in orig_tweets:
if ot['id'] in origins:
questions.append(ot['text'])
answers.append(origins[ot['id']]['text'])
print("collected question/answer pairs", len(questions), len(answers))
return questions, answers
def normalize_tweet(x):
x = " ".join(x.split())
x = x.lower()
x = re.sub("http[^ ]+", "LINK", x)
x = re.sub("#[^ ]+", "TAG", x)
x = re.sub("(@[^ ]+ )*@[^ ]+", "MENTION", x)
for punc in [".", ",", "?", "!"]:
x = re.sub("[{}]+".format(punc), " " + punc, x)
x = x.replace("n't", " not")
x = " ".join(x.split())
x = x.lstrip("MENTION ")
return x.strip()
def get_tweet_qa(twitter_username, max_tweets=None, normalize_tweets=True):
tweets = get_tweets(twitter_username, max_tweets)
questions, answers = find_questions_for_tweets(tweets)
if normalize_tweets:
questions = [normalize_tweet(x) for x in questions]
answers = [normalize_tweet(x) for x in answers]
return questions, answers
def get_rate_limits():
rates = api.request("application/rate_limit_status").json()
timeline = rates['resources']['statuses']['/statuses/user_timeline']
lookup = rates['resources']['users']['/users/lookup']
print("lookup", lookup)
print("timeline", timeline)
return timeline['remaining'] != 0 and lookup['remaining'] != 0
def store_question_answers(username, max_number=None):
questions, answers = get_tweet_qa(username, max_number)
d = "data/tweets/" if os.path.isdir("data/tweets") else "../data/tweets/"
d += "{}-{}.txt"
with open(d.format(username, "questions"), "w") as f:
f.write("\n".join(questions))
print("Saved", d.format(username, "questions"))
with open(d.format(username, "answers"), "w") as f:
f.write("\n".join(answers))
print("Saved", d.format(username, "answers"))
return questions, answers
================================================
FILE: chatbot_website/.gitignore
================================================
# Database
*.sqlite3
# Redis
dump.rdb
================================================
FILE: chatbot_website/chatbot_interface/__init__.py
================================================
================================================
FILE: chatbot_website/chatbot_interface/admin.py
================================================
from django.contrib import admin
# Register your models here.
================================================
FILE: chatbot_website/chatbot_interface/apps.py
================================================
from django.apps import AppConfig
class ChatbotInterfaceConfig(AppConfig):
name = 'chatbot_interface'
================================================
FILE: chatbot_website/chatbot_interface/chatbotmanager.py
================================================
from django.conf import settings
import logging
import sys
chatbotPath = "/".join(settings.BASE_DIR.split('/')[:-1])
sys.path.append(chatbotPath)
from chatbot import chatbot
logger = logging.getLogger(__name__)
class ChatbotManager:
""" Manage a single instance of the chatbot shared over the website
"""
bot = None
@staticmethod
def initBot():
""" Instantiate the chatbot for later use
Should be called only once
"""
if not ChatbotManager.bot:
logger.info('Initializing bot...')
ChatbotManager.bot = chatbot.Chatbot()
ChatbotManager.bot.main(['--modelTag', 'server', '--test', 'daemon', '--rootDir', chatbotPath])
else:
logger.info('Bot already initialized.')
@staticmethod
def callBot(sentence):
""" Use the previously instantiated bot to predict a response to the given sentence
Args:
sentence (str): the question to answer
Return:
str: the answer
"""
if ChatbotManager.bot:
return ChatbotManager.bot.daemonPredict(sentence)
else:
logger.error('Error: Bot not initialized!')
================================================
FILE: chatbot_website/chatbot_interface/consumer.py
================================================
from channels import Group
from channels.sessions import channel_session
import logging
import sys
import json
from .chatbotmanager import ChatbotManager
logger = logging.getLogger(__name__)
def _getClientName(client):
""" Return the unique id for the client
Args:
client list<>: the client which send the message of the from [ip (str), port (int)]
Return:
str: the id associated with the client
"""
return 'room-' + client[0] + '-' + str(client[1])
@channel_session
def ws_connect(message):
""" Called when a client try to open a WebSocket
Args:
message (Obj): object containing the client query
"""
if message['path'] == '/chat': # Check we are on the right channel
clientName = _getClientName(message['client'])
logger.info('New client connected: {}'.format(clientName))
Group(clientName).add(message.reply_channel) # Answer back to the client
message.channel_session['room'] = clientName
@channel_session
def ws_receive(message):
""" Called when a client send a message
Args:
message (Obj): object containing the client query
"""
# Get client info
clientName = message.channel_session['room']
data = json.loads(message['text'])
# Compute the prediction
question = data['message']
try:
answer = ChatbotManager.callBot(question)
except: # Catching all possible mistakes
logger.error('{}: Error with this question {}'.format(clientName, question))
logger.error("Unexpected error:", sys.exc_info()[0])
answer = 'Error: Internal problem'
# Check eventual error
if not answer:
answer = 'Error: Try a shorter sentence'
logger.info('{}: {} -> {}'.format(clientName, question, answer))
# Send the prediction back
Group(clientName).send({'text': json.dumps({'message': answer})})
@channel_session
def ws_disconnect(message):
""" Called when a client disconnect
Args:
message (Obj): object containing the client query
"""
clientName = message.channel_session['room']
logger.info('Client disconnected: {}'.format(clientName))
Group(clientName).discard(message.reply_channel)
================================================
FILE: chatbot_website/chatbot_interface/migrations/__init__.py
================================================
================================================
FILE: chatbot_website/chatbot_interface/models.py
================================================
from django.db import models
# Create your models here.
================================================
FILE: chatbot_website/chatbot_interface/routing.py
================================================
from . import consumer
channel_routing = {
# TODO: From the original examples, there is more (https://github.com/jacobian/channels-example/)
'websocket.connect': consumer.ws_connect,
'websocket.receive': consumer.ws_receive,
'websocket.disconnect': consumer.ws_disconnect,
}
================================================
FILE: chatbot_website/chatbot_interface/static/LICENSE.txt
================================================
Creative Commons Attribution 3.0 Unported
http://creativecommons.org/licenses/by/3.0/
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
1. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
2. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
3. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
4. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
5. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
6. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
7. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
8. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
9. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
1. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
2. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
3. to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
4. to Distribute and Publicly Perform Adaptations.
5.
For the avoidance of doubt:
1. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
2. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and,
3. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License.
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved.
4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
1. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested.
2. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
3. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
1. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
2. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
8. Miscellaneous
1. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
2. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
3. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
4. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
5. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
6. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
================================================
FILE: chatbot_website/chatbot_interface/static/README.txt
================================================
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
Just a fun little profile/card-style template I whipped up during a break between major
projects. Minimal, responsive, and powered by Skel + Sass. Enjoy :)
Demo images* courtesy of Unsplash, a radtastic collection of CC0 (public domain) images
you can use for pretty much whatever.
(* = not included)
AJ
aj@lkn.io | @ajlkn
Credits:
Demo Images:
Unsplash (unsplash.com)
Icons:
Font Awesome (fortawesome.github.com/Font-Awesome)
Other:
html5shiv.js (@afarkas @jdalton @jon_neal @rem)
CSS3 Pie (css3pie.com)
Respond.js (j.mp/respondjs)
Skel (skel.io)
================================================
FILE: chatbot_website/chatbot_interface/static/assets/css/ie8.css
================================================
/*
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
/* List */
ul.icons li a {
-ms-behavior: url("assets/js/PIE.htc");
}
ul.icons li a:before {
text-align: center;
font-size: 26px;
}
/* Main */
#main {
-ms-behavior: url("assets/js/PIE.htc");
}
#main .avatar img {
-ms-behavior: url("assets/js/PIE.htc");
}
/* Footer */
#footer {
color: #fff;
}
#footer .copyright li {
border-left: solid 1px #fff;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/css/ie9.css
================================================
/*
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
/* Basic */
body {
background-image: url("../../images/bg.jpg");
background-repeat: no-repeat;
background-size: cover;
background-position: bottom center;
background-attachment: fixed;
}
body:after {
display: none;
}
/* List */
ul.icons li a:before {
color: #c8cccf;
}
ul.icons li a:hover:before {
color: #ff7496;
}
/* Wrapper */
#wrapper {
text-align: center;
}
/* Main */
#main {
display: inline-block;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/css/main.css
================================================
@charset "UTF-8";
@import url(font-awesome.min.css);
@import url("http://fonts.googleapis.com/css?family=Source+Sans+Pro:300");
/*
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
/* Reset */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after, q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
body {
-webkit-text-size-adjust: none;
}
/* Box Model */
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
/* Basic */
@media screen and (max-width: 480px) {
html, body {
min-width: 320px;
}
}
body.is-loading *, body.is-loading *:before, body.is-loading *:after {
-moz-animation: none !important;
-webkit-animation: none !important;
-ms-animation: none !important;
animation: none !important;
-moz-transition: none !important;
-webkit-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
html {
height: 100%;
}
body {
height: 100%;
background-color: #ffffff;
background-image: url("images/overlay.png"), -moz-linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35)), url("../../images/bg.png");
background-image: url("images/overlay.png"), -webkit-linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35)), url("../../images/bg.png");
background-image: url("images/overlay.png"), -ms-linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35)), url("../../images/bg.png");
background-image: url("images/overlay.png"), linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35)), url("../../images/bg.png");
background-repeat: repeat, no-repeat, no-repeat;
background-size: 100px 100px, cover, cover;
background-position: top left, center center, bottom center;
background-attachment: fixed, fixed, fixed;
}
body:after {
content: '';
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: inherit;
opacity: 0;
z-index: 1;
background-color: #ffffff;
background-image: url("images/overlay.png"), -moz-linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35));
background-image: url("images/overlay.png"), -webkit-linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35));
background-image: url("images/overlay.png"), -ms-linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35));
background-image: url("images/overlay.png"), linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35));
background-repeat: repeat, no-repeat;
background-size: 100px 100px, cover;
background-position: top left, center center;
-moz-transition: opacity 1.75s ease-out;
-webkit-transition: opacity 1.75s ease-out;
-ms-transition: opacity 1.75s ease-out;
transition: opacity 1.75s ease-out;
}
body.is-loading:after {
opacity: 1;
}
/* Type */
body, input, select, textarea {
color: #414f57;
font-family: "Source Sans Pro", Helvetica, sans-serif;
font-size: 14pt;
font-weight: 300;
line-height: 2;
letter-spacing: 0.2em;
text-transform: uppercase;
}
@media screen and (max-width: 1680px) {
body, input, select, textarea {
font-size: 11pt;
}
}
@media screen and (max-width: 480px) {
body, input, select, textarea {
font-size: 10pt;
line-height: 1.75;
}
}
a {
-moz-transition: color 0.2s ease, border-color 0.2s ease;
-webkit-transition: color 0.2s ease, border-color 0.2s ease;
-ms-transition: color 0.2s ease, border-color 0.2s ease;
transition: color 0.2s ease, border-color 0.2s ease;
color: inherit;
text-decoration: none;
}
a:before {
-moz-transition: color 0.2s ease, text-shadow 0.2s ease;
-webkit-transition: color 0.2s ease, text-shadow 0.2s ease;
-ms-transition: color 0.2s ease, text-shadow 0.2s ease;
transition: color 0.2s ease, text-shadow 0.2s ease;
}
a:hover {
color: #ff7496;
}
strong, b {
color: #313f47;
}
em, i {
font-style: italic;
}
p {
margin: 0 0 1.5em 0;
}
h1, h2, h3, h4, h5, h6 {
color: #313f47;
line-height: 1.5;
margin: 0 0 0.75em 0;
}
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
color: inherit;
text-decoration: none;
}
h1 {
font-size: 1.85em;
letter-spacing: 0.22em;
margin: 0 0 0.525em 0;
}
h2 {
font-size: 1.25em;
}
h3 {
font-size: 1em;
}
h4 {
font-size: 1em;
}
h5 {
font-size: 1em;
}
h6 {
font-size: 1em;
}
@media screen and (max-width: 480px) {
h1 {
font-size: 1.65em;
}
}
sub {
font-size: 0.8em;
position: relative;
top: 0.5em;
}
sup {
font-size: 0.8em;
position: relative;
top: -0.5em;
}
hr {
border: 0;
border-bottom: solid 1px #c8cccf;
margin: 3em 0;
}
/* Form */
form {
margin: 0 0 1.5em 0;
}
form > .field {
margin: 0 0 1.5em 0;
}
form > .field > :last-child {
margin-bottom: 0;
}
label {
color: #313f47;
display: block;
font-size: 0.9em;
margin: 0 0 0.75em 0;
}
input[type="text"],
input[type="password"],
input[type="email"],
input[type="tel"],
select,
textarea {
-moz-appearance: none;
-webkit-appearance: none;
-ms-appearance: none;
appearance: none;
border-radius: 4px;
border: solid 1px #c8cccf;
color: inherit;
display: block;
outline: 0;
padding: 0 1em;
text-decoration: none;
width: 100%;
}
input[type="text"]:invalid,
input[type="password"]:invalid,
input[type="email"]:invalid,
input[type="tel"]:invalid,
select:invalid,
textarea:invalid {
box-shadow: none;
}
input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="tel"]:focus,
select:focus,
textarea:focus {
border-color: #ff7496;
}
.select-wrapper {
text-decoration: none;
display: block;
position: relative;
}
.select-wrapper:before {
content: "";
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
.select-wrapper:before {
color: #c8cccf;
display: block;
height: 2.75em;
line-height: 2.75em;
pointer-events: none;
position: absolute;
right: 0;
text-align: center;
top: 0;
width: 2.75em;
}
.select-wrapper select::-ms-expand {
display: none;
}
input[type="text"],
input[type="password"],
input[type="email"],
select {
height: 2.75em;
}
textarea {
padding: 0.75em 1em;
}
input[type="checkbox"],
input[type="radio"] {
-moz-appearance: none;
-webkit-appearance: none;
-ms-appearance: none;
appearance: none;
display: block;
float: left;
margin-right: -2em;
opacity: 0;
width: 1em;
z-index: -1;
}
input[type="checkbox"] + label,
input[type="radio"] + label {
text-decoration: none;
color: #414f57;
cursor: pointer;
display: inline-block;
font-size: 1em;
font-weight: 300;
padding-left: 2.4em;
padding-right: 0.75em;
position: relative;
}
input[type="checkbox"] + label:before,
input[type="radio"] + label:before {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
input[type="checkbox"] + label:before,
input[type="radio"] + label:before {
border-radius: 4px;
border: solid 1px #c8cccf;
content: '';
display: inline-block;
height: 1.65em;
left: 0;
line-height: 1.58125em;
position: absolute;
text-align: center;
top: 0.15em;
width: 1.65em;
}
input[type="checkbox"]:checked + label:before,
input[type="radio"]:checked + label:before {
color: #ff7496;
content: '\f00c';
}
input[type="checkbox"]:focus + label:before,
input[type="radio"]:focus + label:before {
border-color: #ff7496;
}
input[type="checkbox"] + label:before {
border-radius: 4px;
}
input[type="radio"] + label:before {
border-radius: 100%;
}
::-webkit-input-placeholder {
color: #616f77 !important;
opacity: 1.0;
}
:-moz-placeholder {
color: #616f77 !important;
opacity: 1.0;
}
::-moz-placeholder {
color: #616f77 !important;
opacity: 1.0;
}
:-ms-input-placeholder {
color: #616f77 !important;
opacity: 1.0;
}
.formerize-placeholder {
color: #616f77 !important;
opacity: 1.0;
}
/* Icon */
.icon {
text-decoration: none;
position: relative;
border-bottom: none;
}
.icon:before {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
.icon > .label {
display: none;
}
/* List */
ol {
list-style: decimal;
margin: 0 0 1.5em 0;
padding-left: 1.25em;
}
ol li {
padding-left: 0.25em;
}
ul {
list-style: disc;
margin: 0 0 1.5em 0;
padding-left: 1em;
}
ul li {
padding-left: 0.5em;
}
ul.alt {
list-style: none;
padding-left: 0;
}
ul.alt li {
border-top: solid 1px #c8cccf;
padding: 0.5em 0;
}
ul.alt li:first-child {
border-top: 0;
padding-top: 0;
}
ul.icons {
cursor: default;
list-style: none;
padding-left: 0;
margin-top: -0.675em;
}
ul.icons li {
display: inline-block;
padding: 0.675em 0.5em;
}
ul.icons li a {
text-decoration: none;
position: relative;
display: block;
width: 3.75em;
height: 3.75em;
border-radius: 100%;
border: solid 1px #c8cccf;
line-height: 3.75em;
overflow: hidden;
text-align: center;
text-indent: 3.75em;
white-space: nowrap;
}
ul.icons li a:before {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
ul.icons li a:before {
color: #ffffff;
text-shadow: 1.25px 0px 0px #c8cccf, -1.25px 0px 0px #c8cccf, 0px 1.25px 0px #c8cccf, 0px -1.25px 0px #c8cccf;
}
ul.icons li a:hover:before {
text-shadow: 1.25px 0px 0px #ff7496, -1.25px 0px 0px #ff7496, 0px 1.25px 0px #ff7496, 0px -1.25px 0px #ff7496;
}
ul.icons li a:before {
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
font-size: 1.85rem;
line-height: inherit;
text-align: center;
text-indent: 0;
}
ul.icons li a:hover {
border-color: #ff7496;
}
@media screen and (max-width: 480px) {
ul.icons li a:before {
font-size: 1.5rem;
}
}
ul.actions {
cursor: default;
list-style: none;
padding-left: 0;
}
ul.actions li {
display: inline-block;
padding: 0 0.75em 0 0;
vertical-align: middle;
}
ul.actions li:last-child {
padding-right: 0;
}
dl {
margin: 0 0 1.5em 0;
}
dl dt {
display: block;
margin: 0 0 0.75em 0;
}
dl dd {
margin-left: 1.5em;
}
/* Button */
input[type="submit"],
input[type="reset"],
input[type="button"],
button,
.button {
-moz-appearance: none;
-webkit-appearance: none;
-ms-appearance: none;
appearance: none;
-moz-transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out;
-webkit-transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out;
-ms-transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out;
transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out;
display: inline-block;
height: 2.75em;
line-height: 2.75em;
padding: 0 1.5em;
background-color: transparent;
border-radius: 4px;
border: solid 1px #c8cccf;
color: #414f57 !important;
cursor: pointer;
text-align: center;
text-decoration: none;
white-space: nowrap;
}
input[type="submit"]:hover,
input[type="reset"]:hover,
input[type="button"]:hover,
button:hover,
.button:hover {
border-color: #ff7496;
color: #ff7496 !important;
}
input[type="submit"].icon,
input[type="reset"].icon,
input[type="button"].icon,
button.icon,
.button.icon {
padding-left: 1.35em;
}
input[type="submit"].icon:before,
input[type="reset"].icon:before,
input[type="button"].icon:before,
button.icon:before,
.button.icon:before {
margin-right: 0.5em;
}
input[type="submit"].fit,
input[type="reset"].fit,
input[type="button"].fit,
button.fit,
.button.fit {
display: block;
width: 100%;
margin: 0 0 0.75em 0;
}
input[type="submit"].small,
input[type="reset"].small,
input[type="button"].small,
button.small,
.button.small {
font-size: 0.8em;
}
input[type="submit"].big,
input[type="reset"].big,
input[type="button"].big,
button.big,
.button.big {
font-size: 1.35em;
}
input[type="submit"].disabled, input[type="submit"]:disabled,
input[type="reset"].disabled,
input[type="reset"]:disabled,
input[type="button"].disabled,
input[type="button"]:disabled,
button.disabled,
button:disabled,
.button.disabled,
.button:disabled {
-moz-pointer-events: none;
-webkit-pointer-events: none;
-ms-pointer-events: none;
pointer-events: none;
opacity: 0.5;
}
/* Main */
#main {
position: relative;
max-width: 100%;
min-width: 35em; /* HERE IS THE WIDTH OF THE MAIN BLOCK */
padding: 4.5em 3em 3em 3em ;
background: #ffffff;
border-radius: 4px;
cursor: default;
opacity: 0.95;
text-align: center;
-moz-transform-origin: 50% 50%;
-webkit-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-moz-transform: rotateX(0deg);
-webkit-transform: rotateX(0deg);
-ms-transform: rotateX(0deg);
transform: rotateX(0deg);
-moz-transition: opacity 1s ease, -moz-transform 1s ease;
-webkit-transition: opacity 1s ease, -webkit-transform 1s ease;
-ms-transition: opacity 1s ease, -ms-transform 1s ease;
transition: opacity 1s ease, transform 1s ease;
}
#main .avatar {
position: relative;
display: block;
margin-bottom: 1.5em;
}
#main .avatar img {
display: block;
margin: 0 auto;
border-radius: 100%;
box-shadow: 0 0 0 1.5em #ffffff;
}
#main .avatar:before {
content: '';
display: block;
position: absolute;
top: 50%;
left: -3em;
width: calc(100% + 6em);
height: 1px;
z-index: -1;
background: #c8cccf;
}
@media screen and (max-width: 480px) {
#main {
min-width: 0;
width: 100%;
padding: 4em 2em 2.5em 2em ;
}
#main .avatar:before {
left: -2em;
width: calc(100% + 4em);
}
}
body.is-loading #main {
opacity: 0;
-moz-transform: rotateX(15deg);
-webkit-transform: rotateX(15deg);
-ms-transform: rotateX(15deg);
transform: rotateX(15deg);
}
#chat_zone {
font-size: 0.9em;
}
.question {
text-align: right;
margin: 0 0 0.1em 0;
}
.answer {
text-align: left;
margin: 0 0 0.3em 0;
}
/* Footer */
#footer {
-moz-align-self: -moz-flex-end;
-webkit-align-self: -webkit-flex-end;
-ms-align-self: -ms-flex-end;
align-self: flex-end;
width: 100%;
padding: 1.5em 0 0 0;
color: rgba(255, 255, 255, 0.75);
cursor: default;
text-align: center;
}
#footer .copyright {
margin: 0;
padding: 0;
font-size: 0.9em;
list-style: none;
}
#footer .copyright li {
display: inline-block;
margin: 0 0 0 0.45em;
padding: 0 0 0 0.85em;
border-left: solid 1px rgba(255, 255, 255, 0.5);
line-height: 1;
}
#footer .copyright li:first-child {
border-left: 0;
}
/* Wrapper */
#wrapper {
display: -moz-flex;
display: -webkit-flex;
display: -ms-flex;
display: flex;
-moz-align-items: center;
-webkit-align-items: center;
-ms-align-items: center;
align-items: center;
-moz-justify-content: space-between;
-webkit-justify-content: space-between;
-ms-justify-content: space-between;
justify-content: space-between;
-moz-flex-direction: column;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-moz-perspective: 1000px;
-webkit-perspective: 1000px;
-ms-perspective: 1000px;
perspective: 1000px;
position: relative;
min-height: 100%;
padding: 1.5em;
z-index: 2;
}
#wrapper > * {
z-index: 1;
}
#wrapper:before {
content: '';
display: block;
}
@media screen and (max-width: 360px) {
#wrapper {
padding: 0.75em;
}
}
body.is-ie #wrapper {
height: 100%;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/css/noscript.css
================================================
/*
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
/* Basic */
body:after {
display: none;
}
/* Main */
#main {
-moz-transform: none !important;
-webkit-transform: none !important;
-ms-transform: none !important;
transform: none !important;
opacity: 1 !important;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/js/PIE.htc
================================================
<!--
PIE: CSS3 rendering for IE
Version 1.0.0
http://css3pie.com
Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2.
-->
<PUBLIC:COMPONENT lightWeight="true">
<!-- saved from url=(0014)about:internet -->
<PUBLIC:ATTACH EVENT="oncontentready" FOR="element" ONEVENT="init()" />
<PUBLIC:ATTACH EVENT="ondocumentready" FOR="element" ONEVENT="init()" />
<PUBLIC:ATTACH EVENT="ondetach" FOR="element" ONEVENT="cleanup()" />
<script type="text/javascript">
var doc = element.document;var f=window.PIE;
if(!f){f=window.PIE={F:"-pie-",nb:"Pie",La:"pie_",Ac:{TD:1,TH:1},cc:{TABLE:1,THEAD:1,TBODY:1,TFOOT:1,TR:1,INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,IMG:1,HR:1},fc:{A:1,INPUT:1,TEXTAREA:1,SELECT:1,BUTTON:1},Gd:{submit:1,button:1,reset:1},aa:function(){}};try{doc.execCommand("BackgroundImageCache",false,true)}catch(aa){}for(var ba=4,Z=doc.createElement("div"),ca=Z.getElementsByTagName("i"),ga;Z.innerHTML="<!--[if gt IE "+ ++ba+"]><i></i><![endif]--\>",ca[0];);f.O=ba;if(ba===6)f.F=f.F.replace(/^-/,"");f.ja=
doc.documentMode||f.O;Z.innerHTML='<v:shape adj="1"/>';ga=Z.firstChild;ga.style.behavior="url(#default#VML)";f.zc=typeof ga.adj==="object";(function(){var a,b=0,c={};f.p={Za:function(d){if(!a){a=doc.createDocumentFragment();a.namespaces.add("css3vml","urn:schemas-microsoft-com:vml")}return a.createElement("css3vml:"+d)},Ba:function(d){return d&&d._pieId||(d._pieId="_"+ ++b)},Eb:function(d){var e,g,j,i,h=arguments;e=1;for(g=h.length;e<g;e++){i=h[e];for(j in i)if(i.hasOwnProperty(j))d[j]=i[j]}return d},
Rb:function(d,e,g){var j=c[d],i,h;if(j)Object.prototype.toString.call(j)==="[object Array]"?j.push([e,g]):e.call(g,j);else{h=c[d]=[[e,g]];i=new Image;i.onload=function(){j=c[d]={h:i.width,f:i.height};for(var k=0,n=h.length;k<n;k++)h[k][0].call(h[k][1],j);i.onload=null};i.src=d}}}})();f.Na={gc:function(a,b,c,d){function e(){k=j>=90&&j<270?b:0;n=j<180?c:0;m=b-k;p=c-n}function g(){for(;j<0;)j+=360;j%=360}var j=d.sa;d=d.zb;var i,h,k,n,m,p,r,t;if(d){d=d.coords(a,b,c);i=d.x;h=d.y}if(j){j=j.jd();g();e();
if(!d){i=k;h=n}d=f.Na.tc(i,h,j,m,p);a=d[0];d=d[1]}else if(d){a=b-i;d=c-h}else{i=h=a=0;d=c}r=a-i;t=d-h;if(j===void 0){j=!r?t<0?90:270:!t?r<0?180:0:-Math.atan2(t,r)/Math.PI*180;g();e()}return{sa:j,xc:i,yc:h,td:a,ud:d,Wd:k,Xd:n,rd:m,sd:p,kd:r,ld:t,rc:f.Na.dc(i,h,a,d)}},tc:function(a,b,c,d,e){if(c===0||c===180)return[d,b];else if(c===90||c===270)return[a,e];else{c=Math.tan(-c*Math.PI/180);a=c*a-b;b=-1/c;d=b*d-e;e=b-c;return[(d-a)/e,(c*d-b*a)/e]}},dc:function(a,b,c,d){a=c-a;b=d-b;return Math.abs(a===0?
b:b===0?a:Math.sqrt(a*a+b*b))}};f.ea=function(){this.Gb=[];this.oc={}};f.ea.prototype={ba:function(a){var b=f.p.Ba(a),c=this.oc,d=this.Gb;if(!(b in c)){c[b]=d.length;d.push(a)}},Ha:function(a){a=f.p.Ba(a);var b=this.oc;if(a&&a in b){delete this.Gb[b[a]];delete b[a]}},xa:function(){for(var a=this.Gb,b=a.length;b--;)a[b]&&a[b]()}};f.Oa=new f.ea;f.Oa.Rd=function(){var a=this,b;if(!a.Sd){b=doc.documentElement.currentStyle.getAttribute(f.F+"poll-interval")||250;(function c(){a.xa();setTimeout(c,b)})();
a.Sd=1}};(function(){function a(){f.L.xa();window.detachEvent("onunload",a);window.PIE=null}f.L=new f.ea;window.attachEvent("onunload",a);f.L.ta=function(b,c,d){b.attachEvent(c,d);this.ba(function(){b.detachEvent(c,d)})}})();f.Qa=new f.ea;f.L.ta(window,"onresize",function(){f.Qa.xa()});(function(){function a(){f.mb.xa()}f.mb=new f.ea;f.L.ta(window,"onscroll",a);f.Qa.ba(a)})();(function(){function a(){c=f.kb.md()}function b(){if(c){for(var d=0,e=c.length;d<e;d++)f.attach(c[d]);c=0}}var c;if(f.ja<9){f.L.ta(window,
"onbeforeprint",a);f.L.ta(window,"onafterprint",b)}})();f.lb=new f.ea;f.L.ta(doc,"onmouseup",function(){f.lb.xa()});f.he=function(){function a(h){this.Y=h}var b=doc.createElement("length-calc"),c=doc.body||doc.documentElement,d=b.style,e={},g=["mm","cm","in","pt","pc"],j=g.length,i={};d.position="absolute";d.top=d.left="-9999px";for(c.appendChild(b);j--;){d.width="100"+g[j];e[g[j]]=b.offsetWidth/100}c.removeChild(b);d.width="1em";a.prototype={Kb:/(px|em|ex|mm|cm|in|pt|pc|%)$/,ic:function(){var h=
this.Jd;if(h===void 0)h=this.Jd=parseFloat(this.Y);return h},yb:function(){var h=this.ae;if(!h)h=this.ae=(h=this.Y.match(this.Kb))&&h[0]||"px";return h},a:function(h,k){var n=this.ic(),m=this.yb();switch(m){case "px":return n;case "%":return n*(typeof k==="function"?k():k)/100;case "em":return n*this.xb(h);case "ex":return n*this.xb(h)/2;default:return n*e[m]}},xb:function(h){var k=h.currentStyle.fontSize,n,m;if(k.indexOf("px")>0)return parseFloat(k);else if(h.tagName in f.cc){m=this;n=h.parentNode;
return f.n(k).a(n,function(){return m.xb(n)})}else{h.appendChild(b);k=b.offsetWidth;b.parentNode===h&&h.removeChild(b);return k}}};f.n=function(h){return i[h]||(i[h]=new a(h))};return a}();f.Ja=function(){function a(e){this.X=e}var b=f.n("50%"),c={top:1,center:1,bottom:1},d={left:1,center:1,right:1};a.prototype={zd:function(){if(!this.ac){var e=this.X,g=e.length,j=f.v,i=j.qa,h=f.n("0");i=i.na;h=["left",h,"top",h];if(g===1){e.push(new j.ob(i,"center"));g++}if(g===2){i&(e[0].k|e[1].k)&&e[0].d in c&&
e[1].d in d&&e.push(e.shift());if(e[0].k&i)if(e[0].d==="center")h[1]=b;else h[0]=e[0].d;else if(e[0].W())h[1]=f.n(e[0].d);if(e[1].k&i)if(e[1].d==="center")h[3]=b;else h[2]=e[1].d;else if(e[1].W())h[3]=f.n(e[1].d)}this.ac=h}return this.ac},coords:function(e,g,j){var i=this.zd(),h=i[1].a(e,g);e=i[3].a(e,j);return{x:i[0]==="right"?g-h:h,y:i[2]==="bottom"?j-e:e}}};return a}();f.Ka=function(){function a(b,c){this.h=b;this.f=c}a.prototype={a:function(b,c,d,e,g){var j=this.h,i=this.f,h=c/d;e=e/g;if(j===
"contain"){j=e>h?c:d*e;i=e>h?c/e:d}else if(j==="cover"){j=e<h?c:d*e;i=e<h?c/e:d}else if(j==="auto"){i=i==="auto"?g:i.a(b,d);j=i*e}else{j=j.a(b,c);i=i==="auto"?j/e:i.a(b,d)}return{h:j,f:i}}};a.Kc=new a("auto","auto");return a}();f.Ec=function(){function a(b){this.Y=b}a.prototype={Kb:/[a-z]+$/i,yb:function(){return this.ad||(this.ad=this.Y.match(this.Kb)[0].toLowerCase())},jd:function(){var b=this.Vc,c;if(b===undefined){b=this.yb();c=parseFloat(this.Y,10);b=this.Vc=b==="deg"?c:b==="rad"?c/Math.PI*180:
b==="grad"?c/400*360:b==="turn"?c*360:0}return b}};return a}();f.Jc=function(){function a(c){this.Y=c}var b={};a.Qd=/\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d+|\d*\.\d+)\s*\)\s*/;a.Fb={aliceblue:"F0F8FF",antiquewhite:"FAEBD7",aqua:"0FF",aquamarine:"7FFFD4",azure:"F0FFFF",beige:"F5F5DC",bisque:"FFE4C4",black:"000",blanchedalmond:"FFEBCD",blue:"00F",blueviolet:"8A2BE2",brown:"A52A2A",burlywood:"DEB887",cadetblue:"5F9EA0",chartreuse:"7FFF00",chocolate:"D2691E",coral:"FF7F50",cornflowerblue:"6495ED",
cornsilk:"FFF8DC",crimson:"DC143C",cyan:"0FF",darkblue:"00008B",darkcyan:"008B8B",darkgoldenrod:"B8860B",darkgray:"A9A9A9",darkgreen:"006400",darkkhaki:"BDB76B",darkmagenta:"8B008B",darkolivegreen:"556B2F",darkorange:"FF8C00",darkorchid:"9932CC",darkred:"8B0000",darksalmon:"E9967A",darkseagreen:"8FBC8F",darkslateblue:"483D8B",darkslategray:"2F4F4F",darkturquoise:"00CED1",darkviolet:"9400D3",deeppink:"FF1493",deepskyblue:"00BFFF",dimgray:"696969",dodgerblue:"1E90FF",firebrick:"B22222",floralwhite:"FFFAF0",
forestgreen:"228B22",fuchsia:"F0F",gainsboro:"DCDCDC",ghostwhite:"F8F8FF",gold:"FFD700",goldenrod:"DAA520",gray:"808080",green:"008000",greenyellow:"ADFF2F",honeydew:"F0FFF0",hotpink:"FF69B4",indianred:"CD5C5C",indigo:"4B0082",ivory:"FFFFF0",khaki:"F0E68C",lavender:"E6E6FA",lavenderblush:"FFF0F5",lawngreen:"7CFC00",lemonchiffon:"FFFACD",lightblue:"ADD8E6",lightcoral:"F08080",lightcyan:"E0FFFF",lightgoldenrodyellow:"FAFAD2",lightgreen:"90EE90",lightgrey:"D3D3D3",lightpink:"FFB6C1",lightsalmon:"FFA07A",
lightseagreen:"20B2AA",lightskyblue:"87CEFA",lightslategray:"789",lightsteelblue:"B0C4DE",lightyellow:"FFFFE0",lime:"0F0",limegreen:"32CD32",linen:"FAF0E6",magenta:"F0F",maroon:"800000",mediumauqamarine:"66CDAA",mediumblue:"0000CD",mediumorchid:"BA55D3",mediumpurple:"9370D8",mediumseagreen:"3CB371",mediumslateblue:"7B68EE",mediumspringgreen:"00FA9A",mediumturquoise:"48D1CC",mediumvioletred:"C71585",midnightblue:"191970",mintcream:"F5FFFA",mistyrose:"FFE4E1",moccasin:"FFE4B5",navajowhite:"FFDEAD",
navy:"000080",oldlace:"FDF5E6",olive:"808000",olivedrab:"688E23",orange:"FFA500",orangered:"FF4500",orchid:"DA70D6",palegoldenrod:"EEE8AA",palegreen:"98FB98",paleturquoise:"AFEEEE",palevioletred:"D87093",papayawhip:"FFEFD5",peachpuff:"FFDAB9",peru:"CD853F",pink:"FFC0CB",plum:"DDA0DD",powderblue:"B0E0E6",purple:"800080",red:"F00",rosybrown:"BC8F8F",royalblue:"4169E1",saddlebrown:"8B4513",salmon:"FA8072",sandybrown:"F4A460",seagreen:"2E8B57",seashell:"FFF5EE",sienna:"A0522D",silver:"C0C0C0",skyblue:"87CEEB",
slateblue:"6A5ACD",slategray:"708090",snow:"FFFAFA",springgreen:"00FF7F",steelblue:"4682B4",tan:"D2B48C",teal:"008080",thistle:"D8BFD8",tomato:"FF6347",turquoise:"40E0D0",violet:"EE82EE",wheat:"F5DEB3",white:"FFF",whitesmoke:"F5F5F5",yellow:"FF0",yellowgreen:"9ACD32"};a.prototype={parse:function(){if(!this.Ua){var c=this.Y,d;if(d=c.match(a.Qd)){this.Ua="rgb("+d[1]+","+d[2]+","+d[3]+")";this.Yb=parseFloat(d[4])}else{if((d=c.toLowerCase())in a.Fb)c="#"+a.Fb[d];this.Ua=c;this.Yb=c==="transparent"?0:
1}}},U:function(c){this.parse();return this.Ua==="currentColor"?c.currentStyle.color:this.Ua},fa:function(){this.parse();return this.Yb}};f.ha=function(c){return b[c]||(b[c]=new a(c))};return a}();f.v=function(){function a(c){this.$a=c;this.ch=0;this.X=[];this.Ga=0}var b=a.qa={Ia:1,Wb:2,z:4,Lc:8,Xb:16,na:32,K:64,oa:128,pa:256,Ra:512,Tc:1024,URL:2048};a.ob=function(c,d){this.k=c;this.d=d};a.ob.prototype={Ca:function(){return this.k&b.K||this.k&b.oa&&this.d==="0"},W:function(){return this.Ca()||this.k&
b.Ra}};a.prototype={de:/\s/,Kd:/^[\+\-]?(\d*\.)?\d+/,url:/^url\(\s*("([^"]*)"|'([^']*)'|([!#$%&*-~]*))\s*\)/i,nc:/^\-?[_a-z][\w-]*/i,Yd:/^("([^"]*)"|'([^']*)')/,Bd:/^#([\da-f]{6}|[\da-f]{3})/i,be:{px:b.K,em:b.K,ex:b.K,mm:b.K,cm:b.K,"in":b.K,pt:b.K,pc:b.K,deg:b.Ia,rad:b.Ia,grad:b.Ia},fd:{rgb:1,rgba:1,hsl:1,hsla:1},next:function(c){function d(p,r){p=new a.ob(p,r);if(!c){k.X.push(p);k.Ga++}return p}function e(){k.Ga++;return null}var g,j,i,h,k=this;if(this.Ga<this.X.length)return this.X[this.Ga++];for(;this.de.test(this.$a.charAt(this.ch));)this.ch++;
if(this.ch>=this.$a.length)return e();j=this.ch;g=this.$a.substring(this.ch);i=g.charAt(0);switch(i){case "#":if(h=g.match(this.Bd)){this.ch+=h[0].length;return d(b.z,h[0])}break;case '"':case "'":if(h=g.match(this.Yd)){this.ch+=h[0].length;return d(b.Tc,h[2]||h[3]||"")}break;case "/":case ",":this.ch++;return d(b.pa,i);case "u":if(h=g.match(this.url)){this.ch+=h[0].length;return d(b.URL,h[2]||h[3]||h[4]||"")}}if(h=g.match(this.Kd)){i=h[0];this.ch+=i.length;if(g.charAt(i.length)==="%"){this.ch++;
return d(b.Ra,i+"%")}if(h=g.substring(i.length).match(this.nc)){i+=h[0];this.ch+=h[0].length;return d(this.be[h[0].toLowerCase()]||b.Lc,i)}return d(b.oa,i)}if(h=g.match(this.nc)){i=h[0];this.ch+=i.length;if(i.toLowerCase()in f.Jc.Fb||i==="currentColor"||i==="transparent")return d(b.z,i);if(g.charAt(i.length)==="("){this.ch++;if(i.toLowerCase()in this.fd){g=function(p){return p&&p.k&b.oa};h=function(p){return p&&p.k&(b.oa|b.Ra)};var n=function(p,r){return p&&p.d===r},m=function(){return k.next(1)};
if((i.charAt(0)==="r"?h(m()):g(m()))&&n(m(),",")&&h(m())&&n(m(),",")&&h(m())&&(i==="rgb"||i==="hsa"||n(m(),",")&&g(m()))&&n(m(),")"))return d(b.z,this.$a.substring(j,this.ch));return e()}return d(b.Xb,i)}return d(b.na,i)}this.ch++;return d(b.Wb,i)},D:function(){return this.X[this.Ga-- -2]},all:function(){for(;this.next(););return this.X},ma:function(c,d){for(var e=[],g,j;g=this.next();){if(c(g)){j=true;this.D();break}e.push(g)}return d&&!j?null:e}};return a}();var ha=function(a){this.e=a};ha.prototype=
{Z:0,Od:function(){var a=this.qb,b;return!a||(b=this.o())&&(a.x!==b.x||a.y!==b.y)},Td:function(){var a=this.qb,b;return!a||(b=this.o())&&(a.h!==b.h||a.f!==b.f)},hc:function(){var a=this.e,b=a.getBoundingClientRect(),c=f.ja===9,d=f.O===7,e=b.right-b.left;return{x:b.left,y:b.top,h:c||d?a.offsetWidth:e,f:c||d?a.offsetHeight:b.bottom-b.top,Hd:d&&e?a.offsetWidth/e:1}},o:function(){return this.Z?this.Va||(this.Va=this.hc()):this.hc()},Ad:function(){return!!this.qb},cb:function(){++this.Z},hb:function(){if(!--this.Z){if(this.Va)this.qb=
this.Va;this.Va=null}}};(function(){function a(b){var c=f.p.Ba(b);return function(){if(this.Z){var d=this.$b||(this.$b={});return c in d?d[c]:(d[c]=b.call(this))}else return b.call(this)}}f.B={Z:0,ka:function(b){function c(d){this.e=d;this.Zb=this.ia()}f.p.Eb(c.prototype,f.B,b);c.$c={};return c},j:function(){var b=this.ia(),c=this.constructor.$c;return b?b in c?c[b]:(c[b]=this.la(b)):null},ia:a(function(){var b=this.e,c=this.constructor,d=b.style;b=b.currentStyle;var e=this.wa,g=this.Fa,j=c.Yc||(c.Yc=
f.F+e);c=c.Zc||(c.Zc=f.nb+g.charAt(0).toUpperCase()+g.substring(1));return d[c]||b.getAttribute(j)||d[g]||b.getAttribute(e)}),i:a(function(){return!!this.j()}),H:a(function(){var b=this.ia(),c=b!==this.Zb;this.Zb=b;return c}),va:a,cb:function(){++this.Z},hb:function(){--this.Z||delete this.$b}}})();f.Sb=f.B.ka({wa:f.F+"background",Fa:f.nb+"Background",cd:{scroll:1,fixed:1,local:1},fb:{"repeat-x":1,"repeat-y":1,repeat:1,"no-repeat":1},sc:{"padding-box":1,"border-box":1,"content-box":1},Pd:{top:1,right:1,
bottom:1,left:1,center:1},Ud:{contain:1,cover:1},eb:{Ma:"backgroundClip",z:"backgroundColor",da:"backgroundImage",Pa:"backgroundOrigin",S:"backgroundPosition",T:"backgroundRepeat",Sa:"backgroundSize"},la:function(a){function b(s){return s&&s.W()||s.k&k&&s.d in t}function c(s){return s&&(s.W()&&f.n(s.d)||s.d==="auto"&&"auto")}var d=this.e.currentStyle,e,g,j,i=f.v.qa,h=i.pa,k=i.na,n=i.z,m,p,r=0,t=this.Pd,v,l,q={M:[]};if(this.wb()){e=new f.v(a);for(j={};g=e.next();){m=g.k;p=g.d;if(!j.P&&m&i.Xb&&p===
"linear-gradient"){v={ca:[],P:p};for(l={};g=e.next();){m=g.k;p=g.d;if(m&i.Wb&&p===")"){l.color&&v.ca.push(l);v.ca.length>1&&f.p.Eb(j,v);break}if(m&n){if(v.sa||v.zb){g=e.D();if(g.k!==h)break;e.next()}l={color:f.ha(p)};g=e.next();if(g.W())l.db=f.n(g.d);else e.D()}else if(m&i.Ia&&!v.sa&&!l.color&&!v.ca.length)v.sa=new f.Ec(g.d);else if(b(g)&&!v.zb&&!l.color&&!v.ca.length){e.D();v.zb=new f.Ja(e.ma(function(s){return!b(s)},false))}else if(m&h&&p===","){if(l.color){v.ca.push(l);l={}}}else break}}else if(!j.P&&
m&i.URL){j.Ab=p;j.P="image"}else if(b(g)&&!j.$){e.D();j.$=new f.Ja(e.ma(function(s){return!b(s)},false))}else if(m&k)if(p in this.fb&&!j.bb)j.bb=p;else if(p in this.sc&&!j.Wa){j.Wa=p;if((g=e.next())&&g.k&k&&g.d in this.sc)j.ub=g.d;else{j.ub=p;e.D()}}else if(p in this.cd&&!j.bc)j.bc=p;else return null;else if(m&n&&!q.color)q.color=f.ha(p);else if(m&h&&p==="/"&&!j.Xa&&j.$){g=e.next();if(g.k&k&&g.d in this.Ud)j.Xa=new f.Ka(g.d);else if(g=c(g)){m=c(e.next());if(!m){m=g;e.D()}j.Xa=new f.Ka(g,m)}else return null}else if(m&
h&&p===","&&j.P){j.Hb=a.substring(r,e.ch-1);r=e.ch;q.M.push(j);j={}}else return null}if(j.P){j.Hb=a.substring(r);q.M.push(j)}}else this.Bc(f.ja<9?function(){var s=this.eb,o=d[s.S+"X"],u=d[s.S+"Y"],x=d[s.da],y=d[s.z];if(y!=="transparent")q.color=f.ha(y);if(x!=="none")q.M=[{P:"image",Ab:(new f.v(x)).next().d,bb:d[s.T],$:new f.Ja((new f.v(o+" "+u)).all())}]}:function(){var s=this.eb,o=/\s*,\s*/,u=d[s.da].split(o),x=d[s.z],y,z,B,E,D,C;if(x!=="transparent")q.color=f.ha(x);if((E=u.length)&&u[0]!=="none"){x=
d[s.T].split(o);y=d[s.S].split(o);z=d[s.Pa].split(o);B=d[s.Ma].split(o);s=d[s.Sa].split(o);q.M=[];for(o=0;o<E;o++)if((D=u[o])&&D!=="none"){C=s[o].split(" ");q.M.push({Hb:D+" "+x[o]+" "+y[o]+" / "+s[o]+" "+z[o]+" "+B[o],P:"image",Ab:(new f.v(D)).next().d,bb:x[o],$:new f.Ja((new f.v(y[o])).all()),Wa:z[o],ub:B[o],Xa:new f.Ka(C[0],C[1])})}}});return q.color||q.M[0]?q:null},Bc:function(a){var b=f.ja>8,c=this.eb,d=this.e.runtimeStyle,e=d[c.da],g=d[c.z],j=d[c.T],i,h,k,n;if(e)d[c.da]="";if(g)d[c.z]="";if(j)d[c.T]=
"";if(b){i=d[c.Ma];h=d[c.Pa];n=d[c.S];k=d[c.Sa];if(i)d[c.Ma]="";if(h)d[c.Pa]="";if(n)d[c.S]="";if(k)d[c.Sa]=""}a=a.call(this);if(e)d[c.da]=e;if(g)d[c.z]=g;if(j)d[c.T]=j;if(b){if(i)d[c.Ma]=i;if(h)d[c.Pa]=h;if(n)d[c.S]=n;if(k)d[c.Sa]=k}return a},ia:f.B.va(function(){return this.wb()||this.Bc(function(){var a=this.e.currentStyle,b=this.eb;return a[b.z]+" "+a[b.da]+" "+a[b.T]+" "+a[b.S+"X"]+" "+a[b.S+"Y"]})}),wb:f.B.va(function(){var a=this.e;return a.style[this.Fa]||a.currentStyle.getAttribute(this.wa)}),
qc:function(){var a=0;if(f.O<7){a=this.e;a=""+(a.style[f.nb+"PngFix"]||a.currentStyle.getAttribute(f.F+"png-fix"))==="true"}return a},i:f.B.va(function(){return(this.wb()||this.qc())&&!!this.j()})});f.Vb=f.B.ka({wc:["Top","Right","Bottom","Left"],Id:{thin:"1px",medium:"3px",thick:"5px"},la:function(){var a={},b={},c={},d=false,e=true,g=true,j=true;this.Cc(function(){for(var i=this.e.currentStyle,h=0,k,n,m,p,r,t,v;h<4;h++){m=this.wc[h];v=m.charAt(0).toLowerCase();k=b[v]=i["border"+m+"Style"];n=i["border"+
m+"Color"];m=i["border"+m+"Width"];if(h>0){if(k!==p)g=false;if(n!==r)e=false;if(m!==t)j=false}p=k;r=n;t=m;c[v]=f.ha(n);m=a[v]=f.n(b[v]==="none"?"0":this.Id[m]||m);if(m.a(this.e)>0)d=true}});return d?{J:a,Zd:b,gd:c,ee:j,hd:e,$d:g}:null},ia:f.B.va(function(){var a=this.e,b=a.currentStyle,c;a.tagName in f.Ac&&a.offsetParent.currentStyle.borderCollapse==="collapse"||this.Cc(function(){c=b.borderWidth+"|"+b.borderStyle+"|"+b.borderColor});return c}),Cc:function(a){var b=this.e.runtimeStyle,c=b.borderWidth,
d=b.borderColor;if(c)b.borderWidth="";if(d)b.borderColor="";a=a.call(this);if(c)b.borderWidth=c;if(d)b.borderColor=d;return a}});(function(){f.jb=f.B.ka({wa:"border-radius",Fa:"borderRadius",la:function(b){var c=null,d,e,g,j,i=false;if(b){e=new f.v(b);var h=function(){for(var k=[],n;(g=e.next())&&g.W();){j=f.n(g.d);n=j.ic();if(n<0)return null;if(n>0)i=true;k.push(j)}return k.length>0&&k.length<5?{tl:k[0],tr:k[1]||k[0],br:k[2]||k[0],bl:k[3]||k[1]||k[0]}:null};if(b=h()){if(g){if(g.k&f.v.qa.pa&&g.d===
"/")d=h()}else d=b;if(i&&b&&d)c={x:b,y:d}}}return c}});var a=f.n("0");a={tl:a,tr:a,br:a,bl:a};f.jb.Dc={x:a,y:a}})();f.Ub=f.B.ka({wa:"border-image",Fa:"borderImage",fb:{stretch:1,round:1,repeat:1,space:1},la:function(a){var b=null,c,d,e,g,j,i,h=0,k=f.v.qa,n=k.na,m=k.oa,p=k.Ra;if(a){c=new f.v(a);b={};for(var r=function(l){return l&&l.k&k.pa&&l.d==="/"},t=function(l){return l&&l.k&n&&l.d==="fill"},v=function(){g=c.ma(function(l){return!(l.k&(m|p))});if(t(c.next())&&!b.fill)b.fill=true;else c.D();if(r(c.next())){h++;
j=c.ma(function(l){return!l.W()&&!(l.k&n&&l.d==="auto")});if(r(c.next())){h++;i=c.ma(function(l){return!l.Ca()})}}else c.D()};a=c.next();){d=a.k;e=a.d;if(d&(m|p)&&!g){c.D();v()}else if(t(a)&&!b.fill){b.fill=true;v()}else if(d&n&&this.fb[e]&&!b.repeat){b.repeat={f:e};if(a=c.next())if(a.k&n&&this.fb[a.d])b.repeat.Ob=a.d;else c.D()}else if(d&k.URL&&!b.src)b.src=e;else return null}if(!b.src||!g||g.length<1||g.length>4||j&&j.length>4||h===1&&j.length<1||i&&i.length>4||h===2&&i.length<1)return null;if(!b.repeat)b.repeat=
{f:"stretch"};if(!b.repeat.Ob)b.repeat.Ob=b.repeat.f;a=function(l,q){return{t:q(l[0]),r:q(l[1]||l[0]),b:q(l[2]||l[0]),l:q(l[3]||l[1]||l[0])}};b.slice=a(g,function(l){return f.n(l.k&m?l.d+"px":l.d)});if(j&&j[0])b.J=a(j,function(l){return l.W()?f.n(l.d):l.d});if(i&&i[0])b.Da=a(i,function(l){return l.Ca()?f.n(l.d):l.d})}return b}});f.Ic=f.B.ka({wa:"box-shadow",Fa:"boxShadow",la:function(a){var b,c=f.n,d=f.v.qa,e;if(a){e=new f.v(a);b={Da:[],Bb:[]};for(a=function(){for(var g,j,i,h,k,n;g=e.next();){i=g.d;
j=g.k;if(j&d.pa&&i===",")break;else if(g.Ca()&&!k){e.D();k=e.ma(function(m){return!m.Ca()})}else if(j&d.z&&!h)h=i;else if(j&d.na&&i==="inset"&&!n)n=true;else return false}g=k&&k.length;if(g>1&&g<5){(n?b.Bb:b.Da).push({fe:c(k[0].d),ge:c(k[1].d),blur:c(k[2]?k[2].d:"0"),Vd:c(k[3]?k[3].d:"0"),color:f.ha(h||"currentColor")});return true}return false};a(););}return b&&(b.Bb.length||b.Da.length)?b:null}});f.Uc=f.B.ka({ia:f.B.va(function(){var a=this.e.currentStyle;return a.visibility+"|"+a.display}),la:function(){var a=
this.e,b=a.runtimeStyle;a=a.currentStyle;var c=b.visibility,d;b.visibility="";d=a.visibility;b.visibility=c;return{ce:d!=="hidden",nd:a.display!=="none"}},i:function(){return false}});f.u={R:function(a){function b(c,d,e,g){this.e=c;this.s=d;this.g=e;this.parent=g}f.p.Eb(b.prototype,f.u,a);return b},Cb:false,Q:function(){return false},Ea:f.aa,Lb:function(){this.m();this.i()&&this.V()},ib:function(){this.Cb=true},Mb:function(){this.i()?this.V():this.m()},sb:function(a,b){this.vc(a);for(var c=this.ra||
(this.ra=[]),d=a+1,e=c.length,g;d<e;d++)if(g=c[d])break;c[a]=b;this.I().insertBefore(b,g||null)},za:function(a){var b=this.ra;return b&&b[a]||null},vc:function(a){var b=this.za(a),c=this.Ta;if(b&&c){c.removeChild(b);this.ra[a]=null}},Aa:function(a,b,c,d){var e=this.rb||(this.rb={}),g=e[a];if(!g){g=e[a]=f.p.Za("shape");if(b)g.appendChild(g[b]=f.p.Za(b));if(d){c=this.za(d);if(!c){this.sb(d,doc.createElement("group"+d));c=this.za(d)}}c.appendChild(g);a=g.style;a.position="absolute";a.left=a.top=0;a.behavior=
"url(#default#VML)"}return g},vb:function(a){var b=this.rb,c=b&&b[a];if(c){c.parentNode.removeChild(c);delete b[a]}return!!c},kc:function(a){var b=this.e,c=this.s.o(),d=c.h,e=c.f,g,j,i,h,k,n;c=a.x.tl.a(b,d);g=a.y.tl.a(b,e);j=a.x.tr.a(b,d);i=a.y.tr.a(b,e);h=a.x.br.a(b,d);k=a.y.br.a(b,e);n=a.x.bl.a(b,d);a=a.y.bl.a(b,e);d=Math.min(d/(c+j),e/(i+k),d/(n+h),e/(g+a));if(d<1){c*=d;g*=d;j*=d;i*=d;h*=d;k*=d;n*=d;a*=d}return{x:{tl:c,tr:j,br:h,bl:n},y:{tl:g,tr:i,br:k,bl:a}}},ya:function(a,b,c){b=b||1;var d,e,
g=this.s.o();e=g.h*b;g=g.f*b;var j=this.g.G,i=Math.floor,h=Math.ceil,k=a?a.Jb*b:0,n=a?a.Ib*b:0,m=a?a.tb*b:0;a=a?a.Db*b:0;var p,r,t,v,l;if(c||j.i()){d=this.kc(c||j.j());c=d.x.tl*b;j=d.y.tl*b;p=d.x.tr*b;r=d.y.tr*b;t=d.x.br*b;v=d.y.br*b;l=d.x.bl*b;b=d.y.bl*b;e="m"+i(a)+","+i(j)+"qy"+i(c)+","+i(k)+"l"+h(e-p)+","+i(k)+"qx"+h(e-n)+","+i(r)+"l"+h(e-n)+","+h(g-v)+"qy"+h(e-t)+","+h(g-m)+"l"+i(l)+","+h(g-m)+"qx"+i(a)+","+h(g-b)+" x e"}else e="m"+i(a)+","+i(k)+"l"+h(e-n)+","+i(k)+"l"+h(e-n)+","+h(g-m)+"l"+i(a)+
","+h(g-m)+"xe";return e},I:function(){var a=this.parent.za(this.N),b;if(!a){a=doc.createElement(this.Ya);b=a.style;b.position="absolute";b.top=b.left=0;this.parent.sb(this.N,a)}return a},mc:function(){var a=this.e,b=a.currentStyle,c=a.runtimeStyle,d=a.tagName,e=f.O===6,g;if(e&&(d in f.cc||d==="FIELDSET")||d==="BUTTON"||d==="INPUT"&&a.type in f.Gd){c.borderWidth="";d=this.g.w.wc;for(g=d.length;g--;){e=d[g];c["padding"+e]="";c["padding"+e]=f.n(b["padding"+e]).a(a)+f.n(b["border"+e+"Width"]).a(a)+(f.O!==
8&&g%2?1:0)}c.borderWidth=0}else if(e){if(a.childNodes.length!==1||a.firstChild.tagName!=="ie6-mask"){b=doc.createElement("ie6-mask");d=b.style;d.visibility="visible";for(d.zoom=1;d=a.firstChild;)b.appendChild(d);a.appendChild(b);c.visibility="hidden"}}else c.borderColor="transparent"},ie:function(){},m:function(){this.parent.vc(this.N);delete this.rb;delete this.ra}};f.Rc=f.u.R({i:function(){var a=this.ed;for(var b in a)if(a.hasOwnProperty(b)&&a[b].i())return true;return false},Q:function(){return this.g.Pb.H()},
ib:function(){if(this.i()){var a=this.jc(),b=a,c;a=a.currentStyle;var d=a.position,e=this.I().style,g=0,j=0;j=this.s.o();var i=j.Hd;if(d==="fixed"&&f.O>6){g=j.x*i;j=j.y*i;b=d}else{do b=b.offsetParent;while(b&&b.currentStyle.position==="static");if(b){c=b.getBoundingClientRect();b=b.currentStyle;g=(j.x-c.left)*i-(parseFloat(b.borderLeftWidth)||0);j=(j.y-c.top)*i-(parseFloat(b.borderTopWidth)||0)}else{b=doc.documentElement;g=(j.x+b.scrollLeft-b.clientLeft)*i;j=(j.y+b.scrollTop-b.clientTop)*i}b="absolute"}e.position=
b;e.left=g;e.top=j;e.zIndex=d==="static"?-1:a.zIndex;this.Cb=true}},Mb:f.aa,Nb:function(){var a=this.g.Pb.j();this.I().style.display=a.ce&&a.nd?"":"none"},Lb:function(){this.i()?this.Nb():this.m()},jc:function(){var a=this.e;return a.tagName in f.Ac?a.offsetParent:a},I:function(){var a=this.Ta,b;if(!a){b=this.jc();a=this.Ta=doc.createElement("css3-container");a.style.direction="ltr";this.Nb();b.parentNode.insertBefore(a,b)}return a},ab:f.aa,m:function(){var a=this.Ta,b;if(a&&(b=a.parentNode))b.removeChild(a);
delete this.Ta;delete this.ra}});f.Fc=f.u.R({N:2,Ya:"background",Q:function(){var a=this.g;return a.C.H()||a.G.H()},i:function(){var a=this.g;return a.q.i()||a.G.i()||a.C.i()||a.ga.i()&&a.ga.j().Bb},V:function(){var a=this.s.o();if(a.h&&a.f){this.od();this.pd()}},od:function(){var a=this.g.C.j(),b=this.s.o(),c=this.e,d=a&&a.color,e,g;if(d&&d.fa()>0){this.lc();a=this.Aa("bgColor","fill",this.I(),1);e=b.h;b=b.f;a.stroked=false;a.coordsize=e*2+","+b*2;a.coordorigin="1,1";a.path=this.ya(null,2);g=a.style;
g.width=e;g.height=b;a.fill.color=d.U(c);c=d.fa();if(c<1)a.fill.opacity=c}else this.vb("bgColor")},pd:function(){var a=this.g.C.j(),b=this.s.o();a=a&&a.M;var c,d,e,g,j;if(a){this.lc();d=b.h;e=b.f;for(j=a.length;j--;){b=a[j];c=this.Aa("bgImage"+j,"fill",this.I(),2);c.stroked=false;c.fill.type="tile";c.fillcolor="none";c.coordsize=d*2+","+e*2;c.coordorigin="1,1";c.path=this.ya(0,2);g=c.style;g.width=d;g.height=e;if(b.P==="linear-gradient")this.bd(c,b);else{c.fill.src=b.Ab;this.Nd(c,j)}}}for(j=a?a.length:
0;this.vb("bgImage"+j++););},Nd:function(a,b){var c=this;f.p.Rb(a.fill.src,function(d){var e=c.e,g=c.s.o(),j=g.h;g=g.f;if(j&&g){var i=a.fill,h=c.g,k=h.w.j(),n=k&&k.J;k=n?n.t.a(e):0;var m=n?n.r.a(e):0,p=n?n.b.a(e):0;n=n?n.l.a(e):0;h=h.C.j().M[b];e=h.$?h.$.coords(e,j-d.h-n-m,g-d.f-k-p):{x:0,y:0};h=h.bb;p=m=0;var r=j+1,t=g+1,v=f.O===8?0:1;n=Math.round(e.x)+n+0.5;k=Math.round(e.y)+k+0.5;i.position=n/j+","+k/g;i.size.x=1;i.size=d.h+"px,"+d.f+"px";if(h&&h!=="repeat"){if(h==="repeat-x"||h==="no-repeat"){m=
k+1;t=k+d.f+v}if(h==="repeat-y"||h==="no-repeat"){p=n+1;r=n+d.h+v}a.style.clip="rect("+m+"px,"+r+"px,"+t+"px,"+p+"px)"}}})},bd:function(a,b){var c=this.e,d=this.s.o(),e=d.h,g=d.f;a=a.fill;d=b.ca;var j=d.length,i=Math.PI,h=f.Na,k=h.tc,n=h.dc;b=h.gc(c,e,g,b);h=b.sa;var m=b.xc,p=b.yc,r=b.Wd,t=b.Xd,v=b.rd,l=b.sd,q=b.kd,s=b.ld;b=b.rc;e=h%90?Math.atan2(q*e/g,s)/i*180:h+90;e+=180;e%=360;v=k(r,t,h,v,l);g=n(r,t,v[0],v[1]);i=[];v=k(m,p,h,r,t);n=n(m,p,v[0],v[1])/g*100;k=[];for(h=0;h<j;h++)k.push(d[h].db?d[h].db.a(c,
b):h===0?0:h===j-1?b:null);for(h=1;h<j;h++){if(k[h]===null){m=k[h-1];b=h;do p=k[++b];while(p===null);k[h]=m+(p-m)/(b-h+1)}k[h]=Math.max(k[h],k[h-1])}for(h=0;h<j;h++)i.push(n+k[h]/g*100+"% "+d[h].color.U(c));a.angle=e;a.type="gradient";a.method="sigma";a.color=d[0].color.U(c);a.color2=d[j-1].color.U(c);if(a.colors)a.colors.value=i.join(",");else a.colors=i.join(",")},lc:function(){var a=this.e.runtimeStyle;a.backgroundImage="url(about:blank)";a.backgroundColor="transparent"},m:function(){f.u.m.call(this);
var a=this.e.runtimeStyle;a.backgroundImage=a.backgroundColor=""}});f.Gc=f.u.R({N:4,Ya:"border",Q:function(){var a=this.g;return a.w.H()||a.G.H()},i:function(){var a=this.g;return a.G.i()&&!a.q.i()&&a.w.i()},V:function(){var a=this.e,b=this.g.w.j(),c=this.s.o(),d=c.h;c=c.f;var e,g,j,i,h;if(b){this.mc();b=this.wd(2);i=0;for(h=b.length;i<h;i++){j=b[i];e=this.Aa("borderPiece"+i,j.stroke?"stroke":"fill",this.I());e.coordsize=d*2+","+c*2;e.coordorigin="1,1";e.path=j.path;g=e.style;g.width=d;g.height=c;
e.filled=!!j.fill;e.stroked=!!j.stroke;if(j.stroke){e=e.stroke;e.weight=j.Qb+"px";e.color=j.color.U(a);e.dashstyle=j.stroke==="dashed"?"2 2":j.stroke==="dotted"?"1 1":"solid";e.linestyle=j.stroke==="double"&&j.Qb>2?"ThinThin":"Single"}else e.fill.color=j.fill.U(a)}for(;this.vb("borderPiece"+i++););}},wd:function(a){var b=this.e,c,d,e,g=this.g.w,j=[],i,h,k,n,m=Math.round,p,r,t;if(g.i()){c=g.j();g=c.J;r=c.Zd;t=c.gd;if(c.ee&&c.$d&&c.hd){if(t.t.fa()>0){c=g.t.a(b);k=c/2;j.push({path:this.ya({Jb:k,Ib:k,
tb:k,Db:k},a),stroke:r.t,color:t.t,Qb:c})}}else{a=a||1;c=this.s.o();d=c.h;e=c.f;c=m(g.t.a(b));k=m(g.r.a(b));n=m(g.b.a(b));b=m(g.l.a(b));var v={t:c,r:k,b:n,l:b};b=this.g.G;if(b.i())p=this.kc(b.j());i=Math.floor;h=Math.ceil;var l=function(o,u){return p?p[o][u]:0},q=function(o,u,x,y,z,B){var E=l("x",o),D=l("y",o),C=o.charAt(1)==="r";o=o.charAt(0)==="b";return E>0&&D>0?(B?"al":"ae")+(C?h(d-E):i(E))*a+","+(o?h(e-D):i(D))*a+","+(i(E)-u)*a+","+(i(D)-x)*a+","+y*65535+","+2949075*(z?1:-1):(B?"m":"l")+(C?d-
u:u)*a+","+(o?e-x:x)*a},s=function(o,u,x,y){var z=o==="t"?i(l("x","tl"))*a+","+h(u)*a:o==="r"?h(d-u)*a+","+i(l("y","tr"))*a:o==="b"?h(d-l("x","br"))*a+","+i(e-u)*a:i(u)*a+","+h(e-l("y","bl"))*a;o=o==="t"?h(d-l("x","tr"))*a+","+h(u)*a:o==="r"?h(d-u)*a+","+h(e-l("y","br"))*a:o==="b"?i(l("x","bl"))*a+","+i(e-u)*a:i(u)*a+","+i(l("y","tl"))*a;return x?(y?"m"+o:"")+"l"+z:(y?"m"+z:"")+"l"+o};b=function(o,u,x,y,z,B){var E=o==="l"||o==="r",D=v[o],C,F;if(D>0&&r[o]!=="none"&&t[o].fa()>0){C=v[E?o:u];u=v[E?u:
o];F=v[E?o:x];x=v[E?x:o];if(r[o]==="dashed"||r[o]==="dotted"){j.push({path:q(y,C,u,B+45,0,1)+q(y,0,0,B,1,0),fill:t[o]});j.push({path:s(o,D/2,0,1),stroke:r[o],Qb:D,color:t[o]});j.push({path:q(z,F,x,B,0,1)+q(z,0,0,B-45,1,0),fill:t[o]})}else j.push({path:q(y,C,u,B+45,0,1)+s(o,D,0,0)+q(z,F,x,B,0,0)+(r[o]==="double"&&D>2?q(z,F-i(F/3),x-i(x/3),B-45,1,0)+s(o,h(D/3*2),1,0)+q(y,C-i(C/3),u-i(u/3),B,1,0)+"x "+q(y,i(C/3),i(u/3),B+45,0,1)+s(o,i(D/3),1,0)+q(z,i(F/3),i(x/3),B,0,0):"")+q(z,0,0,B-45,1,0)+s(o,0,1,
0)+q(y,0,0,B,1,0),fill:t[o]})}};b("t","l","r","tl","tr",90);b("r","t","b","tr","br",0);b("b","r","l","br","bl",-90);b("l","b","t","bl","tl",-180)}}return j},m:function(){if(this.ec||!this.g.q.i())this.e.runtimeStyle.borderColor="";f.u.m.call(this)}});f.Tb=f.u.R({N:5,Md:["t","tr","r","br","b","bl","l","tl","c"],Q:function(){return this.g.q.H()},i:function(){return this.g.q.i()},V:function(){this.I();var a=this.g.q.j(),b=this.g.w.j(),c=this.s.o(),d=this.e,e=this.uc;f.p.Rb(a.src,function(g){function j(s,
o,u,x,y){s=e[s].style;var z=Math.max;s.width=z(o,0);s.height=z(u,0);s.left=x;s.top=y}function i(s,o,u){for(var x=0,y=s.length;x<y;x++)e[s[x]].imagedata[o]=u}var h=c.h,k=c.f,n=f.n("0"),m=a.J||(b?b.J:{t:n,r:n,b:n,l:n});n=m.t.a(d);var p=m.r.a(d),r=m.b.a(d);m=m.l.a(d);var t=a.slice,v=t.t.a(d),l=t.r.a(d),q=t.b.a(d);t=t.l.a(d);j("tl",m,n,0,0);j("t",h-m-p,n,m,0);j("tr",p,n,h-p,0);j("r",p,k-n-r,h-p,n);j("br",p,r,h-p,k-r);j("b",h-m-p,r,m,k-r);j("bl",m,r,0,k-r);j("l",m,k-n-r,0,n);j("c",h-m-p,k-n-r,m,n);i(["tl",
"t","tr"],"cropBottom",(g.f-v)/g.f);i(["tl","l","bl"],"cropRight",(g.h-t)/g.h);i(["bl","b","br"],"cropTop",(g.f-q)/g.f);i(["tr","r","br"],"cropLeft",(g.h-l)/g.h);i(["l","r","c"],"cropTop",v/g.f);i(["l","r","c"],"cropBottom",q/g.f);i(["t","b","c"],"cropLeft",t/g.h);i(["t","b","c"],"cropRight",l/g.h);e.c.style.display=a.fill?"":"none"},this)},I:function(){var a=this.parent.za(this.N),b,c,d,e=this.Md,g=e.length;if(!a){a=doc.createElement("border-image");b=a.style;b.position="absolute";this.uc={};for(d=
0;d<g;d++){c=this.uc[e[d]]=f.p.Za("rect");c.appendChild(f.p.Za("imagedata"));b=c.style;b.behavior="url(#default#VML)";b.position="absolute";b.top=b.left=0;c.imagedata.src=this.g.q.j().src;c.stroked=false;c.filled=false;a.appendChild(c)}this.parent.sb(this.N,a)}return a},Ea:function(){if(this.i()){var a=this.e,b=a.runtimeStyle,c=this.g.q.j().J;b.borderStyle="solid";if(c){b.borderTopWidth=c.t.a(a)+"px";b.borderRightWidth=c.r.a(a)+"px";b.borderBottomWidth=c.b.a(a)+"px";b.borderLeftWidth=c.l.a(a)+"px"}this.mc()}},
m:function(){var a=this.e.runtimeStyle;a.borderStyle="";if(this.ec||!this.g.w.i())a.borderColor=a.borderWidth="";f.u.m.call(this)}});f.Hc=f.u.R({N:1,Ya:"outset-box-shadow",Q:function(){var a=this.g;return a.ga.H()||a.G.H()},i:function(){var a=this.g.ga;return a.i()&&a.j().Da[0]},V:function(){function a(C,F,O,H,M,P,I){C=b.Aa("shadow"+C+F,"fill",d,j-C);F=C.fill;C.coordsize=n*2+","+m*2;C.coordorigin="1,1";C.stroked=false;C.filled=true;F.color=M.U(c);if(P){F.type="gradienttitle";F.color2=F.color;F.opacity=
0}C.path=I;l=C.style;l.left=O;l.top=H;l.width=n;l.height=m;return C}var b=this,c=this.e,d=this.I(),e=this.g,g=e.ga.j().Da;e=e.G.j();var j=g.length,i=j,h,k=this.s.o(),n=k.h,m=k.f;k=f.O===8?1:0;for(var p=["tl","tr","br","bl"],r,t,v,l,q,s,o,u,x,y,z,B,E,D;i--;){t=g[i];q=t.fe.a(c);s=t.ge.a(c);h=t.Vd.a(c);o=t.blur.a(c);t=t.color;u=-h-o;if(!e&&o)e=f.jb.Dc;u=this.ya({Jb:u,Ib:u,tb:u,Db:u},2,e);if(o){x=(h+o)*2+n;y=(h+o)*2+m;z=x?o*2/x:0;B=y?o*2/y:0;if(o-h>n/2||o-h>m/2)for(h=4;h--;){r=p[h];E=r.charAt(0)==="b";
D=r.charAt(1)==="r";r=a(i,r,q,s,t,o,u);v=r.fill;v.focusposition=(D?1-z:z)+","+(E?1-B:B);v.focussize="0,0";r.style.clip="rect("+((E?y/2:0)+k)+"px,"+(D?x:x/2)+"px,"+(E?y:y/2)+"px,"+((D?x/2:0)+k)+"px)"}else{r=a(i,"",q,s,t,o,u);v=r.fill;v.focusposition=z+","+B;v.focussize=1-z*2+","+(1-B*2)}}else{r=a(i,"",q,s,t,o,u);q=t.fa();if(q<1)r.fill.opacity=q}}}});f.Pc=f.u.R({N:6,Ya:"imgEl",Q:function(){var a=this.g;return this.e.src!==this.Xc||a.G.H()},i:function(){var a=this.g;return a.G.i()||a.C.qc()},V:function(){this.Xc=
j;this.Cd();var a=this.Aa("img","fill",this.I()),b=a.fill,c=this.s.o(),d=c.h;c=c.f;var e=this.g.w.j(),g=e&&e.J;e=this.e;var j=e.src,i=Math.round,h=e.currentStyle,k=f.n;if(!g||f.O<7){g=f.n("0");g={t:g,r:g,b:g,l:g}}a.stroked=false;b.type="frame";b.src=j;b.position=(d?0.5/d:0)+","+(c?0.5/c:0);a.coordsize=d*2+","+c*2;a.coordorigin="1,1";a.path=this.ya({Jb:i(g.t.a(e)+k(h.paddingTop).a(e)),Ib:i(g.r.a(e)+k(h.paddingRight).a(e)),tb:i(g.b.a(e)+k(h.paddingBottom).a(e)),Db:i(g.l.a(e)+k(h.paddingLeft).a(e))},
2);a=a.style;a.width=d;a.height=c},Cd:function(){this.e.runtimeStyle.filter="alpha(opacity=0)"},m:function(){f.u.m.call(this);this.e.runtimeStyle.filter=""}});f.Oc=f.u.R({ib:f.aa,Mb:f.aa,Nb:f.aa,Lb:f.aa,Ld:/^,+|,+$/g,Fd:/,+/g,gb:function(a,b){(this.pb||(this.pb=[]))[a]=b||void 0},ab:function(){var a=this.pb,b;if(a&&(b=a.join(",").replace(this.Ld,"").replace(this.Fd,","))!==this.Wc)this.Wc=this.e.runtimeStyle.background=b},m:function(){this.e.runtimeStyle.background="";delete this.pb}});f.Mc=f.u.R({ua:1,
Q:function(){return this.g.C.H()},i:function(){var a=this.g;return a.C.i()||a.q.i()},V:function(){var a=this.g.C.j(),b,c,d=0,e,g;if(a){b=[];if(c=a.M)for(;e=c[d++];)if(e.P==="linear-gradient"){g=this.vd(e.Wa);g=(e.Xa||f.Ka.Kc).a(this.e,g.h,g.f,g.h,g.f);b.push("url(data:image/svg+xml,"+escape(this.xd(e,g.h,g.f))+") "+this.dd(e.$)+" / "+g.h+"px "+g.f+"px "+(e.bc||"")+" "+(e.Wa||"")+" "+(e.ub||""))}else b.push(e.Hb);a.color&&b.push(a.color.Y);this.parent.gb(this.ua,b.join(","))}},dd:function(a){return a?
a.X.map(function(b){return b.d}).join(" "):"0 0"},vd:function(a){var b=this.e,c=this.s.o(),d=c.h;c=c.f;var e;if(a!=="border-box")if((e=this.g.w.j())&&(e=e.J)){d-=e.l.a(b)+e.l.a(b);c-=e.t.a(b)+e.b.a(b)}if(a==="content-box"){a=f.n;e=b.currentStyle;d-=a(e.paddingLeft).a(b)+a(e.paddingRight).a(b);c-=a(e.paddingTop).a(b)+a(e.paddingBottom).a(b)}return{h:d,f:c}},xd:function(a,b,c){var d=this.e,e=a.ca,g=e.length,j=f.Na.gc(d,b,c,a);a=j.xc;var i=j.yc,h=j.td,k=j.ud;j=j.rc;var n,m,p,r,t;n=[];for(m=0;m<g;m++)n.push(e[m].db?
e[m].db.a(d,j):m===0?0:m===g-1?j:null);for(m=1;m<g;m++)if(n[m]===null){r=n[m-1];p=m;do t=n[++p];while(t===null);n[m]=r+(t-r)/(p-m+1)}b=['<svg width="'+b+'" height="'+c+'" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="'+a/b*100+'%" y1="'+i/c*100+'%" x2="'+h/b*100+'%" y2="'+k/c*100+'%">'];for(m=0;m<g;m++)b.push('<stop offset="'+n[m]/j+'" stop-color="'+e[m].color.U(d)+'" stop-opacity="'+e[m].color.fa()+'"/>');b.push('</linearGradient></defs><rect width="100%" height="100%" fill="url(#g)"/></svg>');
return b.join("")},m:function(){this.parent.gb(this.ua)}});f.Nc=f.u.R({T:"repeat",Sc:"stretch",Qc:"round",ua:0,Q:function(){return this.g.q.H()},i:function(){return this.g.q.i()},V:function(){var a=this,b=a.g.q.j(),c=a.g.w.j(),d=a.s.o(),e=b.repeat,g=e.f,j=e.Ob,i=a.e,h=0;f.p.Rb(b.src,function(k){function n(Q,R,U,V,W,Y,X,S,w,A){K.push('<pattern patternUnits="userSpaceOnUse" id="pattern'+G+'" x="'+(g===l?Q+U/2-w/2:Q)+'" y="'+(j===l?R+V/2-A/2:R)+'" width="'+w+'" height="'+A+'"><svg width="'+w+'" height="'+
A+'" viewBox="'+W+" "+Y+" "+X+" "+S+'" preserveAspectRatio="none"><image xlink:href="'+v+'" x="0" y="0" width="'+r+'" height="'+t+'" /></svg></pattern>');J.push('<rect x="'+Q+'" y="'+R+'" width="'+U+'" height="'+V+'" fill="url(#pattern'+G+')" />');G++}var m=d.h,p=d.f,r=k.h,t=k.f,v=a.Dd(b.src,r,t),l=a.T,q=a.Sc;k=a.Qc;var s=Math.ceil,o=f.n("0"),u=b.J||(c?c.J:{t:o,r:o,b:o,l:o});o=u.t.a(i);var x=u.r.a(i),y=u.b.a(i);u=u.l.a(i);var z=b.slice,B=z.t.a(i),E=z.r.a(i),D=z.b.a(i);z=z.l.a(i);var C=m-u-x,F=p-o-
y,O=r-z-E,H=t-B-D,M=g===q?C:O*o/B,P=j===q?F:H*x/E,I=g===q?C:O*y/D;q=j===q?F:H*u/z;var K=[],J=[],G=0;if(g===k){M-=(M-(C%M||M))/s(C/M);I-=(I-(C%I||I))/s(C/I)}if(j===k){P-=(P-(F%P||P))/s(F/P);q-=(q-(F%q||q))/s(F/q)}k=['<svg width="'+m+'" height="'+p+'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'];n(0,0,u,o,0,0,z,B,u,o);n(u,0,C,o,z,0,O,B,M,o);n(m-x,0,x,o,r-E,0,E,B,x,o);n(0,o,u,F,0,B,z,H,u,q);if(b.fill)n(u,o,C,F,z,B,O,H,M||I||O,q||P||H);n(m-x,o,x,F,r-E,B,E,H,x,P);n(0,
p-y,u,y,0,t-D,z,D,u,y);n(u,p-y,C,y,z,t-D,O,D,I,y);n(m-x,p-y,x,y,r-E,t-D,E,D,x,y);k.push("<defs>"+K.join("\n")+"</defs>"+J.join("\n")+"</svg>");a.parent.gb(a.ua,"url(data:image/svg+xml,"+escape(k.join(""))+") no-repeat border-box border-box");h&&a.parent.ab()},a);h=1},Dd:function(){var a={};return function(b,c,d){var e=a[b],g;if(!e){e=new Image;g=doc.createElement("canvas");e.src=b;g.width=c;g.height=d;g.getContext("2d").drawImage(e,0,0);e=a[b]=g.toDataURL()}return e}}(),Ea:f.Tb.prototype.Ea,m:function(){var a=
this.e.runtimeStyle;this.parent.gb(this.ua);a.borderColor=a.borderStyle=a.borderWidth=""}});f.kb=function(){function a(l,q){l.className+=" "+q}function b(l){var q=v.slice.call(arguments,1),s=q.length;setTimeout(function(){if(l)for(;s--;)a(l,q[s])},0)}function c(l){var q=v.slice.call(arguments,1),s=q.length;setTimeout(function(){if(l)for(;s--;){var o=q[s];o=t[o]||(t[o]=new RegExp("\\b"+o+"\\b","g"));l.className=l.className.replace(o,"")}},0)}function d(l){function q(){if(!U){var w,A,L=f.ja,T=l.currentStyle,
N=T.getAttribute(g)==="true",da=T.getAttribute(i)!=="false",ea=T.getAttribute(h)!=="false";S=T.getAttribute(j);S=L>7?S!=="false":S==="true";if(!R){R=1;l.runtimeStyle.zoom=1;T=l;for(var fa=1;T=T.previousSibling;)if(T.nodeType===1){fa=0;break}fa&&a(l,p)}J.cb();if(N&&(A=J.o())&&(w=doc.documentElement||doc.body)&&(A.y>w.clientHeight||A.x>w.clientWidth||A.y+A.f<0||A.x+A.h<0)){if(!Y){Y=1;f.mb.ba(q)}}else{U=1;Y=R=0;f.mb.Ha(q);if(L===9){G={C:new f.Sb(l),q:new f.Ub(l),w:new f.Vb(l)};Q=[G.C,G.q];K=new f.Oc(l,
J,G);w=[new f.Mc(l,J,G,K),new f.Nc(l,J,G,K)]}else{G={C:new f.Sb(l),w:new f.Vb(l),q:new f.Ub(l),G:new f.jb(l),ga:new f.Ic(l),Pb:new f.Uc(l)};Q=[G.C,G.w,G.q,G.G,G.ga,G.Pb];K=new f.Rc(l,J,G);w=[new f.Hc(l,J,G,K),new f.Fc(l,J,G,K),new f.Gc(l,J,G,K),new f.Tb(l,J,G,K)];l.tagName==="IMG"&&w.push(new f.Pc(l,J,G,K));K.ed=w}I=[K].concat(w);if(w=l.currentStyle.getAttribute(f.F+"watch-ancestors")){w=parseInt(w,10);A=0;for(N=l.parentNode;N&&(w==="NaN"||A++<w);){H(N,"onpropertychange",C);H(N,"onmouseenter",x);
H(N,"onmouseleave",y);H(N,"onmousedown",z);if(N.tagName in f.fc){H(N,"onfocus",E);H(N,"onblur",D)}N=N.parentNode}}if(S){f.Oa.ba(o);f.Oa.Rd()}o(1)}if(!V){V=1;L<9&&H(l,"onmove",s);H(l,"onresize",s);H(l,"onpropertychange",u);ea&&H(l,"onmouseenter",x);if(ea||da)H(l,"onmouseleave",y);da&&H(l,"onmousedown",z);if(l.tagName in f.fc){H(l,"onfocus",E);H(l,"onblur",D)}f.Qa.ba(s);f.L.ba(M)}J.hb()}}function s(){J&&J.Ad()&&o()}function o(w){if(!X)if(U){var A,L=I.length;F();for(A=0;A<L;A++)I[A].Ea();if(w||J.Od())for(A=
0;A<L;A++)I[A].ib();if(w||J.Td())for(A=0;A<L;A++)I[A].Mb();K.ab();O()}else R||q()}function u(){var w,A=I.length,L;w=event;if(!X&&!(w&&w.propertyName in r))if(U){F();for(w=0;w<A;w++)I[w].Ea();for(w=0;w<A;w++){L=I[w];L.Cb||L.ib();L.Q()&&L.Lb()}K.ab();O()}else R||q()}function x(){b(l,k)}function y(){c(l,k,n)}function z(){b(l,n);f.lb.ba(B)}function B(){c(l,n);f.lb.Ha(B)}function E(){b(l,m)}function D(){c(l,m)}function C(){var w=event.propertyName;if(w==="className"||w==="id")u()}function F(){J.cb();for(var w=
Q.length;w--;)Q[w].cb()}function O(){for(var w=Q.length;w--;)Q[w].hb();J.hb()}function H(w,A,L){w.attachEvent(A,L);W.push([w,A,L])}function M(){if(V){for(var w=W.length,A;w--;){A=W[w];A[0].detachEvent(A[1],A[2])}f.L.Ha(M);V=0;W=[]}}function P(){if(!X){var w,A;M();X=1;if(I){w=0;for(A=I.length;w<A;w++){I[w].ec=1;I[w].m()}}S&&f.Oa.Ha(o);f.Qa.Ha(o);I=J=G=Q=l=null}}var I,K,J=new ha(l),G,Q,R,U,V,W=[],Y,X,S;this.Ed=q;this.update=o;this.m=P;this.qd=l}var e={},g=f.F+"lazy-init",j=f.F+"poll",i=f.F+"track-active",
h=f.F+"track-hover",k=f.La+"hover",n=f.La+"active",m=f.La+"focus",p=f.La+"first-child",r={background:1,bgColor:1,display:1},t={},v=[];d.yd=function(l){var q=f.p.Ba(l);return e[q]||(e[q]=new d(l))};d.m=function(l){l=f.p.Ba(l);var q=e[l];if(q){q.m();delete e[l]}};d.md=function(){var l=[],q;if(e){for(var s in e)if(e.hasOwnProperty(s)){q=e[s];l.push(q.qd);q.m()}e={}}return l};return d}();f.supportsVML=f.zc;f.attach=function(a){f.ja<10&&f.zc&&f.kb.yd(a).Ed()};f.detach=function(a){f.kb.m(a)}};
var $=element;function init(){if(doc.media!=="print"){var a=window.PIE;a&&a.attach($)}}function cleanup(){if(doc.media!=="print"){var a=window.PIE;if(a){a.detach($);$=0}}}$.readyState==="complete"&&init();
</script>
</PUBLIC:COMPONENT>
================================================
FILE: chatbot_website/chatbot_interface/static/assets/js/html5shiv.js
================================================
/*
HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/base/_page.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Basic */
// Ensures page width is always >=320px.
@include breakpoint(xsmall) {
html, body {
min-width: 320px;
}
}
body {
// Prevents animation/transition "flicker" on page load.
// Automatically added/removed by js/main.js.
&.is-loading {
*, *:before, *:after {
@include vendor('animation', 'none !important');
@include vendor('transition', 'none !important');
}
}
}
html {
height: 100%;
}
body {
height: 100%;
background-color: _palette(bg);
@include vendor('background-image', (
'url("images/overlay.png")',
'linear-gradient(60deg, #{transparentize(_palette(accent1), 0.5)} 5%, #{transparentize(_palette(accent2), 0.65)})',
'url("../../images/bg.jpg")'
));
background-repeat: repeat, no-repeat, no-repeat;
background-size: 100px 100px, cover, cover;
background-position: top left, center center, bottom center;
background-attachment: fixed, fixed, fixed;
&:after {
content: '';
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: inherit;
opacity: 0;
z-index: 1;
background-color: _palette(bg);
@include vendor('background-image', (
'url("images/overlay.png")',
'linear-gradient(60deg, #{transparentize(_palette(accent1), 0.5)} 5%, #{transparentize(_palette(accent2), 0.65)})'
));
background-repeat: repeat, no-repeat;
background-size: 100px 100px, cover;
background-position: top left, center center;
@include vendor('transition', 'opacity #{_duration(bg)} ease-out');
}
&.is-loading {
&:after {
opacity: 1;
}
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/base/_typography.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Type */
body, input, select, textarea {
color: _palette(fg);
font-family: _font(family);
font-size: 14pt;
font-weight: _font(weight);
line-height: 2;
letter-spacing: _size(letter-spacing);
text-transform: uppercase;
@include breakpoint(xlarge) {
font-size: 11pt;
}
@include breakpoint(xsmall) {
font-size: 10pt;
line-height: 1.75;
}
}
a {
@include vendor('transition', (
'color #{_duration(transition)} ease',
'border-color #{_duration(transition)} ease'
));
color: inherit;
text-decoration: none;
&:before {
@include vendor('transition', (
'color #{_duration(transition)} ease',
'text-shadow #{_duration(transition)} ease'
));
}
&:hover {
color: _palette(highlight);
}
}
strong, b {
color: _palette(fg-bold);
}
em, i {
font-style: italic;
}
p {
margin: 0 0 _size(element-margin) 0;
}
h1, h2, h3, h4, h5, h6 {
color: _palette(fg-bold);
line-height: 1.5;
margin: 0 0 (_size(element-margin) * 0.5) 0;
a {
color: inherit;
text-decoration: none;
}
}
h1 {
font-size: 1.85em;
letter-spacing: (_size(letter-spacing) * 1.1);
margin: 0 0 (_size(element-margin) * 0.35) 0;
}
h2 {
font-size: 1.25em;
}
h3 {
font-size: 1em;
}
h4 {
font-size: 1em;
}
h5 {
font-size: 1em;
}
h6 {
font-size: 1em;
}
@include breakpoint(xsmall) {
h1 {
font-size: 1.65em;
}
}
sub {
font-size: 0.8em;
position: relative;
top: 0.5em;
}
sup {
font-size: 0.8em;
position: relative;
top: -0.5em;
}
hr {
border: 0;
border-bottom: solid _size(border-width) _palette(border);
margin: (_size(element-margin) * 2) 0;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/components/_button.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Button */
input[type="submit"],
input[type="reset"],
input[type="button"],
button,
.button {
@include vendor('appearance', 'none');
@include vendor('transition', (
'background-color #{_duration(transition)} ease-in-out',
'border-color #{_duration(transition)} ease-in-out',
'color #{_duration(transition)} ease-in-out'
));
display: inline-block;
height: _size(element-height);
line-height: _size(element-height);
padding: 0 1.5em;
background-color: transparent;
border-radius: _size(border-radius);
border: solid 1px _palette(border);
color: _palette(fg) !important;
cursor: pointer;
text-align: center;
text-decoration: none;
white-space: nowrap;
&:hover {
border-color: _palette(highlight);
color: _palette(highlight) !important;
}
&.icon {
padding-left: 1.35em;
&:before {
margin-right: 0.5em;
}
}
&.fit {
display: block;
width: 100%;
margin: 0 0 (_size(element-margin) * 0.5) 0;
}
&.small {
font-size: 0.8em;
}
&.big {
font-size: 1.35em;
}
&.disabled,
&:disabled {
@include vendor('pointer-events', 'none');
opacity: 0.5;
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/components/_form.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Form */
form {
margin: 0 0 _size(element-margin) 0;
> .field {
margin: 0 0 _size(element-margin) 0;
> :last-child {
margin-bottom: 0;
}
}
}
label {
color: _palette(fg-bold);
display: block;
font-size: 0.9em;
margin: 0 0 (_size(element-margin) * 0.5) 0;
}
input[type="text"],
input[type="password"],
input[type="email"],
input[type="tel"],
select,
textarea {
@include vendor('appearance', 'none');
border-radius: _size(border-radius);
border: solid 1px _palette(border);
color: inherit;
display: block;
outline: 0;
padding: 0 1em;
text-decoration: none;
width: 100%;
&:invalid {
box-shadow: none;
}
&:focus {
border-color: _palette(highlight);
}
}
.select-wrapper {
@include icon('\f078');
display: block;
position: relative;
&:before {
color: _palette(border);
display: block;
height: _size(element-height);
line-height: _size(element-height);
pointer-events: none;
position: absolute;
right: 0;
text-align: center;
top: 0;
width: _size(element-height);
}
select::-ms-expand {
display: none;
}
}
input[type="text"],
input[type="password"],
input[type="email"],
select {
height: _size(element-height);
}
textarea {
padding: 0.75em 1em;
}
input[type="checkbox"],
input[type="radio"], {
@include vendor('appearance', 'none');
display: block;
float: left;
margin-right: -2em;
opacity: 0;
width: 1em;
z-index: -1;
& + label {
@include icon;
color: _palette(fg);
cursor: pointer;
display: inline-block;
font-size: 1em;
font-weight: _font(weight);
padding-left: (_size(element-height) * 0.6) + 0.75em;
padding-right: 0.75em;
position: relative;
&:before {
background: _palette(border-bg);
border-radius: _size(border-radius);
border: solid 1px _palette(border);
content: '';
display: inline-block;
height: (_size(element-height) * 0.6);
left: 0;
line-height: (_size(element-height) * 0.575);
position: absolute;
text-align: center;
top: 0.15em;
width: (_size(element-height) * 0.6);
}
}
&:checked + label {
&:before {
color: _palette(highlight);
content: '\f00c';
}
}
&:focus + label {
&:before {
border-color: _palette(highlight);
}
}
}
input[type="checkbox"] {
& + label {
&:before {
border-radius: _size(border-radius);
}
}
}
input[type="radio"] {
& + label {
&:before {
border-radius: 100%;
}
}
}
::-webkit-input-placeholder {
color: _palette(fg-light) !important;
opacity: 1.0;
}
:-moz-placeholder {
color: _palette(fg-light) !important;
opacity: 1.0;
}
::-moz-placeholder {
color: _palette(fg-light) !important;
opacity: 1.0;
}
:-ms-input-placeholder {
color: _palette(fg-light) !important;
opacity: 1.0;
}
.formerize-placeholder {
color: _palette(fg-light) !important;
opacity: 1.0;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/components/_icon.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Icon */
.icon {
@include icon;
position: relative;
border-bottom: none;
> .label {
display: none;
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/components/_list.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* List */
ol {
list-style: decimal;
margin: 0 0 _size(element-margin) 0;
padding-left: 1.25em;
li {
padding-left: 0.25em;
}
}
ul {
list-style: disc;
margin: 0 0 _size(element-margin) 0;
padding-left: 1em;
li {
padding-left: 0.5em;
}
&.alt {
list-style: none;
padding-left: 0;
li {
border-top: solid 1px _palette(border);
padding: 0.5em 0;
&:first-child {
border-top: 0;
padding-top: 0;
}
}
}
&.icons {
cursor: default;
list-style: none;
padding-left: 0;
margin-top: -0.675em;
li {
display: inline-block;
padding: 0.675em 0.5em;
a {
@include icon-alt(false, true);
position: relative;
display: block;
width: 3.75em;
height: 3.75em;
border-radius: 100%;
border: solid _size(border-width) _palette(border);
line-height: 3.75em;
overflow: hidden;
text-align: center;
text-indent: 3.75em;
white-space: nowrap;
&:before {
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
font-size: 1.85rem;
line-height: inherit;
text-align: center;
text-indent: 0;
}
&:hover {
border-color: _palette(highlight);
}
}
}
@include breakpoint(xsmall) {
li {
a {
&:before {
font-size: 1.5rem;
}
}
}
}
}
&.actions {
cursor: default;
list-style: none;
padding-left: 0;
li {
display: inline-block;
padding: 0 (_size(element-margin) * 0.5) 0 0;
vertical-align: middle;
&:last-child {
padding-right: 0;
}
}
}
}
dl {
margin: 0 0 _size(element-margin) 0;
dt {
display: block;
font-weight: _font(weight-bold);
margin: 0 0 (_size(element-margin) * 0.5) 0;
}
dd {
margin-left: _size(element-margin);
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/ie8.scss
================================================
@import 'libs/vars';
@import 'libs/functions';
@import 'libs/mixins';
@import 'libs/skel';
/*
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
/* List */
ul {
&.icons {
li {
a {
-ms-behavior: url('assets/js/PIE.htc');
&:before {
text-align: center;
font-size: 26px;
}
}
}
}
}
/* Main */
#main {
-ms-behavior: url('assets/js/PIE.htc');
.avatar {
img {
-ms-behavior: url('assets/js/PIE.htc');
}
}
}
/* Footer */
#footer {
color: #fff;
.copyright {
li {
border-left: solid 1px #fff;
}
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/ie9.scss
================================================
@import 'libs/vars';
@import 'libs/functions';
@import 'libs/mixins';
@import 'libs/skel';
/*
Identity by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
/* Basic */
body {
background-image: url('../../images/bg.jpg');
background-repeat: no-repeat;
background-size: cover;
background-position: bottom center;
background-attachment: fixed;
&:after {
display: none;
}
}
/* List */
ul {
&.icons {
li {
a {
&:before {
color: _palette(border);
}
&:hover {
&:before {
color: _palette(highlight);
}
}
}
}
}
}
/* Wrapper */
#wrapper {
text-align: center;
}
/* Main */
#main {
display: inline-block;
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/layout/_footer.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Footer */
#footer {
@include vendor('align-self', 'flex-end');
width: 100%;
padding: _size(element-margin) 0 0 0;
color: rgba(255,255,255,0.75);
cursor: default;
text-align: center;
.copyright {
margin: 0;
padding: 0;
font-size: 0.9em;
list-style: none;
li {
display: inline-block;
margin: 0 0 0 (0.85em - (_size(letter-spacing) * 2));
padding: 0 0 0 0.85em;
border-left: solid _size(border-width) rgba(255,255,255,0.5);
line-height: 1;
&:first-child {
border-left: 0;
}
}
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/layout/_main.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Main */
#main {
position: relative;
max-width: 100%;
min-width: 27em;
@include padding(4.5em, 3em);
background: _palette(bg);
border-radius: _size(border-radius);
cursor: default;
opacity: 0.95;
text-align: center;
@include vendor('transform-origin', '50% 50%');
@include vendor('transform', 'rotateX(0deg)');
@include vendor('transition', (
'opacity #{_duration(main)} ease',
'transform #{_duration(main)} ease'
));
.avatar {
position: relative;
display: block;
margin-bottom: _size(element-margin);
img {
display: block;
margin: 0 auto;
border-radius: 100%;
box-shadow: 0 0 0 1.5em _palette(bg);
}
&:before {
content: '';
display: block;
position: absolute;
top: 50%;
left: -3em;
width: calc(100% + 6em);
height: _size(border-width);
z-index: -1;
background: _palette(border);
}
}
@include breakpoint(xsmall) {
min-width: 0;
width: 100%;
@include padding(4em, 2em);
.avatar {
&:before {
left: -2em;
width: calc(100% + 4em);
}
}
}
body.is-loading & {
opacity: 0;
@include vendor('transform', 'rotateX(15deg)');
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/layout/_wrapper.scss
================================================
@import '../libs/vars';
@import '../libs/functions';
@import '../libs/mixins';
///
/// Identity by HTML5 UP
/// html5up.net | @ajlkn
/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
///
/* Wrapper */
#wrapper {
@include vendor('display', 'flex');
@include vendor('align-items', 'center');
@include vendor('justify-content', 'space-between');
@include vendor('flex-direction', 'column');
@include vendor('perspective', '1000px');
position: relative;
min-height: 100%;
padding: _size(element-margin);
z-index: 2;
> * {
z-index: 1;
}
&:before {
content: '';
display: block;
}
@include breakpoint(xxsmall) {
padding: (_size(element-margin) * 0.5);
}
body.is-ie & {
height: 100%;
}
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/libs/_functions.scss
================================================
/// Gets a duration value.
/// @param {string} $keys Key(s).
/// @return {string} Value.
@function _duration($keys...) {
@return val($duration, $keys...);
}
/// Gets a font value.
/// @param {string} $keys Key(s).
/// @return {string} Value.
@function _font($keys...) {
@return val($font, $keys...);
}
/// Gets a misc value.
/// @param {string} $keys Key(s).
/// @return {string} Value.
@function _misc($keys...) {
@return val($misc, $keys...);
}
/// Gets a palette value.
/// @param {string} $keys Key(s).
/// @return {string} Value.
@function _palette($keys...) {
@return val($palette, $keys...);
}
/// Gets a size value.
/// @param {string} $keys Key(s).
/// @return {string} Value.
@function _size($keys...) {
@return val($size, $keys...);
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/libs/_mixins.scss
================================================
/// Makes an element's :before pseudoelement a FontAwesome icon.
/// @param {string} $content Optional content value to use.
/// @param {string} $where Optional pseudoelement to target (before or after).
@mixin icon($content: false, $where: before) {
text-decoration: none;
&:#{$where} {
@if $content {
content: $content;
}
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
}
/// Applies padding to an element, taking the current element-margin value into account.
/// @param {mixed} $tb Top/bottom padding.
/// @param {mixed} $lr Left/right padding.
/// @param {list} $pad Optional extra padding (in the following order top, right, bottom, left)
/// @param {bool} $important If true, adds !important.
@mixin padding($tb, $lr, $pad: (0,0,0,0), $important: null) {
@if $important {
$important: '!important';
}
padding: ($tb + nth($pad,1)) ($lr + nth($pad,2)) max(0.1em, $tb - _size(element-margin) + nth($pad,3)) ($lr + nth($pad,4)) #{$important};
}
/// Encodes a SVG data URL so IE doesn't choke (via codepen.io/jakob-e/pen/YXXBrp).
/// @param {string} $svg SVG data URL.
/// @return {string} Encoded SVG data URL.
@function svg-url($svg) {
$svg: str-replace($svg, '"', '\'');
$svg: str-replace($svg, '<', '%3C');
$svg: str-replace($svg, '>', '%3E');
$svg: str-replace($svg, '&', '%26');
$svg: str-replace($svg, '#', '%23');
$svg: str-replace($svg, '{', '%7B');
$svg: str-replace($svg, '}', '%7D');
$svg: str-replace($svg, ';', '%3B');
@return url("data:image/svg+xml;charset=utf8,#{$svg}");
}
================================================
FILE: chatbot_website/chatbot_interface/static/assets/sass/libs/_skel.scss
================================================
// skel.scss v3.0.1 | (c) skel.io | MIT licensed */
// Vars.
/// Breakpoints.
/// @var {list}
$breakpoints: () !global;
/// Vendor prefixes.
/// @var {list}
$vendor-prefixes: (
'-moz-',
'-webkit-',
'-ms-',
''
);
/// Properties that should be vendorized.
/// @var {list}
$vendor-properties: (
'align-content',
'align-items',
'align-self',
'animation',
'animation-delay',
'animation-direction',
'animation-duration',
'animation-fill-mode',
'animation-iteration-count',
'animation-name',
'animation-play-state',
'animation-timing-function',
'appearance',
'backface-visibility',
'box-sizing',
'filter',
'flex',
'flex-basis',
'flex-direction',
'flex-flow',
'flex-grow',
'flex-shrink',
'flex-wrap',
'justify-content',
'order',
'perspective',
'pointer-events',
'transform',
'transform-origin',
'transform-style',
'transition',
'transition-delay',
'transition-duration',
'transition-property',
'transition-timing-function',
'user-select'
);
/// Values that should be vendorized.
/// @var {list}
$vendor-values: (
'filter',
'flex',
'linear-gradient',
'radial-gradient',
'transform'
);
// Functions.
/// Removes a specific item from a list.
/// @author Hugo Giraudel
/// @param {list} $list List.
/// @param {integer} $index Index.
/// @return {list} Updated list.
@function remove-nth($list, $index) {
$result: null;
@if type-of($index) != number {
@warn "$index: #{quote($index)} is not a number for `remove-nth`.";
}
@else if $index == 0 {
@warn "List index 0 must be a non-zero integer for `remove-nth`.";
}
@else if abs($index) > length($list) {
@warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
}
@else {
$result: ();
$index: if($index < 0, length($list) + $index + 1, $index);
@for $i from 1 through length($list) {
@if $i != $index {
$result: append($result, nth($list, $i));
}
}
}
@return $result;
}
/// Replaces a substring within another string.
/// @author Hugo Giraudel
/// @param {string} $string String.
/// @param {string} $search Substring.
/// @param {string} $replace Replacement.
/// @return {string} Updated string.
@function str-replace($string, $search, $replace: '') {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
/// Replaces a substring within each string in a list.
/// @param {list} $strings List of strings.
/// @param {string} $search Substring.
/// @param {string} $replace Replacement.
/// @return {list} Updated list of strings.
@function str-replace-all($strings, $search, $replace: '') {
@each $string in $strings {
$strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace));
}
@return $strings;
}
/// Gets a value from a map.
/// @author Hugo Giraudel
/// @param {map} $map Map.
/// @param {string} $keys Key(s).
/// @return {string} Value.
@function val($map, $keys...) {
@if nth($keys, 1) == null {
$keys: remove-nth($keys, 1);
}
@each $key in $keys {
$map: map-get($map, $key);
}
@return $map;
}
// Mixins.
/// Sets the global box model.
/// @param {string} $model Model (default is content).
@mixin boxModel($model: 'content') {
$x: $model + '-box';
*, *:before, *:after {
-moz-box-sizing: #{$x};
-webkit-box-sizing: #{$x};
box-sizing: #{$x};
}
}
/// Wraps @content in a @media block using a given breakpoint.
/// @param {string} $breakpoint Breakpoint.
/// @param {map} $queries Additional queries.
@mixin breakpoint($breakpoint: null, $queries: null) {
$query: 'screen';
// Breakpoint.
@if $breakpoint and map-has-key($breakpoints, $breakpoint) {
$query: $query + ' and ' + map-get($breakpoints, $breakpoint);
}
// Queries.
@if $queries {
@each $k, $v in $queries {
$query: $query + ' and (' + $k + ':' + $v + ')';
}
}
@media #{$query} {
@content;
}
}
/// Wraps @content in a @media block targeting a specific orientation.
/// @param {string} $orientation Orientation.
@mixin orientation($orientation) {
@media screen and (orientation: #{$orientation}) {
@content;
}
}
/// Utility mixin for containers.
/// @param {mixed} $width Width.
@mixin containers($width) {
// Locked?
$lock: false;
@if length($width) == 2 {
$width: nth($width, 1);
$lock: true;
}
// Modifiers.
.container.\31 25\25 { width: 100%; max-width: $width * 1.25; min-width: $width; }
.container.\37 5\25 { width: $width * 0.75; }
.container.\35 0\25 { width: $width * 0.5; }
.container.\32 5\25 { width: $width * 0.25; }
// Main class.
.container {
@if $lock {
width: $width !important;
}
@else {
width: $width;
}
}
}
/// Utility mixin for grid.
/// @param {list} $gutters Column and row gutters (default is 40px).
/// @param {string} $breakpointName Optional breakpoint name.
@mixin grid($gutters: 40px, $breakpointName: null) {
// Gutters.
@include grid-gutters($gutters);
@include grid-gutters($gutters, \32 00\25, 2);
@include grid-gutters($gutters, \31 50\25, 1.5);
@include grid-gutters($gutters, \35 0\25, 0.5);
@include grid-gutters($gutters, \32 5\25, 0.25);
// Cells.
$x: '';
@if $breakpointName {
$x: '\\28' + $breakpointName + '\\29';
}
.\31 2u#{$x}, .\31 2u\24#{$x} { width: 100%; clear: none; margin-left: 0; }
.\31 1u#{$x}, .\31 1u\24#{$x} { width: 91.6666666667%; clear: none; margin-left: 0; }
.\31 0u#{$x}, .\31 0u\24#{$x} { width: 83.3333333333%; clear: none; margin-left: 0; }
.\39 u#{$x}, .\39 u\24#{$x} { width: 75%; clear: none; margin-left: 0; }
.\38 u#{$x}, .\38 u\24#{$x} { width: 66.6666666667%; clear: none; margin-left: 0; }
.\37 u#{$x}, .\37 u\24#{$x} { width: 58.3333333333%; clear: none; margin-left: 0; }
.\36 u#{$x}, .\36 u\24#{$x} { width: 50%; clear: none; margin-left: 0; }
.\35 u#{$x}, .\35 u\24#{$x} { width: 41.6666666667%; clear: none; margin-left: 0; }
.\34 u#{$x}, .\34 u\24#{$x} { width: 33.3333333333%; clear: none; margin-left: 0; }
.\33 u#{$x}, .\33 u\24#{$x} { width: 25%; clear: none; margin-left: 0; }
.\32 u#{$x}, .\32 u\24#{$x} { width: 16.6666666667%; clear: none; margin-left: 0; }
.\31 u#{$x}, .\31 u\24#{$x} { width: 8.3333333333%; clear: none; margin-left: 0; }
.\31 2u\24#{$x} + *,
.\31 1u\24#{$x} + *,
.\31 0u\24#{$x} + *,
.\39 u\24#{$x} + *,
.\38 u\24#{$x} + *,
.\37 u\24#{$x} + *,
.\36 u\24#{$x} + *,
.\35 u\24#{$x} + *,
.\34 u\24#{$x} + *,
.\33 u\24#{$x} + *,
.\32 u\24#{$x} + *,
.\31 u\24#{$x} + * {
clear: left;
}
.\-11u#{$x} { margin-left: 91.6666666667% }
.\-10u#{$x} { margin-left: 83.3333333333% }
.\-9u#{$x} { margin-left: 75% }
.\-8u#{$x} { margin-left: 66.6666666667% }
.\-7u#{$x} { margin-left: 58.3333333333% }
.\-6u#{$x} { margin-left: 50% }
.\-5u#{$x} { margin-left: 41.6666666667% }
.\-4u#{$x} { margin-left: 33.3333333333% }
.\-3u#{$x} { margin-left: 25% }
.\-2u#{$x} { margin-left: 16.6666666667% }
.\-1u#{$x} { margin-left: 8.3333333333% }
}
/// Utility mixin for grid.
/// @param {list} $gutters Gutters.
/// @param {string} $class Optional class name.
/// @param {integer} $multiplier Multiplier (default is 1).
@mixin grid-gutters($gutters, $class: null, $multiplier: 1) {
// Expand gutters if it's not a list.
@if length($gutters) == 1 {
$gutters: ($gutters, 0);
}
// Get column and row gutter values.
$c: nth($gutters, 1);
$r: nth($gutters, 2);
// Get class (if provided).
$x: '';
@if $class {
$x: '.' + $class;
}
// Default.
.row#{$x} > * { padding: ($r * $multiplier) 0 0 ($c * $multiplier); }
.row#{$x} { margin: ($r * $multiplier * -1) 0 -1px ($c * $multiplier * -1); }
// Uniform.
.row.uniform#{$x} > * { padding: ($c * $multiplier) 0 0 ($c * $multiplier); }
.row.uniform#{$x} { margin: ($c * $multiplier * -1) 0 -1px ($c * $multiplier * -1); }
}
/// Wraps @content in vendorized keyframe blocks.
/// @param {string} $name Name.
@mixin keyframes($name) {
@-moz-keyframes #{$name} { @content; }
@-webkit-keyframes #{$name} { @content; }
@-ms-keyframes #{$name} { @content; }
@keyframes #{$name} { @content; }
}
///
/// Sets breakpoints.
/// @param {map} $x Breakpoints.
///
@mixin skel-breakpoints($x: ()) {
$breakpoints: $x !global;
}
///
/// Initializes layout module.
/// @param {map} config Config.
///
@mixin skel-layout($config: ()) {
// Config.
$configPerBreakpoint: ();
$z: map-get($config, 'breakpoints');
@if $z {
$configPerBreakpoint: $z;
}
// Reset.
$x: map-get($config, 'reset');
@if $x {
/* Reset */
@include reset($x);
}
// Box model.
$x: map-get($config, 'boxModel');
@if $x {
/* Box Model */
@include boxModel($x);
}
// Containers.
$containers: map-get($config, 'containers');
@if $containers {
/* Contain
gitextract_kes89e0b/ ├── .gitignore ├── LICENSE ├── README.md ├── chatbot/ │ ├── __init__.py │ ├── chatbot.py │ ├── cornelldata.py │ ├── model.py │ ├── textdata.py │ ├── trainner.py │ ├── twitter_generate_data_pickle.py │ ├── twitter_get_access_token.py │ └── twitter_qa.py ├── chatbot_website/ │ ├── .gitignore │ ├── chatbot_interface/ │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── chatbotmanager.py │ │ ├── consumer.py │ │ ├── migrations/ │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── routing.py │ │ ├── static/ │ │ │ ├── LICENSE.txt │ │ │ ├── README.txt │ │ │ ├── assets/ │ │ │ │ ├── css/ │ │ │ │ │ ├── ie8.css │ │ │ │ │ ├── ie9.css │ │ │ │ │ ├── main.css │ │ │ │ │ └── noscript.css │ │ │ │ ├── fonts/ │ │ │ │ │ └── FontAwesome.otf │ │ │ │ ├── js/ │ │ │ │ │ ├── PIE.htc │ │ │ │ │ └── html5shiv.js │ │ │ │ └── sass/ │ │ │ │ ├── base/ │ │ │ │ │ ├── _page.scss │ │ │ │ │ └── _typography.scss │ │ │ │ ├── components/ │ │ │ │ │ ├── _button.scss │ │ │ │ │ ├── _form.scss │ │ │ │ │ ├── _icon.scss │ │ │ │ │ └── _list.scss │ │ │ │ ├── ie8.scss │ │ │ │ ├── ie9.scss │ │ │ │ ├── layout/ │ │ │ │ │ ├── _footer.scss │ │ │ │ │ ├── _main.scss │ │ │ │ │ └── _wrapper.scss │ │ │ │ ├── libs/ │ │ │ │ │ ├── _functions.scss │ │ │ │ │ ├── _mixins.scss │ │ │ │ │ ├── _skel.scss │ │ │ │ │ └── _vars.scss │ │ │ │ ├── main.scss │ │ │ │ └── noscript.scss │ │ │ └── js/ │ │ │ ├── chat.js │ │ │ └── reconnecting-websocket.js │ │ ├── templates/ │ │ │ └── index.html │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ ├── chatbot_website/ │ │ ├── __init__.py │ │ ├── asgi.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ ├── logs/ │ │ └── .gitignore │ └── manage.py ├── data/ │ ├── cornell/ │ │ ├── README.txt │ │ ├── movie_conversations.txt │ │ └── movie_lines.txt │ ├── samples/ │ │ └── .gitignore │ ├── test/ │ │ └── samples.txt │ └── tweets/ │ └── README.md ├── main.py ├── requirements.txt ├── save/ │ └── .gitignore ├── setup_server.sh └── testsuite.py
SYMBOL INDEX (86 symbols across 15 files)
FILE: chatbot/chatbot.py
class Chatbot (line 35) | class Chatbot:
class TestMode (line 40) | class TestMode:
method __init__ (line 47) | def __init__(self):
method parseArgs (line 77) | def parseArgs(args):
method main (line 156) | def main(self, args=None):
method mainTrain (line 231) | def mainTrain(self, sess):
method predictTestset (line 284) | def predictTestset(self, sess):
method mainTestInteractive (line 326) | def mainTestInteractive(self, sess):
method singlePredict (line 360) | def singlePredict(self, question, questionSeq=None):
method daemonPredict (line 382) | def daemonPredict(self, sentence):
method daemonClose (line 394) | def daemonClose(self):
method managePreviousModel (line 401) | def managePreviousModel(self, sess):
method _saveSession (line 447) | def _saveSession(self, sess):
method _getModelList (line 458) | def _getModelList(self):
method loadModelParams (line 463) | def loadModelParams(self):
method saveModelParams (line 523) | def saveModelParams(self):
method _getSummaryName (line 547) | def _getSummaryName(self):
method _getModelName (line 555) | def _getModelName(self):
method getDevice (line 567) | def getDevice(self):
FILE: chatbot/cornelldata.py
class CornellData (line 26) | class CornellData:
method __init__ (line 31) | def __init__(self, dirName):
method loadLines (line 47) | def loadLines(self, fileName, fields):
method loadConversations (line 70) | def loadConversations(self, fileName, fields):
method getConversations (line 105) | def getConversations(self):
FILE: chatbot/model.py
class Model (line 28) | class Model:
method __init__ (line 35) | def __init__(self, args, textData):
method buildNetwork (line 60) | def buildNetwork(self):
method step (line 127) | def step(self, batch):
FILE: chatbot/textdata.py
class Batch (line 33) | class Batch:
method __init__ (line 37) | def __init__(self):
class TextData (line 44) | class TextData:
method __init__ (line 49) | def __init__(self, args):
method _constructName (line 82) | def _constructName(self):
method makeLighter (line 91) | def makeLighter(self, ratioDataset):
method shuffle (line 96) | def shuffle(self):
method _createBatch (line 102) | def _createBatch(self, samples):
method getBatches (line 178) | def getBatches(self):
method getSampleSize (line 198) | def getSampleSize(self):
method getVocabularySize (line 205) | def getVocabularySize(self):
method loadCorpus (line 212) | def loadCorpus(self, dirName):
method saveDataset (line 222) | def saveDataset(self, dirName):
method loadDataset (line 236) | def loadDataset(self, dirName):
method createCorpus (line 253) | def createCorpus(self, conversations):
method extractConversation (line 269) | def extractConversation(self, conversation):
method extractText (line 287) | def extractText(self, line, isTarget=False):
method getWordId (line 325) | def getWordId(self, word, create=True):
method printBatch (line 352) | def printBatch(self, batch):
method sequence2str (line 365) | def sequence2str(self, sequence, clean=False, reverse=False):
method batchSeq2str (line 393) | def batchSeq2str(self, batchSeq, seqId=0, **kwargs):
method sentence2enco (line 409) | def sentence2enco(self, sentence):
method deco2sentence (line 434) | def deco2sentence(self, decoderOutputs):
method playDataset (line 446) | def playDataset(self):
FILE: chatbot/trainner.py
function main (line 26) | def main():
FILE: chatbot/twitter_generate_data_pickle.py
function genset (line 6) | def genset(questions, answers, maxLength):
function load_qa (line 29) | def load_qa(username, max_tweets, overwrite):
function get_data (line 48) | def get_data(username, maxLength=35, max_tweets=3200, overwrite=False):
FILE: chatbot/twitter_get_access_token.py
function get_access_token (line 27) | def get_access_token(consumer_key, consumer_secret):
function main (line 70) | def main():
FILE: chatbot/twitter_qa.py
function get_tweets (line 14) | def get_tweets(screen_name, max_tweets=None):
function find_questions_for_tweets (line 47) | def find_questions_for_tweets(tweets):
function normalize_tweet (line 68) | def normalize_tweet(x):
function get_tweet_qa (line 82) | def get_tweet_qa(twitter_username, max_tweets=None, normalize_tweets=True):
function get_rate_limits (line 91) | def get_rate_limits():
function store_question_answers (line 100) | def store_question_answers(username, max_number=None):
FILE: chatbot_website/chatbot_interface/apps.py
class ChatbotInterfaceConfig (line 4) | class ChatbotInterfaceConfig(AppConfig):
FILE: chatbot_website/chatbot_interface/chatbotmanager.py
class ChatbotManager (line 14) | class ChatbotManager:
method initBot (line 20) | def initBot():
method callBot (line 32) | def callBot(sentence):
FILE: chatbot_website/chatbot_interface/consumer.py
function _getClientName (line 13) | def _getClientName(client):
function ws_connect (line 24) | def ws_connect(message):
function ws_receive (line 37) | def ws_receive(message):
function ws_disconnect (line 65) | def ws_disconnect(message):
FILE: chatbot_website/chatbot_interface/static/assets/js/html5shiv.js
function m (line 4) | function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}
function i (line 4) | function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}
function p (line 4) | function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=...
function t (line 4) | function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.cr...
function q (line 5) | function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a...
FILE: chatbot_website/chatbot_interface/static/js/reconnecting-websocket.js
function ReconnectingWebSocket (line 109) | function ReconnectingWebSocket(url, protocols, options) {
FILE: chatbot_website/chatbot_interface/views.py
function mainView (line 3) | def mainView(request):
FILE: testsuite.py
class TestChatbot (line 32) | class TestChatbot(unittest.TestCase):
method setUp (line 33) | def setUp(self):
method test_training_simple (line 36) | def test_training_simple(self):
method test_training_watson (line 43) | def test_training_watson(self):
method test_testing_all (line 46) | def test_testing_all(self):
method test_testing_interactive (line 49) | def test_testing_interactive(self):
method test_testing_daemon (line 62) | def test_testing_daemon(self):
Condensed preview — 71 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,108K chars).
[
{
"path": ".gitignore",
"chars": 1109,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# PyCharm files\n.idea/\n\n# C extensions\n*.so\n\n"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1960,
"preview": "# Deep Twitter Q&A\n\n## Introduction\n\nHave you ever wanted to know how someone special would reply on Twitter? Train a mo"
},
{
"path": "chatbot/__init__.py",
"chars": 22,
"preview": "__all__ = [\"chatbot\"]\n"
},
{
"path": "chatbot/chatbot.py",
"chars": 28015,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
},
{
"path": "chatbot/cornelldata.py",
"chars": 3549,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
},
{
"path": "chatbot/model.py",
"chars": 6404,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
},
{
"path": "chatbot/textdata.py",
"chars": 17336,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
},
{
"path": "chatbot/trainner.py",
"chars": 1641,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
},
{
"path": "chatbot/twitter_generate_data_pickle.py",
"chars": 2477,
"preview": "import os\nimport pickle\nfrom chatbot.twitter_qa import store_question_answers\n\n\ndef genset(questions, answers, maxLength"
},
{
"path": "chatbot/twitter_get_access_token.py",
"chars": 2913,
"preview": "#!/usr/bin/env python\n#\n# Copyright 2007-2013 The Python-Twitter Developers\n#\n# Licensed under the Apache License, Versi"
},
{
"path": "chatbot/twitter_qa.py",
"chars": 3924,
"preview": "import json\nimport os\nimport re\nimport itertools\n\nfrom TwitterAPI import TwitterAPI\n\nwith open(\"chatbot/credentials.json"
},
{
"path": "chatbot_website/.gitignore",
"chars": 38,
"preview": "# Database\n*.sqlite3\n# Redis\ndump.rdb\n"
},
{
"path": "chatbot_website/chatbot_interface/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "chatbot_website/chatbot_interface/admin.py",
"chars": 63,
"preview": "from django.contrib import admin\n\n# Register your models here.\n"
},
{
"path": "chatbot_website/chatbot_interface/apps.py",
"chars": 108,
"preview": "from django.apps import AppConfig\n\n\nclass ChatbotInterfaceConfig(AppConfig):\n name = 'chatbot_interface'\n"
},
{
"path": "chatbot_website/chatbot_interface/chatbotmanager.py",
"chars": 1198,
"preview": "from django.conf import settings\nimport logging\nimport sys\n\nchatbotPath = \"/\".join(settings.BASE_DIR.split('/')[:-1])\nsy"
},
{
"path": "chatbot_website/chatbot_interface/consumer.py",
"chars": 2224,
"preview": "from channels import Group\nfrom channels.sessions import channel_session\nimport logging\nimport sys\nimport json\n\nfrom .ch"
},
{
"path": "chatbot_website/chatbot_interface/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "chatbot_website/chatbot_interface/models.py",
"chars": 57,
"preview": "from django.db import models\n\n# Create your models here.\n"
},
{
"path": "chatbot_website/chatbot_interface/routing.py",
"chars": 292,
"preview": "from . import consumer\n\nchannel_routing = {\n # TODO: From the original examples, there is more (https://github.com/ja"
},
{
"path": "chatbot_website/chatbot_interface/static/LICENSE.txt",
"chars": 17128,
"preview": "Creative Commons Attribution 3.0 Unported\r\nhttp://creativecommons.org/licenses/by/3.0/\r\n\r\nLicense\r\n\r\nTHE WORK (AS DEFINE"
},
{
"path": "chatbot_website/chatbot_interface/static/README.txt",
"chars": 728,
"preview": "Identity by HTML5 UP\r\nhtml5up.net | @ajlkn\r\nFree for personal and commercial use under the CCA 3.0 license (html5up.net/"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/css/ie8.css",
"chars": 527,
"preview": "/*\n\tIdentity by HTML5 UP\n\thtml5up.net | @ajlkn\n\tFree for personal and commercial use under the CCA 3.0 license (html5up."
},
{
"path": "chatbot_website/chatbot_interface/static/assets/css/ie9.css",
"chars": 587,
"preview": "/*\n\tIdentity by HTML5 UP\n\thtml5up.net | @ajlkn\n\tFree for personal and commercial use under the CCA 3.0 license (html5up."
},
{
"path": "chatbot_website/chatbot_interface/static/assets/css/main.css",
"chars": 17755,
"preview": "@charset \"UTF-8\";\n@import url(font-awesome.min.css);\n@import url(\"http://fonts.googleapis.com/css?family=Source+Sans+Pro"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/css/noscript.css",
"chars": 370,
"preview": "/*\n\tIdentity by HTML5 UP\n\thtml5up.net | @ajlkn\n\tFree for personal and commercial use under the CCA 3.0 license (html5up."
},
{
"path": "chatbot_website/chatbot_interface/static/assets/js/PIE.htc",
"chars": 41041,
"preview": "<!--\nPIE: CSS3 rendering for IE\nVersion 1.0.0\nhttp://css3pie.com\nDual-licensed for use under the Apache License Version "
},
{
"path": "chatbot_website/chatbot_interface/static/assets/js/html5shiv.js",
"chars": 2380,
"preview": "/*\n HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed\n*/\n(function(l,f){function m(){var a=e.elem"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/base/_page.scss",
"chars": 1925,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/base/_typography.scss",
"chars": 2012,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/components/_button.scss",
"chars": 1447,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/components/_form.scss",
"chars": 3345,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/components/_icon.scss",
"chars": 369,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/components/_list.scss",
"chars": 2223,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/ie8.scss",
"chars": 712,
"preview": "@import 'libs/vars';\r\n@import 'libs/functions';\r\n@import 'libs/mixins';\r\n@import 'libs/skel';\r\n\r\n/*\r\n\tIdentity by HTML5 "
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/ie9.scss",
"chars": 826,
"preview": "@import 'libs/vars';\r\n@import 'libs/functions';\r\n@import 'libs/mixins';\r\n@import 'libs/skel';\r\n\r\n/*\r\n\tIdentity by HTML5 "
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/layout/_footer.scss",
"chars": 818,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/layout/_main.scss",
"chars": 1486,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/layout/_wrapper.scss",
"chars": 815,
"preview": "@import '../libs/vars';\r\n@import '../libs/functions';\r\n@import '../libs/mixins';\r\n\r\n///\r\n/// Identity by HTML5 UP\r\n/// h"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/libs/_functions.scss",
"chars": 787,
"preview": "/// Gets a duration value.\r\n/// @param {string} $keys Key(s).\r\n/// @return {string} Value.\r\n@function _duration($keys..."
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/libs/_mixins.scss",
"chars": 1723,
"preview": "/// Makes an element's :before pseudoelement a FontAwesome icon.\r\n/// @param {string} $content Optional content value to"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/libs/_skel.scss",
"chars": 16468,
"preview": "// skel.scss v3.0.1 | (c) skel.io | MIT licensed */\r\n\r\n// Vars.\r\n\r\n\t/// Breakpoints.\r\n\t/// @var {list}\r\n\t$breakpoints: ("
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/libs/_vars.scss",
"chars": 683,
"preview": "// Misc.\r\n\t$misc: (\r\n\t\tz-index-base:\t\t10000\r\n\t);\r\n\r\n// Duration.\r\n\t$duration: (\r\n\t\ttransition:\t\t\t0.2s,\r\n\t\tbg:\t\t\t\t\t1.75s,"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/main.scss",
"chars": 1571,
"preview": "@import 'libs/vars';\r\n@import 'libs/functions';\r\n@import 'libs/mixins';\r\n@import 'libs/skel';\r\n@import 'font-awesome.min"
},
{
"path": "chatbot_website/chatbot_interface/static/assets/sass/noscript.scss",
"chars": 411,
"preview": "@import 'libs/vars';\r\n@import 'libs/functions';\r\n@import 'libs/mixins';\r\n@import 'libs/skel';\r\n\r\n/*\r\n\tIdentity by HTML5 "
},
{
"path": "chatbot_website/chatbot_interface/static/js/chat.js",
"chars": 1318,
"preview": "// Credits goes to https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django\n\n$(functi"
},
{
"path": "chatbot_website/chatbot_interface/static/js/reconnecting-websocket.js",
"chars": 14429,
"preview": "// MIT License:\n//\n// Copyright (c) 2010-2012, Joe Walnes\n//\n// Permission is hereby granted, free of charge, to any per"
},
{
"path": "chatbot_website/chatbot_interface/templates/index.html",
"chars": 3134,
"preview": "{% load staticfiles %}\n<!DOCTYPE HTML>\n<!--\n\tIdentity by HTML5 UP\n\thtml5up.net | @ajlkn\n\tFree for personal and commercia"
},
{
"path": "chatbot_website/chatbot_interface/tests.py",
"chars": 60,
"preview": "from django.test import TestCase\n\n# Create your tests here.\n"
},
{
"path": "chatbot_website/chatbot_interface/urls.py",
"chars": 298,
"preview": "from django.conf.urls import url\nfrom . import views\n\nfrom .chatbotmanager import ChatbotManager\n\nurlpatterns = [\n ur"
},
{
"path": "chatbot_website/chatbot_interface/views.py",
"chars": 227,
"preview": "from django.shortcuts import render\n\ndef mainView(request):\n \"\"\" Main view which launch and handle the chatbot view\n "
},
{
"path": "chatbot_website/chatbot_website/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "chatbot_website/chatbot_website/asgi.py",
"chars": 229,
"preview": "\"\"\"\nASGI config for chatbot_website project.\n\nUsed for WebSockets\n\"\"\"\n\nimport os\nimport channels.asgi\n\nos.environ.setdef"
},
{
"path": "chatbot_website/chatbot_website/settings.py",
"chars": 4300,
"preview": "\"\"\"\nDjango settings for chatbot_website project.\n\nGenerated by 'django-admin startproject' using Django 1.10.\n\nFor more "
},
{
"path": "chatbot_website/chatbot_website/urls.py",
"chars": 830,
"preview": "\"\"\"chatbot_website URL Configuration\n\nThe `urlpatterns` list routes URLs to views. For more information please see:\n "
},
{
"path": "chatbot_website/chatbot_website/wsgi.py",
"chars": 408,
"preview": "\"\"\"\nWSGI config for chatbot_website project.\n\nIt exposes the WSGI callable as a module-level variable named ``applicatio"
},
{
"path": "chatbot_website/logs/.gitignore",
"chars": 70,
"preview": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore"
},
{
"path": "chatbot_website/manage.py",
"chars": 813,
"preview": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n os.environ.setdefault(\"DJANGO_SETTINGS_MODULE"
},
{
"path": "data/cornell/README.txt",
"chars": 4180,
"preview": "Cornell Movie-Dialogs Corpus\n\nDistributed together with:\n\n\"Chameleons in imagined conversations: A new approach to under"
},
{
"path": "data/cornell/movie_conversations.txt",
"chars": 6760930,
"preview": "u0 +++$+++ u2 +++$+++ m0 +++$+++ ['L194', 'L195', 'L196', 'L197']\nu0 +++$+++ u2 +++$+++ m0 +++$+++ ['L198', 'L199']\nu0 +"
},
{
"path": "data/samples/.gitignore",
"chars": 70,
"preview": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore"
},
{
"path": "data/test/samples.txt",
"chars": 5801,
"preview": "Hi\nHi!\nAre you conscious?\nHow are you?\nWhat is your name ?\nAre you alive ?\nLuke, I am your father!\nYou shall not pass!\nI"
},
{
"path": "data/tweets/README.md",
"chars": 41,
"preview": "### This is where tweet QA will be saved\n"
},
{
"path": "main.py",
"chars": 885,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
},
{
"path": "requirements.txt",
"chars": 45,
"preview": "tqdm\nTwitterAPI\nrequests_oauthlib\ntensorflow\n"
},
{
"path": "save/.gitignore",
"chars": 70,
"preview": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore"
},
{
"path": "setup_server.sh",
"chars": 373,
"preview": "#!/bin/bash\n\necho \"Don't use this script for now!\"\nexit 1\n\ncd chatbot_website/\n\n# Only necessary the first time\n#python3"
},
{
"path": "testsuite.py",
"chars": 1908,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2015 Conchylicultor. All Rights Reserved.\n#\n# Licensed under the Apache License, Ver"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the kootenpv/TwitterQA GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 71 files (39.7 MB), approximately 1.8M tokens, and a symbol index with 86 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.