diff --git a/aiserver.py b/aiserver.py
index 9a48cd9b..92d33f8f 100644
--- a/aiserver.py
+++ b/aiserver.py
@@ -1,6 +1,6 @@
#==================================================================#
# KoboldAI
-# Version: 1.16.0
+# Version: 1.16.2
# By: KoboldAIDev and the KoboldAI Community
#==================================================================#
@@ -44,10 +44,11 @@ class colors:
# AI models
modellist = [
- ["Custom Neo (GPT-Neo / Converted GPT-J)", "NeoCustom", ""],
- ["Custom GPT-2 (eg CloverEdition)", "GPT2Custom", ""],
- ["GPT Neo 1.3B", "EleutherAI/gpt-neo-1.3B", "8GB"],
- ["GPT Neo 2.7B", "EleutherAI/gpt-neo-2.7B", "16GB"],
+ ["Load a model from its directory", "NeoCustom", ""],
+ ["Load an old GPT-2 model (eg CloverEdition)", "GPT2Custom", ""],
+ ["GPT-Neo 1.3B", "EleutherAI/gpt-neo-1.3B", "8GB"],
+ ["GPT-Neo 2.7B", "EleutherAI/gpt-neo-2.7B", "16GB"],
+ ["GPT-J 6B (HF GIT Required)", "EleutherAI/gpt-j-6B", "24GB"],
["GPT-2", "gpt2", "1GB"],
["GPT-2 Med", "gpt2-medium", "2GB"],
["GPT-2 Large", "gpt2-large", "4GB"],
@@ -397,11 +398,16 @@ print("{0}OK!{1}".format(colors.GREEN, colors.END))
if(not vars.model in ["InferKit", "Colab", "OAI", "ReadOnly"]):
if(not vars.noai):
print("{0}Initializing transformers, please wait...{1}".format(colors.PURPLE, colors.END))
- from transformers import pipeline, GPT2Tokenizer, GPT2LMHeadModel, GPTNeoForCausalLM, GPTNeoModel, AutoModel
+ from transformers import pipeline, GPT2Tokenizer, GPT2LMHeadModel, GPTNeoForCausalLM, GPTNeoModel, AutoModelForCausalLM
# If custom GPT Neo model was chosen
if(vars.model == "NeoCustom"):
- model = GPTNeoForCausalLM.from_pretrained(vars.custmodpth)
+ model_config = open(vars.custmodpth + "/config.json", "r")
+ js = json.load(model_config)
+ if("model_type" in js):
+ model = vars.custmodpth
+ else:
+ model = GPTNeoForCausalLM.from_pretrained(vars.custmodpth)
tokenizer = GPT2Tokenizer.from_pretrained(vars.custmodpth)
# Is CUDA available? If so, use GPU, otherwise fall back to CPU
if(vars.hascuda):
@@ -460,7 +466,7 @@ if(not vars.model in ["InferKit", "Colab", "OAI", "ReadOnly"]):
generator = pipeline('text-generation', model=vars.model, device=0)
elif(vars.breakmodel): # Use both RAM and VRAM (breakmodel)
import breakmodel
- model = AutoModel.from_pretrained(vars.model)
+ model = AutoModelForCausalLM.from_pretrained(vars.model)
n_layers = model.config.num_layers
breakmodel.total_blocks = n_layers
model.half().to('cpu')
@@ -930,33 +936,38 @@ def settingschanged():
#==================================================================#
# Take input text from SocketIO and decide what to do with it
#==================================================================#
-def actionsubmit(data, actionmode=0):
+def actionsubmit(data, actionmode=0, force_submit=False):
# Ignore new submissions if the AI is currently busy
if(vars.aibusy):
return
set_aibusy(1)
vars.recentback = False
+ vars.recentedit = False
vars.actionmode = actionmode
# "Action" mode
if(actionmode == 1):
data = data.strip().lstrip('>')
data = re.sub(r'\n+', ' ', data)
- data = f"\n\n> {data}\n"
+ if(len(data)):
+ data = f"\n\n> {data}\n"
# If we're not continuing, store a copy of the raw input
if(data != ""):
vars.lastact = data
if(not vars.gamestarted):
+ if(not force_submit and len(data.strip()) == 0):
+ set_aibusy(0)
+ return
# Start the game
vars.gamestarted = True
# Save this first action as the prompt
vars.prompt = data
if(not vars.noai):
# Clear the startup text from game screen
- emit('from_server', {'cmd': 'updatescreen', 'gamestarted': vars.gamestarted, 'data': 'Please wait, generating story...'}, broadcast=True)
+ emit('from_server', {'cmd': 'updatescreen', 'gamestarted': False, 'data': 'Please wait, generating story...'}, broadcast=True)
calcsubmit(data) # Run the first action through the generator
emit('from_server', {'cmd': 'scrolldown', 'data': ''}, broadcast=True)
else:
@@ -970,7 +981,10 @@ def actionsubmit(data, actionmode=0):
if(vars.actionmode == 0):
data = applyinputformatting(data)
# Store the result in the Action log
- vars.actions.append(data)
+ if(len(vars.prompt.strip()) == 0):
+ vars.prompt = data
+ else:
+ vars.actions.append(data)
update_story_chunk('last')
if(not vars.noai):
@@ -999,7 +1013,9 @@ def actionretry(data):
remove_story_chunk(last_key + 1)
vars.genseqs = []
calcsubmit('')
+ emit('from_server', {'cmd': 'scrolldown', 'data': ''}, broadcast=True)
vars.recentback = False
+ vars.recentedit = False
elif(not vars.useprompt):
emit('from_server', {'cmd': 'errmsg', 'data': "Please enable \"Always Add Prompt\" to retry with your prompt."})
@@ -1282,7 +1298,10 @@ def genresult(genout):
genout = applyoutputformatting(genout)
# Add formatted text to Actions array and refresh the game screen
- vars.actions.append(genout)
+ if(len(vars.prompt.strip()) == 0):
+ vars.prompt = genout
+ else:
+ vars.actions.append(genout)
update_story_chunk('last')
emit('from_server', {'cmd': 'texteffect', 'data': vars.actions.get_last_key() if len(vars.actions) else 0}, broadcast=True)
@@ -1476,7 +1495,7 @@ def update_story_chunk(idx: Union[int, str]):
item = vars.acregex_ui.sub('\\1', item) # Add special formatting to adventure actions
chunk_text = f'{formatforhtml(item)}'
- emit('from_server', {'cmd': 'updatechunk', 'data': {'index': idx, 'html': chunk_text, 'last': (idx == (vars.actions.get_last_key() if len(vars.actions) else 0))}}, broadcast=True)
+ emit('from_server', {'cmd': 'updatechunk', 'data': {'index': idx, 'html': chunk_text}}, broadcast=True)
#==================================================================#
@@ -1548,6 +1567,7 @@ def editrequest(n):
#
#==================================================================#
def editsubmit(data):
+ vars.recentedit = True
if(vars.editln == 0):
vars.prompt = data
else:
@@ -1562,6 +1582,7 @@ def editsubmit(data):
#
#==================================================================#
def deleterequest():
+ vars.recentedit = True
# Don't delete prompt
if(vars.editln == 0):
# Send error message
@@ -1576,8 +1597,11 @@ def deleterequest():
#
#==================================================================#
def inlineedit(chunk, data):
+ vars.recentedit = True
chunk = int(chunk)
if(chunk == 0):
+ if(len(data.strip()) == 0):
+ return
vars.prompt = data
else:
vars.actions[chunk-1] = data
@@ -1590,6 +1614,7 @@ def inlineedit(chunk, data):
#
#==================================================================#
def inlinedelete(chunk):
+ vars.recentedit = True
chunk = int(chunk)
# Don't delete prompt
if(chunk == 0):
@@ -2094,8 +2119,19 @@ def loadRequest(loadpath):
del vars.actions
vars.actions = structures.KoboldStoryRegister()
- for s in js["actions"]:
- vars.actions.append(s)
+ actions = collections.deque(js["actions"])
+
+ if(len(vars.prompt.strip()) == 0):
+ while(len(actions)):
+ action = actions.popleft()
+ if(len(action.strip()) != 0):
+ vars.prompt = action
+ break
+ else:
+ vars.gamestarted = False
+ if(vars.gamestarted):
+ for s in actions:
+ vars.actions.append(s)
# Try not to break older save files
if("authorsnote" in js):
@@ -2369,7 +2405,7 @@ def newGameRequest():
def randomGameRequest(topic):
newGameRequest()
vars.memory = "You generate the following " + topic + " story concept :"
- actionsubmit("")
+ actionsubmit("", force_submit=True)
vars.memory = ""
#==================================================================#
diff --git a/environments/huggingface.yml b/environments/huggingface.yml
index d3fbd268..48ffc67d 100644
--- a/environments/huggingface.yml
+++ b/environments/huggingface.yml
@@ -11,7 +11,8 @@ dependencies:
- python=3.8.*
- cudatoolkit=11.1
- tensorflow-gpu
- - transformers
- pip
+ - git
- pip:
- - flask-cloudflared
\ No newline at end of file
+ - flask-cloudflared
+ - git+https://github.com/huggingface/transformers#transformer
\ No newline at end of file
diff --git a/static/application.js b/static/application.js
index 2431db49..04cf862e 100644
--- a/static/application.js
+++ b/static/application.js
@@ -69,11 +69,18 @@ var gamestarted = false;
var editmode = false;
var connected = false;
var newly_loaded = true;
-var current_editing_chunk = null;
-var chunk_conflict = false;
+var modified_chunks = new Set();
+var empty_chunks = new Set();
+var mutation_observer = null;
+var gametext_bound = false;
+var saved_prompt = "...";
+var override_focusout = false;
var sman_allow_delete = false;
var sman_allow_rename = false;
+// This is true iff [we're in macOS and the browser is Safari] or [we're in iOS]
+var using_webkit_patch = null;
+
// Key states
var shift_down = false;
var do_clear_ent = false;
@@ -400,7 +407,7 @@ function hideWaitAnimation() {
function scrollToBottom() {
setTimeout(function () {
- $('#gamescreen').animate({scrollTop: $('#gamescreen').prop('scrollHeight')}, 500);
+ game_text.stop(true).animate({scrollTop: game_text.prop('scrollHeight')}, 500);
}, 5);
}
@@ -462,6 +469,7 @@ function enterWiMode() {
hide([button_actback, button_actmem, button_actretry, game_text]);
show([wi_menu]);
disableSendBtn();
+ $("#gamescreen").addClass("wigamescreen");
}
function exitWiMode() {
@@ -470,7 +478,7 @@ function exitWiMode() {
hide([wi_menu]);
show([button_actback, button_actmem, button_actretry, game_text]);
enableSendBtn();
- scrollToBottom();
+ $("#gamescreen").removeClass("wigamescreen");
}
function returnWiList(ar) {
@@ -489,7 +497,10 @@ function returnWiList(ar) {
}
function dosubmit() {
- var txt = input_text.val();
+ var txt = input_text.val().replace(/\u00a0/g, " ");
+ if(!memorymode && !gamestarted && ((!adventure || !action_mode) && txt.trim().length == 0)) {
+ return;
+ }
socket.send({'cmd': 'submit', 'actionmode': adventure ? action_mode : 0, 'data': txt});
if(memorymode) {
memorytext = input_text.val();
@@ -720,9 +731,6 @@ function setadventure(state) {
function autofocus(event) {
if(connected) {
- if(event.target.tagName == "CHUNK") {
- current_editing_chunk = event.target;
- }
event.target.focus();
} else {
event.preventDefault();
@@ -733,72 +741,12 @@ function chunkOnKeyDown(event) {
// Make escape commit the changes (Originally we had Enter here to but its not required and nicer for users if we let them type freely
// You can add the following after 27 if you want it back to committing on enter : || (!event.shiftKey && event.keyCode == 13)
if(event.keyCode == 27) {
- setTimeout(function () {
- event.target.blur();
- }, 5);
+ override_focusout = true;
+ game_text.blur();
event.preventDefault();
return;
}
- // Allow left and right arrow keys (and backspace) to move between chunks
- switch(event.keyCode) {
- case 37: // left
- case 39: // right
- var old_range = getSelection().getRangeAt(0);
- var old_range_start = old_range.startOffset;
- var old_range_end = old_range.endOffset;
- var old_range_ancestor = old_range.commonAncestorContainer;
- var old_range_start_container = old_range.startContainer;
- var old_range_end_container = old_range.endContainer;
- setTimeout(function () {
- // Wait a few milliseconds and check if the caret has moved
- var new_selection = getSelection();
- var new_range = new_selection.getRangeAt(0);
- if(old_range_start != new_range.startOffset || old_range_end != new_range.endOffset || old_range_ancestor != new_range.commonAncestorContainer || old_range_start_container != new_range.startContainer || old_range_end_container != new_range.endContainer) {
- return;
- }
- // If it hasn't moved, we're at the beginning or end of a chunk
- // and the caret must be moved to a different chunk
- var chunk = document.activeElement;
- switch(event.keyCode) {
- case 37: // left
- if((chunk = chunk.previousSibling) && chunk.tagName == "CHUNK") {
- var range = document.createRange();
- range.selectNodeContents(chunk);
- range.collapse(false);
- new_selection.removeAllRanges();
- new_selection.addRange(range);
- }
- break;
-
- case 39: // right
- if((chunk = chunk.nextSibling) && chunk.tagName == "CHUNK") {
- chunk.focus();
- }
- }
- }, 2);
- return;
-
- case 8: // backspace
- var old_length = document.activeElement.innerText.length;
- setTimeout(function () {
- // Wait a few milliseconds and compare the chunk's length
- if(old_length != document.activeElement.innerText.length) {
- return;
- }
- // If it's the same, we're at the beginning of a chunk
- if((chunk = document.activeElement.previousSibling) && chunk.tagName == "CHUNK") {
- var range = document.createRange();
- var selection = getSelection();
- range.selectNodeContents(chunk);
- range.collapse(false);
- selection.removeAllRanges();
- selection.addRange(range);
- }
- }, 2);
- return
- }
-
// Don't allow any edits if not connected to server
if(!connected) {
event.preventDefault();
@@ -820,25 +768,6 @@ function chunkOnKeyDown(event) {
}
}
-function submitEditedChunk(event) {
- // Don't do anything if the current chunk hasn't been edited or if someone
- // else overwrote it while you were busy lollygagging
- if(current_editing_chunk === null || chunk_conflict) {
- chunk_conflict = false;
- return;
- }
-
- var chunk = current_editing_chunk;
- current_editing_chunk = null;
-
- // Submit the edited chunk if it's not empty, otherwise delete it
- if(chunk.innerText.length) {
- socket.send({'cmd': 'inlineedit', 'chunk': chunk.getAttribute("n"), 'data': chunk.innerText.replace(/\u00a0/g, " ")});
- } else {
- socket.send({'cmd': 'inlinedelete', 'data': chunk.getAttribute("n")});
- }
-}
-
function downloadStory(format) {
var filename_without_extension = storyname !== null ? storyname : "untitled";
@@ -890,6 +819,226 @@ function downloadStory(format) {
URL.revokeObjectURL(objectURL);
}
+function buildChunkSetFromNodeArray(nodes) {
+ var set = new Set();
+ for(var i = 0; i < nodes.length; i++) {
+ node = nodes[i];
+ while(node !== null && node.tagName !== "CHUNK") {
+ node = node.parentNode;
+ }
+ if(node === null) {
+ continue;
+ }
+ set.add(node.getAttribute("n"));
+ }
+ return set;
+}
+
+function getSelectedNodes() {
+ var range = rangy.getSelection().getRangeAt(0); // rangy is not a typo
+ var nodes = range.getNodes([1,3]);
+ nodes.push(range.startContainer);
+ nodes.push(range.endContainer);
+ return nodes
+}
+
+function applyChunkDeltas(nodes) {
+ var chunks = Array.from(buildChunkSetFromNodeArray(nodes));
+ for(var i = 0; i < chunks.length; i++) {
+ modified_chunks.add(chunks[i]);
+ }
+ setTimeout(function() {
+ var chunks = Array.from(modified_chunks);
+ var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes());
+ for(var i = 0; i < chunks.length; i++) {
+ var chunk = document.getElementById("n" + chunks[i]);
+ if(chunk && chunk.innerText.length != 0 && chunks[i] != '0') {
+ if(!selected_chunks.has(chunks[i])) {
+ modified_chunks.delete(chunks[i]);
+ socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': chunk.innerText.replace(/\u00a0/g, " ")});
+ }
+ empty_chunks.delete(chunks[i]);
+ } else {
+ if(!selected_chunks.has(chunks[i])) {
+ modified_chunks.delete(chunks[i]);
+ socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': ''});
+ }
+ empty_chunks.add(chunks[i]);
+ }
+ }
+ }, 2);
+}
+
+function syncAllModifiedChunks(including_selected_chunks=false) {
+ var chunks = Array.from(modified_chunks);
+ var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes());
+ for(var i = 0; i < chunks.length; i++) {
+ if(including_selected_chunks || !selected_chunks.has(chunks[i])) {
+ modified_chunks.delete(chunks[i]);
+ var chunk = document.getElementById("n" + chunks[i]);
+ var data = chunk ? document.getElementById("n" + chunks[i]).innerText.replace(/\u00a0/g, " ") : "";
+ if(data.length == 0) {
+ empty_chunks.add(chunks[i]);
+ } else {
+ empty_chunks.delete(chunks[i]);
+ }
+ socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': data});
+ }
+ }
+}
+
+function restorePrompt() {
+ if(game_text[0].firstChild && game_text[0].firstChild.nodeType === 3) {
+ saved_prompt = game_text[0].firstChild.textContent.replace(/\u00a0/g, " ");
+ unbindGametext();
+ game_text[0].innerText = "";
+ bindGametext();
+ }
+ if($("#n0").length) {
+ $("#n0").remove();
+ }
+ var prompt_chunk = document.createElement("chunk");
+ prompt_chunk.setAttribute("n", "0");
+ prompt_chunk.setAttribute("id", "n0");
+ prompt_chunk.setAttribute("tabindex", "-1");
+ prompt_chunk.innerText = saved_prompt;
+ unbindGametext();
+ game_text[0].prepend(prompt_chunk);
+ bindGametext();
+ modified_chunks.delete('0');
+ empty_chunks.delete('0');
+ socket.send({'cmd': 'inlineedit', 'chunk': '0', 'data': saved_prompt});
+}
+
+function deleteEmptyChunks() {
+ var chunks = Array.from(empty_chunks);
+ for(var i = 0; i < chunks.length; i++) {
+ empty_chunks.delete(chunks[i]);
+ if(chunks[i] === "0") {
+ // Don't delete the prompt
+ restorePrompt();
+ } else {
+ socket.send({'cmd': 'inlinedelete', 'data': chunks[i]});
+ }
+ }
+ if(modified_chunks.has('0')) {
+ modified_chunks.delete(chunks[i]);
+ socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': document.getElementById("n0").innerText.replace(/\u00a0/g, " ")});
+ }
+ saved_prompt = $("#n0")[0].innerText.replace(/\u00a0/g, " ");
+}
+
+function highlightEditingChunks() {
+ var chunks = $('chunk.editing').toArray();
+ var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes());
+ for(var i = 0; i < chunks.length; i++) {
+ var chunk = chunks[i];
+ if(!selected_chunks.has(chunks[i].getAttribute("n"))) {
+ unbindGametext();
+ $(chunk).removeClass('editing');
+ bindGametext();
+ }
+ }
+ chunks = Array.from(selected_chunks);
+ for(var i = 0; i < chunks.length; i++) {
+ var chunk = $("#n"+chunks[i]);
+ unbindGametext();
+ chunk.addClass('editing');
+ bindGametext();
+ }
+}
+
+// This gets run every time the text in a chunk is edited
+// or a chunk is deleted
+function chunkOnDOMMutate(mutations, observer) {
+ if(!gametext_bound || !allowedit) {
+ return;
+ }
+ var nodes = [];
+ for(var i = 0; i < mutations.length; i++) {
+ var mutation = mutations[i];
+ nodes = nodes.concat(Array.from(mutation.addedNodes), Array.from(mutation.removedNodes));
+ nodes.push(mutation.target);
+ }
+ applyChunkDeltas(nodes);
+}
+
+// This gets run every time you try to paste text into the editor
+function chunkOnPaste(event) {
+ if(!gametext_bound) {
+ return;
+ }
+ // If possible, intercept paste events into the editor in order to always
+ // paste as plaintext
+ if(event.originalEvent.clipboardData && document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertText')) {
+ event.preventDefault();
+ document.execCommand('insertText', false, event.originalEvent.clipboardData.getData('text/plain'));
+ }
+}
+
+// This gets run every time the caret moves in the editor
+function _chunkOnSelectionChange(event, do_blur_focus) {
+ if(!gametext_bound || !allowedit || override_focusout) {
+ override_focusout = false;
+ return;
+ }
+ setTimeout(function() {
+ syncAllModifiedChunks();
+ setTimeout(function() {
+ highlightEditingChunks();
+ // Attempt to prevent Chromium-based browsers on Android from
+ // scrolling away from the current selection
+ if(do_blur_focus && !using_webkit_patch) {
+ setTimeout(function() {
+ game_text.blur();
+ game_text.focus();
+ }, 144);
+ }
+ }, 2);
+ }, 2);
+}
+
+function chunkOnSelectionChange(event) {
+ return _chunkOnSelectionChange(event, true);
+}
+
+function chunkOnKeyDownSelectionChange(event) {
+ return _chunkOnSelectionChange(event, false);
+}
+
+// This gets run when you defocus the editor by clicking
+// outside of the editor or by pressing escape or tab
+function chunkOnFocusOut(event) {
+ if(!gametext_bound || !allowedit || event.target !== game_text[0]) {
+ return;
+ }
+ setTimeout(function() {
+ if(document.activeElement === game_text[0] || game_text[0].contains(document.activeElement)) {
+ return;
+ }
+ syncAllModifiedChunks(true);
+ setTimeout(function() {
+ var blurred = game_text[0] !== document.activeElement;
+ if(blurred) {
+ deleteEmptyChunks();
+ }
+ setTimeout(function() {
+ $("chunk").removeClass('editing');
+ }, 2);
+ }, 2);
+ }, 2);
+}
+
+function bindGametext() {
+ mutation_observer.observe(game_text[0], {characterData: true, childList: true, subtree: true});
+ gametext_bound = true;
+}
+
+function unbindGametext() {
+ mutation_observer.disconnect();
+ gametext_bound = false;
+}
+
//=================================================================//
// READY/RUNTIME
//=================================================================//
@@ -955,7 +1104,7 @@ $(document).ready(function(){
rs_close = $("#btn_rsclose");
seqselmenu = $("#seqselmenu");
seqselcontents = $("#seqselcontents");
-
+
// Connect to SocketIO server
socket = io.connect(window.document.origin);
@@ -973,13 +1122,43 @@ $(document).ready(function(){
format_menu.html("");
wi_menu.html("");
// Set up "Allow Editing"
- $('body').on('input', autofocus).on('keydown', 'chunk', chunkOnKeyDown).on('focusout', 'chunk', submitEditedChunk);
- $('#allowediting').prop('checked', allowedit).prop('disabled', false).change().on('change', function () {
+ $('body').on('input', autofocus);
+ $('#allowediting').prop('checked', allowedit).prop('disabled', false).change().off('change').on('change', function () {
if(allowtoggle) {
- allowedit = $(this).prop('checked')
- $("chunk").attr('contenteditable', allowedit)
+ allowedit = gamestarted && $(this).prop('checked');
+ game_text.attr('contenteditable', allowedit);
}
});
+ // A simple feature detection test to determine whether the user interface
+ // is using WebKit (Safari browser's rendering engine) because WebKit
+ // requires special treatment to work correctly with the KoboldAI editor
+ if(using_webkit_patch === null) {
+ using_webkit_patch = (function() {
+ try {
+ var active_element = document.activeElement;
+ var c = document.createElement("chunk");
+ var t = document.createTextNode("KoboldAI");
+ c.appendChild(t);
+ game_text[0].appendChild(c);
+ var r = rangy.createRange();
+ r.setStart(t, 6);
+ r.collapse(true);
+ var s = rangy.getSelection();
+ s.removeAllRanges();
+ s.addRange(r);
+ game_text.blur();
+ game_text.focus();
+ var offset = rangy.getSelection().focusOffset;
+ c.removeChild(t);
+ game_text[0].removeChild(c);
+ document.activeElement.blur();
+ active_element.focus();
+ return offset !== 6;
+ } catch (e) {
+ return false;
+ }
+ })();
+ }
} else if(msg.cmd == "updatescreen") {
var _gamestarted = gamestarted;
gamestarted = msg.gamestarted;
@@ -987,13 +1166,16 @@ $(document).ready(function(){
action_mode = 0;
changemode();
}
- // Send game content to Game Screen
- if(allowedit && document.activeElement.tagName == "CHUNK") {
- chunk_conflict = true;
- }
+ unbindGametext();
+ allowedit = gamestarted && $("#allowediting").prop('checked');
+ game_text.attr('contenteditable', allowedit);
+ modified_chunks = new Set();
+ empty_chunks = new Set();
game_text.html(msg.data);
- // Make content editable if need be
- $('chunk').attr('contenteditable', allowedit);
+ bindGametext();
+ if(gamestarted) {
+ saved_prompt = $("#n0")[0].innerText.replace(/\u00a0/g, " ");
+ }
// Scroll to bottom of text
if(newly_loaded) {
scrollToBottom();
@@ -1004,28 +1186,26 @@ $(document).ready(function(){
scrollToBottom();
} else if(msg.cmd == "updatechunk") {
hideMessage();
- const {index, html, last} = msg.data;
+ const {index, html} = msg.data;
const existingChunk = game_text.children(`#n${index}`)
const newChunk = $(html);
+ unbindGametext();
if (existingChunk.length > 0) {
// Update existing chunk
existingChunk.before(newChunk);
existingChunk.remove();
- } else {
+ } else if (!empty_chunks.has(index.toString())) {
// Append at the end
game_text.append(newChunk);
}
- newChunk.attr('contenteditable', allowedit);
+ bindGametext();
hide([$('#curtain')]);
- if(last) {
- // Scroll to bottom of text if it's the last element
- scrollToBottom();
- }
} else if(msg.cmd == "removechunk") {
hideMessage();
let index = msg.data;
- // Remove the chunk
- game_text.children(`#n${index}`).remove()
+ unbindGametext();
+ game_text.children(`#n${index}`).remove() // Remove the chunk
+ bindGametext();
hide([$('#curtain')]);
} else if(msg.cmd == "setgamestate") {
// Enable or Disable buttons
@@ -1252,7 +1432,31 @@ $(document).ready(function(){
connect_status.removeClass("color_green");
connect_status.addClass("color_orange");
});
-
+
+ // Register editing events
+ game_text.on('keydown',
+ chunkOnKeyDown
+ ).on('paste',
+ chunkOnPaste
+ ).on('click',
+ chunkOnSelectionChange
+ ).on('keydown',
+ chunkOnKeyDownSelectionChange
+ ).on('focusout',
+ chunkOnFocusOut
+ );
+ mutation_observer = new MutationObserver(chunkOnDOMMutate);
+
+ // This is required for the editor to work correctly in Firefox on desktop
+ // because the gods of HTML and JavaScript say so
+ $(document.body).on('focusin', function(event) {
+ setTimeout(function() {
+ if(document.activeElement !== game_text[0] && game_text[0].contains(document.activeElement)) {
+ game_text[0].focus();
+ }
+ }, 2);
+ });
+
// Bind actions to UI buttons
button_send.on("click", function(ev) {
dosubmit();
diff --git a/static/custom.css b/static/custom.css
index da040295..2d12c00c 100644
--- a/static/custom.css
+++ b/static/custom.css
@@ -11,12 +11,12 @@ chunk {
font-weight: bold;
}
-chunk[contenteditable="true"]:focus, chunk[contenteditable="true"]:focus * {
+chunk.editing, chunk.editing * {
color: #cdf !important;
font-weight: normal !important;
}
-chunk, chunk * {
+#gametext, chunk, chunk * {
outline: 0px solid transparent;
}
@@ -69,16 +69,19 @@ chunk, chunk * {
#gamescreen {
height: 490px;
margin-top: 10px;
- padding: 10px;
display: flex;
vertical-align: bottom;
- overflow-y: scroll;
background-color: #262626;
color: #ffffff;
font-size: 12pt;
font-family: "Helvetica";
}
+#gamescreen.wigamescreen {
+ padding: 10px;
+ overflow-y: scroll;
+}
+
#gamescreen span {
align-self: flex-end;
}
@@ -87,6 +90,8 @@ chunk, chunk * {
max-height: 100%;
width: 100%;
word-wrap: break-word;
+ padding: 10px;
+ overflow-y: auto;
}
#seqselmenu {
diff --git a/static/rangy-core.min.js b/static/rangy-core.min.js
new file mode 100644
index 00000000..ea65b24d
--- /dev/null
+++ b/static/rangy-core.min.js
@@ -0,0 +1,11 @@
+/**
+ * Rangy, a cross-browser JavaScript range and selection library
+ * https://github.com/timdown/rangy
+ *
+ * Copyright 2015, Tim Down
+ * Licensed under the MIT license.
+ * Version: 1.3.0
+ * Build date: 10 May 2015
+ */
+!function(e,t){"function"==typeof define&&define.amd?define(e):"undefined"!=typeof module&&"object"==typeof exports?module.exports=e():t.rangy=e()}(function(){function e(e,t){var n=typeof e[t];return n==N||!(n!=C||!e[t])||"unknown"==n}function t(e,t){return!(typeof e[t]!=C||!e[t])}function n(e,t){return typeof e[t]!=E}function r(e){return function(t,n){for(var r=n.length;r--;)if(!e(t,n[r]))return!1;return!0}}function o(e){return e&&O(e,T)&&D(e,w)}function i(e){return t(e,"body")?e.body:e.getElementsByTagName("body")[0]}function a(t){typeof console!=E&&e(console,"log")&&console.log(t)}function s(e,t){b&&t?alert(e):a(e)}function c(e){I.initialized=!0,I.supported=!1,s("Rangy is not supported in this environment. Reason: "+e,I.config.alertOnFail)}function d(e){s("Rangy warning: "+e,I.config.alertOnWarn)}function f(e){return e.message||e.description||String(e)}function u(){if(b&&!I.initialized){var t,n=!1,r=!1;e(document,"createRange")&&(t=document.createRange(),O(t,y)&&D(t,S)&&(n=!0));var s=i(document);if(!s||"body"!=s.nodeName.toLowerCase())return void c("No body element found");if(s&&e(s,"createTextRange")&&(t=s.createTextRange(),o(t)&&(r=!0)),!n&&!r)return void c("Neither Range nor TextRange are available");I.initialized=!0,I.features={implementsDomRange:n,implementsTextRange:r};var d,u;for(var l in x)(d=x[l])instanceof p&&d.init(d,I);for(var h=0,g=M.length;g>h;++h)try{M[h](I)}catch(m){u="Rangy init listener threw an exception. Continuing. Detail: "+f(m),a(u)}}}function l(e,t,n){n&&(e+=" in module "+n.name),I.warn("DEPRECATED: "+e+" is deprecated. Please use "+t+" instead.")}function h(e,t,n,r){e[t]=function(){return l(t,n,r),e[n].apply(e,P.toArray(arguments))}}function g(e){e=e||window,u();for(var t=0,n=k.length;n>t;++t)k[t](e)}function p(e,t,n){this.name=e,this.dependencies=t,this.initialized=!1,this.supported=!1,this.initializer=n}function m(e,t,n){var r=new p(e,t,function(t){if(!t.initialized){t.initialized=!0;try{n(I,t),t.supported=!0}catch(r){var o="Module '"+e+"' failed to load: "+f(r);a(o),r.stack&&a(r.stack)}}});return x[e]=r,r}function R(){}function v(){}var C="object",N="function",E="undefined",S=["startContainer","startOffset","endContainer","endOffset","collapsed","commonAncestorContainer"],y=["setStart","setStartBefore","setStartAfter","setEnd","setEndBefore","setEndAfter","collapse","selectNode","selectNodeContents","compareBoundaryPoints","deleteContents","extractContents","cloneContents","insertNode","surroundContents","cloneRange","toString","detach"],w=["boundingHeight","boundingLeft","boundingTop","boundingWidth","htmlText","text"],T=["collapse","compareEndPoints","duplicate","moveToElementText","parentElement","select","setEndPoint","getBoundingClientRect"],O=r(e),_=r(t),D=r(n),A=[].forEach?function(e,t){e.forEach(t)}:function(e,t){for(var n=0,r=e.length;r>n;++n)t(e[n],n)},x={},b=typeof window!=E&&typeof document!=E,P={isHostMethod:e,isHostObject:t,isHostProperty:n,areHostMethods:O,areHostObjects:_,areHostProperties:D,isTextRange:o,getBody:i,forEach:A},I={version:"1.3.0",initialized:!1,isBrowser:b,supported:!0,util:P,features:{},modules:x,config:{alertOnFail:!1,alertOnWarn:!1,preferTextRange:!1,autoInitialize:typeof rangyAutoInitialize==E?!0:rangyAutoInitialize}};I.fail=c,I.warn=d;var B;({}).hasOwnProperty?(P.extend=B=function(e,t,n){var r,o;for(var i in t)t.hasOwnProperty(i)&&(r=e[i],o=t[i],n&&null!==r&&"object"==typeof r&&null!==o&&"object"==typeof o&&B(r,o,!0),e[i]=o);return t.hasOwnProperty("toString")&&(e.toString=t.toString),e},P.createOptions=function(e,t){var n={};return B(n,t),e&&B(n,e),n}):c("hasOwnProperty not supported"),b||c("Rangy can only run in a browser"),function(){var e;if(b){var t=document.createElement("div");t.appendChild(document.createElement("span"));var n=[].slice;try{1==n.call(t.childNodes,0)[0].nodeType&&(e=function(e){return n.call(e,0)})}catch(r){}}e||(e=function(e){for(var t=[],n=0,r=e.length;r>n;++n)t[n]=e[n];return t}),P.toArray=e}();var H;b&&(e(document,"addEventListener")?H=function(e,t,n){e.addEventListener(t,n,!1)}:e(document,"attachEvent")?H=function(e,t,n){e.attachEvent("on"+t,n)}:c("Document does not have required addEventListener or attachEvent method"),P.addListener=H);var M=[];P.deprecationNotice=l,P.createAliasForDeprecatedMethod=h,I.init=u,I.addInitListener=function(e){I.initialized?e(I):M.push(e)};var k=[];I.addShimListener=function(e){k.push(e)},b&&(I.shim=I.createMissingNativeApi=g,h(I,"createMissingNativeApi","shim")),p.prototype={init:function(){for(var e,t,n=this.dependencies||[],r=0,o=n.length;o>r;++r){if(t=n[r],e=x[t],!(e&&e instanceof p))throw new Error("required module '"+t+"' not found");if(e.init(),!e.supported)throw new Error("required module '"+t+"' not supported")}this.initializer(this)},fail:function(e){throw this.initialized=!0,this.supported=!1,new Error(e)},warn:function(e){I.warn("Module "+this.name+": "+e)},deprecationNotice:function(e,t){I.warn("DEPRECATED: "+e+" in module "+this.name+" is deprecated. Please use "+t+" instead")},createError:function(e){return new Error("Error in Rangy "+this.name+" module: "+e)}},I.createModule=function(e){var t,n;2==arguments.length?(t=arguments[1],n=[]):(t=arguments[2],n=arguments[1]);var r=m(e,n,t);I.initialized&&I.supported&&r.init()},I.createCoreModule=function(e,t,n){m(e,t,n)},I.RangePrototype=R,I.rangePrototype=new R,I.selectionPrototype=new v,I.createCoreModule("DomUtil",[],function(e,t){function n(e){var t;return typeof e.namespaceURI==b||null===(t=e.namespaceURI)||"http://www.w3.org/1999/xhtml"==t}function r(e){var t=e.parentNode;return 1==t.nodeType?t:null}function o(e){for(var t=0;e=e.previousSibling;)++t;return t}function i(e){switch(e.nodeType){case 7:case 10:return 0;case 3:case 8:return e.length;default:return e.childNodes.length}}function a(e,t){var n,r=[];for(n=e;n;n=n.parentNode)r.push(n);for(n=t;n;n=n.parentNode)if(M(r,n))return n;return null}function s(e,t,n){for(var r=n?t:t.parentNode;r;){if(r===e)return!0;r=r.parentNode}return!1}function c(e,t){return s(e,t,!0)}function d(e,t,n){for(var r,o=n?e:e.parentNode;o;){if(r=o.parentNode,r===t)return o;o=r}return null}function f(e){var t=e.nodeType;return 3==t||4==t||8==t}function u(e){if(!e)return!1;var t=e.nodeType;return 3==t||8==t}function l(e,t){var n=t.nextSibling,r=t.parentNode;return n?r.insertBefore(e,n):r.appendChild(e),e}function h(e,t,n){var r=e.cloneNode(!1);if(r.deleteData(0,t),e.deleteData(t,e.length-t),l(r,e),n)for(var i,a=0;i=n[a++];)i.node==e&&i.offset>t?(i.node=r,i.offset-=t):i.node==e.parentNode&&i.offset>o(e)&&++i.offset;return r}function g(e){if(9==e.nodeType)return e;if(typeof e.ownerDocument!=b)return e.ownerDocument;if(typeof e.document!=b)return e.document;if(e.parentNode)return g(e.parentNode);throw t.createError("getDocument: no document found for node")}function p(e){var n=g(e);if(typeof n.defaultView!=b)return n.defaultView;if(typeof n.parentWindow!=b)return n.parentWindow;throw t.createError("Cannot get a window object for node")}function m(e){if(typeof e.contentDocument!=b)return e.contentDocument;if(typeof e.contentWindow!=b)return e.contentWindow.document;throw t.createError("getIframeDocument: No Document object found for iframe element")}function R(e){if(typeof e.contentWindow!=b)return e.contentWindow;if(typeof e.contentDocument!=b)return e.contentDocument.defaultView;throw t.createError("getIframeWindow: No Window object found for iframe element")}function v(e){return e&&P.isHostMethod(e,"setTimeout")&&P.isHostObject(e,"document")}function C(e,t,n){var r;if(e?P.isHostProperty(e,"nodeType")?r=1==e.nodeType&&"iframe"==e.tagName.toLowerCase()?m(e):g(e):v(e)&&(r=e.document):r=document,!r)throw t.createError(n+"(): Parameter must be a Window object or DOM node");return r}function N(e){for(var t;t=e.parentNode;)e=t;return e}function E(e,n,r,i){var s,c,f,u,l;if(e==r)return n===i?0:i>n?-1:1;if(s=d(r,e,!0))return n<=o(s)?-1:1;if(s=d(e,r,!0))return o(s)[index:"+o(e)+",length:"+e.childNodes.length+"]["+(e.innerHTML||"[innerHTML not supported]").slice(0,25)+"]"}return e.nodeName}function w(e){for(var t,n=g(e).createDocumentFragment();t=e.firstChild;)n.appendChild(t);return n}function T(e,t,n){var r=I(e),o=e.createElement("div");o.contentEditable=""+!!n,t&&(o.innerHTML=t);var i=r.firstChild;return i?r.insertBefore(o,i):r.appendChild(o),o}function O(e){return e.parentNode.removeChild(e)}function _(e){this.root=e,this._next=e}function D(e){return new _(e)}function A(e,t){this.node=e,this.offset=t}function x(e){this.code=this[e],this.codeName=e,this.message="DOMException: "+this.codeName}var b="undefined",P=e.util,I=P.getBody;P.areHostMethods(document,["createDocumentFragment","createElement","createTextNode"])||t.fail("document missing a Node creation method"),P.isHostMethod(document,"getElementsByTagName")||t.fail("document missing getElementsByTagName method");var B=document.createElement("div");P.areHostMethods(B,["insertBefore","appendChild","cloneNode"]||!P.areHostObjects(B,["previousSibling","nextSibling","childNodes","parentNode"]))||t.fail("Incomplete Element implementation"),P.isHostProperty(B,"innerHTML")||t.fail("Element is missing innerHTML property");var H=document.createTextNode("test");P.areHostMethods(H,["splitText","deleteData","insertData","appendData","cloneNode"]||!P.areHostObjects(B,["previousSibling","nextSibling","childNodes","parentNode"])||!P.areHostProperties(H,["data"]))||t.fail("Incomplete Text Node implementation");var M=function(e,t){for(var n=e.length;n--;)if(e[n]===t)return!0;return!1},k=!1;!function(){var t=document.createElement("b");t.innerHTML="1";var n=t.firstChild;t.innerHTML="
",k=S(n),e.features.crashyTextNodes=k}();var L;typeof window.getComputedStyle!=b?L=function(e,t){return p(e).getComputedStyle(e,null)[t]}:typeof document.documentElement.currentStyle!=b?L=function(e,t){return e.currentStyle?e.currentStyle[t]:""}:t.fail("No means of obtaining computed style properties found"),_.prototype={_current:null,hasNext:function(){return!!this._next},next:function(){var e,t,n=this._current=this._next;if(this._current)if(e=n.firstChild)this._next=e;else{for(t=null;n!==this.root&&!(t=n.nextSibling);)n=n.parentNode;this._next=t}return this._current},detach:function(){this._current=this._next=this.root=null}},A.prototype={equals:function(e){return!!e&&this.node===e.node&&this.offset==e.offset},inspect:function(){return"[DomPosition("+y(this.node)+":"+this.offset+")]"},toString:function(){return this.inspect()}},x.prototype={INDEX_SIZE_ERR:1,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INVALID_STATE_ERR:11,INVALID_NODE_TYPE_ERR:24},x.prototype.toString=function(){return this.message},e.dom={arrayContains:M,isHtmlNamespace:n,parentElement:r,getNodeIndex:o,getNodeLength:i,getCommonAncestor:a,isAncestorOf:s,isOrIsAncestorOf:c,getClosestAncestorIn:d,isCharacterDataNode:f,isTextOrCommentNode:u,insertAfter:l,splitDataNode:h,getDocument:g,getWindow:p,getIframeWindow:R,getIframeDocument:m,getBody:I,isWindow:v,getContentDocument:C,getRootContainer:N,comparePoints:E,isBrokenNode:S,inspectNode:y,getComputedStyleProperty:L,createTestElement:T,removeNode:O,fragmentFromNodeChildren:w,createIterator:D,DomPosition:A},e.DOMException=x}),I.createCoreModule("DomRange",["DomUtil"],function(e){function t(e,t){return 3!=e.nodeType&&(F(e,t.startContainer)||F(e,t.endContainer))}function n(e){return e.document||j(e.startContainer)}function r(e){return Q(e.startContainer)}function o(e){return new M(e.parentNode,W(e))}function i(e){return new M(e.parentNode,W(e)+1)}function a(e,t,n){var r=11==e.nodeType?e.firstChild:e;return L(t)?n==t.length?B.insertAfter(e,t):t.parentNode.insertBefore(e,0==n?t:U(t,n)):n>=t.childNodes.length?t.appendChild(e):t.insertBefore(e,t.childNodes[n]),r}function s(e,t,r){if(w(e),w(t),n(t)!=n(e))throw new k("WRONG_DOCUMENT_ERR");var o=z(e.startContainer,e.startOffset,t.endContainer,t.endOffset),i=z(e.endContainer,e.endOffset,t.startContainer,t.startOffset);return r?0>=o&&i>=0:0>o&&i>0}function c(e){for(var t,r,o,i=n(e.range).createDocumentFragment();r=e.next();){if(t=e.isPartiallySelectedSubtree(),r=r.cloneNode(!t),t&&(o=e.getSubtreeIterator(),r.appendChild(c(o)),o.detach()),10==r.nodeType)throw new k("HIERARCHY_REQUEST_ERR");i.appendChild(r)}return i}function d(e,t,n){var r,o;n=n||{stop:!1};for(var i,a;i=e.next();)if(e.isPartiallySelectedSubtree()){if(t(i)===!1)return void(n.stop=!0);if(a=e.getSubtreeIterator(),d(a,t,n),a.detach(),n.stop)return}else for(r=B.createIterator(i);o=r.next();)if(t(o)===!1)return void(n.stop=!0)}function f(e){for(var t;e.next();)e.isPartiallySelectedSubtree()?(t=e.getSubtreeIterator(),f(t),t.detach()):e.remove()}function u(e){for(var t,r,o=n(e.range).createDocumentFragment();t=e.next();){if(e.isPartiallySelectedSubtree()?(t=t.cloneNode(!1),r=e.getSubtreeIterator(),t.appendChild(u(r)),r.detach()):e.remove(),10==t.nodeType)throw new k("HIERARCHY_REQUEST_ERR");o.appendChild(t)}return o}function l(e,t,n){var r,o=!(!t||!t.length),i=!!n;o&&(r=new RegExp("^("+t.join("|")+")$"));var a=[];return d(new g(e,!1),function(t){if(!(o&&!r.test(t.nodeType)||i&&!n(t))){var s=e.startContainer;if(t!=s||!L(s)||e.startOffset!=s.length){var c=e.endContainer;t==c&&L(c)&&0==e.endOffset||a.push(t)}}}),a}function h(e){var t="undefined"==typeof e.getName?"Range":e.getName();return"["+t+"("+B.inspectNode(e.startContainer)+":"+e.startOffset+", "+B.inspectNode(e.endContainer)+":"+e.endOffset+")]"}function g(e,t){if(this.range=e,this.clonePartiallySelectedTextNodes=t,!e.collapsed){this.sc=e.startContainer,this.so=e.startOffset,this.ec=e.endContainer,this.eo=e.endOffset;var n=e.commonAncestorContainer;this.sc===this.ec&&L(this.sc)?(this.isSingleCharacterDataNode=!0,this._first=this._last=this._next=this.sc):(this._first=this._next=this.sc!==n||L(this.sc)?V(this.sc,n,!0):this.sc.childNodes[this.so],this._last=this.ec!==n||L(this.ec)?V(this.ec,n,!0):this.ec.childNodes[this.eo-1])}}function p(e){return function(t,n){for(var r,o=n?t:t.parentNode;o;){if(r=o.nodeType,Y(e,r))return o;o=o.parentNode}return null}}function m(e,t){if(rt(e,t))throw new k("INVALID_NODE_TYPE_ERR")}function R(e,t){if(!Y(t,e.nodeType))throw new k("INVALID_NODE_TYPE_ERR")}function v(e,t){if(0>t||t>(L(e)?e.length:e.childNodes.length))throw new k("INDEX_SIZE_ERR")}function C(e,t){if(tt(e,!0)!==tt(t,!0))throw new k("WRONG_DOCUMENT_ERR")}function N(e){if(nt(e,!0))throw new k("NO_MODIFICATION_ALLOWED_ERR")}function E(e,t){if(!e)throw new k(t)}function S(e,t){return t<=(L(e)?e.length:e.childNodes.length)}function y(e){return!!e.startContainer&&!!e.endContainer&&!(G&&(B.isBrokenNode(e.startContainer)||B.isBrokenNode(e.endContainer)))&&Q(e.startContainer)==Q(e.endContainer)&&S(e.startContainer,e.startOffset)&&S(e.endContainer,e.endOffset)}function w(e){if(!y(e))throw new Error("Range error: Range is not valid. This usually happens after DOM mutation. Range: ("+e.inspect()+")")}function T(e,t){w(e);var n=e.startContainer,r=e.startOffset,o=e.endContainer,i=e.endOffset,a=n===o;L(o)&&i>0&&i0&&r=W(n)&&i++,r=0),e.setStartAndEnd(n,r,o,i)}function O(e){w(e);var t=e.commonAncestorContainer.parentNode.cloneNode(!1);return t.appendChild(e.cloneContents()),t.innerHTML}function _(e){e.START_TO_START=dt,e.START_TO_END=ft,e.END_TO_END=ut,e.END_TO_START=lt,e.NODE_BEFORE=ht,e.NODE_AFTER=gt,e.NODE_BEFORE_AND_AFTER=pt,e.NODE_INSIDE=mt}function D(e){_(e),_(e.prototype)}function A(e,t){return function(){w(this);var n,r,o=this.startContainer,a=this.startOffset,s=this.commonAncestorContainer,c=new g(this,!0);o!==s&&(n=V(o,s,!0),r=i(n),o=r.node,a=r.offset),d(c,N),c.reset();var f=e(c);return c.detach(),t(this,o,a,o,a),f}}function x(n,r){function a(e,t){return function(n){R(n,Z),R(Q(n),$);var r=(e?o:i)(n);(t?s:c)(this,r.node,r.offset)}}function s(e,t,n){var o=e.endContainer,i=e.endOffset;(t!==e.startContainer||n!==e.startOffset)&&((Q(t)!=Q(o)||1==z(t,n,o,i))&&(o=t,i=n),r(e,t,n,o,i))}function c(e,t,n){var o=e.startContainer,i=e.startOffset;(t!==e.endContainer||n!==e.endOffset)&&((Q(t)!=Q(o)||-1==z(t,n,o,i))&&(o=t,i=n),r(e,o,i,t,n))}var d=function(){};d.prototype=e.rangePrototype,n.prototype=new d,H.extend(n.prototype,{setStart:function(e,t){m(e,!0),v(e,t),s(this,e,t)},setEnd:function(e,t){m(e,!0),v(e,t),c(this,e,t)},setStartAndEnd:function(){var e=arguments,t=e[0],n=e[1],o=t,i=n;switch(e.length){case 3:i=e[2];break;case 4:o=e[2],i=e[3]}r(this,t,n,o,i)},setBoundary:function(e,t,n){this["set"+(n?"Start":"End")](e,t)},setStartBefore:a(!0,!0),setStartAfter:a(!1,!0),setEndBefore:a(!0,!1),setEndAfter:a(!1,!1),collapse:function(e){w(this),e?r(this,this.startContainer,this.startOffset,this.startContainer,this.startOffset):r(this,this.endContainer,this.endOffset,this.endContainer,this.endOffset)},selectNodeContents:function(e){m(e,!0),r(this,e,0,e,q(e))},selectNode:function(e){m(e,!1),R(e,Z);var t=o(e),n=i(e);r(this,t.node,t.offset,n.node,n.offset)},extractContents:A(u,r),deleteContents:A(f,r),canSurroundContents:function(){w(this),N(this.startContainer),N(this.endContainer);var e=new g(this,!0),n=e._first&&t(e._first,this)||e._last&&t(e._last,this);return e.detach(),!n},splitBoundaries:function(){T(this)},splitBoundariesPreservingPositions:function(e){T(this,e)},normalizeBoundaries:function(){w(this);var e,t=this.startContainer,n=this.startOffset,o=this.endContainer,i=this.endOffset,a=function(e){var t=e.nextSibling;t&&t.nodeType==e.nodeType&&(o=e,i=e.length,e.appendData(t.data),X(t))},s=function(e){var r=e.previousSibling;if(r&&r.nodeType==e.nodeType){t=e;var a=e.length;if(n=r.length,e.insertData(0,r.data),X(r),t==o)i+=n,o=t;else if(o==e.parentNode){var s=W(e);i==s?(o=e,i=a):i>s&&i--}}},c=!0;if(L(o))i==o.length?a(o):0==i&&(e=o.previousSibling,e&&e.nodeType==o.nodeType&&(i=e.length,t==o&&(c=!1),e.appendData(o.data),X(o),o=e));else{if(i>0){var d=o.childNodes[i-1];d&&L(d)&&a(d)}c=!this.collapsed}if(c){if(L(t))0==n?s(t):n==t.length&&(e=t.nextSibling,e&&e.nodeType==t.nodeType&&(o==e&&(o=t,i+=t.length),t.appendData(e.data),X(e)));else if(nx",it=3==ot.firstChild.nodeType}catch(at){}e.features.htmlParsingConforms=it;var st=it?function(e){var t=this.startContainer,n=j(t);if(!t)throw new k("INVALID_STATE_ERR");var r=null;return 1==t.nodeType?r=t:L(t)&&(r=B.parentElement(t)),r=null===r||"HTML"==r.nodeName&&B.isHtmlNamespace(j(r).documentElement)&&B.isHtmlNamespace(r)?n.createElement("body"):r.cloneNode(!1),r.innerHTML=e,B.fragmentFromNodeChildren(r)}:function(e){var t=n(this),r=t.createElement("body");return r.innerHTML=e,B.fragmentFromNodeChildren(r)},ct=["startContainer","startOffset","endContainer","endOffset","collapsed","commonAncestorContainer"],dt=0,ft=1,ut=2,lt=3,ht=0,gt=1,pt=2,mt=3;H.extend(e.rangePrototype,{compareBoundaryPoints:function(e,t){w(this),C(this.startContainer,t.startContainer);var n,r,o,i,a=e==lt||e==dt?"start":"end",s=e==ft||e==dt?"start":"end";return n=this[a+"Container"],r=this[a+"Offset"],o=t[s+"Container"],i=t[s+"Offset"],z(n,r,o,i)},insertNode:function(e){if(w(this),R(e,K),N(this.startContainer),F(e,this.startContainer))throw new k("HIERARCHY_REQUEST_ERR");var t=a(e,this.startContainer,this.startOffset);this.setStartBefore(t)},cloneContents:function(){w(this);var e,t;if(this.collapsed)return n(this).createDocumentFragment();if(this.startContainer===this.endContainer&&L(this.startContainer))return e=this.startContainer.cloneNode(!0),e.data=e.data.slice(this.startOffset,this.endOffset),t=n(this).createDocumentFragment(),t.appendChild(e),t;var r=new g(this,!0);return e=c(r),r.detach(),e},canSurroundContents:function(){w(this),N(this.startContainer),N(this.endContainer);var e=new g(this,!0),n=e._first&&t(e._first,this)||e._last&&t(e._last,this);return e.detach(),!n},surroundContents:function(e){if(R(e,et),!this.canSurroundContents())throw new k("INVALID_STATE_ERR");var t=this.extractContents();if(e.hasChildNodes())for(;e.lastChild;)e.removeChild(e.lastChild);a(e,this.startContainer,this.startOffset),e.appendChild(t),this.selectNode(e)},cloneRange:function(){w(this);for(var e,t=new I(n(this)),r=ct.length;r--;)e=ct[r],t[e]=this[e];return t},toString:function(){w(this);var e=this.startContainer;if(e===this.endContainer&&L(e))return 3==e.nodeType||4==e.nodeType?e.data.slice(this.startOffset,this.endOffset):"";var t=[],n=new g(this,!0);return d(n,function(e){(3==e.nodeType||4==e.nodeType)&&t.push(e.data)}),n.detach(),t.join("")},compareNode:function(e){w(this);var t=e.parentNode,n=W(e);if(!t)throw new k("NOT_FOUND_ERR");var r=this.comparePoint(t,n),o=this.comparePoint(t,n+1);return 0>r?o>0?pt:ht:o>0?gt:mt},comparePoint:function(e,t){return w(this),E(e,"HIERARCHY_REQUEST_ERR"),C(e,this.startContainer),z(e,t,this.startContainer,this.startOffset)<0?-1:z(e,t,this.endContainer,this.endOffset)>0?1:0},createContextualFragment:st,toHtml:function(){return O(this)},intersectsNode:function(e,t){if(w(this),Q(e)!=r(this))return!1;var n=e.parentNode,o=W(e);if(!n)return!0;var i=z(n,o,this.endContainer,this.endOffset),a=z(n,o+1,this.startContainer,this.startOffset);return t?0>=i&&a>=0:0>i&&a>0},isPointInRange:function(e,t){return w(this),E(e,"HIERARCHY_REQUEST_ERR"),C(e,this.startContainer),z(e,t,this.startContainer,this.startOffset)>=0&&z(e,t,this.endContainer,this.endOffset)<=0},intersectsRange:function(e){return s(this,e,!1)},intersectsOrTouchesRange:function(e){return s(this,e,!0)},intersection:function(e){if(this.intersectsRange(e)){var t=z(this.startContainer,this.startOffset,e.startContainer,e.startOffset),n=z(this.endContainer,this.endOffset,e.endContainer,e.endOffset),r=this.cloneRange();return-1==t&&r.setStart(e.startContainer,e.startOffset),1==n&&r.setEnd(e.endContainer,e.endOffset),r}return null},union:function(e){if(this.intersectsOrTouchesRange(e)){var t=this.cloneRange();return-1==z(e.startContainer,e.startOffset,this.startContainer,this.startOffset)&&t.setStart(e.startContainer,e.startOffset),1==z(e.endContainer,e.endOffset,this.endContainer,this.endOffset)&&t.setEnd(e.endContainer,e.endOffset),t}throw new k("Ranges do not intersect")},containsNode:function(e,t){return t?this.intersectsNode(e,!1):this.compareNode(e)==mt},containsNodeContents:function(e){return this.comparePoint(e,0)>=0&&this.comparePoint(e,q(e))<=0},containsRange:function(e){var t=this.intersection(e);return null!==t&&e.equals(t)},containsNodeText:function(e){var t=this.cloneRange();t.selectNode(e);var n=t.getNodes([3]);if(n.length>0){t.setStart(n[0],0);var r=n.pop();return t.setEnd(r,r.length),this.containsRange(t)}return this.containsNodeContents(e)},getNodes:function(e,t){return w(this),l(this,e,t)},getDocument:function(){return n(this)},collapseBefore:function(e){this.setEndBefore(e),this.collapse(!1)},collapseAfter:function(e){this.setStartAfter(e),this.collapse(!0)},getBookmark:function(t){var r=n(this),o=e.createRange(r);t=t||B.getBody(r),o.selectNodeContents(t);var i=this.intersection(o),a=0,s=0;return i&&(o.setEnd(i.startContainer,i.startOffset),a=o.toString().length,s=a+i.toString().length),{start:a,end:s,containerNode:t}},moveToBookmark:function(e){var t=e.containerNode,n=0;this.setStart(t,0),this.collapse(!0);for(var r,o,i,a,s=[t],c=!1,d=!1;!d&&(r=s.pop());)if(3==r.nodeType)o=n+r.length,!c&&e.start>=n&&e.start<=o&&(this.setStart(r,e.start-n),c=!0),c&&e.end>=n&&e.end<=o&&(this.setEnd(r,e.end-n),d=!0),n=o;else for(a=r.childNodes,i=a.length;i--;)s.push(a[i])},getName:function(){return"DomRange"},equals:function(e){return I.rangesEqual(this,e)},isValid:function(){return y(this)},inspect:function(){return h(this)},detach:function(){}}),x(I,P),H.extend(I,{rangeProperties:ct,RangeIterator:g,copyComparisonConstants:D,createPrototypeRange:x,inspect:h,toHtml:O,getRangeDocument:n,rangesEqual:function(e,t){return e.startContainer===t.startContainer&&e.startOffset===t.startOffset&&e.endContainer===t.endContainer&&e.endOffset===t.endOffset}}),e.DomRange=I}),I.createCoreModule("WrappedRange",["DomRange"],function(e,t){var n,r,o=e.dom,i=e.util,a=o.DomPosition,s=e.DomRange,c=o.getBody,d=o.getContentDocument,f=o.isCharacterDataNode;if(e.features.implementsDomRange&&!function(){function r(e){for(var t,n=l.length;n--;)t=l[n],e[t]=e.nativeRange[t];e.collapsed=e.startContainer===e.endContainer&&e.startOffset===e.endOffset}function a(e,t,n,r,o){var i=e.startContainer!==t||e.startOffset!=n,a=e.endContainer!==r||e.endOffset!=o,s=!e.equals(e.nativeRange);(i||a||s)&&(e.setEnd(r,o),e.setStart(t,n))}var f,u,l=s.rangeProperties;n=function(e){if(!e)throw t.createError("WrappedRange: Range must be specified");this.nativeRange=e,r(this)},s.createPrototypeRange(n,a),f=n.prototype,f.selectNode=function(e){this.nativeRange.selectNode(e),r(this)},f.cloneContents=function(){return this.nativeRange.cloneContents()},f.surroundContents=function(e){this.nativeRange.surroundContents(e),r(this)},f.collapse=function(e){this.nativeRange.collapse(e),r(this)},f.cloneRange=function(){return new n(this.nativeRange.cloneRange())},f.refresh=function(){r(this)},f.toString=function(){return this.nativeRange.toString()};var h=document.createTextNode("test");c(document).appendChild(h);var g=document.createRange();g.setStart(h,0),g.setEnd(h,0);try{g.setStart(h,1),f.setStart=function(e,t){this.nativeRange.setStart(e,t),r(this)},f.setEnd=function(e,t){this.nativeRange.setEnd(e,t),r(this)},u=function(e){return function(t){this.nativeRange[e](t),r(this)}}}catch(p){f.setStart=function(e,t){try{this.nativeRange.setStart(e,t)}catch(n){this.nativeRange.setEnd(e,t),this.nativeRange.setStart(e,t)}r(this)},f.setEnd=function(e,t){try{this.nativeRange.setEnd(e,t)}catch(n){this.nativeRange.setStart(e,t),this.nativeRange.setEnd(e,t)}r(this)},u=function(e,t){return function(n){try{this.nativeRange[e](n)}catch(o){this.nativeRange[t](n),this.nativeRange[e](n)}r(this)}}}f.setStartBefore=u("setStartBefore","setEndBefore"),f.setStartAfter=u("setStartAfter","setEndAfter"),f.setEndBefore=u("setEndBefore","setStartBefore"),f.setEndAfter=u("setEndAfter","setStartAfter"),f.selectNodeContents=function(e){this.setStartAndEnd(e,0,o.getNodeLength(e))},g.selectNodeContents(h),g.setEnd(h,3);var m=document.createRange();m.selectNodeContents(h),m.setEnd(h,4),m.setStart(h,2),f.compareBoundaryPoints=-1==g.compareBoundaryPoints(g.START_TO_END,m)&&1==g.compareBoundaryPoints(g.END_TO_START,m)?function(e,t){return t=t.nativeRange||t,e==t.START_TO_END?e=t.END_TO_START:e==t.END_TO_START&&(e=t.START_TO_END),this.nativeRange.compareBoundaryPoints(e,t)}:function(e,t){return this.nativeRange.compareBoundaryPoints(e,t.nativeRange||t)};var R=document.createElement("div");R.innerHTML="123";var v=R.firstChild,C=c(document);C.appendChild(R),g.setStart(v,1),g.setEnd(v,2),g.deleteContents(),"13"==v.data&&(f.deleteContents=function(){this.nativeRange.deleteContents(),r(this)},f.extractContents=function(){var e=this.nativeRange.extractContents();return r(this),e}),C.removeChild(R),C=null,i.isHostMethod(g,"createContextualFragment")&&(f.createContextualFragment=function(e){return this.nativeRange.createContextualFragment(e)}),c(document).removeChild(h),f.getName=function(){return"WrappedRange"},e.WrappedRange=n,e.createNativeRange=function(e){return e=d(e,t,"createNativeRange"),e.createRange()}}(),e.features.implementsTextRange){var u=function(e){var t=e.parentElement(),n=e.duplicate();n.collapse(!0);var r=n.parentElement();n=e.duplicate(),n.collapse(!1);var i=n.parentElement(),a=r==i?r:o.getCommonAncestor(r,i);return a==t?a:o.getCommonAncestor(t,a)},l=function(e){return 0==e.compareEndPoints("StartToEnd",e)},h=function(e,t,n,r,i){var s=e.duplicate();s.collapse(n);var c=s.parentElement();if(o.isOrIsAncestorOf(t,c)||(c=t),!c.canHaveHTML){var d=new a(c.parentNode,o.getNodeIndex(c));return{boundaryPosition:d,nodeInfo:{nodeIndex:d.offset,containerElement:d.node}}}var u=o.getDocument(c).createElement("span");u.parentNode&&o.removeNode(u);for(var l,h,g,p,m,R=n?"StartToStart":"StartToEnd",v=i&&i.containerElement==c?i.nodeIndex:0,C=c.childNodes.length,N=C,E=N;;){if(E==C?c.appendChild(u):c.insertBefore(u,c.childNodes[E]),s.moveToElementText(u),l=s.compareEndPoints(R,e),0==l||v==N)break;if(-1==l){if(N==v+1)break;v=E}else N=N==v+1?v:E;E=Math.floor((v+N)/2),c.removeChild(u)}if(m=u.nextSibling,-1==l&&m&&f(m)){s.setEndPoint(n?"EndToStart":"EndToEnd",e);var S;if(/[\r\n]/.test(m.data)){var y=s.duplicate(),w=y.text.replace(/\r\n/g,"\r").length;for(S=y.moveStart("character",w);-1==(l=y.compareEndPoints("StartToEnd",y));)S++,y.moveStart("character",1)}else S=s.text.length;p=new a(m,S)}else h=(r||!n)&&u.previousSibling,g=(r||n)&&u.nextSibling,p=g&&f(g)?new a(g,0):h&&f(h)?new a(h,h.data.length):new a(c,o.getNodeIndex(u));return o.removeNode(u),{boundaryPosition:p,nodeInfo:{nodeIndex:E,containerElement:c}}},g=function(e,t){var n,r,i,a,s=e.offset,d=o.getDocument(e.node),u=c(d).createTextRange(),l=f(e.node);return l?(n=e.node,r=n.parentNode):(a=e.node.childNodes,n=st;++t)if(!D.isAncestorOf(e[0],e[t]))return!1;return!0}function l(e){var n=e.getNodes();if(!u(n))throw t.createError("getSingleElementFromRange: range "+e.inspect()+" did not consist of a single element");return n[0]}function h(e){return!!e&&"undefined"!=typeof e.text}function g(e,t){var n=new P(t);e._ranges=[n],s(e,n,!1),e.rangeCount=1,e.isCollapsed=n.collapsed}function p(t){if(t._ranges.length=0,"None"==t.docSelection.type)d(t);else{var n=t.docSelection.createRange();if(h(n))g(t,n);else{t.rangeCount=n.length;for(var r,o=k(n.item(0)),i=0;is;++s)a.add(r.item(s));try{a.add(o)}catch(d){throw t.createError("addRange(): Element within the specified Range could not be added to control selection (does it have layout?)")}a.select(),p(e)}function R(e,t,n){this.nativeSelection=e,this.docSelection=t,this._ranges=[],this.win=n,this.refresh()}function v(e){e.win=e.anchorNode=e.focusNode=e._ranges=null,e.rangeCount=e.anchorOffset=e.focusOffset=0,e.detached=!0}function C(e,t){for(var n,r,o=tt.length;o--;)if(n=tt[o],r=n.selection,"deleteAll"==t)v(r);else if(n.win==e)return"delete"==t?(tt.splice(o,1),!0):r;return"deleteAll"==t&&(tt.length=0),null}function N(e,n){for(var r,o=k(n[0].startContainer),i=L(o).createControlRange(),a=0,s=n.length;s>a;++a){r=l(n[a]);try{i.add(r)}catch(c){throw t.createError("setRanges(): Element within one of the specified Ranges could not be added to control selection (does it have layout?)")}}i.select(),p(e)}function E(e,t){if(e.win.document!=k(t))throw new I("WRONG_DOCUMENT_ERR")}function S(t){return function(n,r){var o;this.rangeCount?(o=this.getRangeAt(0),o["set"+(t?"Start":"End")](n,r)):(o=e.createRange(this.win.document),o.setStartAndEnd(n,r)),this.setSingleRange(o,this.isBackward())}}function y(e){var t=[],n=new B(e.anchorNode,e.anchorOffset),r=new B(e.focusNode,e.focusOffset),o="function"==typeof e.getName?e.getName():"Selection";if("undefined"!=typeof e.rangeCount)for(var i=0,a=e.rangeCount;a>i;++i)t[i]=b.inspect(e.getRangeAt(i));return"["+o+"(Ranges: "+t.join(", ")+")(anchor: "+n.inspect()+", focus: "+r.inspect()+"]"}e.config.checkSelectionRanges=!0;var w,T,O="boolean",_="number",D=e.dom,A=e.util,x=A.isHostMethod,b=e.DomRange,P=e.WrappedRange,I=e.DOMException,B=D.DomPosition,H=e.features,M="Control",k=D.getDocument,L=D.getBody,W=b.rangesEqual,F=x(window,"getSelection"),j=A.isHostObject(document,"selection");H.implementsWinGetSelection=F,H.implementsDocSelection=j;var z=j&&(!F||e.config.preferTextRange);if(z)w=i,e.isSelectionValid=function(e){var t=r(e,"isSelectionValid").document,n=t.selection;return"None"!=n.type||k(n.createRange().parentElement())==t};else{if(!F)return t.fail("Neither document.selection or window.getSelection() detected."),!1;w=o,e.isSelectionValid=function(){return!0}}e.getNativeSelection=w;var U=w();if(!U)return t.fail("Native selection was null (possibly issue 138?)"),!1;var V=e.createNativeRange(document),q=L(document),Y=A.areHostProperties(U,["anchorNode","focusNode","anchorOffset","focusOffset"]);H.selectionHasAnchorAndFocus=Y;var Q=x(U,"extend");H.selectionHasExtend=Q;var G=typeof U.rangeCount==_;H.selectionHasRangeCount=G;var X=!1,Z=!0,$=Q?function(t,n){var r=b.getRangeDocument(n),o=e.createRange(r);o.collapseToPoint(n.endContainer,n.endOffset),t.addRange(f(o)),t.extend(n.startContainer,n.startOffset)}:null;A.areHostMethods(U,["addRange","getRangeAt","removeAllRanges"])&&typeof U.rangeCount==_&&H.implementsDomRange&&!function(){var t=window.getSelection();if(t){for(var n=t.rangeCount,r=n>1,o=[],i=a(t),s=0;n>s;++s)o[s]=t.getRangeAt(s);var c=D.createTestElement(document,"",!1),d=c.appendChild(document.createTextNode(" ")),f=document.createRange();if(f.setStart(d,1),f.collapse(!0),t.removeAllRanges(),t.addRange(f),Z=1==t.rangeCount,t.removeAllRanges(),!r){var u=window.navigator.appVersion.match(/Chrome\/(.*?) /);if(u&&parseInt(u[1])>=36)X=!1;else{var l=f.cloneRange();f.setStart(d,0),l.setEnd(d,3),l.setStart(d,2),t.addRange(f),t.addRange(l),X=2==t.rangeCount}}for(D.removeNode(c),t.removeAllRanges(),s=0;n>s;++s)0==s&&i?$?$(t,o[s]):(e.warn("Rangy initialization: original selection was backwards but selection has been restored forwards because the browser does not support Selection.extend"),t.addRange(o[s])):t.addRange(o[s])}}(),H.selectionSupportsMultipleRanges=X,H.collapsedNonEditableSelectionsSupported=Z;var J,K=!1;q&&x(q,"createControlRange")&&(J=q.createControlRange(),A.areHostProperties(J,["item","add"])&&(K=!0)),H.implementsControlRange=K,T=Y?function(e){return e.anchorNode===e.focusNode&&e.anchorOffset===e.focusOffset}:function(e){return e.rangeCount?e.getRangeAt(e.rangeCount-1).collapsed:!1};var et;x(U,"getRangeAt")?et=function(e,t){try{return e.getRangeAt(t)}catch(n){return null}}:Y&&(et=function(t){var n=k(t.anchorNode),r=e.createRange(n);return r.setStartAndEnd(t.anchorNode,t.anchorOffset,t.focusNode,t.focusOffset),r.collapsed!==this.isCollapsed&&r.setStartAndEnd(t.focusNode,t.focusOffset,t.anchorNode,t.anchorOffset),r}),R.prototype=e.selectionPrototype;var tt=[],nt=function(e){if(e&&e instanceof R)return e.refresh(),e;e=r(e,"getNativeSelection");var t=C(e),n=w(e),o=j?i(e):null;return t?(t.nativeSelection=n,t.docSelection=o,t.refresh()):(t=new R(n,o,e),tt.push({win:e,selection:t})),t};e.getSelection=nt,A.createAliasForDeprecatedMethod(e,"getIframeSelection","getSelection");var rt=R.prototype;if(!z&&Y&&A.areHostMethods(U,["removeAllRanges","addRange"])){rt.removeAllRanges=function(){this.nativeSelection.removeAllRanges(),d(this)};var ot=function(e,t){$(e.nativeSelection,t),e.refresh()};rt.addRange=G?function(t,r){if(K&&j&&this.docSelection.type==M)m(this,t);else if(n(r)&&Q)ot(this,t);else{var o;X?o=this.rangeCount:(this.removeAllRanges(),o=0);var i=f(t).cloneRange();try{this.nativeSelection.addRange(i)}catch(a){}if(this.rangeCount=this.nativeSelection.rangeCount,this.rangeCount==o+1){if(e.config.checkSelectionRanges){var c=et(this.nativeSelection,this.rangeCount-1);c&&!W(c,t)&&(t=new P(c))}this._ranges[this.rangeCount-1]=t,s(this,t,st(this.nativeSelection)),this.isCollapsed=T(this)}else this.refresh()}}:function(e,t){n(t)&&Q?ot(this,e):(this.nativeSelection.addRange(f(e)),this.refresh())},rt.setRanges=function(e){if(K&&j&&e.length>1)N(this,e);else{this.removeAllRanges();for(var t=0,n=e.length;n>t;++t)this.addRange(e[t])}}}else{if(!(x(U,"empty")&&x(V,"select")&&K&&z))return t.fail("No means of selecting a Range or TextRange was found"),!1;rt.removeAllRanges=function(){try{if(this.docSelection.empty(),"None"!=this.docSelection.type){var e;if(this.anchorNode)e=k(this.anchorNode);else if(this.docSelection.type==M){var t=this.docSelection.createRange();t.length&&(e=k(t.item(0)))}if(e){var n=L(e).createTextRange();n.select(),this.docSelection.empty()}}}catch(r){}d(this)},rt.addRange=function(t){this.docSelection.type==M?m(this,t):(e.WrappedTextRange.rangeToTextRange(t).select(),this._ranges[0]=t,this.rangeCount=1,this.isCollapsed=this._ranges[0].collapsed,s(this,t,!1))},rt.setRanges=function(e){this.removeAllRanges();var t=e.length;t>1?N(this,e):t&&this.addRange(e[0])}}rt.getRangeAt=function(e){if(0>e||e>=this.rangeCount)throw new I("INDEX_SIZE_ERR");return this._ranges[e].cloneRange()};var it;if(z)it=function(t){var n;e.isSelectionValid(t.win)?n=t.docSelection.createRange():(n=L(t.win.document).createTextRange(),n.collapse(!0)),t.docSelection.type==M?p(t):h(n)?g(t,n):d(t)};else if(x(U,"getRangeAt")&&typeof U.rangeCount==_)it=function(t){if(K&&j&&t.docSelection.type==M)p(t);else if(t._ranges.length=t.rangeCount=t.nativeSelection.rangeCount,t.rangeCount){for(var n=0,r=t.rangeCount;r>n;++n)t._ranges[n]=new e.WrappedRange(t.nativeSelection.getRangeAt(n));s(t,t._ranges[t.rangeCount-1],st(t.nativeSelection)),t.isCollapsed=T(t)}else d(t)};else{if(!Y||typeof U.isCollapsed!=O||typeof V.collapsed!=O||!H.implementsDomRange)return t.fail("No means of obtaining a Range or TextRange from the user's selection was found"),!1;it=function(e){var t,n=e.nativeSelection;n.anchorNode?(t=et(n,0),e._ranges=[t],e.rangeCount=1,c(e),e.isCollapsed=T(e)):d(e)}}rt.refresh=function(e){var t=e?this._ranges.slice(0):null,n=this.anchorNode,r=this.anchorOffset;if(it(this),e){var o=t.length;if(o!=this._ranges.length)return!0;if(this.anchorNode!=n||this.anchorOffset!=r)return!0;for(;o--;)if(!W(t[o],this._ranges[o]))return!0;return!1}};var at=function(e,t){var n=e.getAllRanges();e.removeAllRanges();for(var r=0,o=n.length;o>r;++r)W(t,n[r])||e.addRange(n[r]);e.rangeCount||d(e)};rt.removeRange=K&&j?function(e){if(this.docSelection.type==M){for(var t,n=this.docSelection.createRange(),r=l(e),o=k(n.item(0)),i=L(o).createControlRange(),a=!1,s=0,c=n.length;c>s;++s)t=n.item(s),t!==r||a?i.add(n.item(s)):a=!0;i.select(),p(this)}else at(this,e)}:function(e){at(this,e)};var st;!z&&Y&&H.implementsDomRange?(st=a,rt.isBackward=function(){return st(this)}):st=rt.isBackward=function(){return!1},rt.isBackwards=rt.isBackward,rt.toString=function(){for(var e=[],t=0,n=this.rangeCount;n>t;++t)e[t]=""+this._ranges[t];return e.join("")},rt.collapse=function(t,n){E(this,t);var r=e.createRange(t);r.collapseToPoint(t,n),this.setSingleRange(r),this.isCollapsed=!0},rt.collapseToStart=function(){if(!this.rangeCount)throw new I("INVALID_STATE_ERR");var e=this._ranges[0];this.collapse(e.startContainer,e.startOffset)},rt.collapseToEnd=function(){if(!this.rangeCount)throw new I("INVALID_STATE_ERR");var e=this._ranges[this.rangeCount-1];this.collapse(e.endContainer,e.endOffset)},rt.selectAllChildren=function(t){E(this,t);var n=e.createRange(t);n.selectNodeContents(t),this.setSingleRange(n)},rt.deleteFromDocument=function(){if(K&&j&&this.docSelection.type==M){for(var e,t=this.docSelection.createRange();t.length;)e=t.item(0),t.remove(e),D.removeNode(e);this.refresh()}else if(this.rangeCount){var n=this.getAllRanges();if(n.length){this.removeAllRanges();for(var r=0,o=n.length;o>r;++r)n[r].deleteContents();this.addRange(n[o-1])}}},rt.eachRange=function(e,t){for(var n=0,r=this._ranges.length;r>n;++n)if(e(this.getRangeAt(n)))return t},rt.getAllRanges=function(){var e=[];return this.eachRange(function(t){e.push(t)}),e},rt.setSingleRange=function(e,t){this.removeAllRanges(),this.addRange(e,t)},rt.callMethodOnEachRange=function(e,t){var n=[];return this.eachRange(function(r){n.push(r[e].apply(r,t||[]))}),n},rt.setStart=S(!0),rt.setEnd=S(!1),e.rangePrototype.select=function(e){nt(this.getDocument()).setSingleRange(this,e)},rt.changeEachRange=function(e){var t=[],n=this.isBackward();this.eachRange(function(n){e(n),t.push(n)}),this.removeAllRanges(),n&&1==t.length?this.addRange(t[0],"backward"):this.setRanges(t)},rt.containsNode=function(e,t){return this.eachRange(function(n){return n.containsNode(e,t)},!0)||!1},rt.getBookmark=function(e){return{backward:this.isBackward(),rangeBookmarks:this.callMethodOnEachRange("getBookmark",[e])}},rt.moveToBookmark=function(t){for(var n,r,o=[],i=0;n=t.rangeBookmarks[i++];)r=e.createRange(this.win),r.moveToBookmark(n),o.push(r);t.backward?this.setSingleRange(o[0],"backward"):this.setRanges(o)},rt.saveRanges=function(){return{backward:this.isBackward(),ranges:this.callMethodOnEachRange("cloneRange")}},rt.restoreRanges=function(e){this.removeAllRanges();for(var t,n=0;t=e.ranges[n];++n)this.addRange(t,e.backward&&0==n)},rt.toHtml=function(){var e=[];return this.eachRange(function(t){e.push(b.toHtml(t))}),e.join("")},H.implementsTextRange&&(rt.getNativeTextRange=function(){var n;if(n=this.docSelection){var r=n.createRange();if(h(r))return r;throw t.createError("getNativeTextRange: selection is a control selection")}if(this.rangeCount>0)return e.WrappedTextRange.rangeToTextRange(this.getRangeAt(0));throw t.createError("getNativeTextRange: selection contains no range")}),rt.getName=function(){return"WrappedSelection"},rt.inspect=function(){return y(this)},rt.detach=function(){C(this.win,"delete"),v(this)},R.detachAll=function(){C(null,"deleteAll")},R.inspect=y,R.isDirectionBackward=n,e.Selection=R,e.selectionPrototype=rt,e.addShimListener(function(e){"undefined"==typeof e.getSelection&&(e.getSelection=function(){return nt(e)}),e=null})});var L=!1,W=function(){L||(L=!0,!I.initialized&&I.config.autoInitialize&&u())};return b&&("complete"==document.readyState?W():(e(document,"addEventListener")&&document.addEventListener("DOMContentLoaded",W,!1),H(window,"load",W))),I},this);
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
index e9bf94e4..55978aec 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -6,13 +6,14 @@
-
+
+
-
+
@@ -81,7 +82,7 @@