├── .gitignore ├── README.md ├── __init__.py ├── data └── pull_data.sh ├── data_utils.py ├── env_setup.sh ├── execute.py ├── neuralconvo.ini ├── seq2seq.ini ├── seq2seq_model.py ├── seq2seq_serve.ini ├── ui ├── .gitignore ├── README.md ├── __init.py__ ├── app.py ├── requirements.txt ├── setup.sh ├── static │ ├── css │ │ ├── normalize.css │ │ └── style.css │ ├── js │ │ ├── index.js │ │ ├── jquery-latest.js │ │ ├── jquery.mCustomScrollbar.concat.min.js │ │ ├── jquery.mCustomScrollbar.min.css │ │ └── jquery.min.js │ ├── res │ │ ├── botim.png │ │ ├── hd1.jpg │ │ └── hd2.jpg │ └── scss │ │ └── style.scss └── templates │ └── index.html └── working_dir ├── vocab20000.dec └── vocab20000.enc /.gitignore: -------------------------------------------------------------------------------- 1 | data/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easy\_seq2seq 2 | 3 | ![](https://img.shields.io/badge/status-unmaintained-red.svg) 4 | 5 | * Go to [*practical_seq2seq*](https://github.com/suriyadeepan/practical_seq2seq) 6 | 7 | An implementation of Seq2Seq that actually works. I want to make it easy for people to train their own seq2seq model with any corpus. I am also adding the parameters of my trained model for people to just use it without training. If you have a model that works share your model params here, as external link or do a pull request. I have used Cornell Movie Dialog Corpus to train my model. A link to preprocessed data and scripts for preprocessing can be found in this repo. 8 | 9 | *Have Fun!* 10 | 11 | ## Update 1.1.2017 12 | 13 | 14 | I have created another repository - [practical_seq2seq](https://github.com/suriyadeepan/practical_seq2seq) to experiment with the seq2seq model. The new model trained on Twitter chat log and Cornell Movie Dialog corpus performs well. I wrote an article - [Practical seq2seq](http://suriyadeepan.github.io/2016-12-31-practical-seq2seq/), explaining the code. 15 | 16 | Happy New Year, **2017** 17 | 18 | 19 | ## Setup 20 | 21 | 22 | * Create temporary working directory prior to training 23 | 24 | ```bash 25 | mkdir working_dir 26 | ``` 27 | 28 | * Download test/train data from Cornell Movie Dialog Corpus 29 | 30 | ```bash 31 | cd data/ 32 | bash pull_data.sh 33 | ``` 34 | 35 | ## Training 36 | 37 | ```bash 38 | # edit seq2seq.ini file to set 39 | # mode = train 40 | python execute.py 41 | # or use custom ini file 42 | # python execute.py my_custom_conf.ini 43 | ``` 44 | 45 | ## Testing 46 | 47 | ```bash 48 | # edit seq2seq.ini file to set 49 | # mode = test 50 | python execute.py 51 | ``` 52 | 53 | ## Serve 54 | 55 | ```bash 56 | # configuration : seq2seq_serve.ini 57 | python ui/app.py 58 | # wait until this message shows up 59 | # "Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)" 60 | # open up the address in browser, chat with the bot 61 | ``` 62 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/__init__.py -------------------------------------------------------------------------------- /data/pull_data.sh: -------------------------------------------------------------------------------- 1 | wget -c 'https://www.dropbox.com/s/ncfa5t950gvtaeb/test.enc?dl=0' -O test.enc 2 | wget -c 'https://www.dropbox.com/s/48ro4759jaikque/test.dec?dl=0' -O test.dec 3 | wget -c 'https://www.dropbox.com/s/gu54ngk3xpwite4/train.enc?dl=0' -O train.enc 4 | wget -c 'https://www.dropbox.com/s/g3z2msjziqocndl/train.dec?dl=0' -O train.dec 5 | -------------------------------------------------------------------------------- /data_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | """Utilities for downloading data from WMT, tokenizing, vocabularies.""" 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import os 22 | import re 23 | 24 | from six.moves import urllib 25 | 26 | from tensorflow.python.platform import gfile 27 | 28 | # Special vocabulary symbols - we always put them at the start. 29 | _PAD = b"_PAD" 30 | _GO = b"_GO" 31 | _EOS = b"_EOS" 32 | _UNK = b"_UNK" 33 | _START_VOCAB = [_PAD, _GO, _EOS, _UNK] 34 | 35 | PAD_ID = 0 36 | GO_ID = 1 37 | EOS_ID = 2 38 | UNK_ID = 3 39 | 40 | # Regular expressions used to tokenize. 41 | _WORD_SPLIT = re.compile(b"([.,!?\"':;)(])") 42 | _DIGIT_RE = re.compile(br"\d") 43 | 44 | 45 | 46 | def basic_tokenizer(sentence): 47 | """Very basic tokenizer: split the sentence into a list of tokens.""" 48 | words = [] 49 | for space_separated_fragment in sentence.strip().split(): 50 | if isinstance(space_separated_fragment, str): 51 | word = str.encode(space_separated_fragment) 52 | else: 53 | word = space_separated_fragment 54 | words.extend(re.split(_WORD_SPLIT, word)) 55 | return [w for w in words if w] 56 | 57 | 58 | def create_vocabulary(vocabulary_path, data_path, max_vocabulary_size, 59 | tokenizer=None, normalize_digits=True): 60 | 61 | if not gfile.Exists(vocabulary_path): 62 | print("Creating vocabulary %s from %s" % (vocabulary_path, data_path)) 63 | vocab = {} 64 | with gfile.GFile(data_path, mode="rb") as f: 65 | counter = 0 66 | for line in f: 67 | counter += 1 68 | if counter % 100000 == 0: 69 | print(" processing line %d" % counter) 70 | tokens = tokenizer(line) if tokenizer else basic_tokenizer(line) 71 | for w in tokens: 72 | word = re.sub(_DIGIT_RE, b"0", w) if normalize_digits else w 73 | if word in vocab: 74 | vocab[word] += 1 75 | else: 76 | vocab[word] = 1 77 | vocab_list = _START_VOCAB + sorted(vocab, key=vocab.get, reverse=True) 78 | print('>> Full Vocabulary Size :',len(vocab_list)) 79 | if len(vocab_list) > max_vocabulary_size: 80 | vocab_list = vocab_list[:max_vocabulary_size] 81 | with gfile.GFile(vocabulary_path, mode="wb") as vocab_file: 82 | for w in vocab_list: 83 | vocab_file.write(w + b"\n") 84 | 85 | 86 | def initialize_vocabulary(vocabulary_path): 87 | 88 | if gfile.Exists(vocabulary_path): 89 | rev_vocab = [] 90 | with gfile.GFile(vocabulary_path, mode="rb") as f: 91 | rev_vocab.extend(f.readlines()) 92 | rev_vocab = [line.strip() for line in rev_vocab] 93 | vocab = dict([(x, y) for (y, x) in enumerate(rev_vocab)]) 94 | return vocab, rev_vocab 95 | else: 96 | raise ValueError("Vocabulary file %s not found.", vocabulary_path) 97 | 98 | 99 | def sentence_to_token_ids(sentence, vocabulary, tokenizer=None, normalize_digits=True): 100 | 101 | if tokenizer: 102 | words = tokenizer(sentence) 103 | else: 104 | words = basic_tokenizer(sentence) 105 | if not normalize_digits: 106 | return [vocabulary.get(w, UNK_ID) for w in words] 107 | # Normalize digits by 0 before looking words up in the vocabulary. 108 | return [vocabulary.get(re.sub(_DIGIT_RE, b"0", w), UNK_ID) for w in words] 109 | 110 | 111 | def data_to_token_ids(data_path, target_path, vocabulary_path, 112 | tokenizer=None, normalize_digits=True): 113 | 114 | if not gfile.Exists(target_path): 115 | print("Tokenizing data in %s" % data_path) 116 | vocab, _ = initialize_vocabulary(vocabulary_path) 117 | with gfile.GFile(data_path, mode="rb") as data_file: 118 | with gfile.GFile(target_path, mode="w") as tokens_file: 119 | counter = 0 120 | for line in data_file: 121 | counter += 1 122 | if counter % 100000 == 0: 123 | print(" tokenizing line %d" % counter) 124 | token_ids = sentence_to_token_ids(line, vocab, tokenizer, 125 | normalize_digits) 126 | tokens_file.write(" ".join([str(tok) for tok in token_ids]) + "\n") 127 | 128 | 129 | 130 | def prepare_custom_data(working_directory, train_enc, train_dec, test_enc, test_dec, enc_vocabulary_size, dec_vocabulary_size, tokenizer=None): 131 | 132 | # Create vocabularies of the appropriate sizes. 133 | enc_vocab_path = os.path.join(working_directory, "vocab%d.enc" % enc_vocabulary_size) 134 | dec_vocab_path = os.path.join(working_directory, "vocab%d.dec" % dec_vocabulary_size) 135 | create_vocabulary(enc_vocab_path, train_enc, enc_vocabulary_size, tokenizer) 136 | create_vocabulary(dec_vocab_path, train_dec, dec_vocabulary_size, tokenizer) 137 | 138 | # Create token ids for the training data. 139 | enc_train_ids_path = train_enc + (".ids%d" % enc_vocabulary_size) 140 | dec_train_ids_path = train_dec + (".ids%d" % dec_vocabulary_size) 141 | data_to_token_ids(train_enc, enc_train_ids_path, enc_vocab_path, tokenizer) 142 | data_to_token_ids(train_dec, dec_train_ids_path, dec_vocab_path, tokenizer) 143 | 144 | # Create token ids for the development data. 145 | enc_dev_ids_path = test_enc + (".ids%d" % enc_vocabulary_size) 146 | dec_dev_ids_path = test_dec + (".ids%d" % dec_vocabulary_size) 147 | data_to_token_ids(test_enc, enc_dev_ids_path, enc_vocab_path, tokenizer) 148 | data_to_token_ids(test_dec, dec_dev_ids_path, dec_vocab_path, tokenizer) 149 | 150 | return (enc_train_ids_path, dec_train_ids_path, enc_dev_ids_path, dec_dev_ids_path, enc_vocab_path, dec_vocab_path) 151 | -------------------------------------------------------------------------------- /env_setup.sh: -------------------------------------------------------------------------------- 1 | echo 'export PYTHONPATH=$PYTHONPATH:$PWD' >> ~/.bashrc 2 | -------------------------------------------------------------------------------- /execute.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | import math 21 | import os 22 | import random 23 | import sys 24 | import time 25 | 26 | import numpy as np 27 | from six.moves import xrange # pylint: disable=redefined-builtin 28 | import tensorflow as tf 29 | 30 | import data_utils 31 | import seq2seq_model 32 | 33 | try: 34 | from ConfigParser import SafeConfigParser 35 | except: 36 | from configparser import SafeConfigParser # In Python 3, ConfigParser has been renamed to configparser for PEP 8 compliance. 37 | 38 | gConfig = {} 39 | 40 | def get_config(config_file='seq2seq.ini'): 41 | parser = SafeConfigParser() 42 | parser.read(config_file) 43 | # get the ints, floats and strings 44 | _conf_ints = [ (key, int(value)) for key,value in parser.items('ints') ] 45 | _conf_floats = [ (key, float(value)) for key,value in parser.items('floats') ] 46 | _conf_strings = [ (key, str(value)) for key,value in parser.items('strings') ] 47 | return dict(_conf_ints + _conf_floats + _conf_strings) 48 | 49 | # We use a number of buckets and pad to the closest one for efficiency. 50 | # See seq2seq_model.Seq2SeqModel for details of how they work. 51 | _buckets = [(5, 10), (10, 15), (20, 25), (40, 50)] 52 | 53 | 54 | def read_data(source_path, target_path, max_size=None): 55 | """Read data from source and target files and put into buckets. 56 | 57 | Args: 58 | source_path: path to the files with token-ids for the source language. 59 | target_path: path to the file with token-ids for the target language; 60 | it must be aligned with the source file: n-th line contains the desired 61 | output for n-th line from the source_path. 62 | max_size: maximum number of lines to read, all other will be ignored; 63 | if 0 or None, data files will be read completely (no limit). 64 | 65 | Returns: 66 | data_set: a list of length len(_buckets); data_set[n] contains a list of 67 | (source, target) pairs read from the provided data files that fit 68 | into the n-th bucket, i.e., such that len(source) < _buckets[n][0] and 69 | len(target) < _buckets[n][1]; source and target are lists of token-ids. 70 | """ 71 | data_set = [[] for _ in _buckets] 72 | with tf.gfile.GFile(source_path, mode="r") as source_file: 73 | with tf.gfile.GFile(target_path, mode="r") as target_file: 74 | source, target = source_file.readline(), target_file.readline() 75 | counter = 0 76 | while source and target and (not max_size or counter < max_size): 77 | counter += 1 78 | if counter % 100000 == 0: 79 | print(" reading data line %d" % counter) 80 | sys.stdout.flush() 81 | source_ids = [int(x) for x in source.split()] 82 | target_ids = [int(x) for x in target.split()] 83 | target_ids.append(data_utils.EOS_ID) 84 | for bucket_id, (source_size, target_size) in enumerate(_buckets): 85 | if len(source_ids) < source_size and len(target_ids) < target_size: 86 | data_set[bucket_id].append([source_ids, target_ids]) 87 | break 88 | source, target = source_file.readline(), target_file.readline() 89 | return data_set 90 | 91 | 92 | def create_model(session, forward_only): 93 | 94 | """Create model and initialize or load parameters""" 95 | model = seq2seq_model.Seq2SeqModel( gConfig['enc_vocab_size'], gConfig['dec_vocab_size'], _buckets, gConfig['layer_size'], gConfig['num_layers'], gConfig['max_gradient_norm'], gConfig['batch_size'], gConfig['learning_rate'], gConfig['learning_rate_decay_factor'], forward_only=forward_only) 96 | 97 | if 'pretrained_model' in gConfig: 98 | model.saver.restore(session,gConfig['pretrained_model']) 99 | return model 100 | 101 | ckpt = tf.train.get_checkpoint_state(gConfig['working_directory']) 102 | if ckpt and ckpt.model_checkpoint_path: 103 | print("Reading model parameters from %s" % ckpt.model_checkpoint_path) 104 | model.saver.restore(session, ckpt.model_checkpoint_path) 105 | else: 106 | print("Created model with fresh parameters.") 107 | session.run(tf.global_variables_initializer()) 108 | return model 109 | 110 | 111 | def train(): 112 | # prepare dataset 113 | print("Preparing data in %s" % gConfig['working_directory']) 114 | enc_train, dec_train, enc_dev, dec_dev, _, _ = data_utils.prepare_custom_data(gConfig['working_directory'],gConfig['train_enc'],gConfig['train_dec'],gConfig['test_enc'],gConfig['test_dec'],gConfig['enc_vocab_size'],gConfig['dec_vocab_size']) 115 | 116 | # setup config to use BFC allocator 117 | config = tf.ConfigProto() 118 | config.gpu_options.allocator_type = 'BFC' 119 | 120 | with tf.Session(config=config) as sess: 121 | # Create model. 122 | print("Creating %d layers of %d units." % (gConfig['num_layers'], gConfig['layer_size'])) 123 | model = create_model(sess, False) 124 | 125 | # Read data into buckets and compute their sizes. 126 | print ("Reading development and training data (limit: %d)." 127 | % gConfig['max_train_data_size']) 128 | dev_set = read_data(enc_dev, dec_dev) 129 | train_set = read_data(enc_train, dec_train, gConfig['max_train_data_size']) 130 | train_bucket_sizes = [len(train_set[b]) for b in xrange(len(_buckets))] 131 | train_total_size = float(sum(train_bucket_sizes)) 132 | 133 | # A bucket scale is a list of increasing numbers from 0 to 1 that we'll use 134 | # to select a bucket. Length of [scale[i], scale[i+1]] is proportional to 135 | # the size if i-th training bucket, as used later. 136 | train_buckets_scale = [sum(train_bucket_sizes[:i + 1]) / train_total_size 137 | for i in xrange(len(train_bucket_sizes))] 138 | 139 | # This is the training loop. 140 | step_time, loss = 0.0, 0.0 141 | current_step = 0 142 | previous_losses = [] 143 | while True: 144 | # Choose a bucket according to data distribution. We pick a random number 145 | # in [0, 1] and use the corresponding interval in train_buckets_scale. 146 | random_number_01 = np.random.random_sample() 147 | bucket_id = min([i for i in xrange(len(train_buckets_scale)) 148 | if train_buckets_scale[i] > random_number_01]) 149 | 150 | # Get a batch and make a step. 151 | start_time = time.time() 152 | encoder_inputs, decoder_inputs, target_weights = model.get_batch( 153 | train_set, bucket_id) 154 | _, step_loss, _ = model.step(sess, encoder_inputs, decoder_inputs, 155 | target_weights, bucket_id, False) 156 | step_time += (time.time() - start_time) / gConfig['steps_per_checkpoint'] 157 | loss += step_loss / gConfig['steps_per_checkpoint'] 158 | current_step += 1 159 | 160 | # Once in a while, we save checkpoint, print statistics, and run evals. 161 | if current_step % gConfig['steps_per_checkpoint'] == 0: 162 | # Print statistics for the previous epoch. 163 | perplexity = math.exp(loss) if loss < 300 else float('inf') 164 | print ("global step %d learning rate %.4f step-time %.2f perplexity " 165 | "%.2f" % (model.global_step.eval(), model.learning_rate.eval(), 166 | step_time, perplexity)) 167 | # Decrease learning rate if no improvement was seen over last 3 times. 168 | if len(previous_losses) > 2 and loss > max(previous_losses[-3:]): 169 | sess.run(model.learning_rate_decay_op) 170 | previous_losses.append(loss) 171 | # Save checkpoint and zero timer and loss. 172 | checkpoint_path = os.path.join(gConfig['working_directory'], "seq2seq.ckpt") 173 | model.saver.save(sess, checkpoint_path, global_step=model.global_step) 174 | step_time, loss = 0.0, 0.0 175 | # Run evals on development set and print their perplexity. 176 | for bucket_id in xrange(len(_buckets)): 177 | if len(dev_set[bucket_id]) == 0: 178 | print(" eval: empty bucket %d" % (bucket_id)) 179 | continue 180 | encoder_inputs, decoder_inputs, target_weights = model.get_batch( 181 | dev_set, bucket_id) 182 | _, eval_loss, _ = model.step(sess, encoder_inputs, decoder_inputs, 183 | target_weights, bucket_id, True) 184 | eval_ppx = math.exp(eval_loss) if eval_loss < 300 else float('inf') 185 | print(" eval: bucket %d perplexity %.2f" % (bucket_id, eval_ppx)) 186 | sys.stdout.flush() 187 | 188 | 189 | def decode(): 190 | with tf.Session() as sess: 191 | # Create model and load parameters. 192 | model = create_model(sess, True) 193 | model.batch_size = 1 # We decode one sentence at a time. 194 | 195 | # Load vocabularies. 196 | enc_vocab_path = os.path.join(gConfig['working_directory'],"vocab%d.enc" % gConfig['enc_vocab_size']) 197 | dec_vocab_path = os.path.join(gConfig['working_directory'],"vocab%d.dec" % gConfig['dec_vocab_size']) 198 | 199 | enc_vocab, _ = data_utils.initialize_vocabulary(enc_vocab_path) 200 | _, rev_dec_vocab = data_utils.initialize_vocabulary(dec_vocab_path) 201 | 202 | # Decode from standard input. 203 | sys.stdout.write("> ") 204 | sys.stdout.flush() 205 | sentence = sys.stdin.readline() 206 | while sentence: 207 | # Get token-ids for the input sentence. 208 | token_ids = data_utils.sentence_to_token_ids(tf.compat.as_bytes(sentence), enc_vocab) 209 | # Which bucket does it belong to? 210 | bucket_id = min([b for b in xrange(len(_buckets)) 211 | if _buckets[b][0] > len(token_ids)]) 212 | # Get a 1-element batch to feed the sentence to the model. 213 | encoder_inputs, decoder_inputs, target_weights = model.get_batch( 214 | {bucket_id: [(token_ids, [])]}, bucket_id) 215 | # Get output logits for the sentence. 216 | _, _, output_logits = model.step(sess, encoder_inputs, decoder_inputs, 217 | target_weights, bucket_id, True) 218 | # This is a greedy decoder - outputs are just argmaxes of output_logits. 219 | outputs = [int(np.argmax(logit, axis=1)) for logit in output_logits] 220 | # If there is an EOS symbol in outputs, cut them at that point. 221 | if data_utils.EOS_ID in outputs: 222 | outputs = outputs[:outputs.index(data_utils.EOS_ID)] 223 | # Print out French sentence corresponding to outputs. 224 | print(" ".join([tf.compat.as_str(rev_dec_vocab[output]) for output in outputs])) 225 | print("> ", end="") 226 | sys.stdout.flush() 227 | sentence = sys.stdin.readline() 228 | 229 | 230 | def self_test(): 231 | """Test the translation model.""" 232 | with tf.Session() as sess: 233 | print("Self-test for neural translation model.") 234 | # Create model with vocabularies of 10, 2 small buckets, 2 layers of 32. 235 | model = seq2seq_model.Seq2SeqModel(10, 10, [(3, 3), (6, 6)], 32, 2, 236 | 5.0, 32, 0.3, 0.99, num_samples=8) 237 | sess.run(tf.initialize_all_variables()) 238 | 239 | # Fake data set for both the (3, 3) and (6, 6) bucket. 240 | data_set = ([([1, 1], [2, 2]), ([3, 3], [4]), ([5], [6])], 241 | [([1, 1, 1, 1, 1], [2, 2, 2, 2, 2]), ([3, 3, 3], [5, 6])]) 242 | for _ in xrange(5): # Train the fake model for 5 steps. 243 | bucket_id = random.choice([0, 1]) 244 | encoder_inputs, decoder_inputs, target_weights = model.get_batch( 245 | data_set, bucket_id) 246 | model.step(sess, encoder_inputs, decoder_inputs, target_weights, 247 | bucket_id, False) 248 | 249 | 250 | def init_session(sess, conf='seq2seq.ini'): 251 | global gConfig 252 | gConfig = get_config(conf) 253 | 254 | # Create model and load parameters. 255 | model = create_model(sess, True) 256 | model.batch_size = 1 # We decode one sentence at a time. 257 | 258 | # Load vocabularies. 259 | enc_vocab_path = os.path.join(gConfig['working_directory'],"vocab%d.enc" % gConfig['enc_vocab_size']) 260 | dec_vocab_path = os.path.join(gConfig['working_directory'],"vocab%d.dec" % gConfig['dec_vocab_size']) 261 | 262 | enc_vocab, _ = data_utils.initialize_vocabulary(enc_vocab_path) 263 | _, rev_dec_vocab = data_utils.initialize_vocabulary(dec_vocab_path) 264 | 265 | return sess, model, enc_vocab, rev_dec_vocab 266 | 267 | def decode_line(sess, model, enc_vocab, rev_dec_vocab, sentence): 268 | # Get token-ids for the input sentence. 269 | token_ids = data_utils.sentence_to_token_ids(tf.compat.as_bytes(sentence), enc_vocab) 270 | 271 | # Which bucket does it belong to? 272 | bucket_id = min([b for b in xrange(len(_buckets)) if _buckets[b][0] > len(token_ids)]) 273 | 274 | # Get a 1-element batch to feed the sentence to the model. 275 | encoder_inputs, decoder_inputs, target_weights = model.get_batch({bucket_id: [(token_ids, [])]}, bucket_id) 276 | 277 | # Get output logits for the sentence. 278 | _, _, output_logits = model.step(sess, encoder_inputs, decoder_inputs, target_weights, bucket_id, True) 279 | 280 | # This is a greedy decoder - outputs are just argmaxes of output_logits. 281 | outputs = [int(np.argmax(logit, axis=1)) for logit in output_logits] 282 | 283 | # If there is an EOS symbol in outputs, cut them at that point. 284 | if data_utils.EOS_ID in outputs: 285 | outputs = outputs[:outputs.index(data_utils.EOS_ID)] 286 | 287 | return " ".join([tf.compat.as_str(rev_dec_vocab[output]) for output in outputs]) 288 | 289 | if __name__ == '__main__': 290 | if len(sys.argv) - 1: 291 | gConfig = get_config(sys.argv[1]) 292 | else: 293 | # get configuration from seq2seq.ini 294 | gConfig = get_config() 295 | 296 | print('\n>> Mode : %s\n' %(gConfig['mode'])) 297 | 298 | if gConfig['mode'] == 'train': 299 | # start training 300 | train() 301 | elif gConfig['mode'] == 'test': 302 | # interactive decode 303 | decode() 304 | else: 305 | # wrong way to execute "serve" 306 | # Use : >> python ui/app.py 307 | # uses seq2seq_serve.ini as conf file 308 | print('Serve Usage : >> python ui/app.py') 309 | print('# uses seq2seq_serve.ini as conf file') 310 | -------------------------------------------------------------------------------- /neuralconvo.ini: -------------------------------------------------------------------------------- 1 | [strings] 2 | # Mode : train, test, serve 3 | mode = train 4 | train_enc = data/train.enc 5 | train_dec = data/train.dec 6 | test_enc = data/test.enc 7 | test_dec = data/test.enc 8 | # folder where checkpoints, vocabulary, temporary data will be stored 9 | working_directory = working_dir/ 10 | [ints] 11 | # vocabulary size 12 | # 20,000 is a reasonable size 13 | enc_vocab_size = 45000 14 | dec_vocab_size = 45000 15 | # number of LSTM layers : 1/2/3 16 | num_layers = 2 17 | # typical options : 128, 256, 512, 1024 18 | layer_size = 900 19 | # dataset size limit; typically none : no limit 20 | max_train_data_size = 50000 21 | batch_size = 10 22 | # steps per checkpoint 23 | # Note : At a checkpoint, models parameters are saved, model is evaluated 24 | # and results are printed 25 | steps_per_checkpoint = 200 26 | [floats] 27 | learning_rate = 0.001 28 | learning_rate_decay_factor = 0.9 29 | max_gradient_norm = 5.0 30 | ############################################################################## 31 | # Note : Edit the bucket sizes at line47 of execute.py (_buckets) 32 | # 33 | # Learn more about the configurations from this link 34 | # https://www.tensorflow.org/versions/r0.9/tutorials/seq2seq/index.html 35 | ############################################################################## 36 | -------------------------------------------------------------------------------- /seq2seq.ini: -------------------------------------------------------------------------------- 1 | [strings] 2 | # Mode : train, test, serve 3 | mode = train 4 | train_enc = data/train.enc 5 | train_dec = data/train.dec 6 | test_enc = data/test.enc 7 | test_dec = data/test.dec 8 | # folder where checkpoints, vocabulary, temporary data will be stored 9 | working_directory = working_dir/ 10 | [ints] 11 | # vocabulary size 12 | # 20,000 is a reasonable size 13 | enc_vocab_size = 20000 14 | dec_vocab_size = 20000 15 | # number of LSTM layers : 1/2/3 16 | num_layers = 3 17 | # typical options : 128, 256, 512, 1024 18 | layer_size = 256 19 | # dataset size limit; typically none : no limit 20 | max_train_data_size = 0 21 | batch_size = 64 22 | # steps per checkpoint 23 | # Note : At a checkpoint, models parameters are saved, model is evaluated 24 | # and results are printed 25 | steps_per_checkpoint = 300 26 | [floats] 27 | learning_rate = 0.5 28 | learning_rate_decay_factor = 0.99 29 | max_gradient_norm = 5.0 30 | ############################################################################## 31 | # Note : Edit the bucket sizes at line47 of execute.py (_buckets) 32 | # 33 | # Learn more about the configurations from this link 34 | # https://www.tensorflow.org/versions/r0.9/tutorials/seq2seq/index.html 35 | ############################################################################## 36 | -------------------------------------------------------------------------------- /seq2seq_model.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | """Sequence-to-sequence model with an attention mechanism.""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import division 20 | from __future__ import print_function 21 | 22 | import random 23 | 24 | import numpy as np 25 | from six.moves import xrange # pylint: disable=redefined-builtin 26 | import tensorflow as tf 27 | 28 | from tensorflow.models.rnn.translate import data_utils 29 | 30 | 31 | class Seq2SeqModel(object): 32 | """Sequence-to-sequence model with attention and for multiple buckets. 33 | 34 | This class implements a multi-layer recurrent neural network as encoder, 35 | and an attention-based decoder. This is the same as the model described in 36 | this paper: http://arxiv.org/abs/1412.7449 - please look there for details, 37 | or into the seq2seq library for complete model implementation. 38 | This class also allows to use GRU cells in addition to LSTM cells, and 39 | sampled softmax to handle large output vocabulary size. A single-layer 40 | version of this model, but with bi-directional encoder, was presented in 41 | http://arxiv.org/abs/1409.0473 42 | and sampled softmax is described in Section 3 of the following paper. 43 | http://arxiv.org/abs/1412.2007 44 | """ 45 | 46 | def __init__(self, source_vocab_size, target_vocab_size, buckets, size, 47 | num_layers, max_gradient_norm, batch_size, learning_rate, 48 | learning_rate_decay_factor, use_lstm=False, 49 | num_samples=512, forward_only=False): 50 | """Create the model. 51 | 52 | Args: 53 | source_vocab_size: size of the source vocabulary. 54 | target_vocab_size: size of the target vocabulary. 55 | buckets: a list of pairs (I, O), where I specifies maximum input length 56 | that will be processed in that bucket, and O specifies maximum output 57 | length. Training instances that have inputs longer than I or outputs 58 | longer than O will be pushed to the next bucket and padded accordingly. 59 | We assume that the list is sorted, e.g., [(2, 4), (8, 16)]. 60 | size: number of units in each layer of the model. 61 | num_layers: number of layers in the model. 62 | max_gradient_norm: gradients will be clipped to maximally this norm. 63 | batch_size: the size of the batches used during training; 64 | the model construction is independent of batch_size, so it can be 65 | changed after initialization if this is convenient, e.g., for decoding. 66 | learning_rate: learning rate to start with. 67 | learning_rate_decay_factor: decay learning rate by this much when needed. 68 | use_lstm: if true, we use LSTM cells instead of GRU cells. 69 | num_samples: number of samples for sampled softmax. 70 | forward_only: if set, we do not construct the backward pass in the model. 71 | """ 72 | self.source_vocab_size = source_vocab_size 73 | self.target_vocab_size = target_vocab_size 74 | self.buckets = buckets 75 | self.batch_size = batch_size 76 | self.learning_rate = tf.Variable(float(learning_rate), trainable=False) 77 | self.learning_rate_decay_op = self.learning_rate.assign( 78 | self.learning_rate * learning_rate_decay_factor) 79 | self.global_step = tf.Variable(0, trainable=False) 80 | 81 | # If we use sampled softmax, we need an output projection. 82 | output_projection = None 83 | softmax_loss_function = None 84 | # Sampled softmax only makes sense if we sample less than vocabulary size. 85 | if num_samples > 0 and num_samples < self.target_vocab_size: 86 | w = tf.get_variable("proj_w", [size, self.target_vocab_size]) 87 | w_t = tf.transpose(w) 88 | b = tf.get_variable("proj_b", [self.target_vocab_size]) 89 | output_projection = (w, b) 90 | 91 | def sampled_loss(inputs, labels): 92 | labels = tf.reshape(labels, [-1, 1]) 93 | return tf.nn.sampled_softmax_loss(w_t, b, inputs, labels, num_samples, 94 | self.target_vocab_size) 95 | softmax_loss_function = sampled_loss 96 | 97 | # Create the internal multi-layer cell for our RNN. 98 | single_cell = tf.nn.rnn_cell.GRUCell(size) 99 | if use_lstm: 100 | single_cell = tf.nn.rnn_cell.BasicLSTMCell(size) 101 | cell = single_cell 102 | cell = tf.nn.rnn_cell.DropoutWrapper(cell, output_keep_prob=0.5) 103 | if num_layers > 1: 104 | cell = tf.nn.rnn_cell.MultiRNNCell([single_cell] * num_layers) 105 | 106 | # The seq2seq function: we use embedding for the input and attention. 107 | def seq2seq_f(encoder_inputs, decoder_inputs, do_decode): 108 | return tf.nn.seq2seq.embedding_attention_seq2seq( 109 | encoder_inputs, decoder_inputs, cell, 110 | num_encoder_symbols=source_vocab_size, 111 | num_decoder_symbols=target_vocab_size, 112 | embedding_size=size, 113 | output_projection=output_projection, 114 | feed_previous=do_decode) 115 | 116 | # Feeds for inputs. 117 | self.encoder_inputs = [] 118 | self.decoder_inputs = [] 119 | self.target_weights = [] 120 | for i in xrange(buckets[-1][0]): # Last bucket is the biggest one. 121 | self.encoder_inputs.append(tf.placeholder(tf.int32, shape=[None], 122 | name="encoder{0}".format(i))) 123 | for i in xrange(buckets[-1][1] + 1): 124 | self.decoder_inputs.append(tf.placeholder(tf.int32, shape=[None], 125 | name="decoder{0}".format(i))) 126 | self.target_weights.append(tf.placeholder(tf.float32, shape=[None], 127 | name="weight{0}".format(i))) 128 | 129 | # Our targets are decoder inputs shifted by one. 130 | targets = [self.decoder_inputs[i + 1] 131 | for i in xrange(len(self.decoder_inputs) - 1)] 132 | 133 | # Training outputs and losses. 134 | if forward_only: 135 | self.outputs, self.losses = tf.nn.seq2seq.model_with_buckets( 136 | self.encoder_inputs, self.decoder_inputs, targets, 137 | self.target_weights, buckets, lambda x, y: seq2seq_f(x, y, True), 138 | softmax_loss_function=softmax_loss_function) 139 | # If we use output projection, we need to project outputs for decoding. 140 | if output_projection is not None: 141 | for b in xrange(len(buckets)): 142 | self.outputs[b] = [ 143 | tf.matmul(output, output_projection[0]) + output_projection[1] 144 | for output in self.outputs[b] 145 | ] 146 | else: 147 | self.outputs, self.losses = tf.nn.seq2seq.model_with_buckets( 148 | self.encoder_inputs, self.decoder_inputs, targets, 149 | self.target_weights, buckets, 150 | lambda x, y: seq2seq_f(x, y, False), 151 | softmax_loss_function=softmax_loss_function) 152 | 153 | # Gradients and SGD update operation for training the model. 154 | params = tf.trainable_variables() 155 | if not forward_only: 156 | self.gradient_norms = [] 157 | self.updates = [] 158 | opt = tf.train.AdamOptimizer() 159 | for b in xrange(len(buckets)): 160 | gradients = tf.gradients(self.losses[b], params) 161 | clipped_gradients, norm = tf.clip_by_global_norm(gradients, 162 | max_gradient_norm) 163 | self.gradient_norms.append(norm) 164 | self.updates.append(opt.apply_gradients( 165 | zip(clipped_gradients, params), global_step=self.global_step)) 166 | 167 | self.saver = tf.train.Saver(tf.global_variables()) 168 | 169 | def step(self, session, encoder_inputs, decoder_inputs, target_weights, 170 | bucket_id, forward_only): 171 | """Run a step of the model feeding the given inputs. 172 | 173 | Args: 174 | session: tensorflow session to use. 175 | encoder_inputs: list of numpy int vectors to feed as encoder inputs. 176 | decoder_inputs: list of numpy int vectors to feed as decoder inputs. 177 | target_weights: list of numpy float vectors to feed as target weights. 178 | bucket_id: which bucket of the model to use. 179 | forward_only: whether to do the backward step or only forward. 180 | 181 | Returns: 182 | A triple consisting of gradient norm (or None if we did not do backward), 183 | average perplexity, and the outputs. 184 | 185 | Raises: 186 | ValueError: if length of encoder_inputs, decoder_inputs, or 187 | target_weights disagrees with bucket size for the specified bucket_id. 188 | """ 189 | # Check if the sizes match. 190 | encoder_size, decoder_size = self.buckets[bucket_id] 191 | if len(encoder_inputs) != encoder_size: 192 | raise ValueError("Encoder length must be equal to the one in bucket," 193 | " %d != %d." % (len(encoder_inputs), encoder_size)) 194 | if len(decoder_inputs) != decoder_size: 195 | raise ValueError("Decoder length must be equal to the one in bucket," 196 | " %d != %d." % (len(decoder_inputs), decoder_size)) 197 | if len(target_weights) != decoder_size: 198 | raise ValueError("Weights length must be equal to the one in bucket," 199 | " %d != %d." % (len(target_weights), decoder_size)) 200 | 201 | # Input feed: encoder inputs, decoder inputs, target_weights, as provided. 202 | input_feed = {} 203 | for l in xrange(encoder_size): 204 | input_feed[self.encoder_inputs[l].name] = encoder_inputs[l] 205 | for l in xrange(decoder_size): 206 | input_feed[self.decoder_inputs[l].name] = decoder_inputs[l] 207 | input_feed[self.target_weights[l].name] = target_weights[l] 208 | 209 | # Since our targets are decoder inputs shifted by one, we need one more. 210 | last_target = self.decoder_inputs[decoder_size].name 211 | input_feed[last_target] = np.zeros([self.batch_size], dtype=np.int32) 212 | 213 | # Output feed: depends on whether we do a backward step or not. 214 | if not forward_only: 215 | output_feed = [self.updates[bucket_id], # Update Op that does SGD. 216 | self.gradient_norms[bucket_id], # Gradient norm. 217 | self.losses[bucket_id]] # Loss for this batch. 218 | else: 219 | output_feed = [self.losses[bucket_id]] # Loss for this batch. 220 | for l in xrange(decoder_size): # Output logits. 221 | output_feed.append(self.outputs[bucket_id][l]) 222 | 223 | outputs = session.run(output_feed, input_feed) 224 | if not forward_only: 225 | return outputs[1], outputs[2], None # Gradient norm, loss, no outputs. 226 | else: 227 | return None, outputs[0], outputs[1:] # No gradient norm, loss, outputs. 228 | 229 | def get_batch(self, data, bucket_id): 230 | """Get a random batch of data from the specified bucket, prepare for step. 231 | 232 | To feed data in step(..) it must be a list of batch-major vectors, while 233 | data here contains single length-major cases. So the main logic of this 234 | function is to re-index data cases to be in the proper format for feeding. 235 | 236 | Args: 237 | data: a tuple of size len(self.buckets) in which each element contains 238 | lists of pairs of input and output data that we use to create a batch. 239 | bucket_id: integer, which bucket to get the batch for. 240 | 241 | Returns: 242 | The triple (encoder_inputs, decoder_inputs, target_weights) for 243 | the constructed batch that has the proper format to call step(...) later. 244 | """ 245 | encoder_size, decoder_size = self.buckets[bucket_id] 246 | encoder_inputs, decoder_inputs = [], [] 247 | 248 | # Get a random batch of encoder and decoder inputs from data, 249 | # pad them if needed, reverse encoder inputs and add GO to decoder. 250 | for _ in xrange(self.batch_size): 251 | encoder_input, decoder_input = random.choice(data[bucket_id]) 252 | 253 | # Encoder inputs are padded and then reversed. 254 | encoder_pad = [data_utils.PAD_ID] * (encoder_size - len(encoder_input)) 255 | encoder_inputs.append(list(reversed(encoder_input + encoder_pad))) 256 | 257 | # Decoder inputs get an extra "GO" symbol, and are padded then. 258 | decoder_pad_size = decoder_size - len(decoder_input) - 1 259 | decoder_inputs.append([data_utils.GO_ID] + decoder_input + 260 | [data_utils.PAD_ID] * decoder_pad_size) 261 | 262 | # Now we create batch-major vectors from the data selected above. 263 | batch_encoder_inputs, batch_decoder_inputs, batch_weights = [], [], [] 264 | 265 | # Batch encoder inputs are just re-indexed encoder_inputs. 266 | for length_idx in xrange(encoder_size): 267 | batch_encoder_inputs.append( 268 | np.array([encoder_inputs[batch_idx][length_idx] 269 | for batch_idx in xrange(self.batch_size)], dtype=np.int32)) 270 | 271 | # Batch decoder inputs are re-indexed decoder_inputs, we create weights. 272 | for length_idx in xrange(decoder_size): 273 | batch_decoder_inputs.append( 274 | np.array([decoder_inputs[batch_idx][length_idx] 275 | for batch_idx in xrange(self.batch_size)], dtype=np.int32)) 276 | 277 | # Create target_weights to be 0 for targets that are padding. 278 | batch_weight = np.ones(self.batch_size, dtype=np.float32) 279 | for batch_idx in xrange(self.batch_size): 280 | # We set weight to 0 if the corresponding target is a PAD symbol. 281 | # The corresponding target is decoder_input shifted by 1 forward. 282 | if length_idx < decoder_size - 1: 283 | target = decoder_inputs[batch_idx][length_idx + 1] 284 | if length_idx == decoder_size - 1 or target == data_utils.PAD_ID: 285 | batch_weight[batch_idx] = 0.0 286 | batch_weights.append(batch_weight) 287 | return batch_encoder_inputs, batch_decoder_inputs, batch_weights 288 | -------------------------------------------------------------------------------- /seq2seq_serve.ini: -------------------------------------------------------------------------------- 1 | [strings] 2 | # Mode : train, test, serve 3 | mode = serve 4 | train_enc = data/train.enc 5 | train_dec = data/train.dec 6 | test_enc = data/test.enc 7 | test_dec = data/test.enc 8 | # folder where checkpoints, vocabulary, temporary data will be stored 9 | working_directory = working_dir/ 10 | [ints] 11 | # vocabulary size 12 | # 20,000 is a reasonable size 13 | enc_vocab_size = 20000 14 | dec_vocab_size = 20000 15 | # number of LSTM layers : 1/2/3 16 | num_layers = 3 17 | # typical options : 128, 256, 512, 1024 18 | layer_size = 256 19 | # dataset size limit; typically none : no limit 20 | max_train_data_size = 0 21 | batch_size = 64 22 | # steps per checkpoint 23 | # Note : At a checkpoint, models parameters are saved, model is evaluated 24 | # and results are printed 25 | steps_per_checkpoint = 300 26 | [floats] 27 | learning_rate = 0.5 28 | learning_rate_decay_factor = 0.99 29 | max_gradient_norm = 5.0 30 | ############################################################################## 31 | # Note : Edit the bucket sizes at line47 of execute.py (_buckets) 32 | # 33 | # Learn more about the configurations from this link 34 | # https://www.tensorflow.org/versions/r0.9/tutorials/seq2seq/index.html 35 | ############################################################################## 36 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.pyo 4 | env 5 | env* 6 | dist 7 | build 8 | *.egg 9 | *.egg-info 10 | _mailinglist 11 | .tox 12 | .cache/ 13 | .idea/ 14 | -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 | # Flask Chatbox 2 | 3 | A simple flask application that provides an UI for chat and handles the model internally. 4 | -------------------------------------------------------------------------------- /ui/__init.py__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/ui/__init.py__ -------------------------------------------------------------------------------- /ui/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | from flask import jsonify 3 | 4 | app = Flask(__name__,static_url_path="/static") 5 | 6 | ############# 7 | # Routing 8 | # 9 | @app.route('/message', methods=['POST']) 10 | def reply(): 11 | return jsonify( { 'text': execute.decode_line(sess, model, enc_vocab, rev_dec_vocab, request.form['msg'] ) } ) 12 | 13 | @app.route("/") 14 | def index(): 15 | return render_template("index.html") 16 | ############# 17 | 18 | ''' 19 | Init seq2seq model 20 | 21 | 1. Call main from execute.py 22 | 2. Create decode_line function that takes message as input 23 | ''' 24 | #_________________________________________________________________ 25 | import sys 26 | import os.path 27 | 28 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 29 | import tensorflow as tf 30 | import execute 31 | 32 | sess = tf.Session() 33 | sess, model, enc_vocab, rev_dec_vocab = execute.init_session(sess, conf='seq2seq_serve.ini') 34 | #_________________________________________________________________ 35 | 36 | # start app 37 | if (__name__ == "__main__"): 38 | app.run(port = 5000) 39 | -------------------------------------------------------------------------------- /ui/requirements.txt: -------------------------------------------------------------------------------- 1 | click==6.6 2 | Flask==0.11.1 3 | itsdangerous==0.24 4 | Jinja2==2.8 5 | MarkupSafe==0.23 6 | Werkzeug==0.11.10 7 | -------------------------------------------------------------------------------- /ui/setup.sh: -------------------------------------------------------------------------------- 1 | sudo -H pip install --upgrade pip 2 | sudo -H pip install -r requirements.txt 3 | -------------------------------------------------------------------------------- /ui/static/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}template,[hidden]{display:none}a{background-color:transparent}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}button,input,select{overflow:visible}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{cursor:pointer}[disabled]{cursor:default}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button:-moz-focusring,input:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type="checkbox"],[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none} 2 | -------------------------------------------------------------------------------- /ui/static/css/style.css: -------------------------------------------------------------------------------- 1 | /*-------------------- 2 | Mixins 3 | --------------------*/ 4 | /*-------------------- 5 | Body 6 | --------------------*/ 7 | *, 8 | *::before, 9 | *::after { 10 | box-sizing: border-box; 11 | } 12 | 13 | html, 14 | body { 15 | height: 100%; 16 | } 17 | 18 | body { 19 | background: -webkit-linear-gradient(315deg, #044f48, #2a7561); 20 | background: linear-gradient(135deg, #044f48, #2a7561); 21 | background-size: cover; 22 | font-family: 'Open Sans', sans-serif; 23 | font-size: 12px; 24 | line-height: 1.3; 25 | overflow: hidden; 26 | } 27 | 28 | .bg { 29 | width: 100%; 30 | height: 100%; 31 | top: 0; 32 | left: 0; 33 | z-index: 1; 34 | background: url("/static/res/hd2.jpg") no-repeat 0 0; 35 | -webkit-filter: blur(80px); 36 | filter: blur(80px); 37 | -webkit-transform: scale(1.2); 38 | transform: scale(1.2); 39 | } 40 | 41 | /*-------------------- 42 | Chat 43 | --------------------*/ 44 | .chat { 45 | position: absolute; 46 | top: 50%; 47 | left: 50%; 48 | -webkit-transform: translate(-50%, -50%); 49 | transform: translate(-50%, -50%); 50 | width: 300px; 51 | height: 80vh; 52 | max-height: 500px; 53 | z-index: 2; 54 | overflow: hidden; 55 | box-shadow: 0 5px 30px rgba(0, 0, 0, 0.2); 56 | background: rgba(0, 0, 0, 0.5); 57 | border-radius: 20px; 58 | display: -webkit-box; 59 | display: -webkit-flex; 60 | display: -ms-flexbox; 61 | display: flex; 62 | -webkit-box-pack: justify; 63 | -webkit-justify-content: space-between; 64 | -ms-flex-pack: justify; 65 | justify-content: space-between; 66 | -webkit-box-orient: vertical; 67 | -webkit-box-direction: normal; 68 | -webkit-flex-direction: column; 69 | -ms-flex-direction: column; 70 | flex-direction: column; 71 | } 72 | 73 | /*-------------------- 74 | Chat Title 75 | --------------------*/ 76 | .chat-title { 77 | -webkit-box-flex: 0; 78 | -webkit-flex: 0 1 45px; 79 | -ms-flex: 0 1 45px; 80 | flex: 0 1 45px; 81 | position: relative; 82 | z-index: 2; 83 | background: rgba(0, 0, 0, 0.2); 84 | color: #fff; 85 | text-transform: uppercase; 86 | text-align: left; 87 | padding: 10px 10px 10px 50px; 88 | } 89 | .chat-title h1, .chat-title h2 { 90 | font-weight: normal; 91 | font-size: 10px; 92 | margin: 0; 93 | padding: 0; 94 | } 95 | .chat-title h2 { 96 | color: rgba(255, 255, 255, 0.5); 97 | font-size: 8px; 98 | letter-spacing: 1px; 99 | } 100 | .chat-title .avatar { 101 | position: absolute; 102 | z-index: 1; 103 | top: 8px; 104 | left: 9px; 105 | border-radius: 30px; 106 | width: 30px; 107 | height: 30px; 108 | overflow: hidden; 109 | margin: 0; 110 | padding: 0; 111 | border: 2px solid rgba(255, 255, 255, 0.24); 112 | } 113 | .chat-title .avatar img { 114 | width: 100%; 115 | height: auto; 116 | } 117 | 118 | /*-------------------- 119 | Messages 120 | --------------------*/ 121 | .messages { 122 | -webkit-box-flex: 1; 123 | -webkit-flex: 1 1 auto; 124 | -ms-flex: 1 1 auto; 125 | flex: 1 1 auto; 126 | color: rgba(255, 255, 255, 0.5); 127 | overflow: hidden; 128 | position: relative; 129 | width: 100%; 130 | } 131 | .messages .messages-content { 132 | position: absolute; 133 | top: 0; 134 | left: 0; 135 | height: 101%; 136 | width: 100%; 137 | } 138 | .messages .message { 139 | clear: both; 140 | float: left; 141 | padding: 6px 10px 7px; 142 | border-radius: 10px 10px 10px 0; 143 | background: rgba(0, 0, 0, 0.3); 144 | margin: 8px 0; 145 | font-size: 11px; 146 | line-height: 1.4; 147 | margin-left: 35px; 148 | position: relative; 149 | text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); 150 | } 151 | .messages .message .timestamp { 152 | position: absolute; 153 | bottom: -15px; 154 | font-size: 9px; 155 | color: rgba(255, 255, 255, 0.3); 156 | } 157 | .messages .message::before { 158 | content: ''; 159 | position: absolute; 160 | bottom: -6px; 161 | border-top: 6px solid rgba(0, 0, 0, 0.3); 162 | left: 0; 163 | border-right: 7px solid transparent; 164 | } 165 | .messages .message .avatar { 166 | position: absolute; 167 | z-index: 1; 168 | bottom: -15px; 169 | left: -35px; 170 | border-radius: 30px; 171 | width: 30px; 172 | height: 30px; 173 | overflow: hidden; 174 | margin: 0; 175 | padding: 0; 176 | border: 2px solid rgba(255, 255, 255, 0.24); 177 | } 178 | .messages .message .avatar img { 179 | width: 100%; 180 | height: auto; 181 | } 182 | .messages .message.message-personal { 183 | float: right; 184 | color: #fff; 185 | text-align: right; 186 | background: -webkit-linear-gradient(330deg, #248A52, #257287); 187 | background: linear-gradient(120deg, #248A52, #257287); 188 | border-radius: 10px 10px 0 10px; 189 | } 190 | .messages .message.message-personal::before { 191 | left: auto; 192 | right: 0; 193 | border-right: none; 194 | border-left: 5px solid transparent; 195 | border-top: 4px solid #257287; 196 | bottom: -4px; 197 | } 198 | .messages .message:last-child { 199 | margin-bottom: 30px; 200 | } 201 | .messages .message.new { 202 | -webkit-transform: scale(0); 203 | transform: scale(0); 204 | -webkit-transform-origin: 0 0; 205 | transform-origin: 0 0; 206 | -webkit-animation: bounce 500ms linear both; 207 | animation: bounce 500ms linear both; 208 | } 209 | .messages .message.loading::before { 210 | position: absolute; 211 | top: 50%; 212 | left: 50%; 213 | -webkit-transform: translate(-50%, -50%); 214 | transform: translate(-50%, -50%); 215 | content: ''; 216 | display: block; 217 | width: 3px; 218 | height: 3px; 219 | border-radius: 50%; 220 | background: rgba(255, 255, 255, 0.5); 221 | z-index: 2; 222 | margin-top: 4px; 223 | -webkit-animation: ball 0.45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 224 | animation: ball 0.45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 225 | border: none; 226 | -webkit-animation-delay: .15s; 227 | animation-delay: .15s; 228 | } 229 | .messages .message.loading span { 230 | display: block; 231 | font-size: 0; 232 | width: 20px; 233 | height: 10px; 234 | position: relative; 235 | } 236 | .messages .message.loading span::before { 237 | position: absolute; 238 | top: 50%; 239 | left: 50%; 240 | -webkit-transform: translate(-50%, -50%); 241 | transform: translate(-50%, -50%); 242 | content: ''; 243 | display: block; 244 | width: 3px; 245 | height: 3px; 246 | border-radius: 50%; 247 | background: rgba(255, 255, 255, 0.5); 248 | z-index: 2; 249 | margin-top: 4px; 250 | -webkit-animation: ball 0.45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 251 | animation: ball 0.45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 252 | margin-left: -7px; 253 | } 254 | .messages .message.loading span::after { 255 | position: absolute; 256 | top: 50%; 257 | left: 50%; 258 | -webkit-transform: translate(-50%, -50%); 259 | transform: translate(-50%, -50%); 260 | content: ''; 261 | display: block; 262 | width: 3px; 263 | height: 3px; 264 | border-radius: 50%; 265 | background: rgba(255, 255, 255, 0.5); 266 | z-index: 2; 267 | margin-top: 4px; 268 | -webkit-animation: ball 0.45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 269 | animation: ball 0.45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 270 | margin-left: 7px; 271 | -webkit-animation-delay: .3s; 272 | animation-delay: .3s; 273 | } 274 | 275 | /*-------------------- 276 | Message Box 277 | --------------------*/ 278 | .message-box { 279 | -webkit-box-flex: 0; 280 | -webkit-flex: 0 1 40px; 281 | -ms-flex: 0 1 40px; 282 | flex: 0 1 40px; 283 | width: 100%; 284 | background: rgba(0, 0, 0, 0.3); 285 | padding: 10px; 286 | position: relative; 287 | } 288 | .message-box .message-input { 289 | background: none; 290 | border: none; 291 | outline: none !important; 292 | resize: none; 293 | color: rgba(255, 255, 255, 0.7); 294 | font-size: 11px; 295 | height: 17px; 296 | margin: 0; 297 | padding-right: 20px; 298 | width: 265px; 299 | } 300 | .message-box textarea:focus:-webkit-placeholder { 301 | color: transparent; 302 | } 303 | .message-box .message-submit { 304 | position: absolute; 305 | z-index: 1; 306 | top: 9px; 307 | right: 10px; 308 | color: #fff; 309 | border: none; 310 | background: #248A52; 311 | font-size: 10px; 312 | text-transform: uppercase; 313 | line-height: 1; 314 | padding: 6px 10px; 315 | border-radius: 10px; 316 | outline: none !important; 317 | -webkit-transition: background .2s ease; 318 | transition: background .2s ease; 319 | } 320 | .message-box .message-submit:hover { 321 | background: #1D7745; 322 | } 323 | 324 | /*-------------------- 325 | Custom Srollbar 326 | --------------------*/ 327 | .mCSB_scrollTools { 328 | margin: 1px -3px 1px 0; 329 | opacity: 0; 330 | } 331 | 332 | .mCSB_inside > .mCSB_container { 333 | margin-right: 0px; 334 | padding: 0 10px; 335 | } 336 | 337 | .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar { 338 | background-color: rgba(0, 0, 0, 0.5) !important; 339 | } 340 | 341 | /*-------------------- 342 | Bounce 343 | --------------------*/ 344 | @-webkit-keyframes bounce { 345 | 0% { 346 | -webkit-transform: matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 347 | transform: matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 348 | } 349 | 4.7% { 350 | -webkit-transform: matrix3d(0.45, 0, 0, 0, 0, 0.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 351 | transform: matrix3d(0.45, 0, 0, 0, 0, 0.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 352 | } 353 | 9.41% { 354 | -webkit-transform: matrix3d(0.883, 0, 0, 0, 0, 0.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 355 | transform: matrix3d(0.883, 0, 0, 0, 0, 0.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 356 | } 357 | 14.11% { 358 | -webkit-transform: matrix3d(1.141, 0, 0, 0, 0, 1.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 359 | transform: matrix3d(1.141, 0, 0, 0, 0, 1.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 360 | } 361 | 18.72% { 362 | -webkit-transform: matrix3d(1.212, 0, 0, 0, 0, 1.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 363 | transform: matrix3d(1.212, 0, 0, 0, 0, 1.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 364 | } 365 | 24.32% { 366 | -webkit-transform: matrix3d(1.151, 0, 0, 0, 0, 1.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 367 | transform: matrix3d(1.151, 0, 0, 0, 0, 1.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 368 | } 369 | 29.93% { 370 | -webkit-transform: matrix3d(1.048, 0, 0, 0, 0, 1.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 371 | transform: matrix3d(1.048, 0, 0, 0, 0, 1.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 372 | } 373 | 35.54% { 374 | -webkit-transform: matrix3d(0.979, 0, 0, 0, 0, 0.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 375 | transform: matrix3d(0.979, 0, 0, 0, 0, 0.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 376 | } 377 | 41.04% { 378 | -webkit-transform: matrix3d(0.961, 0, 0, 0, 0, 0.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 379 | transform: matrix3d(0.961, 0, 0, 0, 0, 0.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 380 | } 381 | 52.15% { 382 | -webkit-transform: matrix3d(0.991, 0, 0, 0, 0, 0.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 383 | transform: matrix3d(0.991, 0, 0, 0, 0, 0.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 384 | } 385 | 63.26% { 386 | -webkit-transform: matrix3d(1.007, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 387 | transform: matrix3d(1.007, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 388 | } 389 | 85.49% { 390 | -webkit-transform: matrix3d(0.999, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 391 | transform: matrix3d(0.999, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 392 | } 393 | 100% { 394 | -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 395 | transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 396 | } 397 | } 398 | @keyframes bounce { 399 | 0% { 400 | -webkit-transform: matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 401 | transform: matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 402 | } 403 | 4.7% { 404 | -webkit-transform: matrix3d(0.45, 0, 0, 0, 0, 0.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 405 | transform: matrix3d(0.45, 0, 0, 0, 0, 0.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 406 | } 407 | 9.41% { 408 | -webkit-transform: matrix3d(0.883, 0, 0, 0, 0, 0.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 409 | transform: matrix3d(0.883, 0, 0, 0, 0, 0.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 410 | } 411 | 14.11% { 412 | -webkit-transform: matrix3d(1.141, 0, 0, 0, 0, 1.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 413 | transform: matrix3d(1.141, 0, 0, 0, 0, 1.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 414 | } 415 | 18.72% { 416 | -webkit-transform: matrix3d(1.212, 0, 0, 0, 0, 1.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 417 | transform: matrix3d(1.212, 0, 0, 0, 0, 1.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 418 | } 419 | 24.32% { 420 | -webkit-transform: matrix3d(1.151, 0, 0, 0, 0, 1.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 421 | transform: matrix3d(1.151, 0, 0, 0, 0, 1.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 422 | } 423 | 29.93% { 424 | -webkit-transform: matrix3d(1.048, 0, 0, 0, 0, 1.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 425 | transform: matrix3d(1.048, 0, 0, 0, 0, 1.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 426 | } 427 | 35.54% { 428 | -webkit-transform: matrix3d(0.979, 0, 0, 0, 0, 0.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 429 | transform: matrix3d(0.979, 0, 0, 0, 0, 0.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 430 | } 431 | 41.04% { 432 | -webkit-transform: matrix3d(0.961, 0, 0, 0, 0, 0.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 433 | transform: matrix3d(0.961, 0, 0, 0, 0, 0.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 434 | } 435 | 52.15% { 436 | -webkit-transform: matrix3d(0.991, 0, 0, 0, 0, 0.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 437 | transform: matrix3d(0.991, 0, 0, 0, 0, 0.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 438 | } 439 | 63.26% { 440 | -webkit-transform: matrix3d(1.007, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 441 | transform: matrix3d(1.007, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 442 | } 443 | 85.49% { 444 | -webkit-transform: matrix3d(0.999, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 445 | transform: matrix3d(0.999, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 446 | } 447 | 100% { 448 | -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 449 | transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 450 | } 451 | } 452 | @-webkit-keyframes ball { 453 | from { 454 | -webkit-transform: translateY(0) scaleY(0.8); 455 | transform: translateY(0) scaleY(0.8); 456 | } 457 | to { 458 | -webkit-transform: translateY(-10px); 459 | transform: translateY(-10px); 460 | } 461 | } 462 | @keyframes ball { 463 | from { 464 | -webkit-transform: translateY(0) scaleY(0.8); 465 | transform: translateY(0) scaleY(0.8); 466 | } 467 | to { 468 | -webkit-transform: translateY(-10px); 469 | transform: translateY(-10px); 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /ui/static/js/index.js: -------------------------------------------------------------------------------- 1 | var $messages = $('.messages-content'), 2 | d, h, m, 3 | i = 0; 4 | 5 | $(window).load(function() { 6 | $messages.mCustomScrollbar(); 7 | setTimeout(function() { 8 | //fakeMessage(); 9 | }, 100); 10 | }); 11 | 12 | function updateScrollbar() { 13 | $messages.mCustomScrollbar("update").mCustomScrollbar('scrollTo', 'bottom', { 14 | scrollInertia: 10, 15 | timeout: 0 16 | }); 17 | } 18 | 19 | function setDate(){ 20 | d = new Date() 21 | if (m != d.getMinutes()) { 22 | m = d.getMinutes(); 23 | $('
' + d.getHours() + ':' + m + '
').appendTo($('.message:last')); 24 | } 25 | } 26 | 27 | function insertMessage() { 28 | msg = $('.message-input').val(); 29 | if ($.trim(msg) == '') { 30 | return false; 31 | } 32 | $('
' + msg + '
').appendTo($('.mCSB_container')).addClass('new'); 33 | setDate(); 34 | $('.message-input').val(null); 35 | updateScrollbar(); 36 | interact(msg); 37 | setTimeout(function() { 38 | //fakeMessage(); 39 | }, 1000 + (Math.random() * 20) * 100); 40 | } 41 | 42 | $('.message-submit').click(function() { 43 | insertMessage(); 44 | }); 45 | 46 | $(window).on('keydown', function(e) { 47 | if (e.which == 13) { 48 | insertMessage(); 49 | return false; 50 | } 51 | }) 52 | 53 | 54 | function interact(message){ 55 | // loading message 56 | $('
').appendTo($('.mCSB_container')); 57 | // make a POST request [ajax call] 58 | $.post('/message', { 59 | msg: message, 60 | }).done(function(reply) { 61 | // Message Received 62 | // remove loading meassage 63 | $('.message.loading').remove(); 64 | // Add message to chatbox 65 | $('
' + reply['text'] + '
').appendTo($('.mCSB_container')).addClass('new'); 66 | setDate(); 67 | updateScrollbar(); 68 | 69 | }).fail(function() { 70 | alert('error calling function'); 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /ui/static/js/jquery.mCustomScrollbar.concat.min.js: -------------------------------------------------------------------------------- 1 | /* == jquery mousewheel plugin == Version: 3.1.13, License: MIT License (MIT) */ 2 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}); 3 | /* == malihu jquery custom scrollbar plugin == Version: 3.1.3, License: MIT License (MIT) */ 4 | !function(e){"undefined"!=typeof module&&module.exports?module.exports=e:e(jQuery,window,document)}(function(e){!function(t){var o="function"==typeof define&&define.amd,a="undefined"!=typeof module&&module.exports,n="https:"==document.location.protocol?"https:":"http:",i="cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js";o||(a?require("jquery-mousewheel")(e):e.event.special.mousewheel||e("head").append(decodeURI("%3Cscript src="+n+"//"+i+"%3E%3C/script%3E"))),t()}(function(){var t,o="mCustomScrollbar",a="mCS",n=".mCustomScrollbar",i={setTop:0,setLeft:0,axis:"y",scrollbarPosition:"inside",scrollInertia:950,autoDraggerLength:!0,alwaysShowScrollbar:0,snapOffset:0,mouseWheel:{enable:!0,scrollAmount:"auto",axis:"y",deltaFactor:"auto",disableOver:["select","option","keygen","datalist","textarea"]},scrollButtons:{scrollType:"stepless",scrollAmount:"auto"},keyboard:{enable:!0,scrollType:"stepless",scrollAmount:"auto"},contentTouchScroll:25,documentTouchScroll:!0,advanced:{autoScrollOnFocus:"input,textarea,select,button,datalist,keygen,a[tabindex],area,object,[contenteditable='true']",updateOnContentResize:!0,updateOnImageLoad:"auto",autoUpdateTimeout:60},theme:"light",callbacks:{onTotalScrollOffset:0,onTotalScrollBackOffset:0,alwaysTriggerOffsets:!0}},r=0,l={},s=window.attachEvent&&!window.addEventListener?1:0,c=!1,d=["mCSB_dragger_onDrag","mCSB_scrollTools_onDrag","mCS_img_loaded","mCS_disabled","mCS_destroyed","mCS_no_scrollbar","mCS-autoHide","mCS-dir-rtl","mCS_no_scrollbar_y","mCS_no_scrollbar_x","mCS_y_hidden","mCS_x_hidden","mCSB_draggerContainer","mCSB_buttonUp","mCSB_buttonDown","mCSB_buttonLeft","mCSB_buttonRight"],u={init:function(t){var t=e.extend(!0,{},i,t),o=f.call(this);if(t.live){var s=t.liveSelector||this.selector||n,c=e(s);if("off"===t.live)return void m(s);l[s]=setTimeout(function(){c.mCustomScrollbar(t),"once"===t.live&&c.length&&m(s)},500)}else m(s);return t.setWidth=t.set_width?t.set_width:t.setWidth,t.setHeight=t.set_height?t.set_height:t.setHeight,t.axis=t.horizontalScroll?"x":p(t.axis),t.scrollInertia=t.scrollInertia>0&&t.scrollInertia<17?17:t.scrollInertia,"object"!=typeof t.mouseWheel&&1==t.mouseWheel&&(t.mouseWheel={enable:!0,scrollAmount:"auto",axis:"y",preventDefault:!1,deltaFactor:"auto",normalizeDelta:!1,invert:!1}),t.mouseWheel.scrollAmount=t.mouseWheelPixels?t.mouseWheelPixels:t.mouseWheel.scrollAmount,t.mouseWheel.normalizeDelta=t.advanced.normalizeMouseWheelDelta?t.advanced.normalizeMouseWheelDelta:t.mouseWheel.normalizeDelta,t.scrollButtons.scrollType=g(t.scrollButtons.scrollType),h(t),e(o).each(function(){var o=e(this);if(!o.data(a)){o.data(a,{idx:++r,opt:t,scrollRatio:{y:null,x:null},overflowed:null,contentReset:{y:null,x:null},bindEvents:!1,tweenRunning:!1,sequential:{},langDir:o.css("direction"),cbOffsets:null,trigger:null,poll:{size:{o:0,n:0},img:{o:0,n:0},change:{o:0,n:0}}});var n=o.data(a),i=n.opt,l=o.data("mcs-axis"),s=o.data("mcs-scrollbar-position"),c=o.data("mcs-theme");l&&(i.axis=l),s&&(i.scrollbarPosition=s),c&&(i.theme=c,h(i)),v.call(this),n&&i.callbacks.onCreate&&"function"==typeof i.callbacks.onCreate&&i.callbacks.onCreate.call(this),e("#mCSB_"+n.idx+"_container img:not(."+d[2]+")").addClass(d[2]),u.update.call(null,o)}})},update:function(t,o){var n=t||f.call(this);return e(n).each(function(){var t=e(this);if(t.data(a)){var n=t.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container"),l=e("#mCSB_"+n.idx),s=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];if(!r.length)return;n.tweenRunning&&N(t),o&&n&&i.callbacks.onBeforeUpdate&&"function"==typeof i.callbacks.onBeforeUpdate&&i.callbacks.onBeforeUpdate.call(this),t.hasClass(d[3])&&t.removeClass(d[3]),t.hasClass(d[4])&&t.removeClass(d[4]),l.css("max-height","none"),l.height()!==t.height()&&l.css("max-height",t.height()),_.call(this),"y"===i.axis||i.advanced.autoExpandHorizontalScroll||r.css("width",x(r)),n.overflowed=y.call(this),M.call(this),i.autoDraggerLength&&S.call(this),b.call(this),T.call(this);var c=[Math.abs(r[0].offsetTop),Math.abs(r[0].offsetLeft)];"x"!==i.axis&&(n.overflowed[0]?s[0].height()>s[0].parent().height()?B.call(this):(V(t,c[0].toString(),{dir:"y",dur:0,overwrite:"none"}),n.contentReset.y=null):(B.call(this),"y"===i.axis?k.call(this):"yx"===i.axis&&n.overflowed[1]&&V(t,c[1].toString(),{dir:"x",dur:0,overwrite:"none"}))),"y"!==i.axis&&(n.overflowed[1]?s[1].width()>s[1].parent().width()?B.call(this):(V(t,c[1].toString(),{dir:"x",dur:0,overwrite:"none"}),n.contentReset.x=null):(B.call(this),"x"===i.axis?k.call(this):"yx"===i.axis&&n.overflowed[0]&&V(t,c[0].toString(),{dir:"y",dur:0,overwrite:"none"}))),o&&n&&(2===o&&i.callbacks.onImageLoad&&"function"==typeof i.callbacks.onImageLoad?i.callbacks.onImageLoad.call(this):3===o&&i.callbacks.onSelectorChange&&"function"==typeof i.callbacks.onSelectorChange?i.callbacks.onSelectorChange.call(this):i.callbacks.onUpdate&&"function"==typeof i.callbacks.onUpdate&&i.callbacks.onUpdate.call(this)),X.call(this)}})},scrollTo:function(t,o){if("undefined"!=typeof t&&null!=t){var n=f.call(this);return e(n).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l={trigger:"external",scrollInertia:r.scrollInertia,scrollEasing:"mcsEaseInOut",moveDragger:!1,timeout:60,callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},s=e.extend(!0,{},l,o),c=q.call(this,t),d=s.scrollInertia>0&&s.scrollInertia<17?17:s.scrollInertia;c[0]=Y.call(this,c[0],"y"),c[1]=Y.call(this,c[1],"x"),s.moveDragger&&(c[0]*=i.scrollRatio.y,c[1]*=i.scrollRatio.x),s.dur=oe()?0:d,setTimeout(function(){null!==c[0]&&"undefined"!=typeof c[0]&&"x"!==r.axis&&i.overflowed[0]&&(s.dir="y",s.overwrite="all",V(n,c[0].toString(),s)),null!==c[1]&&"undefined"!=typeof c[1]&&"y"!==r.axis&&i.overflowed[1]&&(s.dir="x",s.overwrite="none",V(n,c[1].toString(),s))},s.timeout)}})}},stop:function(){var t=f.call(this);return e(t).each(function(){var t=e(this);t.data(a)&&N(t)})},disable:function(t){var o=f.call(this);return e(o).each(function(){var o=e(this);if(o.data(a)){{o.data(a)}X.call(this,"remove"),k.call(this),t&&B.call(this),M.call(this,!0),o.addClass(d[3])}})},destroy:function(){var t=f.call(this);return e(t).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx),s=e("#mCSB_"+i.idx+"_container"),c=e(".mCSB_"+i.idx+"_scrollbar");r.live&&m(r.liveSelector||e(t).selector),X.call(this,"remove"),k.call(this),B.call(this),n.removeData(a),K(this,"mcs"),c.remove(),s.find("img."+d[2]).removeClass(d[2]),l.replaceWith(s.contents()),n.removeClass(o+" _"+a+"_"+i.idx+" "+d[6]+" "+d[7]+" "+d[5]+" "+d[3]).addClass(d[4])}})}},f=function(){return"object"!=typeof e(this)||e(this).length<1?n:this},h=function(t){var o=["rounded","rounded-dark","rounded-dots","rounded-dots-dark"],a=["rounded-dots","rounded-dots-dark","3d","3d-dark","3d-thick","3d-thick-dark","inset","inset-dark","inset-2","inset-2-dark","inset-3","inset-3-dark"],n=["minimal","minimal-dark"],i=["minimal","minimal-dark"],r=["minimal","minimal-dark"];t.autoDraggerLength=e.inArray(t.theme,o)>-1?!1:t.autoDraggerLength,t.autoExpandScrollbar=e.inArray(t.theme,a)>-1?!1:t.autoExpandScrollbar,t.scrollButtons.enable=e.inArray(t.theme,n)>-1?!1:t.scrollButtons.enable,t.autoHideScrollbar=e.inArray(t.theme,i)>-1?!0:t.autoHideScrollbar,t.scrollbarPosition=e.inArray(t.theme,r)>-1?"outside":t.scrollbarPosition},m=function(e){l[e]&&(clearTimeout(l[e]),K(l,e))},p=function(e){return"yx"===e||"xy"===e||"auto"===e?"yx":"x"===e||"horizontal"===e?"x":"y"},g=function(e){return"stepped"===e||"pixels"===e||"step"===e||"click"===e?"stepped":"stepless"},v=function(){var t=e(this),n=t.data(a),i=n.opt,r=i.autoExpandScrollbar?" "+d[1]+"_expand":"",l=["
","
"],s="yx"===i.axis?"mCSB_vertical_horizontal":"x"===i.axis?"mCSB_horizontal":"mCSB_vertical",c="yx"===i.axis?l[0]+l[1]:"x"===i.axis?l[1]:l[0],u="yx"===i.axis?"
":"",f=i.autoHideScrollbar?" "+d[6]:"",h="x"!==i.axis&&"rtl"===n.langDir?" "+d[7]:"";i.setWidth&&t.css("width",i.setWidth),i.setHeight&&t.css("height",i.setHeight),i.setLeft="y"!==i.axis&&"rtl"===n.langDir?"989999px":i.setLeft,t.addClass(o+" _"+a+"_"+n.idx+f+h).wrapInner("
");var m=e("#mCSB_"+n.idx),p=e("#mCSB_"+n.idx+"_container");"y"===i.axis||i.advanced.autoExpandHorizontalScroll||p.css("width",x(p)),"outside"===i.scrollbarPosition?("static"===t.css("position")&&t.css("position","relative"),t.css("overflow","visible"),m.addClass("mCSB_outside").after(c)):(m.addClass("mCSB_inside").append(c),p.wrap(u)),w.call(this);var g=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];g[0].css("min-height",g[0].height()),g[1].css("min-width",g[1].width())},x=function(t){var o=[t[0].scrollWidth,Math.max.apply(Math,t.children().map(function(){return e(this).outerWidth(!0)}).get())],a=t.parent().width();return o[0]>a?o[0]:o[1]>a?o[1]:"100%"},_=function(){var t=e(this),o=t.data(a),n=o.opt,i=e("#mCSB_"+o.idx+"_container");if(n.advanced.autoExpandHorizontalScroll&&"y"!==n.axis){i.css({width:"auto","min-width":0,"overflow-x":"scroll"});var r=Math.ceil(i[0].scrollWidth);3===n.advanced.autoExpandHorizontalScroll||2!==n.advanced.autoExpandHorizontalScroll&&r>i.parent().width()?i.css({width:r,"min-width":"100%","overflow-x":"inherit"}):i.css({"overflow-x":"inherit",position:"absolute"}).wrap("
").css({width:Math.ceil(i[0].getBoundingClientRect().right+.4)-Math.floor(i[0].getBoundingClientRect().left),"min-width":"100%",position:"relative"}).unwrap()}},w=function(){var t=e(this),o=t.data(a),n=o.opt,i=e(".mCSB_"+o.idx+"_scrollbar:first"),r=ee(n.scrollButtons.tabindex)?"tabindex='"+n.scrollButtons.tabindex+"'":"",l=["","","",""],s=["x"===n.axis?l[2]:l[0],"x"===n.axis?l[3]:l[1],l[2],l[3]];n.scrollButtons.enable&&i.prepend(s[0]).append(s[1]).next(".mCSB_scrollTools").prepend(s[2]).append(s[3])},S=function(){var t=e(this),o=t.data(a),n=e("#mCSB_"+o.idx),i=e("#mCSB_"+o.idx+"_container"),r=[e("#mCSB_"+o.idx+"_dragger_vertical"),e("#mCSB_"+o.idx+"_dragger_horizontal")],l=[n.height()/i.outerHeight(!1),n.width()/i.outerWidth(!1)],c=[parseInt(r[0].css("min-height")),Math.round(l[0]*r[0].parent().height()),parseInt(r[1].css("min-width")),Math.round(l[1]*r[1].parent().width())],d=s&&c[1]r&&(r=s),c>l&&(l=c),[r>n.height(),l>n.width()]},B=function(){var t=e(this),o=t.data(a),n=o.opt,i=e("#mCSB_"+o.idx),r=e("#mCSB_"+o.idx+"_container"),l=[e("#mCSB_"+o.idx+"_dragger_vertical"),e("#mCSB_"+o.idx+"_dragger_horizontal")];if(N(t),("x"!==n.axis&&!o.overflowed[0]||"y"===n.axis&&o.overflowed[0])&&(l[0].add(r).css("top",0),V(t,"_resetY")),"y"!==n.axis&&!o.overflowed[1]||"x"===n.axis&&o.overflowed[1]){var s=dx=0;"rtl"===o.langDir&&(s=i.width()-r.outerWidth(!1),dx=Math.abs(s/o.scrollRatio.x)),r.css("left",s),l[1].css("left",dx),V(t,"_resetX")}},T=function(){function t(){r=setTimeout(function(){e.event.special.mousewheel?(clearTimeout(r),R.call(o[0])):t()},100)}var o=e(this),n=o.data(a),i=n.opt;if(!n.bindEvents){if(I.call(this),i.contentTouchScroll&&D.call(this),E.call(this),i.mouseWheel.enable){var r;t()}L.call(this),P.call(this),i.advanced.autoScrollOnFocus&&z.call(this),i.scrollButtons.enable&&H.call(this),i.keyboard.enable&&U.call(this),n.bindEvents=!0}},k=function(){var t=e(this),o=t.data(a),n=o.opt,i=a+"_"+o.idx,r=".mCSB_"+o.idx+"_scrollbar",l=e("#mCSB_"+o.idx+",#mCSB_"+o.idx+"_container,#mCSB_"+o.idx+"_container_wrapper,"+r+" ."+d[12]+",#mCSB_"+o.idx+"_dragger_vertical,#mCSB_"+o.idx+"_dragger_horizontal,"+r+">a"),s=e("#mCSB_"+o.idx+"_container");n.advanced.releaseDraggableSelectors&&l.add(e(n.advanced.releaseDraggableSelectors)),n.advanced.extraDraggableSelectors&&l.add(e(n.advanced.extraDraggableSelectors)),o.bindEvents&&(e(document).add(e(!W()||top.document)).unbind("."+i),l.each(function(){e(this).unbind("."+i)}),clearTimeout(t[0]._focusTimeout),K(t[0],"_focusTimeout"),clearTimeout(o.sequential.step),K(o.sequential,"step"),clearTimeout(s[0].onCompleteTimeout),K(s[0],"onCompleteTimeout"),o.bindEvents=!1)},M=function(t){var o=e(this),n=o.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container_wrapper"),l=r.length?r:e("#mCSB_"+n.idx+"_container"),s=[e("#mCSB_"+n.idx+"_scrollbar_vertical"),e("#mCSB_"+n.idx+"_scrollbar_horizontal")],c=[s[0].find(".mCSB_dragger"),s[1].find(".mCSB_dragger")];"x"!==i.axis&&(n.overflowed[0]&&!t?(s[0].add(c[0]).add(s[0].children("a")).css("display","block"),l.removeClass(d[8]+" "+d[10])):(i.alwaysShowScrollbar?(2!==i.alwaysShowScrollbar&&c[0].css("display","none"),l.removeClass(d[10])):(s[0].css("display","none"),l.addClass(d[10])),l.addClass(d[8]))),"y"!==i.axis&&(n.overflowed[1]&&!t?(s[1].add(c[1]).add(s[1].children("a")).css("display","block"),l.removeClass(d[9]+" "+d[11])):(i.alwaysShowScrollbar?(2!==i.alwaysShowScrollbar&&c[1].css("display","none"),l.removeClass(d[11])):(s[1].css("display","none"),l.addClass(d[11])),l.addClass(d[9]))),n.overflowed[0]||n.overflowed[1]?o.removeClass(d[5]):o.addClass(d[5])},O=function(t){var o=t.type,a=t.target.ownerDocument!==document?[e(frameElement).offset().top,e(frameElement).offset().left]:null,n=W()&&t.target.ownerDocument!==top.document?[e(t.view.frameElement).offset().top,e(t.view.frameElement).offset().left]:[0,0];switch(o){case"pointerdown":case"MSPointerDown":case"pointermove":case"MSPointerMove":case"pointerup":case"MSPointerUp":return a?[t.originalEvent.pageY-a[0]+n[0],t.originalEvent.pageX-a[1]+n[1],!1]:[t.originalEvent.pageY,t.originalEvent.pageX,!1];case"touchstart":case"touchmove":case"touchend":var i=t.originalEvent.touches[0]||t.originalEvent.changedTouches[0],r=t.originalEvent.touches.length||t.originalEvent.changedTouches.length;return t.target.ownerDocument!==document?[i.screenY,i.screenX,r>1]:[i.pageY,i.pageX,r>1];default:return a?[t.pageY-a[0]+n[0],t.pageX-a[1]+n[1],!1]:[t.pageY,t.pageX,!1]}},I=function(){function t(e){var t=m.find("iframe");if(t.length){var o=e?"auto":"none";t.css("pointer-events",o)}}function o(e,t,o,a){if(m[0].idleTimer=u.scrollInertia<233?250:0,n.attr("id")===h[1])var i="x",r=(n[0].offsetLeft-t+a)*d.scrollRatio.x;else var i="y",r=(n[0].offsetTop-e+o)*d.scrollRatio.y;V(l,r.toString(),{dir:i,drag:!0})}var n,i,r,l=e(this),d=l.data(a),u=d.opt,f=a+"_"+d.idx,h=["mCSB_"+d.idx+"_dragger_vertical","mCSB_"+d.idx+"_dragger_horizontal"],m=e("#mCSB_"+d.idx+"_container"),p=e("#"+h[0]+",#"+h[1]),g=u.advanced.releaseDraggableSelectors?p.add(e(u.advanced.releaseDraggableSelectors)):p,v=u.advanced.extraDraggableSelectors?e(!W()||top.document).add(e(u.advanced.extraDraggableSelectors)):e(!W()||top.document);p.bind("mousedown."+f+" touchstart."+f+" pointerdown."+f+" MSPointerDown."+f,function(o){if(o.stopImmediatePropagation(),o.preventDefault(),Z(o)){c=!0,s&&(document.onselectstart=function(){return!1}),t(!1),N(l),n=e(this);var a=n.offset(),d=O(o)[0]-a.top,f=O(o)[1]-a.left,h=n.height()+a.top,m=n.width()+a.left;h>d&&d>0&&m>f&&f>0&&(i=d,r=f),C(n,"active",u.autoExpandScrollbar)}}).bind("touchmove."+f,function(e){e.stopImmediatePropagation(),e.preventDefault();var t=n.offset(),a=O(e)[0]-t.top,l=O(e)[1]-t.left;o(i,r,a,l)}),e(document).add(v).bind("mousemove."+f+" pointermove."+f+" MSPointerMove."+f,function(e){if(n){var t=n.offset(),a=O(e)[0]-t.top,l=O(e)[1]-t.left;if(i===a&&r===l)return;o(i,r,a,l)}}).add(g).bind("mouseup."+f+" touchend."+f+" pointerup."+f+" MSPointerUp."+f,function(e){n&&(C(n,"active",u.autoExpandScrollbar),n=null),c=!1,s&&(document.onselectstart=null),t(!0)})},D=function(){function o(e){if(!$(e)||c||O(e)[2])return void(t=0);t=1,b=0,C=0,d=1,y.removeClass("mCS_touch_action");var o=I.offset();u=O(e)[0]-o.top,f=O(e)[1]-o.left,z=[O(e)[0],O(e)[1]]}function n(e){if($(e)&&!c&&!O(e)[2]&&(T.documentTouchScroll||e.preventDefault(),e.stopImmediatePropagation(),(!C||b)&&d)){g=G();var t=M.offset(),o=O(e)[0]-t.top,a=O(e)[1]-t.left,n="mcsLinearOut";if(E.push(o),R.push(a),z[2]=Math.abs(O(e)[0]-z[0]),z[3]=Math.abs(O(e)[1]-z[1]),B.overflowed[0])var i=D[0].parent().height()-D[0].height(),r=u-o>0&&o-u>-(i*B.scrollRatio.y)&&(2*z[3]0&&a-f>-(l*B.scrollRatio.x)&&(2*z[2]30)){_=1e3/(v-p);var n="mcsEaseOut",i=2.5>_,r=i?[E[E.length-2],R[R.length-2]]:[0,0];x=i?[o-r[0],a-r[1]]:[o-h,a-m];var u=[Math.abs(x[0]),Math.abs(x[1])];_=i?[Math.abs(x[0]/4),Math.abs(x[1]/4)]:[_,_];var f=[Math.abs(I[0].offsetTop)-x[0]*l(u[0]/_[0],_[0]),Math.abs(I[0].offsetLeft)-x[1]*l(u[1]/_[1],_[1])];w="yx"===T.axis?[f[0],f[1]]:"x"===T.axis?[null,f[1]]:[f[0],null],S=[4*u[0]+T.scrollInertia,4*u[1]+T.scrollInertia];var y=parseInt(T.contentTouchScroll)||0;w[0]=u[0]>y?w[0]:0,w[1]=u[1]>y?w[1]:0,B.overflowed[0]&&s(w[0],S[0],n,"y",L,!1),B.overflowed[1]&&s(w[1],S[1],n,"x",L,!1)}}}function l(e,t){var o=[1.5*t,2*t,t/1.5,t/2];return e>90?t>4?o[0]:o[3]:e>60?t>3?o[3]:o[2]:e>30?t>8?o[1]:t>6?o[0]:t>4?t:o[2]:t>8?t:o[3]}function s(e,t,o,a,n,i){e&&V(y,e.toString(),{dur:t,scrollEasing:o,dir:a,overwrite:n,drag:i})}var d,u,f,h,m,p,g,v,x,_,w,S,b,C,y=e(this),B=y.data(a),T=B.opt,k=a+"_"+B.idx,M=e("#mCSB_"+B.idx),I=e("#mCSB_"+B.idx+"_container"),D=[e("#mCSB_"+B.idx+"_dragger_vertical"),e("#mCSB_"+B.idx+"_dragger_horizontal")],E=[],R=[],A=0,L="yx"===T.axis?"none":"all",z=[],P=I.find("iframe"),H=["touchstart."+k+" pointerdown."+k+" MSPointerDown."+k,"touchmove."+k+" pointermove."+k+" MSPointerMove."+k,"touchend."+k+" pointerup."+k+" MSPointerUp."+k],U=void 0!==document.body.style.touchAction;I.bind(H[0],function(e){o(e)}).bind(H[1],function(e){n(e)}),M.bind(H[0],function(e){i(e)}).bind(H[2],function(e){r(e)}),P.length&&P.each(function(){e(this).load(function(){W(this)&&e(this.contentDocument||this.contentWindow.document).bind(H[0],function(e){o(e),i(e)}).bind(H[1],function(e){n(e)}).bind(H[2],function(e){r(e)})})})},E=function(){function o(){return window.getSelection?window.getSelection().toString():document.selection&&"Control"!=document.selection.type?document.selection.createRange().text:0}function n(e,t,o){d.type=o&&i?"stepped":"stepless",d.scrollAmount=10,F(r,e,t,"mcsLinearOut",o?60:null)}var i,r=e(this),l=r.data(a),s=l.opt,d=l.sequential,u=a+"_"+l.idx,f=e("#mCSB_"+l.idx+"_container"),h=f.parent();f.bind("mousedown."+u,function(e){t||i||(i=1,c=!0)}).add(document).bind("mousemove."+u,function(e){if(!t&&i&&o()){var a=f.offset(),r=O(e)[0]-a.top+f[0].offsetTop,c=O(e)[1]-a.left+f[0].offsetLeft;r>0&&r0&&cr?n("on",38):r>h.height()&&n("on",40)),"y"!==s.axis&&l.overflowed[1]&&(0>c?n("on",37):c>h.width()&&n("on",39)))}}).bind("mouseup."+u+" dragend."+u,function(e){t||(i&&(i=0,n("off",null)),c=!1)})},R=function(){function t(t,a){if(N(o),!A(o,t.target)){var r="auto"!==i.mouseWheel.deltaFactor?parseInt(i.mouseWheel.deltaFactor):s&&t.deltaFactor<100?100:t.deltaFactor||100,d=i.scrollInertia;if("x"===i.axis||"x"===i.mouseWheel.axis)var u="x",f=[Math.round(r*n.scrollRatio.x),parseInt(i.mouseWheel.scrollAmount)],h="auto"!==i.mouseWheel.scrollAmount?f[1]:f[0]>=l.width()?.9*l.width():f[0],m=Math.abs(e("#mCSB_"+n.idx+"_container")[0].offsetLeft),p=c[1][0].offsetLeft,g=c[1].parent().width()-c[1].width(),v=t.deltaX||t.deltaY||a;else var u="y",f=[Math.round(r*n.scrollRatio.y),parseInt(i.mouseWheel.scrollAmount)],h="auto"!==i.mouseWheel.scrollAmount?f[1]:f[0]>=l.height()?.9*l.height():f[0],m=Math.abs(e("#mCSB_"+n.idx+"_container")[0].offsetTop),p=c[0][0].offsetTop,g=c[0].parent().height()-c[0].height(),v=t.deltaY||a;"y"===u&&!n.overflowed[0]||"x"===u&&!n.overflowed[1]||((i.mouseWheel.invert||t.webkitDirectionInvertedFromDevice)&&(v=-v),i.mouseWheel.normalizeDelta&&(v=0>v?-1:1),(v>0&&0!==p||0>v&&p!==g||i.mouseWheel.preventDefault)&&(t.stopImmediatePropagation(),t.preventDefault()),t.deltaFactor<2&&!i.mouseWheel.normalizeDelta&&(h=t.deltaFactor,d=17),V(o,(m-v*h).toString(),{dir:u,dur:d}))}}if(e(this).data(a)){var o=e(this),n=o.data(a),i=n.opt,r=a+"_"+n.idx,l=e("#mCSB_"+n.idx),c=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")],d=e("#mCSB_"+n.idx+"_container").find("iframe");d.length&&d.each(function(){e(this).load(function(){W(this)&&e(this.contentDocument||this.contentWindow.document).bind("mousewheel."+r,function(e,o){t(e,o)})})}),l.bind("mousewheel."+r,function(e,o){t(e,o)})}},W=function(e){var t=null;if(e){try{var o=e.contentDocument||e.contentWindow.document;t=o.body.innerHTML}catch(a){}return null!==t}try{var o=top.document;t=o.body.innerHTML}catch(a){}return null!==t},A=function(t,o){var n=o.nodeName.toLowerCase(),i=t.data(a).opt.mouseWheel.disableOver,r=["select","textarea"];return e.inArray(n,i)>-1&&!(e.inArray(n,r)>-1&&!e(o).is(":focus"))},L=function(){var t,o=e(this),n=o.data(a),i=a+"_"+n.idx,r=e("#mCSB_"+n.idx+"_container"),l=r.parent(),s=e(".mCSB_"+n.idx+"_scrollbar ."+d[12]);s.bind("mousedown."+i+" touchstart."+i+" pointerdown."+i+" MSPointerDown."+i,function(o){c=!0,e(o.target).hasClass("mCSB_dragger")||(t=1)}).bind("touchend."+i+" pointerup."+i+" MSPointerUp."+i,function(e){c=!1}).bind("click."+i,function(a){if(t&&(t=0,e(a.target).hasClass(d[12])||e(a.target).hasClass("mCSB_draggerRail"))){N(o);var i=e(this),s=i.find(".mCSB_dragger");if(i.parent(".mCSB_scrollTools_horizontal").length>0){if(!n.overflowed[1])return;var c="x",u=a.pageX>s.offset().left?-1:1,f=Math.abs(r[0].offsetLeft)-.9*u*l.width()}else{if(!n.overflowed[0])return;var c="y",u=a.pageY>s.offset().top?-1:1,f=Math.abs(r[0].offsetTop)-.9*u*l.height()}V(o,f.toString(),{dir:c,scrollEasing:"mcsEaseInOut"})}})},z=function(){var t=e(this),o=t.data(a),n=o.opt,i=a+"_"+o.idx,r=e("#mCSB_"+o.idx+"_container"),l=r.parent();r.bind("focusin."+i,function(o){var a=e(document.activeElement),i=r.find(".mCustomScrollBox").length,s=0;a.is(n.advanced.autoScrollOnFocus)&&(N(t),clearTimeout(t[0]._focusTimeout),t[0]._focusTimer=i?(s+17)*i:0,t[0]._focusTimeout=setTimeout(function(){var e=[te(a)[0],te(a)[1]],o=[r[0].offsetTop,r[0].offsetLeft],i=[o[0]+e[0]>=0&&o[0]+e[0]=0&&o[0]+e[1]a");s.bind("mousedown."+r+" touchstart."+r+" pointerdown."+r+" MSPointerDown."+r+" mouseup."+r+" touchend."+r+" pointerup."+r+" MSPointerUp."+r+" mouseout."+r+" pointerout."+r+" MSPointerOut."+r+" click."+r,function(a){function r(e,o){i.scrollAmount=n.scrollButtons.scrollAmount,F(t,e,o)}if(a.preventDefault(),Z(a)){var l=e(this).attr("class");switch(i.type=n.scrollButtons.scrollType,a.type){case"mousedown":case"touchstart":case"pointerdown":case"MSPointerDown":if("stepped"===i.type)return;c=!0,o.tweenRunning=!1,r("on",l);break;case"mouseup":case"touchend":case"pointerup":case"MSPointerUp":case"mouseout":case"pointerout":case"MSPointerOut":if("stepped"===i.type)return;c=!1,i.dir&&r("off",l);break;case"click":if("stepped"!==i.type||o.tweenRunning)return;r("on",l)}}})},U=function(){function t(t){function a(e,t){r.type=i.keyboard.scrollType,r.scrollAmount=i.keyboard.scrollAmount,"stepped"===r.type&&n.tweenRunning||F(o,e,t)}switch(t.type){case"blur":n.tweenRunning&&r.dir&&a("off",null);break;case"keydown":case"keyup":var l=t.keyCode?t.keyCode:t.which,s="on";if("x"!==i.axis&&(38===l||40===l)||"y"!==i.axis&&(37===l||39===l)){if((38===l||40===l)&&!n.overflowed[0]||(37===l||39===l)&&!n.overflowed[1])return;"keyup"===t.type&&(s="off"),e(document.activeElement).is(u)||(t.preventDefault(),t.stopImmediatePropagation(),a(s,l))}else if(33===l||34===l){if((n.overflowed[0]||n.overflowed[1])&&(t.preventDefault(),t.stopImmediatePropagation()),"keyup"===t.type){N(o);var f=34===l?-1:1;if("x"===i.axis||"yx"===i.axis&&n.overflowed[1]&&!n.overflowed[0])var h="x",m=Math.abs(c[0].offsetLeft)-.9*f*d.width();else var h="y",m=Math.abs(c[0].offsetTop)-.9*f*d.height();V(o,m.toString(),{dir:h,scrollEasing:"mcsEaseInOut"})}}else if((35===l||36===l)&&!e(document.activeElement).is(u)&&((n.overflowed[0]||n.overflowed[1])&&(t.preventDefault(),t.stopImmediatePropagation()),"keyup"===t.type)){if("x"===i.axis||"yx"===i.axis&&n.overflowed[1]&&!n.overflowed[0])var h="x",m=35===l?Math.abs(d.width()-c.outerWidth(!1)):0;else var h="y",m=35===l?Math.abs(d.height()-c.outerHeight(!1)):0;V(o,m.toString(),{dir:h,scrollEasing:"mcsEaseInOut"})}}}var o=e(this),n=o.data(a),i=n.opt,r=n.sequential,l=a+"_"+n.idx,s=e("#mCSB_"+n.idx),c=e("#mCSB_"+n.idx+"_container"),d=c.parent(),u="input,textarea,select,datalist,keygen,[contenteditable='true']",f=c.find("iframe"),h=["blur."+l+" keydown."+l+" keyup."+l];f.length&&f.each(function(){e(this).load(function(){W(this)&&e(this.contentDocument||this.contentWindow.document).bind(h[0],function(e){t(e)})})}),s.attr("tabindex","0").bind(h[0],function(e){t(e)})},F=function(t,o,n,i,r){function l(e){u.snapAmount&&(f.scrollAmount=u.snapAmount instanceof Array?"x"===f.dir[0]?u.snapAmount[1]:u.snapAmount[0]:u.snapAmount);var o="stepped"!==f.type,a=r?r:e?o?p/1.5:g:1e3/60,n=e?o?7.5:40:2.5,s=[Math.abs(h[0].offsetTop),Math.abs(h[0].offsetLeft)],d=[c.scrollRatio.y>10?10:c.scrollRatio.y,c.scrollRatio.x>10?10:c.scrollRatio.x],m="x"===f.dir[0]?s[1]+f.dir[1]*d[1]*n:s[0]+f.dir[1]*d[0]*n,v="x"===f.dir[0]?s[1]+f.dir[1]*parseInt(f.scrollAmount):s[0]+f.dir[1]*parseInt(f.scrollAmount),x="auto"!==f.scrollAmount?v:m,_=i?i:e?o?"mcsLinearOut":"mcsEaseInOut":"mcsLinear",w=e?!0:!1;return e&&17>a&&(x="x"===f.dir[0]?s[1]:s[0]),V(t,x.toString(),{dir:f.dir[0],scrollEasing:_,dur:a,onComplete:w}),e?void(f.dir=!1):(clearTimeout(f.step),void(f.step=setTimeout(function(){l()},a)))}function s(){clearTimeout(f.step),K(f,"step"),N(t)}var c=t.data(a),u=c.opt,f=c.sequential,h=e("#mCSB_"+c.idx+"_container"),m="stepped"===f.type?!0:!1,p=u.scrollInertia<26?26:u.scrollInertia,g=u.scrollInertia<1?17:u.scrollInertia;switch(o){case"on":if(f.dir=[n===d[16]||n===d[15]||39===n||37===n?"x":"y",n===d[13]||n===d[15]||38===n||37===n?-1:1],N(t),ee(n)&&"stepped"===f.type)return;l(m);break;case"off":s(),(m||c.tweenRunning&&f.dir)&&l(!0)}},q=function(t){var o=e(this).data(a).opt,n=[];return"function"==typeof t&&(t=t()),t instanceof Array?n=t.length>1?[t[0],t[1]]:"x"===o.axis?[null,t[0]]:[t[0],null]:(n[0]=t.y?t.y:t.x||"x"===o.axis?null:t,n[1]=t.x?t.x:t.y||"y"===o.axis?null:t),"function"==typeof n[0]&&(n[0]=n[0]()),"function"==typeof n[1]&&(n[1]=n[1]()),n},Y=function(t,o){if(null!=t&&"undefined"!=typeof t){var n=e(this),i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx+"_container"),s=l.parent(),c=typeof t;o||(o="x"===r.axis?"x":"y");var d="x"===o?l.outerWidth(!1):l.outerHeight(!1),f="x"===o?l[0].offsetLeft:l[0].offsetTop,h="x"===o?"left":"top";switch(c){case"function":return t();case"object":var m=t.jquery?t:e(t);if(!m.length)return;return"x"===o?te(m)[1]:te(m)[0];case"string":case"number":if(ee(t))return Math.abs(t);if(-1!==t.indexOf("%"))return Math.abs(d*parseInt(t)/100);if(-1!==t.indexOf("-="))return Math.abs(f-parseInt(t.split("-=")[1]));if(-1!==t.indexOf("+=")){var p=f+parseInt(t.split("+=")[1]);return p>=0?0:Math.abs(p)}if(-1!==t.indexOf("px")&&ee(t.split("px")[0]))return Math.abs(t.split("px")[0]);if("top"===t||"left"===t)return 0;if("bottom"===t)return Math.abs(s.height()-l.outerHeight(!1));if("right"===t)return Math.abs(s.width()-l.outerWidth(!1));if("first"===t||"last"===t){var m=l.find(":"+t);return"x"===o?te(m)[1]:te(m)[0]}return e(t).length?"x"===o?te(e(t))[1]:te(e(t))[0]:(l.css(h,t),void u.update.call(null,n[0]))}}},X=function(t){function o(){return clearTimeout(f[0].autoUpdate),0===l.parents("html").length?void(l=null):void(f[0].autoUpdate=setTimeout(function(){return c.advanced.updateOnSelectorChange&&(s.poll.change.n=i(),s.poll.change.n!==s.poll.change.o)?(s.poll.change.o=s.poll.change.n,void r(3)):c.advanced.updateOnContentResize&&(s.poll.size.n=l[0].scrollHeight+l[0].scrollWidth+f[0].offsetHeight+l[0].offsetHeight+l[0].offsetWidth,s.poll.size.n!==s.poll.size.o)?(s.poll.size.o=s.poll.size.n,void r(1)):!c.advanced.updateOnImageLoad||"auto"===c.advanced.updateOnImageLoad&&"y"===c.axis||(s.poll.img.n=f.find("img").length,s.poll.img.n===s.poll.img.o)?void((c.advanced.updateOnSelectorChange||c.advanced.updateOnContentResize||c.advanced.updateOnImageLoad)&&o()):(s.poll.img.o=s.poll.img.n,void f.find("img").each(function(){n(this)}))},c.advanced.autoUpdateTimeout))}function n(t){function o(e,t){return function(){return t.apply(e,arguments)}}function a(){this.onload=null,e(t).addClass(d[2]),r(2)}if(e(t).hasClass(d[2]))return void r();var n=new Image;n.onload=o(n,a),n.src=t.src}function i(){c.advanced.updateOnSelectorChange===!0&&(c.advanced.updateOnSelectorChange="*");var e=0,t=f.find(c.advanced.updateOnSelectorChange); 5 | 6 | return c.advanced.updateOnSelectorChange&&t.length>0&&t.each(function(){e+=this.offsetHeight+this.offsetWidth}),e}function r(e){clearTimeout(f[0].autoUpdate),u.update.call(null,l[0],e)}var l=e(this),s=l.data(a),c=s.opt,f=e("#mCSB_"+s.idx+"_container");return t?(clearTimeout(f[0].autoUpdate),void K(f[0],"autoUpdate")):void o()},j=function(e,t,o){return Math.round(e/t)*t-o},N=function(t){var o=t.data(a),n=e("#mCSB_"+o.idx+"_container,#mCSB_"+o.idx+"_container_wrapper,#mCSB_"+o.idx+"_dragger_vertical,#mCSB_"+o.idx+"_dragger_horizontal");n.each(function(){J.call(this)})},V=function(t,o,n){function i(e){return s&&c.callbacks[e]&&"function"==typeof c.callbacks[e]}function r(){return[c.callbacks.alwaysTriggerOffsets||w>=S[0]+y,c.callbacks.alwaysTriggerOffsets||-B>=w]}function l(){var e=[h[0].offsetTop,h[0].offsetLeft],o=[x[0].offsetTop,x[0].offsetLeft],a=[h.outerHeight(!1),h.outerWidth(!1)],i=[f.height(),f.width()];t[0].mcs={content:h,top:e[0],left:e[1],draggerTop:o[0],draggerLeft:o[1],topPct:Math.round(100*Math.abs(e[0])/(Math.abs(a[0])-i[0])),leftPct:Math.round(100*Math.abs(e[1])/(Math.abs(a[1])-i[1])),direction:n.dir}}var s=t.data(a),c=s.opt,d={trigger:"internal",dir:"y",scrollEasing:"mcsEaseOut",drag:!1,dur:c.scrollInertia,overwrite:"all",callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},n=e.extend(d,n),u=[n.dur,n.drag?0:n.dur],f=e("#mCSB_"+s.idx),h=e("#mCSB_"+s.idx+"_container"),m=h.parent(),p=c.callbacks.onTotalScrollOffset?q.call(t,c.callbacks.onTotalScrollOffset):[0,0],g=c.callbacks.onTotalScrollBackOffset?q.call(t,c.callbacks.onTotalScrollBackOffset):[0,0];if(s.trigger=n.trigger,(0!==m.scrollTop()||0!==m.scrollLeft())&&(e(".mCSB_"+s.idx+"_scrollbar").css("visibility","visible"),m.scrollTop(0).scrollLeft(0)),"_resetY"!==o||s.contentReset.y||(i("onOverflowYNone")&&c.callbacks.onOverflowYNone.call(t[0]),s.contentReset.y=1),"_resetX"!==o||s.contentReset.x||(i("onOverflowXNone")&&c.callbacks.onOverflowXNone.call(t[0]),s.contentReset.x=1),"_resetY"!==o&&"_resetX"!==o){if(!s.contentReset.y&&t[0].mcs||!s.overflowed[0]||(i("onOverflowY")&&c.callbacks.onOverflowY.call(t[0]),s.contentReset.x=null),!s.contentReset.x&&t[0].mcs||!s.overflowed[1]||(i("onOverflowX")&&c.callbacks.onOverflowX.call(t[0]),s.contentReset.x=null),c.snapAmount){var v=c.snapAmount instanceof Array?"x"===n.dir?c.snapAmount[1]:c.snapAmount[0]:c.snapAmount;o=j(o,v,c.snapOffset)}switch(n.dir){case"x":var x=e("#mCSB_"+s.idx+"_dragger_horizontal"),_="left",w=h[0].offsetLeft,S=[f.width()-h.outerWidth(!1),x.parent().width()-x.width()],b=[o,0===o?0:o/s.scrollRatio.x],y=p[1],B=g[1],T=y>0?y/s.scrollRatio.x:0,k=B>0?B/s.scrollRatio.x:0;break;case"y":var x=e("#mCSB_"+s.idx+"_dragger_vertical"),_="top",w=h[0].offsetTop,S=[f.height()-h.outerHeight(!1),x.parent().height()-x.height()],b=[o,0===o?0:o/s.scrollRatio.y],y=p[0],B=g[0],T=y>0?y/s.scrollRatio.y:0,k=B>0?B/s.scrollRatio.y:0}b[1]<0||0===b[0]&&0===b[1]?b=[0,0]:b[1]>=S[1]?b=[S[0],S[1]]:b[0]=-b[0],t[0].mcs||(l(),i("onInit")&&c.callbacks.onInit.call(t[0])),clearTimeout(h[0].onCompleteTimeout),Q(x[0],_,Math.round(b[1]),u[1],n.scrollEasing),(s.tweenRunning||!(0===w&&b[0]>=0||w===S[0]&&b[0]<=S[0]))&&Q(h[0],_,Math.round(b[0]),u[0],n.scrollEasing,n.overwrite,{onStart:function(){n.callbacks&&n.onStart&&!s.tweenRunning&&(i("onScrollStart")&&(l(),c.callbacks.onScrollStart.call(t[0])),s.tweenRunning=!0,C(x),s.cbOffsets=r())},onUpdate:function(){n.callbacks&&n.onUpdate&&i("whileScrolling")&&(l(),c.callbacks.whileScrolling.call(t[0]))},onComplete:function(){if(n.callbacks&&n.onComplete){"yx"===c.axis&&clearTimeout(h[0].onCompleteTimeout);var e=h[0].idleTimer||0;h[0].onCompleteTimeout=setTimeout(function(){i("onScroll")&&(l(),c.callbacks.onScroll.call(t[0])),i("onTotalScroll")&&b[1]>=S[1]-T&&s.cbOffsets[0]&&(l(),c.callbacks.onTotalScroll.call(t[0])),i("onTotalScrollBack")&&b[1]<=k&&s.cbOffsets[1]&&(l(),c.callbacks.onTotalScrollBack.call(t[0])),s.tweenRunning=!1,h[0].idleTimer=0,C(x,"hide")},e)}}})}},Q=function(e,t,o,a,n,i,r){function l(){S.stop||(x||m.call(),x=G()-v,s(),x>=S.time&&(S.time=x>S.time?x+f-(x-S.time):x+f-1,S.time0?(S.currVal=u(S.time,_,b,a,n),w[t]=Math.round(S.currVal)+"px"):w[t]=o+"px",p.call()}function c(){f=1e3/60,S.time=x+f,h=window.requestAnimationFrame?window.requestAnimationFrame:function(e){return s(),setTimeout(e,.01)},S.id=h(l)}function d(){null!=S.id&&(window.requestAnimationFrame?window.cancelAnimationFrame(S.id):clearTimeout(S.id),S.id=null)}function u(e,t,o,a,n){switch(n){case"linear":case"mcsLinear":return o*e/a+t;case"mcsLinearOut":return e/=a,e--,o*Math.sqrt(1-e*e)+t;case"easeInOutSmooth":return e/=a/2,1>e?o/2*e*e+t:(e--,-o/2*(e*(e-2)-1)+t);case"easeInOutStrong":return e/=a/2,1>e?o/2*Math.pow(2,10*(e-1))+t:(e--,o/2*(-Math.pow(2,-10*e)+2)+t);case"easeInOut":case"mcsEaseInOut":return e/=a/2,1>e?o/2*e*e*e+t:(e-=2,o/2*(e*e*e+2)+t);case"easeOutSmooth":return e/=a,e--,-o*(e*e*e*e-1)+t;case"easeOutStrong":return o*(-Math.pow(2,-10*e/a)+1)+t;case"easeOut":case"mcsEaseOut":default:var i=(e/=a)*e,r=i*e;return t+o*(.499999999999997*r*i+-2.5*i*i+5.5*r+-6.5*i+4*e)}}e._mTween||(e._mTween={top:{},left:{}});var f,h,r=r||{},m=r.onStart||function(){},p=r.onUpdate||function(){},g=r.onComplete||function(){},v=G(),x=0,_=e.offsetTop,w=e.style,S=e._mTween[t];"left"===t&&(_=e.offsetLeft);var b=o-_;S.stop=0,"none"!==i&&d(),c()},G=function(){return window.performance&&window.performance.now?window.performance.now():window.performance&&window.performance.webkitNow?window.performance.webkitNow():Date.now?Date.now():(new Date).getTime()},J=function(){var e=this;e._mTween||(e._mTween={top:{},left:{}});for(var t=["top","left"],o=0;o=0&&a[0]+te(n)[0]=0&&a[1]+te(n)[1].mCSB_container{margin-right:30px}.mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden{margin-right:0}.mCS-dir-rtl>.mCSB_inside>.mCSB_container{margin-right:0;margin-left:30px}.mCS-dir-rtl>.mCSB_inside>.mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden{margin-left:0}.mCSB_scrollTools{position:absolute;width:16px;height:auto;left:auto;top:0;right:0;bottom:0;opacity:.75;filter:"alpha(opacity=75)";-ms-filter:"alpha(opacity=75)"}.mCSB_outside+.mCSB_scrollTools{right:-26px}.mCS-dir-rtl>.mCSB_inside>.mCSB_scrollTools,.mCS-dir-rtl>.mCSB_outside+.mCSB_scrollTools{right:auto;left:0}.mCS-dir-rtl>.mCSB_outside+.mCSB_scrollTools{left:-26px}.mCSB_scrollTools .mCSB_draggerContainer{position:absolute;top:0;left:0;bottom:0;right:0;height:auto}.mCSB_scrollTools a+.mCSB_draggerContainer{margin:20px 0}.mCSB_scrollTools .mCSB_draggerRail{width:2px;height:100%;margin:0 auto;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px}.mCSB_scrollTools .mCSB_dragger{cursor:pointer;width:100%;height:30px;z-index:1}.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{position:relative;width:4px;height:100%;margin:0 auto;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px;text-align:center}.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{width:12px}.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{width:8px}.mCSB_scrollTools .mCSB_buttonDown,.mCSB_scrollTools .mCSB_buttonUp{display:block;position:absolute;height:20px;width:100%;overflow:hidden;margin:0 auto;cursor:pointer}.mCSB_scrollTools .mCSB_buttonDown{bottom:0}.mCSB_horizontal.mCSB_inside>.mCSB_container{margin-right:0;margin-bottom:30px}.mCSB_horizontal.mCSB_outside>.mCSB_container{min-height:100%}.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar_x.mCS_x_hidden{margin-bottom:0}.mCSB_scrollTools.mCSB_scrollTools_horizontal{width:auto;height:16px;top:auto;right:0;bottom:0;left:0}.mCustomScrollBox+.mCSB_scrollTools+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox+.mCSB_scrollTools.mCSB_scrollTools_horizontal{bottom:-26px}.mCSB_scrollTools.mCSB_scrollTools_horizontal a+.mCSB_draggerContainer{margin:0 20px}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:2px;margin:7px 0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger{width:30px;height:100%;left:0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:4px;margin:6px auto}.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{height:12px;margin:2px auto}.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{height:8px;margin:4px 0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft,.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight{display:block;position:absolute;width:20px;height:100%;overflow:hidden;margin:0 auto;cursor:pointer}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft{left:0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight{right:0}.mCSB_container_wrapper{position:absolute;height:auto;width:auto;overflow:hidden;top:0;left:0;right:0;bottom:0;margin-right:30px;margin-bottom:30px}.mCSB_container_wrapper>.mCSB_container{padding-right:30px;padding-bottom:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.mCSB_vertical_horizontal>.mCSB_scrollTools.mCSB_scrollTools_vertical{bottom:20px}.mCSB_vertical_horizontal>.mCSB_scrollTools.mCSB_scrollTools_horizontal{right:20px}.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden+.mCSB_scrollTools.mCSB_scrollTools_vertical{bottom:0}.mCS-dir-rtl>.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden+.mCSB_scrollTools~.mCSB_scrollTools.mCSB_scrollTools_horizontal{right:0}.mCS-dir-rtl>.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_scrollTools.mCSB_scrollTools_horizontal{left:20px}.mCS-dir-rtl>.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden+.mCSB_scrollTools~.mCSB_scrollTools.mCSB_scrollTools_horizontal{left:0}.mCS-dir-rtl>.mCSB_inside>.mCSB_container_wrapper{margin-right:0;margin-left:30px}.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden>.mCSB_container{padding-right:0}.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden>.mCSB_container{padding-bottom:0}.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden{margin-right:0;margin-left:0}.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden{margin-bottom:0}.mCSB_scrollTools,.mCSB_scrollTools .mCSB_buttonDown,.mCSB_scrollTools .mCSB_buttonLeft,.mCSB_scrollTools .mCSB_buttonRight,.mCSB_scrollTools .mCSB_buttonUp,.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{-webkit-transition:opacity .2s ease-in-out,background-color .2s ease-in-out;-moz-transition:opacity .2s ease-in-out,background-color .2s ease-in-out;-o-transition:opacity .2s ease-in-out,background-color .2s ease-in-out;transition:opacity .2s ease-in-out,background-color .2s ease-in-out}.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail,.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar{-webkit-transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out;-moz-transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out;-o-transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out;transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out}.mCS-autoHide>.mCustomScrollBox>.mCSB_scrollTools,.mCS-autoHide>.mCustomScrollBox~.mCSB_scrollTools{opacity:0;filter:"alpha(opacity=0)";-ms-filter:"alpha(opacity=0)"}.mCS-autoHide:hover>.mCustomScrollBox>.mCSB_scrollTools,.mCS-autoHide:hover>.mCustomScrollBox~.mCSB_scrollTools,.mCustomScrollBox:hover>.mCSB_scrollTools,.mCustomScrollBox:hover~.mCSB_scrollTools,.mCustomScrollbar>.mCustomScrollBox>.mCSB_scrollTools.mCSB_scrollTools_onDrag,.mCustomScrollbar>.mCustomScrollBox~.mCSB_scrollTools.mCSB_scrollTools_onDrag{opacity:1;filter:"alpha(opacity=100)";-ms-filter:"alpha(opacity=100)"}.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.4);filter:"alpha(opacity=40)";-ms-filter:"alpha(opacity=40)"}.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.75);filter:"alpha(opacity=75)";-ms-filter:"alpha(opacity=75)"}.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85);filter:"alpha(opacity=85)";-ms-filter:"alpha(opacity=85)"}.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9);filter:"alpha(opacity=90)";-ms-filter:"alpha(opacity=90)"}.mCSB_scrollTools .mCSB_buttonDown,.mCSB_scrollTools .mCSB_buttonLeft,.mCSB_scrollTools .mCSB_buttonRight,.mCSB_scrollTools .mCSB_buttonUp{background-image:url(mCSB_buttons.png);background-repeat:no-repeat;opacity:.4;filter:"alpha(opacity=40)";-ms-filter:"alpha(opacity=40)"}.mCSB_scrollTools .mCSB_buttonUp{background-position:0 0}.mCSB_scrollTools .mCSB_buttonDown{background-position:0 -20px}.mCSB_scrollTools .mCSB_buttonLeft{background-position:0 -40px}.mCSB_scrollTools .mCSB_buttonRight{background-position:0 -56px}.mCSB_scrollTools .mCSB_buttonDown:hover,.mCSB_scrollTools .mCSB_buttonLeft:hover,.mCSB_scrollTools .mCSB_buttonRight:hover,.mCSB_scrollTools .mCSB_buttonUp:hover{opacity:.75;filter:"alpha(opacity=75)";-ms-filter:"alpha(opacity=75)"}.mCSB_scrollTools .mCSB_buttonDown:active,.mCSB_scrollTools .mCSB_buttonLeft:active,.mCSB_scrollTools .mCSB_buttonRight:active,.mCSB_scrollTools .mCSB_buttonUp:active{opacity:.9;filter:"alpha(opacity=90)";-ms-filter:"alpha(opacity=90)"}.mCS-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.15)}.mCS-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:rgba(0,0,0,.85)}.mCS-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:rgba(0,0,0,.9)}.mCS-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-80px 0}.mCS-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-80px -20px}.mCS-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-80px -40px}.mCS-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-80px -56px}.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail,.mCS-light-2.mCSB_scrollTools .mCSB_draggerRail{width:4px;background-color:#fff;background-color:rgba(255,255,255,.1);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:4px;background-color:#fff;background-color:rgba(255,255,255,.75);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:4px;margin:6px auto}.mCS-light-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85)}.mCS-light-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-light-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9)}.mCS-light-2.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px 0}.mCS-light-2.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -20px}.mCS-light-2.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -40px}.mCS-light-2.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -56px}.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px 0}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -20px}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -40px}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -56px}.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail,.mCS-light-thick.mCSB_scrollTools .mCSB_draggerRail{width:4px;background-color:#fff;background-color:rgba(255,255,255,.1);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:6px;background-color:#fff;background-color:rgba(255,255,255,.75);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:4px;margin:6px 0}.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:6px;margin:5px auto}.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85)}.mCS-light-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9)}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonUp{background-position:-16px 0}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonDown{background-position:-16px -20px}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonLeft{background-position:-20px -40px}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonRight{background-position:-20px -56px}.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonUp{background-position:-96px 0}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonDown{background-position:-96px -20px}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonLeft{background-position:-100px -40px}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonRight{background-position:-100px -56px}.mCS-light-thin.mCSB_scrollTools .mCSB_draggerRail{background-color:#fff;background-color:rgba(255,255,255,.1)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:2px}.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%}.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:2px;margin:7px auto}.mCS-dark-thin.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.15)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonUp{background-position:-80px 0}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonDown{background-position:-80px -20px}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonLeft{background-position:-80px -40px}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonRight{background-position:-80px -56px}.mCS-rounded.mCSB_scrollTools .mCSB_draggerRail{background-color:#fff;background-color:rgba(255,255,255,.15)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger,.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger,.mCS-rounded.mCSB_scrollTools .mCSB_dragger{height:14px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:14px;margin:0 1px}.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger{width:14px}.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{height:14px;margin:1px 0}.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{width:16px;height:16px;margin:-1px 0}.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{width:4px}.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{height:16px;width:16px;margin:0 -1px}.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{height:4px;margin:6px 0}.mCS-rounded.mCSB_scrollTools .mCSB_buttonUp{background-position:0 -72px}.mCS-rounded.mCSB_scrollTools .mCSB_buttonDown{background-position:0 -92px}.mCS-rounded.mCSB_scrollTools .mCSB_buttonLeft{background-position:0 -112px}.mCS-rounded.mCSB_scrollTools .mCSB_buttonRight{background-position:0 -128px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.15)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-80px -72px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-80px -92px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-80px -112px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-80px -128px}.mCS-rounded-dots-dark.mCSB_scrollTools_vertical .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools_vertical .mCSB_draggerRail{width:4px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail{background-color:transparent;background-position:center}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAANElEQVQYV2NkIAAYiVbw//9/Y6DiM1ANJoyMjGdBbLgJQAX/kU0DKgDLkaQAvxW4HEvQFwCRcxIJK1XznAAAAABJRU5ErkJggg==);background-repeat:repeat-y;opacity:.3;filter:"alpha(opacity=30)";-ms-filter:"alpha(opacity=30)"}.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail{height:4px;margin:6px 0;background-repeat:repeat-x}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonUp{background-position:-16px -72px}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonDown{background-position:-16px -92px}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonLeft{background-position:-20px -112px}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonRight{background-position:-20px -128px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAALElEQVQYV2NkIAAYSVFgDFR8BqrBBEifBbGRTfiPZhpYjiQFBK3A6l6CvgAAE9kGCd1mvgEAAAAASUVORK5CYII=)}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-96px -72px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-96px -92px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-100px -112px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-100px -128px}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-repeat:repeat-y;background-image:-moz-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,.5)),color-stop(100%,rgba(255,255,255,0)));background-image:-webkit-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-o-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-ms-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:linear-gradient(to right,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%)}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{background-repeat:repeat-x;background-image:-moz-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,rgba(255,255,255,.5)),color-stop(100%,rgba(255,255,255,0)));background-image:-webkit-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-o-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-ms-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:linear-gradient(to bottom,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%)}.mCS-3d-dark.mCSB_scrollTools_vertical .mCSB_dragger,.mCS-3d.mCSB_scrollTools_vertical .mCSB_dragger{height:70px}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger{width:70px}.mCS-3d-dark.mCSB_scrollTools,.mCS-3d.mCSB_scrollTools{opacity:1;filter:"alpha(opacity=30)";-ms-filter:"alpha(opacity=30)"}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_draggerRail{-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px}.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-3d.mCSB_scrollTools .mCSB_draggerRail{width:8px;background-color:#000;background-color:rgba(0,0,0,.2);box-shadow:inset 1px 0 1px rgba(0,0,0,.5),inset -1px 0 1px rgba(255,255,255,.2)}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#555}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:8px}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:8px;margin:4px 0;box-shadow:inset 0 1px 1px rgba(0,0,0,.5),inset 0 -1px 1px rgba(255,255,255,.2)}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:8px;margin:4px auto}.mCS-3d.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-3d.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-3d.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-3d.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1);box-shadow:inset 1px 0 1px rgba(0,0,0,.1)}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{box-shadow:inset 0 1px 1px rgba(0,0,0,.1)}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCS-3d-thick-dark.mCSB_scrollTools,.mCS-3d-thick.mCSB_scrollTools{opacity:1;filter:"alpha(opacity=30)";-ms-filter:"alpha(opacity=30)"}.mCS-3d-thick-dark.mCSB_scrollTools,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer,.mCS-3d-thick.mCSB_scrollTools,.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer{-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mCSB_inside+.mCS-3d-thick-dark.mCSB_scrollTools_vertical,.mCSB_inside+.mCS-3d-thick.mCSB_scrollTools_vertical{right:1px}.mCS-3d-thick-dark.mCSB_scrollTools_vertical,.mCS-3d-thick.mCSB_scrollTools_vertical{box-shadow:inset 1px 0 1px rgba(0,0,0,.1),inset 0 0 14px rgba(0,0,0,.5)}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal,.mCS-3d-thick.mCSB_scrollTools_horizontal{bottom:1px;box-shadow:inset 0 1px 1px rgba(0,0,0,.1),inset 0 0 14px rgba(0,0,0,.5)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;box-shadow:inset 1px 0 0 rgba(255,255,255,.4);width:12px;margin:2px;position:absolute;height:auto;top:0;bottom:0;left:0;right:0}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 0 1px 0 rgba(255,255,255,.4);height:12px;width:auto}.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#555}.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer{background-color:#000;background-color:rgba(0,0,0,.05);box-shadow:inset 1px 1px 16px rgba(0,0,0,.1)}.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-3d-thick-dark.mCSB_scrollTools{box-shadow:inset 0 0 14px rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal{box-shadow:inset 0 1px 1px rgba(0,0,0,.1),inset 0 0 14px rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 1px 0 0 rgba(255,255,255,.4),inset -1px 0 0 rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 0 1px 0 rgba(255,255,255,.4),inset 0 -1px 0 rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#777}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer{background-color:#fff;background-color:rgba(0,0,0,.05);box-shadow:inset 1px 1px 16px rgba(0,0,0,.1)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-minimal-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-minimal.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCSB_outside+.mCS-minimal-dark.mCSB_scrollTools_vertical,.mCSB_outside+.mCS-minimal.mCSB_scrollTools_vertical{right:0;margin:12px 0}.mCustomScrollBox.mCS-minimal+.mCSB_scrollTools+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox.mCS-minimal+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox.mCS-minimal-dark+.mCSB_scrollTools+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox.mCS-minimal-dark+.mCSB_scrollTools.mCSB_scrollTools_horizontal{bottom:0;margin:0 12px}.mCS-dir-rtl>.mCSB_outside+.mCS-minimal-dark.mCSB_scrollTools_vertical,.mCS-dir-rtl>.mCSB_outside+.mCS-minimal.mCSB_scrollTools_vertical{left:0;right:auto}.mCS-minimal-dark.mCSB_scrollTools_vertical .mCSB_dragger,.mCS-minimal.mCSB_scrollTools_vertical .mCSB_dragger{height:50px}.mCS-minimal-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-minimal.mCSB_scrollTools_horizontal .mCSB_dragger{width:50px}.mCS-minimal.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.2);filter:"alpha(opacity=20)";-ms-filter:"alpha(opacity=20)"}.mCS-minimal.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-minimal.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.5);filter:"alpha(opacity=50)";-ms-filter:"alpha(opacity=50)"}.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.2);filter:"alpha(opacity=20)";-ms-filter:"alpha(opacity=20)"}.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.5);filter:"alpha(opacity=50)";-ms-filter:"alpha(opacity=50)"}.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools .mCSB_draggerRail{width:6px;background-color:#000;background-color:rgba(0,0,0,.2)}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:6px}.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:6px;margin:5px 0}.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{width:12px}.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{height:12px;margin:2px 0}.mCS-light-3.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-light-3.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-light-3.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-light-3.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1)}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset.mCSB_scrollTools .mCSB_draggerRail{width:12px;background-color:#000;background-color:rgba(0,0,0,.2)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:6px;margin:3px 5px;position:absolute;height:auto;top:0;bottom:0;left:0;right:0}.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{height:6px;margin:5px 3px;position:absolute;width:auto;top:0;bottom:0;left:0;right:0}.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:12px;margin:2px 0}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent;border-width:1px;border-style:solid;border-color:#fff;border-color:rgba(255,255,255,.2);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail{border-color:#000;border-color:rgba(0,0,0,.2)}.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail{background-color:#fff;background-color:rgba(255,255,255,.6)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.6)}.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-inset-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.75)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9)} -------------------------------------------------------------------------------- /ui/static/res/botim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/ui/static/res/botim.png -------------------------------------------------------------------------------- /ui/static/res/hd1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/ui/static/res/hd1.jpg -------------------------------------------------------------------------------- /ui/static/res/hd2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/ui/static/res/hd2.jpg -------------------------------------------------------------------------------- /ui/static/scss/style.scss: -------------------------------------------------------------------------------- 1 | /*-------------------- 2 | Mixins 3 | --------------------*/ 4 | @mixin center { 5 | position: absolute; 6 | top: 50%; 7 | left: 50%; 8 | transform: translate(-50%, -50%); 9 | } 10 | 11 | @mixin ball { 12 | @include center; 13 | content: ''; 14 | display: block; 15 | width: 3px; 16 | height: 3px; 17 | border-radius: 50%; 18 | background: rgba(255, 255, 255, .5); 19 | z-index: 2; 20 | margin-top: 4px; 21 | animation: ball .45s cubic-bezier(0, 0, 0.15, 1) alternate infinite; 22 | } 23 | 24 | 25 | /*-------------------- 26 | Body 27 | --------------------*/ 28 | *, 29 | *::before, 30 | *::after { 31 | box-sizing: border-box; 32 | } 33 | 34 | html, 35 | body { 36 | height: 100%; 37 | } 38 | 39 | body { 40 | background: linear-gradient(135deg, #044f48, #2a7561); 41 | background-size: cover; 42 | font-family: 'Open Sans', sans-serif; 43 | font-size: 12px; 44 | line-height: 1.3; 45 | overflow: hidden; 46 | } 47 | 48 | .bg { 49 | width: 100%; 50 | height: 100%; 51 | top: 0; 52 | left: 0; 53 | z-index: 1; 54 | background: url('https://images.unsplash.com/photo-1451186859696-371d9477be93?crop=entropy&fit=crop&fm=jpg&h=975&ixjsv=2.1.0&ixlib=rb-0.3.5&q=80&w=1925') no-repeat 0 0; 55 | filter: blur(80px); 56 | transform: scale(1.2); 57 | } 58 | 59 | 60 | /*-------------------- 61 | Chat 62 | --------------------*/ 63 | .chat { 64 | @include center; 65 | width: 300px; 66 | height: 80vh; 67 | max-height: 500px; 68 | z-index: 2; 69 | overflow: hidden; 70 | box-shadow: 0 5px 30px rgba(0, 0, 0, .2); 71 | background: rgba(0, 0, 0, .5); 72 | border-radius: 20px; 73 | display: flex; 74 | justify-content: space-between; 75 | flex-direction: column; 76 | } 77 | 78 | 79 | /*-------------------- 80 | Chat Title 81 | --------------------*/ 82 | .chat-title { 83 | flex: 0 1 45px; 84 | position: relative; 85 | z-index: 2; 86 | background: rgba(0, 0, 0, 0.2); 87 | color: #fff; 88 | text-transform: uppercase; 89 | text-align: left; 90 | padding: 10px 10px 10px 50px; 91 | 92 | h1, h2 { 93 | font-weight: normal; 94 | font-size: 10px; 95 | margin: 0; 96 | padding: 0; 97 | } 98 | 99 | h2 { 100 | color: rgba(255, 255, 255, .5); 101 | font-size: 8px; 102 | letter-spacing: 1px; 103 | } 104 | 105 | .avatar { 106 | position: absolute; 107 | z-index: 1; 108 | top: 8px; 109 | left: 9px; 110 | border-radius: 30px; 111 | width: 30px; 112 | height: 30px; 113 | overflow: hidden; 114 | margin: 0; 115 | padding: 0; 116 | border: 2px solid rgba(255, 255, 255, 0.24); 117 | 118 | img { 119 | width: 100%; 120 | height: auto; 121 | } 122 | } 123 | } 124 | 125 | 126 | /*-------------------- 127 | Messages 128 | --------------------*/ 129 | .messages { 130 | flex: 1 1 auto; 131 | color: rgba(255, 255, 255, .5); 132 | overflow: hidden; 133 | position: relative; 134 | width: 100%; 135 | 136 | & .messages-content { 137 | position: absolute; 138 | top: 0; 139 | left: 0; 140 | height: 101%; 141 | width: 100%; 142 | } 143 | 144 | 145 | .message { 146 | clear: both; 147 | float: left; 148 | padding: 6px 10px 7px; 149 | border-radius: 10px 10px 10px 0; 150 | background: rgba(0, 0, 0, .3); 151 | margin: 8px 0; 152 | font-size: 11px; 153 | line-height: 1.4; 154 | margin-left: 35px; 155 | position: relative; 156 | text-shadow: 0 1px 1px rgba(0, 0, 0, .2); 157 | 158 | .timestamp { 159 | position: absolute; 160 | bottom: -15px; 161 | font-size: 9px; 162 | color: rgba(255, 255, 255, .3); 163 | } 164 | 165 | &::before { 166 | content: ''; 167 | position: absolute; 168 | bottom: -6px; 169 | border-top: 6px solid rgba(0, 0, 0, .3); 170 | left: 0; 171 | border-right: 7px solid transparent; 172 | } 173 | 174 | .avatar { 175 | position: absolute; 176 | z-index: 1; 177 | bottom: -15px; 178 | left: -35px; 179 | border-radius: 30px; 180 | width: 30px; 181 | height: 30px; 182 | overflow: hidden; 183 | margin: 0; 184 | padding: 0; 185 | border: 2px solid rgba(255, 255, 255, 0.24); 186 | 187 | img { 188 | width: 100%; 189 | height: auto; 190 | } 191 | } 192 | 193 | &.message-personal { 194 | float: right; 195 | color: #fff; 196 | text-align: right; 197 | background: linear-gradient(120deg, #248A52, #257287); 198 | border-radius: 10px 10px 0 10px; 199 | 200 | &::before { 201 | left: auto; 202 | right: 0; 203 | border-right: none; 204 | border-left: 5px solid transparent; 205 | border-top: 4px solid #257287; 206 | bottom: -4px; 207 | } 208 | } 209 | 210 | &:last-child { 211 | margin-bottom: 30px; 212 | } 213 | 214 | &.new { 215 | transform: scale(0); 216 | transform-origin: 0 0; 217 | animation: bounce 500ms linear both; 218 | } 219 | 220 | &.loading { 221 | 222 | &::before { 223 | @include ball; 224 | border: none; 225 | animation-delay: .15s; 226 | } 227 | 228 | & span { 229 | display: block; 230 | font-size: 0; 231 | width: 20px; 232 | height: 10px; 233 | position: relative; 234 | 235 | &::before { 236 | @include ball; 237 | margin-left: -7px; 238 | } 239 | 240 | &::after { 241 | @include ball; 242 | margin-left: 7px; 243 | animation-delay: .3s; 244 | } 245 | } 246 | } 247 | 248 | } 249 | } 250 | 251 | 252 | /*-------------------- 253 | Message Box 254 | --------------------*/ 255 | .message-box { 256 | flex: 0 1 40px; 257 | width: 100%; 258 | background: rgba(0, 0, 0, 0.3); 259 | padding: 10px; 260 | position: relative; 261 | 262 | & .message-input { 263 | background: none; 264 | border: none; 265 | outline: none!important; 266 | resize: none; 267 | color: rgba(255, 255, 255, .7); 268 | font-size: 11px; 269 | height: 17px; 270 | margin: 0; 271 | padding-right: 20px; 272 | width: 265px; 273 | } 274 | 275 | textarea:focus:-webkit-placeholder{ 276 | color: transparent; 277 | } 278 | 279 | & .message-submit { 280 | position: absolute; 281 | z-index: 1; 282 | top: 9px; 283 | right: 10px; 284 | color: #fff; 285 | border: none; 286 | background: #248A52; 287 | font-size: 10px; 288 | text-transform: uppercase; 289 | line-height: 1; 290 | padding: 6px 10px; 291 | border-radius: 10px; 292 | outline: none!important; 293 | transition: background .2s ease; 294 | 295 | &:hover { 296 | background: #1D7745; 297 | } 298 | } 299 | } 300 | 301 | 302 | /*-------------------- 303 | Custom Srollbar 304 | --------------------*/ 305 | .mCSB_scrollTools { 306 | margin: 1px -3px 1px 0; 307 | opacity: 0; 308 | } 309 | 310 | .mCSB_inside > .mCSB_container { 311 | margin-right: 0px; 312 | padding: 0 10px; 313 | } 314 | 315 | .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar { 316 | background-color: rgba(0, 0, 0, 0.5)!important; 317 | } 318 | 319 | 320 | /*-------------------- 321 | Bounce 322 | --------------------*/ 323 | @keyframes bounce { 324 | 0% { transform: matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 325 | 4.7% { transform: matrix3d(0.45, 0, 0, 0, 0, 0.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 326 | 9.41% { transform: matrix3d(0.883, 0, 0, 0, 0, 0.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 327 | 14.11% { transform: matrix3d(1.141, 0, 0, 0, 0, 1.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 328 | 18.72% { transform: matrix3d(1.212, 0, 0, 0, 0, 1.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 329 | 24.32% { transform: matrix3d(1.151, 0, 0, 0, 0, 1.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 330 | 29.93% { transform: matrix3d(1.048, 0, 0, 0, 0, 1.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 331 | 35.54% { transform: matrix3d(0.979, 0, 0, 0, 0, 0.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 332 | 41.04% { transform: matrix3d(0.961, 0, 0, 0, 0, 0.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 333 | 52.15% { transform: matrix3d(0.991, 0, 0, 0, 0, 0.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 334 | 63.26% { transform: matrix3d(1.007, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 335 | 85.49% { transform: matrix3d(0.999, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 336 | 100% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 337 | } 338 | 339 | 340 | @keyframes ball { 341 | from { 342 | transform: translateY(0) scaleY(.8); 343 | } 344 | to { 345 | transform: translateY(-10px); 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /ui/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @Janus 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |

JANUS

20 |

Ask Me Anything

21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 29 | 30 |
31 | 32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /working_dir/vocab20000.dec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/working_dir/vocab20000.dec -------------------------------------------------------------------------------- /working_dir/vocab20000.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suriyadeepan/easy_seq2seq/c05b0d02f15e9bd1947ff79ddcd0b761a214e2a9/working_dir/vocab20000.enc --------------------------------------------------------------------------------