From 2e6f12725bc01011c545c99c1f1c1da6065063d9 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 1 Jan 2014 00:41:45 -0600 Subject: [PATCH 001/545] #1744: Refactor document delta handling Refactor delta handling code to: - Combine the "insertText" and "insertLines" delta types into a single "insert" delta type - Combine the "removeText" and "removeLines" delta types into a single "remove" delta type - Make all document mutations in a single applyDelta function. - Add basic delta validation (more needed . . . see TODOs) - Rework anchor logic to handle new delta types (also simplified) - Rename "insert()" to "insertText()" and "remove()" to "removeText()" - Rename "insertLines()" to "insertFullLines()" and "removeLines()" to "removeFullLines()" See related issue for more information. All tests are passing and the changes appear functional under preliminary testing, but careful review and testing will be necessary. --- lib/ace/anchor.js | 108 +++--- lib/ace/anchor_test.js | 16 +- lib/ace/autocomplete.js | 2 +- lib/ace/background_tokenizer.js | 2 +- lib/ace/background_tokenizer_test.js | 2 +- lib/ace/commands/default_commands.js | 4 +- lib/ace/document.js | 516 +++++++++++++------------ lib/ace/document_test.js | 18 +- lib/ace/edit_session.js | 58 ++- lib/ace/edit_session/folding.js | 2 +- lib/ace/edit_session_test.js | 18 +- lib/ace/editor.js | 39 +- lib/ace/editor_change_document_test.js | 2 +- lib/ace/editor_navigation_test.js | 2 +- lib/ace/ext/chromevox.js | 4 +- lib/ace/ext/elastic_tabstops_lite.js | 2 +- lib/ace/ext/whitespace.js | 2 +- lib/ace/keyboard/vim/commands.js | 10 +- lib/ace/keyboard/vim/maps/motions.js | 6 +- lib/ace/layer/gutter.js | 4 +- lib/ace/line_widgets.js | 2 +- lib/ace/mode/javascript_test.js | 2 +- lib/ace/mode/text.js | 12 +- lib/ace/mouse/dragdrop_handler.js | 2 +- lib/ace/multi_select.js | 10 +- lib/ace/occur_test.js | 12 +- lib/ace/placeholder.js | 12 +- lib/ace/placeholder_test.js | 18 +- 28 files changed, 437 insertions(+), 450 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 3a62e632..91a62eb0 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -100,67 +100,55 @@ var Anchor = exports.Anchor = function(doc, row, column) { * **/ this.onChange = function(e) { - var delta = e.data; - var range = delta.range; - - if (range.start.row == range.end.row && range.start.row != this.row) - return; - - if (range.start.row > this.row) - return; - - if (range.start.row == this.row && range.start.column > this.column) - return; - - var row = this.row; - var column = this.column; - var start = range.start; - var end = range.end; - - if (delta.action === "insertText") { - if (start.row === row && start.column <= column) { - if (start.column === column && this.$insertRight) { - // do nothing - } else if (start.row === end.row) { - column += end.column - start.column; - } else { - column -= start.column; - row += end.row - start.row; - } - } else if (start.row !== end.row && start.row < row) { - row += end.row - start.row; - } - } else if (delta.action === "insertLines") { - if (start.row <= row) { - row += end.row - start.row; - } - } else if (delta.action === "removeText") { - if (start.row === row && start.column < column) { - if (end.column >= column) - column = start.column; - else - column = Math.max(0, column - (end.column - start.column)); - - } else if (start.row !== end.row && start.row < row) { - if (end.row === row) - column = Math.max(0, column - end.column) + start.column; - row -= (end.row - start.row); - } else if (end.row === row) { - row -= end.row - start.row; - column = Math.max(0, column - end.column) + start.column; - } - } else if (delta.action == "removeLines") { - if (start.row <= row) { - if (end.row <= row) - row -= end.row - start.row; - else { - row = start.row; - column = 0; - } - } + + function _pointsInOrder(point1, point2, equalPointsInOrder) + { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); } - - this.setPosition(row, column, true); + + function getTransformedPoint(delta, point, moveIfEqual) + { + // Get delta info. + var deltaIsInsert = (delta.action == 'insert') + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.row - delta.range.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.column - delta.range.start.column); + var deltaStart = delta.range.start; + var deltaEnd = (deltaIsInsert ? deltaStart : delta.range.end); // Collapse insert range. + + // DELTA AFTER POINT: No change needed. + if (_pointsInOrder(point, deltaStart, moveIfEqual)) + { + return ( + { + row: point.row, + column: point.column + }); + } + + // DELTA BEFORE POINT: Move point by delta shift. + if (_pointsInOrder(deltaEnd, point, !moveIfEqual)) + { + return ( + { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }); + } + + // DELTA ENVELOPS POINT (delete only): Move point to delta start. + if (delta.action != 'delete') + throw 'Delete action expected.'; + return ( + { + row: deltaStart.row, + column: deltaStart.column + }); + } + + var delta = e.data; + var point = getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); + this.setPosition(point.row, point.column, true); }; /** diff --git a/lib/ace/anchor_test.js b/lib/ace/anchor_test.js index 2d7fcb63..0588c9b6 100644 --- a/lib/ace/anchor_test.js +++ b/lib/ace/anchor_test.js @@ -54,7 +54,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insert({row: 1, column: 1}, "123"); + doc.insertText({row: 1, column: 1}, "123"); assert.position(anchor.getPosition(), 1, 7); }, @@ -62,7 +62,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertLines(1, ["123", "456"]); + doc.insertFullLines(1, ["123", "456"]); assert.position(anchor.getPosition(), 3, 4); }, @@ -70,7 +70,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertNewLine({row: 0, column: 0}); + doc.insertLines({row: 0, column: 0}, ['', '']); assert.position(anchor.getPosition(), 2, 4); }, @@ -78,7 +78,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertNewLine({row: 1, column: 2}); + doc.insertLines({row: 1, column: 2}, ['', '']); assert.position(anchor.getPosition(), 2, 2); }, @@ -110,7 +110,7 @@ module.exports = { var doc = new Document("juhu\n1\n2\nkinners"); var anchor = new Anchor(doc, 3, 4); - doc.removeLines(1, 2); + doc.removeFullLines(1, 2); assert.position(anchor.getPosition(), 1, 4); }, @@ -134,7 +134,7 @@ module.exports = { var doc = new Document("juhu\nkinners\n123"); var anchor = new Anchor(doc, 1, 5); - doc.removeLines(1, 1); + doc.removeFullLines(1, 1); assert.position(anchor.getPosition(), 1, 0); }, @@ -173,9 +173,9 @@ module.exports = { var doc = new Document("juhu\nkinners\n123"); var anchor = new Anchor(doc, 2, 4); - doc.removeLines(0, 3); + doc.removeFullLines(0, 3); assert.position(anchor.getPosition(), 0, 0); - doc.insertLines(0, ["a", "b", "c"]); + doc.insertFullLines(0, ["a", "b", "c"]); assert.position(anchor.getPosition(), 3, 0); assert.equal(doc.getValue(), "a\nb\nc\n"); } diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 50154c01..2344aede 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -170,7 +170,7 @@ var Autocomplete = function() { "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, "Esc": function(editor) { editor.completer.detach(); }, - "Space": function(editor) { editor.completer.detach(); editor.insert(" ");}, + "Space": function(editor) { editor.completer.detach(); editor.insertText(" ");}, "Return": function(editor) { editor.completer.insertMatch(); }, "Shift-Return": function(editor) { editor.completer.insertMatch(true); }, "Tab": function(editor) { editor.completer.insertMatch(); }, diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 217be1b3..cb3ffe23 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -183,7 +183,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { if (len === 0) { this.lines[startRow] = null; - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "delete") { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { diff --git a/lib/ace/background_tokenizer_test.js b/lib/ace/background_tokenizer_test.js index 7a4cc78c..16c63132 100644 --- a/lib/ace/background_tokenizer_test.js +++ b/lib/ace/background_tokenizer_test.js @@ -70,7 +70,7 @@ module.exports = { forceTokenize(doc) testStates(doc, ["comment_regex_allowed", "comment_regex_allowed"]) - doc.insert({row:0, column:2}, "\n*/") + doc.insertText({row:0, column:2}, "\n*/") testStates(doc, [undefined, undefined, "comment_regex_allowed"]) forceTokenize(doc) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index e4a8212e..0fd9686c 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -508,13 +508,13 @@ exports.commands = [{ scrollIntoView: "selectionPart" }, { name: "insertstring", - exec: function(editor, str) { editor.insert(str); }, + exec: function(editor, str) { editor.insertText(str); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "inserttext", exec: function(editor, args) { - editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); + editor.insertText(lang.stringRepeat(args.text || "", args.times || 1)); }, multiSelectAction: "forEach" }, { diff --git a/lib/ace/document.js b/lib/ace/document.js index 75a7920d..ace69e32 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -51,17 +51,17 @@ var Anchor = require("./anchor").Anchor; * @constructor **/ -var Document = function(text) { - this.$lines = []; +var Document = function(textOrLines) { + this.$lines = ['']; // There has to be one line at least in the document. If you pass an empty // string to the insert function, nothing will happen. Workaround. - if (text.length == 0) { + if (textOrLines.length == 0) { this.$lines = [""]; - } else if (Array.isArray(text)) { - this._insertLines(0, text); + } else if (Array.isArray(textOrLines)) { + this.insertLines({row: 0, column: 0}, textOrLines); } else { - this.insert({row: 0, column:0}, text); + this.insertText({row: 0, column:0}, textOrLines); } }; @@ -77,7 +77,7 @@ var Document = function(text) { this.setValue = function(text) { var len = this.getLength(); this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insert({row: 0, column:0}, text); + this.insertText({row: 0, column:0}, text); }; /** @@ -211,27 +211,85 @@ var Document = function(text) { * @returns {String} **/ this.getTextRange = function(range) { + return this._getLinesForRange(range).join(this.getNewLineCharacter()); + }; + + this._getLinesForRange = function(range) { if (range.start.row == range.end.row) { - return this.getLine(range.start.row) - .substring(range.start.column, range.end.column); + return [this.getLine(range.start.row) + .substring(range.start.column, range.end.column)]; } var lines = this.getLines(range.start.row, range.end.row); lines[0] = (lines[0] || "").substring(range.start.column); var l = lines.length - 1; if (range.end.row - range.start.row == l) lines[l] = lines[l].substring(0, range.end.column); - return lines.join(this.getNewLineCharacter()); + return lines; }; this.$clipPosition = function(position) { + var length = this.getLength(); - if (position.row >= length) { + if (position.row >= length) + { position.row = Math.max(0, length - 1); - position.column = this.getLine(length-1).length; - } else if (position.row < 0) - position.row = 0; + position.column = this.getLine(length - 1).length; + } + else + { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); + } return position; }; + + this.$getClippedRange = function(range) + { + // Get Range object. + if (!range instanceof Range) + range = Range.fromPoints(range.start, range.end); + + // Return clipped range. + this.$clipPosition(range.start); + this.$clipPosition(range.end); + return range; + } + + this.$validateDelta = function(delta) + { + function fnThrow(errorText) + { + errorText = 'Invalid Delta: ' + errorText; + console.log(errorText, delta); + throw errorText; + } + + if (!delta.lines instanceof Array) + { + fnThrow('Delta object lines must be an array'); + } + + if (!delta.range instanceof Range) + { + fnThrow('Range object is not an instance of the Range class'); + } + + var start = delta.range.start; + if (Math.min(Math.max(start.row, 0), this.getLength() - 1 ) != start.row || + Math.min(Math.max(start.column, 0), this.$lines[start.row].length) != start.column) + { + fnThrow('Range start point not contained in document'); + } + + if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row) + { + fnThrow('Range row offsets does not match delta lines'); + } + + // TODO: Validate that the ending column offset matches the lines. + // TODO: Validate for deletions that the lines deleted match the lines + // in the document. + }, /** * Inserts a block of `text` at the indicated `position`. @@ -240,54 +298,34 @@ var Document = function(text) { * @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. * **/ - this.insert = function(position, text) { - if (!text || text.length === 0) - return position; - - position = this.$clipPosition(position); - - // only detect new lines if the document has no line break yet + this.insertText = function(position, text) { + + // Only detect new lines if the document has no line break yet. if (this.getLength() <= 1) this.$detectNewLine(text); - - var lines = this.$split(text); - var firstLine = lines.splice(0, 1)[0]; - var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; - - position = this.insertInLine(position, firstLine); - if (lastLine !== null) { - position = this.insertNewLine(position); // terminate first line - position = this._insertLines(position.row, lines); - position = this.insertInLine(position, lastLine || ""); - } - return position; + + return this.insertLines(position, this.$split(text)); }; /** - * Fires whenever the document changes. - * - * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: - * - * * `"insertLines"` (emitted by [[Document.insertLines]]) - * * `range`: the [[Range]] of the change within the document - * * `lines`: the lines in the document that are changing - * * `"insertText"` (emitted by [[Document.insertNewLine]]) - * * `range`: the [[Range]] of the change within the document - * * `text`: the text that's being added - * * `"removeLines"` (emitted by [[Document.insertLines]]) - * * `range`: the [[Range]] of the change within the document - * * `lines`: the lines in the document that were removed - * * `nl`: the new line character (as defined by [[Document.getNewLineCharacter]]) - * * `"removeText"` (emitted by [[Document.removeInLine]] and [[Document.removeNewLine]]) - * * `range`: the [[Range]] of the change within the document - * * `text`: the text that's being removed - * - * @event change - * @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. - * - **/ + * Fires whenever the document changes. + * + * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: + * + * * `"insert"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being added + * * `"delete"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being removed + * + * @event change + * @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. + * + **/ + /** - * Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event. + * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `'change'` event. * @param {Number} row The index of the row to insert at * @param {Array} lines An array of strings * @returns {Object} Contains the final row and column, like this: @@ -300,100 +338,62 @@ var Document = function(text) { * ``` * **/ - this.insertLines = function(row, lines) { - if (row >= this.getLength()) - return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); - return this._insertLines(Math.max(row, 0), lines); - }; - this._insertLines = function(row, lines) { - if (lines.length == 0) - return {row: row, column: 0}; - - // apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF) - // to circumvent that we have to break huge inserts into smaller chunks here - if (lines.length > 0xFFFF) { - var end = this._insertLines(row, lines.slice(0xFFFF)); - lines = lines.slice(0, 0xFFFF); + this.insertFullLines = function(row, lines) + { + // Clip to document. + // Allow one past the document end. + row = Math.min(Math.max(row, 0), this.getLength()); + + // Calculate insertion point. + var column = 0; + if (row < this.getLength()) // Insert before the specified row. + { + lines = lines.concat(['']); + column = 0; } + else // Insert after the last row in the document. + { + lines = [''].concat(lines); + row--; + var column = this.$lines[row].length; + } + + // Insert. + this.insertLines({row: row, column: column}, lines); + }, - var args = [row, 0]; - args.push.apply(args, lines); - this.$lines.splice.apply(this.$lines, args); + /** + * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `'change'` event. + * @param {Number} row The index of the row to insert at + * @param {Array} lines An array of strings + * @returns {Object} Contains the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If `lines` is empty, this function returns an object containing the current row, and column, like this: + * ``` + * {row: row, column: 0} + * ``` + * + **/ + this.insertLines = function(position, lines){ - var range = new Range(row, 0, row + lines.length, 0); - var delta = { - action: "insertLines", - range: range, + // Calculate insertion range end point. + this.$clipPosition(position); + var endPoint = { + row : position.row + lines.length - 1, + column : (lines.length == 1 ? position.column : 0) + lines[lines.length - 1].length + }; + + // Apply delta (emits change). + this.applyDelta({ + action: "insert", + range: Range.fromPoints(position, endPoint), lines: lines - }; - this._emit("change", { data: delta }); - return end || range.end; - }; - - /** - * Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event. - * @param {Object} position The position to insert at - * @returns {Object} Returns an object containing the final row and column, like this:
- * ``` - * {row: endRow, column: 0} - * ``` - * - **/ - this.insertNewLine = function(position) { - position = this.$clipPosition(position); - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column); - this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); - - var end = { - row : position.row + 1, - column : 0 - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: this.getNewLineCharacter() - }; - this._emit("change", { data: delta }); - - return end; - }; - - /** - * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event. - * @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}` - * @param {String} text A chunk of text - * @returns {Object} Returns an object containing the final row and column, like this: - * ``` - * {row: endRow, column: 0} - * ``` - * - **/ - this.insertInLine = function(position, text) { - if (text.length == 0) - return position; - - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column) + text - + line.substring(position.column); - - var end = { - row : position.row, - column : position.column + text.length - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: text - }; - this._emit("change", { data: delta }); - - return end; - }; + }); + + return endPoint; + } /** * Removes the `range` from the document. @@ -402,37 +402,16 @@ var Document = function(text) { * **/ this.remove = function(range) { - if (!range instanceof Range) - range = Range.fromPoints(range.start, range.end); - // clip to document - range.start = this.$clipPosition(range.start); - range.end = this.$clipPosition(range.end); - - if (range.isEmpty()) - return range.start; - - var firstRow = range.start.row; - var lastRow = range.end.row; - - if (range.isMultiLine()) { - var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; - var lastFullRow = lastRow - 1; - - if (range.end.column > 0) - this.removeInLine(lastRow, 0, range.end.column); - - if (lastFullRow >= firstFullRow) - this._removeLines(firstFullRow, lastFullRow); - - if (firstFullRow != firstRow) { - this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); - this.removeNewLine(range.start.row); - } - } - else { - this.removeInLine(firstRow, range.start.column, range.end.column); - } - return range.start; + + // Apply delta (emits change). + range = this.$getClippedRange(range); + this.applyDelta( + { + action: 'delete', + range: range, + lines: this._getLinesForRange(range), + }); + return range.start; }; /** @@ -444,21 +423,18 @@ var Document = function(text) { * **/ this.removeInLine = function(row, startColumn, endColumn) { - if (startColumn == endColumn) - return; - + + // Calculate deleteion range. var range = new Range(row, startColumn, row, endColumn); - var line = this.getLine(row); - var removed = line.substring(startColumn, endColumn); - var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); - this.$lines.splice(row, 1, newLine); - - var delta = { - action: "removeText", + range = this.$getClippedRange(range); + + // Apply delta (emits change). + this.applyDelta({ + action: "delete", range: range, - text: removed - }; - this._emit("change", { data: delta }); + lines: this._getLinesForRange(range) + }); + return range.start; }; @@ -469,24 +445,35 @@ var Document = function(text) { * @returns {[String]} Returns all the removed lines. * **/ - this.removeLines = function(firstRow, lastRow) { - if (firstRow < 0 || lastRow >= this.getLength()) - return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); - return this._removeLines(firstRow, lastRow); - }; - - this._removeLines = function(firstRow, lastRow) { - var range = new Range(firstRow, 0, lastRow + 1, 0); - var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); - - var delta = { - action: "removeLines", + this.removeFullLines = function(firstRow, lastRow) { + + // Clip to document. + firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); + lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); + + // Calculate deletion range. + // Delete the ending new line unless we're at the end of the document. + // If we're at the end of the document, delete the starting new line. + var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; + var deleteLastNewLine = lastRow < this.getLength() - 1; + var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); + var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); + var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); + var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); + var range = new Range(startRow, startCol, endRow, endCol); + + // Store delelted lines with bounding newlines ommitted (maintains previous behavior). + var deletedLines = this.$lines.slice(firstRow, lastRow + 1); + + // Apply delta (emits change). + this.applyDelta({ + action: "delete", range: range, - nl: this.getNewLineCharacter(), - lines: removed - }; - this._emit("change", { data: delta }); - return removed; + lines: this._getLinesForRange(range) + }); + + // Return the deleted lines. + return deletedLines; }; /** @@ -495,20 +482,16 @@ var Document = function(text) { * **/ this.removeNewLine = function(row) { - var firstLine = this.getLine(row); - var secondLine = this.getLine(row+1); - - var range = new Range(row, firstLine.length, row+1, 0); - var line = firstLine + secondLine; - - this.$lines.splice(row, 2, line); - - var delta = { - action: "removeText", - range: range, - text: this.getNewLineCharacter() - }; - this._emit("change", { data: delta }); + + if (row < this.getLength() - 1 && row >= 0) + { + // Apply delta (emits change). + this.applyDelta({ + action: "delete", + range: new Range(row, this.getLine(row).length, row + 1, 0), + lines: ['', ''] + }); + } }; /** @@ -534,53 +517,90 @@ var Document = function(text) { this.remove(range); if (text) { - var end = this.insert(range.start, text); + var end = this.insertText(range.start, text); } else { end = range.start; } - + return end; }; /** - * Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. + * Applies all the changes previously accumulated. These can be either `'insert'` or `'delete'`. **/ this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { - var delta = deltas[i]; - - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this._removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "insertText") - this.remove(range); - else if (delta.action == "removeLines") - this._insertLines(range.start.row, delta.lines); - else if (delta.action == "removeText") - this.insert(range.start, delta.text); + this.revertDelta(deltas[i]); } }; + + this.revertDelta = function(delta) + { + this.applyDelta({ + action: (delta.action == 'insert' ? 'delete' : 'insert'), + range: delta.range.clone(), + lines: delta.lines.slice() + }); + }, /** * Converts an index position in a document to a `{row, column}` object. diff --git a/lib/ace/document_test.js b/lib/ace/document_test.js index 5c324db0..50bd8b49 100644 --- a/lib/ace/document_test.js +++ b/lib/ace/document_test.js @@ -48,7 +48,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 0, column: 1}, "juhu"); + doc.insertText({row: 0, column: 1}, "juhu"); assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); var d = deltas.concat(); @@ -65,7 +65,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertNewLine({row: 0, column: 1}); + doc.insertLines({row: 0, column: 1}, ['', '']); assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); var d = deltas.concat(); @@ -82,7 +82,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines(0, ["aa", "bb"]); + doc.insertFullLines(0, ["aa", "bb"]); assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); var d = deltas.concat(); @@ -99,7 +99,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines(2, ["aa", "bb"]); + doc.insertFullLines(2, ["aa", "bb"]); assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); }, @@ -109,7 +109,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines(1, ["aa", "bb"]); + doc.insertFullLines(1, ["aa", "bb"]); assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); var d = deltas.concat(); @@ -126,7 +126,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); + doc.insertText({row: 0, column: 0}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); var d = deltas.concat(); @@ -143,7 +143,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 2, column: 0}, "aa\nbb\ncc"); + doc.insertText({row: 1, column: 2}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); var d = deltas.concat(); @@ -160,7 +160,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); + doc.insertText({row: 0, column: 1}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); var d = deltas.concat(); @@ -235,7 +235,7 @@ module.exports = { "test: remove lines should return the removed lines" : function() { var doc = new Document(["1234", "5678", "abcd"]); - var removed = doc.removeLines(1, 2); + var removed = doc.removeFullLines(1, 2); assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n")); }, diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index a63ceeef..98c255a4 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1136,8 +1136,8 @@ var EditSession = function(text, mode) { * * **/ - this.insert = function(position, text) { - return this.doc.insert(position, text); + this.insertText = function(position, text) { + return this.doc.insertText(position, text); }; /** @@ -1151,6 +1151,19 @@ var EditSession = function(text, mode) { this.remove = function(range) { return this.doc.remove(range); }; + + /** + * Removes a range of full lines. This method also triggers the `'change'` event. + * @param {Number} firstRow The first row to be removed + * @param {Number} lastRow The last row to be removed + * @returns {[String]} Returns all the removed lines. + * + * @related Document.removeFullLines + * + **/ + this.removeFullLines = function(firstRow, lastRow){ + return this.doc.removeFullLines(firstRow, lastRow) + } /** * Reverts previous changes to your document. @@ -1227,9 +1240,7 @@ var EditSession = function(text, mode) { this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { function isInsert(delta) { - var insert = - delta.action === "insertText" || delta.action === "insertLines"; - return isUndo ? !insert : insert; + return isUndo ? delta.action !== "insert" : delta.action === "insert"; } var delta = deltas[0]; @@ -1339,7 +1350,7 @@ var EditSession = function(text, mode) { } } - toRange.end = this.insert(toRange.start, text); + toRange.end = this.insertText(toRange.start, text); if (folds.length) { var oldStart = fromRange.start; var newStart = toRange.start; @@ -1373,7 +1384,7 @@ var EditSession = function(text, mode) { this.indentRows = function(startRow, endRow, indentString) { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) - this.insert({row: row, column:0}, indentString); + this.insertText({row: row, column:0}, indentString); }; /** @@ -1430,11 +1441,11 @@ var EditSession = function(text, mode) { x.end.row += diff; return x; }); - + var lines = dir == 0 ? this.doc.getLines(firstRow, lastRow) - : this.doc.removeLines(firstRow, lastRow); - this.doc.insertLines(firstRow+diff, lines); + : this.doc.removeFullLines(firstRow, lastRow); + this.doc.insertFullLines(firstRow+diff, lines); folds.length && this.addFolds(folds); return diff; }; @@ -1444,8 +1455,6 @@ var EditSession = function(text, mode) { * @param {Number} lastRow The final row to move up * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. * - * @related Document.insertLines - * **/ this.moveLinesUp = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, -1); @@ -1456,8 +1465,6 @@ var EditSession = function(text, mode) { * @param {Number} firstRow The starting row to move down * @param {Number} lastRow The final row to move down * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. - * - * @related Document.insertLines **/ this.moveLinesDown = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, 1); @@ -1668,28 +1675,17 @@ var EditSession = function(text, mode) { this.$updateInternalDataOnChange = function(e) { var useWrapMode = this.$useWrapMode; - var len; var action = e.data.action; - var firstRow = e.data.range.start.row; - var lastRow = e.data.range.end.row; var start = e.data.range.start; var end = e.data.range.end; + var firstRow = start.row; + var lastRow = end.row; + var len = lastRow - firstRow; var removedFolds = null; - - if (action.indexOf("Lines") != -1) { - if (action == "insertLines") { - lastRow = firstRow + (e.data.lines.length); - } else { - lastRow = firstRow; - } - len = e.data.lines ? e.data.lines.length : lastRow - firstRow; - } else { - len = lastRow - firstRow; - } - + this.$updating = true; if (len != 0) { - if (action.indexOf("remove") != -1) { + if (action == "delete") { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; @@ -1764,7 +1760,7 @@ var EditSession = function(text, mode) { // Realign folds. E.g. if you add some new chars before a fold, the // fold should "move" to the right. len = Math.abs(e.data.range.start.column - e.data.range.end.column); - if (action.indexOf("remove") != -1) { + if (action == "delete") { // Get all the folds in the change range and remove them. removedFolds = this.getFoldsInRange(e.data.range); this.removeFolds(removedFolds); diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 474818b2..9df35593 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -833,7 +833,7 @@ function Folding() { if (len === 0) { this.foldWidgets[firstRow] = null; - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "delete") { this.foldWidgets.splice(firstRow, len + 1, null); } else { var args = Array(len + 1); diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index 87cc9567..855da4d1 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -430,12 +430,12 @@ module.exports = { session.setTabSize(4); assert.equal(session.getScreenWidth(), 2); - session.doc.insertNewLine({row: 0, column: Infinity}); - session.doc.insertLines(1, ["123"]); + session.doc.insertLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertFullLines(1, ["123"]); assert.equal(session.getScreenWidth(), 3); - session.doc.insertNewLine({row: 0, column: Infinity}); - session.doc.insertLines(1, ["\t\t"]); + session.doc.insertLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertFullLines(1, ["\t\t"]); assert.equal(session.getScreenWidth(), 8); @@ -459,9 +459,9 @@ module.exports = { session.setUseWrapMode(true); - document.insertLines(0, ["a", "b"]); - document.insertLines(2, ["c", "d"]); - document.removeLines(1, 2); + document.insertFullLines(0, ["a", "b"]); + document.insertFullLines(2, ["c", "d"]); + document.removeFullLines(1, 2); }, "test wrapMode init has to create wrapData array": function() { @@ -649,7 +649,7 @@ module.exports = { var foldLines = session.$foldData; function insert(row, column, text) { - session.insert({row: row, column: column}, text); + session.insertText({row: row, column: column}, text); // Force the session to store all changes made to the document NOW // on the undoManager's queue. Otherwise we can't undo in separate @@ -748,7 +748,7 @@ module.exports = { undoManager = session.getUndoManager(), foldLines = session.$foldData; function insert(row, column, text) { - session.insert({row: row, column: column}, text); + session.insertText({row: row, column: column}, text); // Force the session to store all changes made to the document NOW // on the undoManager's queue. Otherwise we can't undo in separate // steps later. diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 6486a881..3926fc81 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -601,19 +601,10 @@ var Editor = function(renderer, session) { * **/ this.onDocumentChange = function(e) { - var delta = e.data; - var range = delta.range; - var lastRow; - - if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines") - lastRow = range.end.row; - else - lastRow = Infinity; - this.renderer.updateLines(range.start.row, lastRow); - + this.renderer.updateLines(e.data.range.start.row, e.data.range.end.row); this._emit("change", e); - - // update cursor because tab characters can influence the cursor position + + // update cursor because tab characters can influence the cursor position. this.$cursorChange(); }; @@ -827,7 +818,7 @@ var Editor = function(renderer, session) { if (this.$readOnly) return; this._emit("paste", text); - this.insert(text); + this.insertText(text); }; @@ -841,7 +832,7 @@ var Editor = function(renderer, session) { * * **/ - this.insert = function(text) { + this.insertText = function(text) { var session = this.session; var mode = session.getMode(); var cursor = this.getCursorPosition(); @@ -887,7 +878,7 @@ var Editor = function(renderer, session) { var lineState = session.getState(cursor.row); var line = session.getLine(cursor.row); var shouldOutdent = mode.checkOutdent(lineState, line, text); - var end = session.insert(cursor, text); + var end = session.insertText(cursor, text); if (transform && transform.selection) { if (transform.selection.length == 2) { // Transform relative to the current column @@ -906,7 +897,7 @@ var Editor = function(renderer, session) { if (session.getDocument().isNewLine(text)) { var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); - session.insert({row: cursor.row+1, column: 0}, lineIndent); + session.insertText({row: cursor.row+1, column: 0}, lineIndent); } if (shouldOutdent) mode.autoOutdent(lineState, session, cursor.row); @@ -1279,7 +1270,7 @@ var Editor = function(renderer, session) { } var cursor = this.getCursorPosition(); - this.insert("\n"); + this.insertText("\n"); this.moveCursorToPosition(cursor); }; @@ -1378,7 +1369,7 @@ var Editor = function(renderer, session) { this.selection.setSelectionRange(range); indentString = "\t"; } - return this.insert(indentString); + return this.insertText(indentString); }; /** @@ -1516,15 +1507,7 @@ var Editor = function(renderer, session) { **/ this.removeLines = function() { var rows = this.$getSelectedRows(); - var range; - if (rows.first === 0 || rows.last+1 < this.session.getLength()) - range = new Range(rows.first, 0, rows.last+1, 0); - else - range = new Range( - rows.first-1, this.session.getLine(rows.first-1).length, - rows.last, this.session.getLine(rows.last).length - ); - this.session.remove(range); + this.session.removeFullLines(rows.first, rows.last); this.clearSelection(); }; @@ -1538,7 +1521,7 @@ var Editor = function(renderer, session) { doc.duplicateLines(row, row); } else { var point = reverse ? range.start : range.end; - var endPoint = doc.insert(point, doc.getTextRange(range), false); + var endPoint = doc.insertText(point, doc.getTextRange(range), false); range.start = point; range.end = endPoint; diff --git a/lib/ace/editor_change_document_test.js b/lib/ace/editor_change_document_test.js index a1fdaad9..83fffeb3 100644 --- a/lib/ace/editor_change_document_test.js +++ b/lib/ace/editor_change_document_test.js @@ -172,7 +172,7 @@ module.exports = { self.session1.setMode(new HtmlMode()); // 5. Try to type valid HTML - self.session1.insert({row: 0, column: 0}, ""); + self.session1.insertText({row: 0, column: 0}, ""); setTimeout(function() { assert.equal(Object.keys(self.session1.getAnnotations()).length, 0); diff --git a/lib/ace/editor_navigation_test.js b/lib/ace/editor_navigation_test.js index ab348241..b60d391d 100644 --- a/lib/ace/editor_navigation_test.js +++ b/lib/ace/editor_navigation_test.js @@ -150,7 +150,7 @@ module.exports = { var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"])); editor.navigateTo(0, 3); - editor.insert("juhu"); + editor.insertText("juhu"); editor.navigateDown(); assert.position(editor.getCursorPosition(), 1, 7); diff --git a/lib/ace/ext/chromevox.js b/lib/ace/ext/chromevox.js index 9f7a7996..20bbb6c7 100644 --- a/lib/ace/ext/chromevox.js +++ b/lib/ace/ext/chromevox.js @@ -581,12 +581,12 @@ var onSelectionChange = function(evt) { var onChange = function(evt) { var data = evt.data; switch (data.action) { - case 'removeText': + case 'delete': cvox.Api.speak(data.text, 0, DELETED_PROP); /* Let the future cursor change event know it's from text change. */ changed = true; break; - case 'insertText': + case 'insert': cvox.Api.speak(data.text, 0); /* Let the future cursor change event know it's from text change. */ changed = true; diff --git a/lib/ace/ext/elastic_tabstops_lite.js b/lib/ace/ext/elastic_tabstops_lite.js index 9901c5df..4d3a40d4 100644 --- a/lib/ace/ext/elastic_tabstops_lite.js +++ b/lib/ace/ext/elastic_tabstops_lite.js @@ -236,7 +236,7 @@ var ElasticTabstopsLite = function(editor) { if (difference > 0) { // put the spaces after the tab and then delete the tab, so any insertion // points behave as expected - this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); + this.$editor.session.getDocument().insertText({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); this.$editor.session.getDocument().removeInLine(row, it, it + 1); bias += difference; diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index 83486fb0..736e991d 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -153,7 +153,7 @@ exports.convertIndentation = function(session, ch, len) { if (toInsert != match) { doc.removeInLine(i, 0, match.length); - doc.insertInLine({row: i, column: 0}, toInsert); + doc.insertText({row: i, column: 0}, toInsert); } } } diff --git a/lib/ace/keyboard/vim/commands.js b/lib/ace/keyboard/vim/commands.js index dd3357d6..defca037 100644 --- a/lib/ace/keyboard/vim/commands.js +++ b/lib/ace/keyboard/vim/commands.js @@ -104,7 +104,7 @@ var actions = exports.actions = { if (param && param.length) { if (param.length > 1) param = param == "return" ? "\n" : param == "tab" ? "\t" : param; - repeat(function() { editor.insert(param); }, count || 1); + repeat(function() { editor.insertText(param); }, count || 1); editor.navigateLeft(); } } @@ -224,12 +224,12 @@ var actions = exports.actions = { var pos = editor.getCursorPosition(); pos.column = editor.session.getLine(pos.row).length; var text = lang.stringRepeat("\n" + defaultReg.text, count || 1); - editor.session.insert(pos, text); + editor.session.insertText(pos, text); editor.moveCursorTo(pos.row + 1, 0); } else { editor.navigateRight(); - editor.insert(lang.stringRepeat(defaultReg.text, count || 1)); + editor.insertText(lang.stringRepeat(defaultReg.text, count || 1)); editor.navigateLeft(); } editor.setOverwrite(true); @@ -245,11 +245,11 @@ var actions = exports.actions = { var pos = editor.getCursorPosition(); pos.column = 0; var text = lang.stringRepeat(defaultReg.text + "\n", count || 1); - editor.session.insert(pos, text); + editor.session.insertText(pos, text); editor.moveCursorToPosition(pos); } else { - editor.insert(lang.stringRepeat(defaultReg.text, count || 1)); + editor.insertText(lang.stringRepeat(defaultReg.text, count || 1)); } editor.setOverwrite(true); editor.selection.clearSelection(); diff --git a/lib/ace/keyboard/vim/maps/motions.js b/lib/ace/keyboard/vim/maps/motions.js index 91c8b8af..2bf580b0 100644 --- a/lib/ace/keyboard/vim/maps/motions.js +++ b/lib/ace/keyboard/vim/maps/motions.js @@ -545,7 +545,7 @@ module.exports = { if (content.length) { editor.navigateLineEnd() - editor.insert(content); + editor.insertText(content); util.insertMode(editor); } } @@ -562,9 +562,9 @@ module.exports = { if(row > 0) { editor.navigateUp(); editor.navigateLineEnd() - editor.insert(content); + editor.insertText(content); } else { - editor.session.insert({row: 0, column: 0}, content); + editor.session.insertText({row: 0, column: 0}, content); editor.navigateUp(); } util.insertMode(editor); diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 5a535094..9d813d2a 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -108,8 +108,8 @@ var Gutter = function(parentEl) { var len = range.end.row - firstRow; if (len === 0) { // do nothing - } else if (delta.action == "removeText" || delta.action == "removeLines") { - this.$annotations.splice(firstRow, len + 1, null); + } else if (delta.action == "delete") { + this.$annotations.splice(firstRow, len, null); } else { var args = new Array(len + 1); args.unshift(firstRow, 1); diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 597b3ca2..4023bd55 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -123,7 +123,7 @@ function LineWidgets(session) { if (len === 0) { // return - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "delete") { var removed = cells.splice(startRow + 1, len); removed.forEach(function(w) { w && this.removeLineWidget(w); diff --git a/lib/ace/mode/javascript_test.js b/lib/ace/mode/javascript_test.js index b413765a..cc2b22d7 100644 --- a/lib/ace/mode/javascript_test.js +++ b/lib/ace/mode/javascript_test.js @@ -131,7 +131,7 @@ module.exports = { this.mode.toggleCommentLines("start", session, 0, 2); assert.equal([" abc", " cde", " fg"].join("\n"), session.toString()); - session.insert({row: 0, column: 0}, " "); + session.insertText({row: 0, column: 0}, " "); this.mode.toggleCommentLines("start", session, 0, 2); assert.equal(["// abc", "// cde", "// fg"].join("\n"), session.toString()); }, diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index d04fed78..534ac03c 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -92,8 +92,8 @@ var Mode = function() { if (testRemove(line, i)) return; if (!ignoreBlankLines || /\S/.test(line)) { - doc.insertInLine({row: i, column: line.length}, lineCommentEnd); - doc.insertInLine({row: i, column: minIndent}, lineCommentStart); + doc.insertText({row: i, column: line.length}, lineCommentEnd); + doc.insertText({row: i, column: minIndent}, lineCommentStart); } }; @@ -138,9 +138,9 @@ var Mode = function() { var comment = function(line, i) { if (!ignoreBlankLines || /\S/.test(line)) { if (shouldInsertSpace(line, minIndent, minIndent)) - doc.insertInLine({row: i, column: minIndent}, commentWithSpace); + doc.insertText({row: i, column: minIndent}, commentWithSpace); else - doc.insertInLine({row: i, column: minIndent}, lineCommentStart); + doc.insertText({row: i, column: minIndent}, lineCommentStart); } }; var testRemove = function(line, i) { @@ -244,8 +244,8 @@ var Mode = function() { } else { colDiff = comment.start.length startRow = range.start.row; - session.insert(range.end, comment.end); - session.insert(range.start, comment.start); + session.insertText(range.end, comment.end); + session.insertText(range.start, comment.start); } // todo: selection should have ended up in the right place automatically! if (initialRange.start.row == startRow) diff --git a/lib/ace/mouse/dragdrop_handler.js b/lib/ace/mouse/dragdrop_handler.js index 3a4bc188..3ad54bb8 100644 --- a/lib/ace/mouse/dragdrop_handler.js +++ b/lib/ace/mouse/dragdrop_handler.js @@ -176,7 +176,7 @@ function DragdropHandler(mouseHandler) { var dropData = dataTransfer.getData('Text'); range = { start: dragCursor, - end: editor.session.insert(dragCursor, dropData) + end: editor.session.insertText(dragCursor, dropData) }; editor.focus(); dragOperation = null; diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index 7f4c5355..883d9a7c 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -544,7 +544,7 @@ var Editor = require("./editor").Editor; this._signal("paste", text); if (!this.inMultiSelectMode || this.inVirtualSelectionMode) - return this.insert(text); + return this.insertText(text); var lines = text.split(/\r\n|\r|\n/); var ranges = this.selection.rangeList.ranges; @@ -557,7 +557,7 @@ var Editor = require("./editor").Editor; if (!range.isEmpty()) this.session.remove(range); - this.session.insert(range.start, lines[i]); + this.session.insertText(range.start, lines[i]); } }; @@ -740,9 +740,9 @@ var Editor = require("./editor").Editor; if (fr < 0) fr = 0; if (lr >= max) lr = max - 1; } - var lines = this.session.doc.removeLines(fr, lr); + var lines = this.session.removeFullLines(fr, lr); lines = this.$reAlignText(lines, guessRange); - this.session.doc.insert({row: fr, column: 0}, lines.join("\n") + "\n"); + this.session.insertText({row: fr, column: 0}, lines.join("\n") + "\n"); if (!guessRange) { range.start.column = 0; range.end.column = lines[lines.length - 1].length; @@ -778,7 +778,7 @@ var Editor = require("./editor").Editor; var l = maxCol - p.column; var d = spaceOffsets[i] - minSpace; if (l > d) - session.insert(p, lang.stringRepeat(" ", l - d)); + session.insertText(p, lang.stringRepeat(" ", l - d)); else session.remove(new Range(p.row, p.column, p.row, p.column - l + d)); diff --git a/lib/ace/occur_test.js b/lib/ace/occur_test.js index 59fb8548..a9b2c894 100644 --- a/lib/ace/occur_test.js +++ b/lib/ace/occur_test.js @@ -55,7 +55,7 @@ module.exports = { }, "test: find lines matching" : function() { - editor.session.insert({row: 0, column: 0}, 'abc\ndef\nxyz\nbcxbc'); + editor.session.insertText({row: 0, column: 0}, 'abc\ndef\nxyz\nbcxbc'); var result = occur.matchingLines(editor.session, {needle: 'bc'}), expected = [{row: 0, content: 'abc'}, {row: 3, content: 'bcxbc'}]; assert.deepEqual(result, expected); @@ -63,7 +63,7 @@ module.exports = { "test: display occurrences" : function() { var text = 'abc\ndef\nxyz\nbcx\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); occur.displayOccurContent(editor, {needle: 'bc'}); assert.equal(editor.getValue(), 'abc\nbcx'); occur.displayOriginalContent(editor); @@ -72,7 +72,7 @@ module.exports = { "test: original position from occur doc" : function() { var text = 'abc\ndef\nxyz\nbcx\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); occur.displayOccurContent(editor, {needle: 'bc'}); assert.equal(editor.getValue(), 'abc\nbcx'); var pos = occur.occurToOriginalPosition(editor.session, {row: 1, column: 2}); @@ -82,7 +82,7 @@ module.exports = { "test: occur command" : function() { // setup var text = 'hel\nlo\n\nwo\nrld\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); // run occur for lines including 'o' @@ -106,7 +106,7 @@ module.exports = { "test: occur navigation" : function() { // setup var text = 'hel\nlo\n\nwo\nrld\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); editor.moveCursorToPosition({row: 1, column: 1}); @@ -125,7 +125,7 @@ module.exports = { "test: recursive occur" : function() { // setup var text = 'x\nabc1\nx\nabc2\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); // orig -> occur1 diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index bcb44ce2..9d0a3c3c 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -155,21 +155,21 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) if(range.start.row !== this.pos.row) return; if (this.$updating) return; this.$updating = true; - var lengthDiff = delta.action === "insertText" ? range.end.column - range.start.column : range.start.column - range.end.column; + var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column; if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) { var distanceFromStart = range.start.column - this.pos.column; this.length += lengthDiff; if(!this.session.$fromUndo) { - if(delta.action === "insertText") { + if(delta.action === "insert") { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; - this.doc.insert(newPos, delta.text); + this.doc.insertLines(newPos, delta.lines); } - } else if(delta.action === "removeText") { + } else if(delta.action === "delete") { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; @@ -179,7 +179,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) } } // Special case: insert in beginning - if(range.start.column === this.pos.column && delta.action === "insertText") { + if(range.start.column === this.pos.column && delta.action === "insert") { setTimeout(function() { this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff); for (var i = 0; i < this.others.length; i++) { @@ -191,7 +191,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) } }.bind(this), 0); } - else if(range.start.column === this.pos.column && delta.action === "removeText") { + else if(range.start.column === this.pos.column && delta.action === "delete") { setTimeout(function() { for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; diff --git a/lib/ace/placeholder_test.js b/lib/ace/placeholder_test.js index 97e561fd..dc7e4b23 100644 --- a/lib/ace/placeholder_test.js +++ b/lib/ace/placeholder_test.js @@ -53,9 +53,9 @@ module.exports = { new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insert('b'); + editor.insertText('b'); assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); - editor.insert('cd'); + editor.insertText('cd'); assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(abcd, abcd);"); editor.remove('left'); editor.remove('left'); @@ -70,7 +70,7 @@ module.exports = { new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(2, 0); - editor.insert('b'); + editor.insertText('b'); assert.equal(session.doc.getValue(), "var a = 10;\nconsole.log(a, a);\nb"); }, @@ -81,12 +81,12 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 4); - editor.insert('$'); + editor.insertText('$'); assert.equal(session.doc.getValue(), "var $a = 10;\nconsole.log($a, $a);"); editor.moveCursorTo(0, 4); // Have to put this in a setTimeout because the anchor is only fixed later. setTimeout(function() { - editor.insert('v'); + editor.insertText('v'); assert.equal(session.doc.getValue(), "var v$a = 10;\nconsole.log(v$a, v$a);"); next(); }, 10); @@ -99,10 +99,10 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insert('b'); + editor.insertText('b'); assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); p.detach(); - editor.insert('cd'); + editor.insertText('cd'); assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(ab, ab);"); }, @@ -136,8 +136,8 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insert('b'); - editor.insert('cd'); + editor.insertText('b'); + editor.insertText('cd'); editor.remove('left'); assert.equal(session.doc.getValue(), "var abc = 10;\nconsole.log(abc, abc);"); // Wait a little for the changes to enter the undo stack From 27768230c86eadb6f3a65f6c212af6c0f6a2972b Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 1 Jan 2014 11:05:27 -0600 Subject: [PATCH 002/545] Maintain public API and update coding convention This seeks to keep the public API in-tact while improving method names within ace by keeping the old methods as wrappers around the new better-named methods. For example, document.insert() now simply calls document.insertText() and warns the caller via a console.log() that they are using a deprecated method. I've also updated the coding style of my changes (where I noticed discrepancies) to match the rest of Ace. --- lib/ace/anchor.js | 22 ++++------ lib/ace/anchor_test.js | 4 +- lib/ace/document.js | 80 +++++++++++++++++++++--------------- lib/ace/document_test.js | 2 +- lib/ace/edit_session.js | 6 +++ lib/ace/edit_session_test.js | 4 +- lib/ace/editor.js | 6 +++ lib/ace/placeholder.js | 2 +- 8 files changed, 73 insertions(+), 53 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 91a62eb0..affb4f19 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -117,33 +117,29 @@ var Anchor = exports.Anchor = function(doc, row, column) { var deltaEnd = (deltaIsInsert ? deltaStart : delta.range.end); // Collapse insert range. // DELTA AFTER POINT: No change needed. - if (_pointsInOrder(point, deltaStart, moveIfEqual)) - { - return ( - { + if (_pointsInOrder(point, deltaStart, moveIfEqual)) { + return { row: point.row, column: point.column - }); + }; } // DELTA BEFORE POINT: Move point by delta shift. - if (_pointsInOrder(deltaEnd, point, !moveIfEqual)) - { - return ( - { + if (_pointsInOrder(deltaEnd, point, !moveIfEqual)) { + return { row: point.row + deltaRowShift, column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) - }); + }; } // DELTA ENVELOPS POINT (delete only): Move point to delta start. if (delta.action != 'delete') throw 'Delete action expected.'; - return ( - { + + return { row: deltaStart.row, column: deltaStart.column - }); + }; } var delta = e.data; diff --git a/lib/ace/anchor_test.js b/lib/ace/anchor_test.js index 0588c9b6..0661765b 100644 --- a/lib/ace/anchor_test.js +++ b/lib/ace/anchor_test.js @@ -70,7 +70,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertLines({row: 0, column: 0}, ['', '']); + doc.insertMergedLines({row: 0, column: 0}, ['', '']); assert.position(anchor.getPosition(), 2, 4); }, @@ -78,7 +78,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertLines({row: 1, column: 2}, ['', '']); + doc.insertMergedLines({row: 1, column: 2}, ['', '']); assert.position(anchor.getPosition(), 2, 2); }, diff --git a/lib/ace/document.js b/lib/ace/document.js index ace69e32..07726de7 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -59,7 +59,7 @@ var Document = function(textOrLines) { if (textOrLines.length == 0) { this.$lines = [""]; } else if (Array.isArray(textOrLines)) { - this.insertLines({row: 0, column: 0}, textOrLines); + this.insertMergedLines({row: 0, column: 0}, textOrLines); } else { this.insertText({row: 0, column:0}, textOrLines); } @@ -230,13 +230,10 @@ var Document = function(textOrLines) { this.$clipPosition = function(position) { var length = this.getLength(); - if (position.row >= length) - { + if (position.row >= length) { position.row = Math.max(0, length - 1); position.column = this.getLine(length - 1).length; - } - else - { + } else { position.row = Math.max(0, position.row); position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); } @@ -264,16 +261,15 @@ var Document = function(textOrLines) { throw errorText; } + // Validate lines. if (!delta.lines instanceof Array) - { fnThrow('Delta object lines must be an array'); - } + // Validate range type. if (!delta.range instanceof Range) - { fnThrow('Range object is not an instance of the Range class'); - } + // Validate start point. var start = delta.range.start; if (Math.min(Math.max(start.row, 0), this.getLength() - 1 ) != start.row || Math.min(Math.max(start.column, 0), this.$lines[start.row].length) != start.column) @@ -281,16 +277,37 @@ var Document = function(textOrLines) { fnThrow('Range start point not contained in document'); } + // Validate ending row offset. if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row) - { fnThrow('Range row offsets does not match delta lines'); - } - // TODO: Validate that the ending column offset matches the lines. - // TODO: Validate for deletions that the lines deleted match the lines - // in the document. + // TODO: + // - Validate that the ending column offset matches the lines. + // - Validate the deleted lines match the lines in the document. }, + // Deprecated methods retained for backwards compatibility. + this.insert = function(position, text){ + console.log('Warning: document.insert is deprecated. Use the insertText method instead.'); + return this.insertText(position, text); + } + this.insertLines = function(row, lines) { + console.log('Warning: document.insertLines is deprecated. Use the insertFullLines method instead.'); + return this.insertFullLines(row, lines); + } + this.removeLines = function(firstRow, lastRow) { + console.log('Warning: document.removeLines is deprecated. Use the removeFullLines method instead.'); + return this.removeFullLines(firstRow, lastRow); + } + this.insertNewLine = function(position) { + console.log('Warning: document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.'); + return this.insertMergedLines(position, ['', '']); + } + this.insertInLine = function(position, text) { + console.log('Warning: document.insertInLine is deprecated. Use insertText instead.'); + return this.insertText(position, text); + } + /** * Inserts a block of `text` at the indicated `position`. * @param {Object} position The position to start inserting at; it's an object that looks like `{ row: row, column: column}` @@ -304,9 +321,9 @@ var Document = function(textOrLines) { if (this.getLength() <= 1) this.$detectNewLine(text); - return this.insertLines(position, this.$split(text)); + return this.insertMergedLines(position, this.$split(text)); }; - + /** * Fires whenever the document changes. * @@ -338,28 +355,26 @@ var Document = function(textOrLines) { * ``` * **/ - this.insertFullLines = function(row, lines) - { + this.insertFullLines = function(row, lines) { // Clip to document. // Allow one past the document end. row = Math.min(Math.max(row, 0), this.getLength()); // Calculate insertion point. var column = 0; - if (row < this.getLength()) // Insert before the specified row. - { + if (row < this.getLength()) { + // Insert before the specified row. lines = lines.concat(['']); column = 0; - } - else // Insert after the last row in the document. - { + } else { + // Insert after the last row in the document. lines = [''].concat(lines); row--; var column = this.$lines[row].length; } // Insert. - this.insertLines({row: row, column: column}, lines); + this.insertMergedLines({row: row, column: column}, lines); }, /** @@ -376,7 +391,7 @@ var Document = function(textOrLines) { * ``` * **/ - this.insertLines = function(position, lines){ + this.insertMergedLines = function(position, lines) { // Calculate insertion range end point. this.$clipPosition(position); @@ -405,8 +420,7 @@ var Document = function(textOrLines) { // Apply delta (emits change). range = this.$getClippedRange(range); - this.applyDelta( - { + this.applyDelta({ action: 'delete', range: range, lines: this._getLinesForRange(range), @@ -483,14 +497,13 @@ var Document = function(textOrLines) { **/ this.removeNewLine = function(row) { - if (row < this.getLength() - 1 && row >= 0) - { + if (row < this.getLength() - 1 && row >= 0) { // Apply delta (emits change). this.applyDelta({ action: "delete", range: new Range(row, this.getLine(row).length, row + 1, 0), lines: ['', ''] - }); + }); } }; @@ -558,8 +571,7 @@ var Document = function(textOrLines) { { case 'insert': splitLine(this.$lines, delta.range.start); - for (var i = 0; i < delta.lines.length; i++) - { + for (var i = 0; i < delta.lines.length; i++) { var row = delta.range.start.row + 1 + i; this.$lines.splice(row, 0, delta.lines[i]); } @@ -571,7 +583,7 @@ var Document = function(textOrLines) { splitLine(this.$lines, delta.range.end); splitLine(this.$lines, delta.range.start); this.$lines.splice( - delta.range.start.row + 1, // Where to start deleting + delta.range.start.row + 1, // Where to start deleting delta.range.end.row - delta.range.start.row + 1 // Num lines to delete. ); joinLineWithNext(this.$lines, delta.range.start.row); diff --git a/lib/ace/document_test.js b/lib/ace/document_test.js index 50bd8b49..c29d6133 100644 --- a/lib/ace/document_test.js +++ b/lib/ace/document_test.js @@ -65,7 +65,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines({row: 0, column: 1}, ['', '']); + doc.insertMergedLines({row: 0, column: 1}, ['', '']); assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); var d = deltas.concat(); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 98c255a4..e48bdc37 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1127,6 +1127,12 @@ var EditSession = function(text, mode) { this.getTextRange = function(range) { return this.doc.getTextRange(range || this.selection.getRange()); }; + + // Deprecated method retained for backwards compatibility. + this.insert = function(position, text){ + console.log('Warning: editsession.insert is deprecated. Use the insertText method instead.'); + return this.insertText(position, text) + } /** * Inserts a block of `text` and the indicated `position`. diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index 855da4d1..fd20259c 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -430,11 +430,11 @@ module.exports = { session.setTabSize(4); assert.equal(session.getScreenWidth(), 2); - session.doc.insertLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertMergedLines({row: 0, column: Infinity}, ['', '']); session.doc.insertFullLines(1, ["123"]); assert.equal(session.getScreenWidth(), 3); - session.doc.insertLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertMergedLines({row: 0, column: Infinity}, ['', '']); session.doc.insertFullLines(1, ["\t\t"]); assert.equal(session.getScreenWidth(), 8); diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 3926fc81..2854eaaf 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -825,6 +825,12 @@ var Editor = function(renderer, session) { this.execCommand = function(command, args) { this.commands.exec(command, this, args); }; + + // Deprecated method retained for backwards compatibility. + this.insert = function(text){ + console.log('Warning: editor.insert is deprecated. Use the insertText method instead.'); + return this.insertText(text) + } /** * Inserts `text` into wherever the cursor is pointing. diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index 9d0a3c3c..c9a44e50 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -167,7 +167,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; - this.doc.insertLines(newPos, delta.lines); + this.doc.insertMergedLines(newPos, delta.lines); } } else if(delta.action === "delete") { for (var i = this.others.length - 1; i >= 0; i--) { From 026af74016a2829003a7dfa2ccde906309abd40b Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 1 Jan 2014 12:04:12 -0600 Subject: [PATCH 003/545] Fix render bugs Both were introduced in 2e6f12725bc01011c545c99c1f1c1da6065063d9. --- lib/ace/editor.js | 8 ++++++-- lib/ace/layer/gutter.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 2854eaaf..73873b4a 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -601,10 +601,14 @@ var Editor = function(renderer, session) { * **/ this.onDocumentChange = function(e) { - this.renderer.updateLines(e.data.range.start.row, e.data.range.end.row); + + // Rerender and emit "change" event. + var range = e.data.range; + var lastRow = (range.start.row == range.end.row ? range.end.row : Infinity); + this.renderer.updateLines(range.start.row, lastRow); this._emit("change", e); - // update cursor because tab characters can influence the cursor position. + // Update cursor because tab characters can influence the cursor position. this.$cursorChange(); }; diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 9d813d2a..82dcf245 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -109,7 +109,7 @@ var Gutter = function(parentEl) { if (len === 0) { // do nothing } else if (delta.action == "delete") { - this.$annotations.splice(firstRow, len, null); + this.$annotations.splice(firstRow, len + 1, null); } else { var args = new Array(len + 1); args.unshift(firstRow, 1); From 810e196cc6f1d49da208c8c4ed98045e6c29ebbb Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 1 Jan 2014 12:06:19 -0600 Subject: [PATCH 004/545] Use console.warn for deprecated methods console.warn makes better sense than console.log and matches similar warnings in ace (see gutter.js for example). --- lib/ace/document.js | 10 +++++----- lib/ace/edit_session.js | 2 +- lib/ace/editor.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index 07726de7..c689553c 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -288,23 +288,23 @@ var Document = function(textOrLines) { // Deprecated methods retained for backwards compatibility. this.insert = function(position, text){ - console.log('Warning: document.insert is deprecated. Use the insertText method instead.'); + console.warn('Use of document.insert is deprecated. Use the insertText method instead.'); return this.insertText(position, text); } this.insertLines = function(row, lines) { - console.log('Warning: document.insertLines is deprecated. Use the insertFullLines method instead.'); + console.warn('Use of document.insertLines is deprecated. Use the insertFullLines method instead.'); return this.insertFullLines(row, lines); } this.removeLines = function(firstRow, lastRow) { - console.log('Warning: document.removeLines is deprecated. Use the removeFullLines method instead.'); + console.warn('Use of document.removeLines is deprecated. Use the removeFullLines method instead.'); return this.removeFullLines(firstRow, lastRow); } this.insertNewLine = function(position) { - console.log('Warning: document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.'); + console.warn('Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.'); return this.insertMergedLines(position, ['', '']); } this.insertInLine = function(position, text) { - console.log('Warning: document.insertInLine is deprecated. Use insertText instead.'); + console.warn('Use of document.insertInLine is deprecated. Use insertText instead.'); return this.insertText(position, text); } diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index e48bdc37..0845418b 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1130,7 +1130,7 @@ var EditSession = function(text, mode) { // Deprecated method retained for backwards compatibility. this.insert = function(position, text){ - console.log('Warning: editsession.insert is deprecated. Use the insertText method instead.'); + console.warn('Use of editsession.insert is deprecated. Use the insertText method instead.'); return this.insertText(position, text) } diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 73873b4a..6f5980a1 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -832,7 +832,7 @@ var Editor = function(renderer, session) { // Deprecated method retained for backwards compatibility. this.insert = function(text){ - console.log('Warning: editor.insert is deprecated. Use the insertText method instead.'); + console.warn('Use of editor.insert is deprecated. Use the insertText method instead.'); return this.insertText(text) } From 612478e39f26e32c985ca8e66b8a4a37ca3834a5 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 1 Jan 2014 14:45:54 -0600 Subject: [PATCH 005/545] Speed up single-line deltas 2e6f12725bc01011c545c99c1f1c1da6065063d9 slowed down the application of deltas that only affect a single line. The slow-down, though trivial for a single line, is significant for operations than separately modify thousands of rows (such as indenting a large document). This commit speeds up single-line deltas by avoiding unnecessary calls to splitLine() and joinLineWithNext(). --- lib/ace/document.js | 70 ++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index c689553c..9d6aaac3 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -261,9 +261,13 @@ var Document = function(textOrLines) { throw errorText; } + // Validate action. + if (delta.action != 'insert' && delta.action != 'delete') + fnThrow('Delta action must be "insert" or "delete".'); + // Validate lines. if (!delta.lines instanceof Array) - fnThrow('Delta object lines must be an array'); + fnThrow('Delta lines must be an array'); // Validate range type. if (!delta.range instanceof Range) @@ -567,30 +571,50 @@ var Document = function(textOrLines) { this.$validateDelta(delta); // Apply delta. - switch (delta.action) + if (delta.range.start.row == delta.range.end.row) { - case 'insert': - splitLine(this.$lines, delta.range.start); - for (var i = 0; i < delta.lines.length; i++) { - var row = delta.range.start.row + 1 + i; - this.$lines.splice(row, 0, delta.lines[i]); - } - joinLineWithNext(this.$lines, delta.range.start.row); - joinLineWithNext(this.$lines, delta.range.end.row); - break; + // Apply single-line delta. + // Note: The multi-line code below correctly handle single-line + // deltas too, but we need to short-circuit for speed. + var row = delta.range.start.row; + var startColumn = delta.range.start.column; + var endColumn = delta.range.end.column; + var line = this.$lines[row]; + switch (delta.action) { + + case 'insert': + this.$lines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + break; + + case 'delete': + this.$lines[row] = line.substring(0, startColumn) + line.substring(endColumn); + break; + } + } else { - case 'delete': - splitLine(this.$lines, delta.range.end); - splitLine(this.$lines, delta.range.start); - this.$lines.splice( - delta.range.start.row + 1, // Where to start deleting - delta.range.end.row - delta.range.start.row + 1 // Num lines to delete. - ); - joinLineWithNext(this.$lines, delta.range.start.row); - break; - - default: - throw 'Invalid delta type: ' + delta.action + // Apply multi-line delta. + switch (delta.action) { + + case 'insert': + splitLine(this.$lines, delta.range.start); + for (var i = 0; i < delta.lines.length; i++) { + var row = delta.range.start.row + 1 + i; + this.$lines.splice(row, 0, delta.lines[i]); + } + joinLineWithNext(this.$lines, delta.range.start.row); + joinLineWithNext(this.$lines, delta.range.end.row); + break; + + case 'delete': + splitLine(this.$lines, delta.range.end); + splitLine(this.$lines, delta.range.start); + this.$lines.splice( + delta.range.start.row + 1, // Where to start deleting + delta.range.end.row - delta.range.start.row + 1 // Num lines to delete. + ); + joinLineWithNext(this.$lines, delta.range.start.row); + break; + } } this._emit("change", { data: delta }); From b503e65e0370cb01a251a34719bde5ddb508e2c4 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Fri, 3 Jan 2014 14:59:22 -0600 Subject: [PATCH 006/545] Break on applyDelta into its own module This makes it possible to break out helper functions without exposing them to the rest of the document class. Also, long term, we may want to have a stand-alone test suite for applyDelta, so it makes sense in its own file. All other changes involve syntax corrections (some syntax issues were mine, others pre-existed) to make the documentation compilation work. --- lib/ace/apply_delta.js | 137 +++++++++++++++++++++++++++ lib/ace/document.js | 204 +++++++++++++--------------------------- lib/ace/edit_session.js | 14 +-- lib/ace/editor.js | 8 +- lib/ace/scrollbar.js | 8 +- 5 files changed, 215 insertions(+), 156 deletions(-) create mode 100644 lib/ace/apply_delta.js diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js new file mode 100644 index 00000000..02c0a498 --- /dev/null +++ b/lib/ace/apply_delta.js @@ -0,0 +1,137 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("./range").Range; + +function splitLine (lines, point) { + var text = lines[point.row]; + lines[point.row] = text.slice(0, point.column); + lines.splice(point.row + 1, 0, text.slice(point.column)); +} + +function joinLineWithNext(lines, row) { + lines[row] += lines[row + 1]; + lines.splice(row + 1, 1); +} + +function throwDeltaError(delta, errorText){ + errorText = 'Invalid Delta: ' + errorText; + console.log(errorText, delta); + throw errorText; +} + +function validateDelta(lines, delta) { + + // Validate action. + if (delta.action != 'insert' && delta.action != 'delete') + fnThrow('Delta action must be "insert" or "delete".'); + + // Validate lines. + if (!delta.lines instanceof Array) + fnThrow('Delta lines must be an array'); + + // Validate range type. + if (!delta.range instanceof Range) + fnThrow('Range object is not an instance of the Range class'); + + // Validate start point. + var start = delta.range.start; + if (Math.min(Math.max(start.row, 0), lines.length - 1 ) != start.row || + Math.min(Math.max(start.column, 0), lines[start.row].length) != start.column) + { + fnThrow('Range start point not contained in document'); + } + + // Validate ending row offset. + if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row) + fnThrow('Range row offsets does not match delta lines'); + + // TODO: + // - Validate that the ending column offset matches the lines. + // - Validate the deleted lines match the lines in the document. +} + + +exports.applyDelta = function(lines, delta) { + + // Validate delta. + validateDelta(lines, delta); + + // Apply delta. + if (delta.range.start.row == delta.range.end.row) + { + // Apply single-line delta. + // Note: The multi-line code below correctly handle single-line + // deltas too, but we need to short-circuit for speed. + var row = delta.range.start.row; + var startColumn = delta.range.start.column; + var endColumn = delta.range.end.column; + var line = lines[row]; + switch (delta.action) { + + case 'insert': + lines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + break; + + case 'delete': + lines[row] = line.substring(0, startColumn) + line.substring(endColumn); + break; + } + } else { + + // Apply multi-line delta. + switch (delta.action) { + + case 'insert': + splitLine(lines, delta.range.start); + for (var i = 0; i < delta.lines.length; i++) { + var row = delta.range.start.row + 1 + i; + lines.splice(row, 0, delta.lines[i]); + } + joinLineWithNext(lines, delta.range.start.row); + joinLineWithNext(lines, delta.range.end.row); + break; + + case 'delete': + splitLine(lines, delta.range.end); + splitLine(lines, delta.range.start); + lines.splice( + delta.range.start.row + 1, // Where to start deleting + delta.range.end.row - delta.range.start.row + 1 // Num lines to delete. + ); + joinLineWithNext(lines, delta.range.start.row); + break; + } + } +} +}); diff --git a/lib/ace/document.js b/lib/ace/document.js index 9d6aaac3..768182a4 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -32,6 +32,7 @@ define(function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); +var applyDelta = require("./apply_delta").applyDelta; var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; @@ -56,7 +57,7 @@ var Document = function(textOrLines) { // There has to be one line at least in the document. If you pass an empty // string to the insert function, nothing will happen. Workaround. - if (textOrLines.length == 0) { + if (textOrLines.length === 0) { this.$lines = [""]; } else if (Array.isArray(textOrLines)) { this.insertMergedLines({row: 0, column: 0}, textOrLines); @@ -107,10 +108,10 @@ var Document = function(textOrLines) { **/ // check for IE split bug - if ("aaa".split(/a/).length == 0) + if ("aaa".split(/a/).length === 0) this.$split = function(text) { return text.replace(/\r\n|\r/g, "\n").split("\n"); - } + }; else this.$split = function(text) { return text.split(/\r\n|\r|\n/); @@ -205,30 +206,41 @@ var Document = function(textOrLines) { }; /** - * [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc} - * @param {Range} range The range to work with + * Returns all the text within `range` as a single string. + * @param {Range} range The range to work with. * * @returns {String} **/ this.getTextRange = function(range) { - return this._getLinesForRange(range).join(this.getNewLineCharacter()); + return this.getLinesForRange(range).join(this.getNewLineCharacter()); }; - this._getLinesForRange = function(range) { + /** + * Returns all the text within `range` as an array of lines. + * @param {Range} range The range to work with. + * + * @returns {Array} + **/ + this.getLinesForRange = function(range) { + var lines; if (range.start.row == range.end.row) { - return [this.getLine(range.start.row) - .substring(range.start.column, range.end.column)]; + + // Handle a single-line range. + lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; + + } else { + + // Handle a multi-line range. + lines = this.getLines(range.start.row, range.end.row); + lines[0] = (lines[0] || "").substring(range.start.column); + var l = lines.length - 1; + if (range.end.row - range.start.row == l) + lines[l] = lines[l].substring(0, range.end.column); } - var lines = this.getLines(range.start.row, range.end.row); - lines[0] = (lines[0] || "").substring(range.start.column); - var l = lines.length - 1; - if (range.end.row - range.start.row == l) - lines[l] = lines[l].substring(0, range.end.column); return lines; }; this.$clipPosition = function(position) { - var length = this.getLength(); if (position.row >= length) { position.row = Math.max(0, length - 1); @@ -240,8 +252,8 @@ var Document = function(textOrLines) { return position; }; - this.$getClippedRange = function(range) - { + this.$getClippedRange = function(range) { + // Get Range object. if (!range instanceof Range) range = Range.fromPoints(range.start, range.end); @@ -250,67 +262,29 @@ var Document = function(textOrLines) { this.$clipPosition(range.start); this.$clipPosition(range.end); return range; - } + }; - this.$validateDelta = function(delta) - { - function fnThrow(errorText) - { - errorText = 'Invalid Delta: ' + errorText; - console.log(errorText, delta); - throw errorText; - } - - // Validate action. - if (delta.action != 'insert' && delta.action != 'delete') - fnThrow('Delta action must be "insert" or "delete".'); - - // Validate lines. - if (!delta.lines instanceof Array) - fnThrow('Delta lines must be an array'); - - // Validate range type. - if (!delta.range instanceof Range) - fnThrow('Range object is not an instance of the Range class'); - - // Validate start point. - var start = delta.range.start; - if (Math.min(Math.max(start.row, 0), this.getLength() - 1 ) != start.row || - Math.min(Math.max(start.column, 0), this.$lines[start.row].length) != start.column) - { - fnThrow('Range start point not contained in document'); - } - - // Validate ending row offset. - if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row) - fnThrow('Range row offsets does not match delta lines'); - - // TODO: - // - Validate that the ending column offset matches the lines. - // - Validate the deleted lines match the lines in the document. - }, - // Deprecated methods retained for backwards compatibility. this.insert = function(position, text){ console.warn('Use of document.insert is deprecated. Use the insertText method instead.'); return this.insertText(position, text); - } + }; this.insertLines = function(row, lines) { console.warn('Use of document.insertLines is deprecated. Use the insertFullLines method instead.'); return this.insertFullLines(row, lines); - } + }; this.removeLines = function(firstRow, lastRow) { console.warn('Use of document.removeLines is deprecated. Use the removeFullLines method instead.'); return this.removeFullLines(firstRow, lastRow); - } + }; this.insertNewLine = function(position) { console.warn('Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.'); return this.insertMergedLines(position, ['', '']); - } + }; this.insertInLine = function(position, text) { console.warn('Use of document.insertInLine is deprecated. Use insertText instead.'); return this.insertText(position, text); - } + }; /** * Inserts a block of `text` at the indicated `position`. @@ -374,12 +348,12 @@ var Document = function(textOrLines) { // Insert after the last row in the document. lines = [''].concat(lines); row--; - var column = this.$lines[row].length; + column = this.$lines[row].length; } // Insert. this.insertMergedLines({row: row, column: column}, lines); - }, + }; /** * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `'change'` event. @@ -412,7 +386,7 @@ var Document = function(textOrLines) { }); return endPoint; - } + }; /** * Removes the `range` from the document. @@ -427,7 +401,7 @@ var Document = function(textOrLines) { this.applyDelta({ action: 'delete', range: range, - lines: this._getLinesForRange(range), + lines: this.getLinesForRange(range), }); return range.start; }; @@ -450,7 +424,7 @@ var Document = function(textOrLines) { this.applyDelta({ action: "delete", range: range, - lines: this._getLinesForRange(range) + lines: this.getLinesForRange(range) }); return range.start; @@ -487,7 +461,7 @@ var Document = function(textOrLines) { this.applyDelta({ action: "delete", range: range, - lines: this._getLinesForRange(range) + lines: this.getLinesForRange(range) }); // Return the deleted lines. @@ -524,7 +498,7 @@ var Document = function(textOrLines) { this.replace = function(range, text) { if (!range instanceof Range) range = Range.fromPoints(range.start, range.end); - if (text.length == 0 && range.isEmpty()) + if (text.length === 0 && range.isEmpty()) return range.start; // Shortcut: If the text we want to insert is the same as it is already @@ -533,8 +507,9 @@ var Document = function(textOrLines) { return range.end; this.remove(range); + var end; if (text) { - var end = this.insertText(range.start, text); + end = this.insertText(range.start, text); } else { end = range.start; @@ -544,7 +519,8 @@ var Document = function(textOrLines) { }; /** - * Applies all the changes previously accumulated. These can be either `'insert'` or `'delete'`. + * Applies all changes in `deltas` to the document. + * @param {Array} deltas An array of delta objects (can include 'insert' and 'delete' actions) **/ this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { @@ -629,6 +538,19 @@ var Document = function(textOrLines) { } }; + /** + * Applies `delta` to the document. + * @param {Object} delta A delta object (can include 'insert' and 'delete' actions) + **/ + this.applyDelta = function(delta) { + applyDelta(this.$lines, delta); + this._emit("change", { data: delta }); + }; + + /** + * Reverts `delta` from the document. + * @param {Object} delta A delta object (can include 'insert' and 'delete' actions) + **/ this.revertDelta = function(delta) { this.applyDelta({ @@ -636,8 +558,8 @@ var Document = function(textOrLines) { range: delta.range.clone(), lines: delta.lines.slice() }); - }, - + }; + /** * Converts an index position in a document to a `{row, column}` object. * diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 0845418b..0d4df080 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1131,8 +1131,8 @@ var EditSession = function(text, mode) { // Deprecated method retained for backwards compatibility. this.insert = function(position, text){ console.warn('Use of editsession.insert is deprecated. Use the insertText method instead.'); - return this.insertText(position, text) - } + return this.insertText(position, text); + }; /** * Inserts a block of `text` and the indicated `position`. @@ -1168,8 +1168,8 @@ var EditSession = function(text, mode) { * **/ this.removeFullLines = function(firstRow, lastRow){ - return this.doc.removeFullLines(firstRow, lastRow) - } + return this.doc.removeFullLines(firstRow, lastRow); + }; /** * Reverts previous changes to your document. @@ -1619,7 +1619,7 @@ var EditSession = function(text, mode) { * @private **/ this.adjustWrapLimit = function(desiredLimit, $printMargin) { - var limits = this.$wrapLimitRange + var limits = this.$wrapLimitRange; if (limits.max < 0) limits = {min: $printMargin, max: $printMargin}; var wrapLimit = this.$constrainWrapLimit(desiredLimit, limits.min, limits.max); @@ -1738,7 +1738,7 @@ var EditSession = function(text, mode) { var foldLine = this.getFoldLine(firstRow); var idx = 0; if (foldLine) { - var cmp = foldLine.range.compareInside(start.row, start.column) + var cmp = foldLine.range.compareInside(start.row, start.column); // Inside of the foldLine range. Need to split stuff up. if (cmp == 0) { foldLine = foldLine.split(start.row, start.column); @@ -2215,7 +2215,7 @@ var EditSession = function(text, mode) { return { row: maxRow, column: this.getLine(maxRow).length - } + }; } else { line = this.getLine(docRow); foldLine = null; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 6f5980a1..79f59e68 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -833,8 +833,8 @@ var Editor = function(renderer, session) { // Deprecated method retained for backwards compatibility. this.insert = function(text){ console.warn('Use of editor.insert is deprecated. Use the insertText method instead.'); - return this.insertText(text) - } + return this.insertText(text); + }; /** * Inserts `text` into wherever the cursor is pointing. @@ -876,7 +876,7 @@ var Editor = function(renderer, session) { } if (text == "\n" || text == "\r\n") { - var line = session.getLine(cursor.row) + var line = session.getLine(cursor.row); if (cursor.column > line.search(/\S|$/)) { var d = line.substr(cursor.column).search(/\S|$/); session.doc.removeInLine(cursor.row, cursor.column, cursor.column + d); @@ -1362,7 +1362,7 @@ var Editor = function(renderer, session) { } } - var line = session.getLine(range.start.row) + var line = session.getLine(range.start.row); var position = range.start; var size = session.getTabSize(); var column = session.documentToScreenColumn(position.row, position.column); diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 28f41fe4..466d1af1 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -156,9 +156,9 @@ oop.inherits(VScrollBar, ScrollBar); * Sets the scroll top of the scroll bar. * @param {Number} scrollTop The new scroll top **/ - // on chrome 17+ for small zoom levels after calling this function - // this.element.scrollTop != scrollTop which makes page to scroll up. this.setScrollTop = function(scrollTop) { + // on chrome 17+ for small zoom levels after calling this function + // this.element.scrollTop != scrollTop which makes page to scroll up. if (this.scrollTop != scrollTop) { this.skipEvent = true; this.scrollTop = this.element.scrollTop = scrollTop; @@ -249,9 +249,9 @@ oop.inherits(HScrollBar, ScrollBar); * Sets the scroll left of the scroll bar. * @param {Number} scrollTop The new scroll left **/ - // on chrome 17+ for small zoom levels after calling this function - // this.element.scrollTop != scrollTop which makes page to scroll up. this.setScrollLeft = function(scrollLeft) { + // on chrome 17+ for small zoom levels after calling this function + // this.element.scrollTop != scrollTop which makes page to scroll up. if (this.scrollLeft != scrollLeft) { this.skipEvent = true; this.scrollLeft = this.element.scrollLeft = scrollLeft; From 8624ab8dcb9bac917488feb8856e8b709418adb7 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 4 Jan 2014 01:59:30 -0600 Subject: [PATCH 007/545] Stop using splice.appy() in ace Since .apply() can't handle more than 65535 parameters, splice.apply() is brittle. It's also hard to read. This replaces splice.apply() calls throughout ace code with lang.spliceIntoArray(). --- lib/ace/background_tokenizer.js | 14 ++++++++------ lib/ace/edit_session.js | 14 +++++++------- lib/ace/edit_session/folding.js | 6 +++--- lib/ace/layer/gutter.js | 5 ++--- lib/ace/lib/lang.js | 14 ++++++++++++++ lib/ace/line_widgets.js | 5 ++--- lib/ace/mode/asciidoc_highlight_rules.js | 8 +++++--- lib/ace/mode/text_highlight_rules.js | 6 +++--- lib/ace/snippets.js | 18 +++++++++--------- 9 files changed, 53 insertions(+), 37 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index cb3ffe23..4b82f19a 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -32,6 +32,7 @@ define(function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); +var lang = require("./lib/lang"); var EventEmitter = require("./lib/event_emitter").EventEmitter; @@ -187,14 +188,15 @@ var BackgroundTokenizer = function(tokenizer, editor) { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { - var args = Array(len + 1); - args.unshift(startRow, 1); - this.lines.splice.apply(this.lines, args); - this.states.splice.apply(this.states, args); + this.lines.splice( startRow, 1); + this.states.splice(startRow, 1); + var toInsert = Array(len + 1); + lang.spliceIntoArray(this.lines, startRow, toInsert); + lang.spliceIntoArray(this.states, startRow, toInsert); } - + this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); - + this.stop(); }; diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 0d4df080..cd14c1a5 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1723,15 +1723,15 @@ var EditSession = function(text, mode) { } else { var args; if (useWrapMode) { - args = [firstRow, 0]; - for (var i = 0; i < len; i++) args.push([]); - this.$wrapData.splice.apply(this.$wrapData, args); + var toInsert = []; + for (var i = 0; i < len; i++) + toInsert.push([]); + lang.spliceIntoArray(this.$wrapData, firstRow, toInsert); } else { - args = Array(len); - args.unshift(firstRow, 0); - this.$rowLengthCache.splice.apply(this.$rowLengthCache, args); + var toInsert = Array(len); + lang.spliceIntoArray(this.$rowLengthCache, firstRow, toInsert); } - + // If some new line is added inside of a foldLine, then split // the fold line up. var foldLines = this.$foldData; diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 9df35593..1563bd67 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -31,6 +31,7 @@ define(function(require, exports, module) { "use strict"; +var lang = require("../lib/lang"); var Range = require("../range").Range; var FoldLine = require("./fold_line").FoldLine; var Fold = require("./fold").Fold; @@ -836,9 +837,8 @@ function Folding() { } else if (delta.action == "delete") { this.foldWidgets.splice(firstRow, len + 1, null); } else { - var args = Array(len + 1); - args.unshift(firstRow, 1); - this.foldWidgets.splice.apply(this.foldWidgets, args); + this.foldWidgets.splice(firstRow, 1); + lang.spliceIntoArray(this.foldWidgets, firstRow, Array(len + 1)); } }; diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 82dcf245..24f9c430 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -111,9 +111,8 @@ var Gutter = function(parentEl) { } else if (delta.action == "delete") { this.$annotations.splice(firstRow, len + 1, null); } else { - var args = new Array(len + 1); - args.unshift(firstRow, 1); - this.$annotations.splice.apply(this.$annotations, args); + this.$annotations.splice(firstRow, 1); + lang.spliceIntoArray(this.$annotations, firstRow, new Array(len + 1)); } }; diff --git a/lib/ace/lib/lang.js b/lib/ace/lib/lang.js index 4405b5c2..e0e9d826 100644 --- a/lib/ace/lib/lang.js +++ b/lib/ace/lib/lang.js @@ -123,6 +123,20 @@ exports.arrayRemove = function(array, value) { } }; +/* + * Splice the items in `a2` into `a1` at position `offset`. + */ +exports.spliceIntoArray = function(a1, offset, a2) { + + // Handle negative offsets. + if (offset < 0) + offset = Math.max(a1.length + offset, 0); + + // Splice. + for (var i = 0; i < a2.length; i++) + a1.splice(i + offset, 0, a2[i]); +} + exports.escapeRegExp = function(str) { return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); }; diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 4023bd55..7cbe9809 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -32,6 +32,7 @@ define(function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); +var lang = require("./lib/lang"); var dom = require("./lib/dom"); var Range = require("./range").Range; @@ -130,9 +131,7 @@ function LineWidgets(session) { }, this); this.$updateRows(); } else { - var args = Array(len); - args.unshift(startRow, 0); - cells.splice.apply(cells, args); + lang.spliceIntoArray(cells, startRow, new Array(len)); this.$updateRows(); } }; diff --git a/lib/ace/mode/asciidoc_highlight_rules.js b/lib/ace/mode/asciidoc_highlight_rules.js index c0d1a305..308fc8e4 100644 --- a/lib/ace/mode/asciidoc_highlight_rules.js +++ b/lib/ace/mode/asciidoc_highlight_rules.js @@ -32,6 +32,7 @@ define(function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); +var lang = require("../lib/lang"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var AsciidocHighlightRules = function() { @@ -215,13 +216,14 @@ var AsciidocHighlightRules = function() { for (var i = stateRules.length; i--; ) { var rule = stateRules[i]; if (rule.include || typeof rule == "string") { - var args = [i, 1].concat(this.$rules[rule.include || rule]); + var toInsert = this.$rules[rule.include || rule]; if (rule.noEscape) { - args = args.filter(function(x) { + toInsert = toInsert.filter(function(x) { return !x.next; }); } - stateRules.splice.apply(stateRules, args); + stateRules.splice(i, 1); + lang.spliceIntoArray(stateRules, i, toInsert); } else if (rule.token in tokenMap) { rule.token = tokenMap[rule.token]; } diff --git a/lib/ace/mode/text_highlight_rules.js b/lib/ace/mode/text_highlight_rules.js index 48e016b0..9e304a53 100644 --- a/lib/ace/mode/text_highlight_rules.js +++ b/lib/ace/mode/text_highlight_rules.js @@ -181,10 +181,10 @@ var TextHighlightRules = function() { toInsert = rule; if (toInsert) { - var args = [i, 1].concat(toInsert); if (rule.noEscape) - args = args.filter(function(x) {return !x.next;}); - state.splice.apply(state, args); + toInsert = toInsert.filter(function(x) {return !x.next;}); + state.splice(i, 1); + lang.spliceIntoArray(state, i, toInsert); // skip included rules since they are already processed //i += args.length - 3; i--; diff --git a/lib/ace/snippets.js b/lib/ace/snippets.js index ee1a5498..e5d585bb 100644 --- a/lib/ace/snippets.js +++ b/lib/ace/snippets.js @@ -335,12 +335,12 @@ var SnippetManager = function() { } var ts = tabstops[id]; - var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); - arg.unshift(i + 1, Math.max(0, i1 - i)); - arg.push(p); + var toInsert = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); + toInsert.push(p); expanding[id] = p; - tokens.splice.apply(tokens, arg); - + tokens.splice(i + 1, Math.max(0, i1 - i)); + lang.spliceIntoArray(tokens, i + 1, toInsert); + if (ts.indexOf(p) === -1) ts.push(p); }; @@ -755,7 +755,7 @@ var TabstopManager = function(editor) { } var i = this.index; - var arg = [i, 0]; + var toInsert = []; var ranges = this.ranges; var editor = this.editor; tabstops.forEach(function(ts) { @@ -776,12 +776,12 @@ var TabstopManager = function(editor) { } if (!ts.firstNonLinked) ts.hasLinkedRanges = false; - arg.push(ts); + toInsert.push(ts); this.addTabstopMarkers(ts); }, this); // tabstop 0 is the last one - arg.push(arg.splice(2, 1)[0]); - this.tabstops.splice.apply(this.tabstops, arg); + toInsert.push(toInsert.splice(0, 1)[0]); + lang.spliceIntoArray(this.tabstops, this.index, toInsert); }; this.addTabstopMarkers = function(ts) { From 91df7cd6635110dca0a97e7419150739f8d9ffd6 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 8 Jan 2014 21:39:30 -0600 Subject: [PATCH 008/545] Revert "Stop using splice.appy() in ace" This reverts commit 8624ab8dcb9bac917488feb8856e8b709418adb7. --- lib/ace/background_tokenizer.js | 14 ++++++-------- lib/ace/edit_session.js | 14 +++++++------- lib/ace/edit_session/folding.js | 6 +++--- lib/ace/layer/gutter.js | 5 +++-- lib/ace/lib/lang.js | 14 -------------- lib/ace/line_widgets.js | 5 +++-- lib/ace/mode/asciidoc_highlight_rules.js | 8 +++----- lib/ace/mode/text_highlight_rules.js | 6 +++--- lib/ace/snippets.js | 18 +++++++++--------- 9 files changed, 37 insertions(+), 53 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 4b82f19a..cb3ffe23 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -32,7 +32,6 @@ define(function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); -var lang = require("./lib/lang"); var EventEmitter = require("./lib/event_emitter").EventEmitter; @@ -188,15 +187,14 @@ var BackgroundTokenizer = function(tokenizer, editor) { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { - this.lines.splice( startRow, 1); - this.states.splice(startRow, 1); - var toInsert = Array(len + 1); - lang.spliceIntoArray(this.lines, startRow, toInsert); - lang.spliceIntoArray(this.states, startRow, toInsert); + var args = Array(len + 1); + args.unshift(startRow, 1); + this.lines.splice.apply(this.lines, args); + this.states.splice.apply(this.states, args); } - + this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); - + this.stop(); }; diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index cd14c1a5..0d4df080 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1723,15 +1723,15 @@ var EditSession = function(text, mode) { } else { var args; if (useWrapMode) { - var toInsert = []; - for (var i = 0; i < len; i++) - toInsert.push([]); - lang.spliceIntoArray(this.$wrapData, firstRow, toInsert); + args = [firstRow, 0]; + for (var i = 0; i < len; i++) args.push([]); + this.$wrapData.splice.apply(this.$wrapData, args); } else { - var toInsert = Array(len); - lang.spliceIntoArray(this.$rowLengthCache, firstRow, toInsert); + args = Array(len); + args.unshift(firstRow, 0); + this.$rowLengthCache.splice.apply(this.$rowLengthCache, args); } - + // If some new line is added inside of a foldLine, then split // the fold line up. var foldLines = this.$foldData; diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 1563bd67..9df35593 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -31,7 +31,6 @@ define(function(require, exports, module) { "use strict"; -var lang = require("../lib/lang"); var Range = require("../range").Range; var FoldLine = require("./fold_line").FoldLine; var Fold = require("./fold").Fold; @@ -837,8 +836,9 @@ function Folding() { } else if (delta.action == "delete") { this.foldWidgets.splice(firstRow, len + 1, null); } else { - this.foldWidgets.splice(firstRow, 1); - lang.spliceIntoArray(this.foldWidgets, firstRow, Array(len + 1)); + var args = Array(len + 1); + args.unshift(firstRow, 1); + this.foldWidgets.splice.apply(this.foldWidgets, args); } }; diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 24f9c430..82dcf245 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -111,8 +111,9 @@ var Gutter = function(parentEl) { } else if (delta.action == "delete") { this.$annotations.splice(firstRow, len + 1, null); } else { - this.$annotations.splice(firstRow, 1); - lang.spliceIntoArray(this.$annotations, firstRow, new Array(len + 1)); + var args = new Array(len + 1); + args.unshift(firstRow, 1); + this.$annotations.splice.apply(this.$annotations, args); } }; diff --git a/lib/ace/lib/lang.js b/lib/ace/lib/lang.js index e0e9d826..4405b5c2 100644 --- a/lib/ace/lib/lang.js +++ b/lib/ace/lib/lang.js @@ -123,20 +123,6 @@ exports.arrayRemove = function(array, value) { } }; -/* - * Splice the items in `a2` into `a1` at position `offset`. - */ -exports.spliceIntoArray = function(a1, offset, a2) { - - // Handle negative offsets. - if (offset < 0) - offset = Math.max(a1.length + offset, 0); - - // Splice. - for (var i = 0; i < a2.length; i++) - a1.splice(i + offset, 0, a2[i]); -} - exports.escapeRegExp = function(str) { return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); }; diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 7cbe9809..4023bd55 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -32,7 +32,6 @@ define(function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); -var lang = require("./lib/lang"); var dom = require("./lib/dom"); var Range = require("./range").Range; @@ -131,7 +130,9 @@ function LineWidgets(session) { }, this); this.$updateRows(); } else { - lang.spliceIntoArray(cells, startRow, new Array(len)); + var args = Array(len); + args.unshift(startRow, 0); + cells.splice.apply(cells, args); this.$updateRows(); } }; diff --git a/lib/ace/mode/asciidoc_highlight_rules.js b/lib/ace/mode/asciidoc_highlight_rules.js index 308fc8e4..c0d1a305 100644 --- a/lib/ace/mode/asciidoc_highlight_rules.js +++ b/lib/ace/mode/asciidoc_highlight_rules.js @@ -32,7 +32,6 @@ define(function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); -var lang = require("../lib/lang"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var AsciidocHighlightRules = function() { @@ -216,14 +215,13 @@ var AsciidocHighlightRules = function() { for (var i = stateRules.length; i--; ) { var rule = stateRules[i]; if (rule.include || typeof rule == "string") { - var toInsert = this.$rules[rule.include || rule]; + var args = [i, 1].concat(this.$rules[rule.include || rule]); if (rule.noEscape) { - toInsert = toInsert.filter(function(x) { + args = args.filter(function(x) { return !x.next; }); } - stateRules.splice(i, 1); - lang.spliceIntoArray(stateRules, i, toInsert); + stateRules.splice.apply(stateRules, args); } else if (rule.token in tokenMap) { rule.token = tokenMap[rule.token]; } diff --git a/lib/ace/mode/text_highlight_rules.js b/lib/ace/mode/text_highlight_rules.js index 9e304a53..48e016b0 100644 --- a/lib/ace/mode/text_highlight_rules.js +++ b/lib/ace/mode/text_highlight_rules.js @@ -181,10 +181,10 @@ var TextHighlightRules = function() { toInsert = rule; if (toInsert) { + var args = [i, 1].concat(toInsert); if (rule.noEscape) - toInsert = toInsert.filter(function(x) {return !x.next;}); - state.splice(i, 1); - lang.spliceIntoArray(state, i, toInsert); + args = args.filter(function(x) {return !x.next;}); + state.splice.apply(state, args); // skip included rules since they are already processed //i += args.length - 3; i--; diff --git a/lib/ace/snippets.js b/lib/ace/snippets.js index e5d585bb..ee1a5498 100644 --- a/lib/ace/snippets.js +++ b/lib/ace/snippets.js @@ -335,12 +335,12 @@ var SnippetManager = function() { } var ts = tabstops[id]; - var toInsert = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); - toInsert.push(p); + var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); + arg.unshift(i + 1, Math.max(0, i1 - i)); + arg.push(p); expanding[id] = p; - tokens.splice(i + 1, Math.max(0, i1 - i)); - lang.spliceIntoArray(tokens, i + 1, toInsert); - + tokens.splice.apply(tokens, arg); + if (ts.indexOf(p) === -1) ts.push(p); }; @@ -755,7 +755,7 @@ var TabstopManager = function(editor) { } var i = this.index; - var toInsert = []; + var arg = [i, 0]; var ranges = this.ranges; var editor = this.editor; tabstops.forEach(function(ts) { @@ -776,12 +776,12 @@ var TabstopManager = function(editor) { } if (!ts.firstNonLinked) ts.hasLinkedRanges = false; - toInsert.push(ts); + arg.push(ts); this.addTabstopMarkers(ts); }, this); // tabstop 0 is the last one - toInsert.push(toInsert.splice(0, 1)[0]); - lang.spliceIntoArray(this.tabstops, this.index, toInsert); + arg.push(arg.splice(2, 1)[0]); + this.tabstops.splice.apply(this.tabstops, arg); }; this.addTabstopMarkers = function(ts) { From 6fe381f6335790f7a0ee6646cdcb9ab442893df5 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 8 Jan 2014 22:00:11 -0600 Subject: [PATCH 009/545] Rename insertText back to insert --- lib/ace/anchor_test.js | 2 +- lib/ace/autocomplete.js | 2 +- lib/ace/background_tokenizer_test.js | 2 +- lib/ace/commands/default_commands.js | 4 ++-- lib/ace/document.js | 16 ++++++---------- lib/ace/document_test.js | 8 ++++---- lib/ace/edit_session.js | 14 ++++---------- lib/ace/edit_session_test.js | 4 ++-- lib/ace/editor.js | 20 +++++++------------- lib/ace/editor_change_document_test.js | 2 +- lib/ace/editor_navigation_test.js | 2 +- lib/ace/ext/elastic_tabstops_lite.js | 2 +- lib/ace/ext/whitespace.js | 2 +- lib/ace/keyboard/vim/commands.js | 10 +++++----- lib/ace/keyboard/vim/maps/motions.js | 6 +++--- lib/ace/mode/javascript_test.js | 2 +- lib/ace/mode/text.js | 12 ++++++------ lib/ace/mouse/dragdrop_handler.js | 2 +- lib/ace/multi_select.js | 8 ++++---- lib/ace/occur_test.js | 12 ++++++------ lib/ace/placeholder_test.js | 18 +++++++++--------- 21 files changed, 67 insertions(+), 83 deletions(-) diff --git a/lib/ace/anchor_test.js b/lib/ace/anchor_test.js index 0661765b..d40d459b 100644 --- a/lib/ace/anchor_test.js +++ b/lib/ace/anchor_test.js @@ -54,7 +54,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertText({row: 1, column: 1}, "123"); + doc.insert({row: 1, column: 1}, "123"); assert.position(anchor.getPosition(), 1, 7); }, diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 2344aede..50154c01 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -170,7 +170,7 @@ var Autocomplete = function() { "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, "Esc": function(editor) { editor.completer.detach(); }, - "Space": function(editor) { editor.completer.detach(); editor.insertText(" ");}, + "Space": function(editor) { editor.completer.detach(); editor.insert(" ");}, "Return": function(editor) { editor.completer.insertMatch(); }, "Shift-Return": function(editor) { editor.completer.insertMatch(true); }, "Tab": function(editor) { editor.completer.insertMatch(); }, diff --git a/lib/ace/background_tokenizer_test.js b/lib/ace/background_tokenizer_test.js index 16c63132..7a4cc78c 100644 --- a/lib/ace/background_tokenizer_test.js +++ b/lib/ace/background_tokenizer_test.js @@ -70,7 +70,7 @@ module.exports = { forceTokenize(doc) testStates(doc, ["comment_regex_allowed", "comment_regex_allowed"]) - doc.insertText({row:0, column:2}, "\n*/") + doc.insert({row:0, column:2}, "\n*/") testStates(doc, [undefined, undefined, "comment_regex_allowed"]) forceTokenize(doc) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 0fd9686c..e4a8212e 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -508,13 +508,13 @@ exports.commands = [{ scrollIntoView: "selectionPart" }, { name: "insertstring", - exec: function(editor, str) { editor.insertText(str); }, + exec: function(editor, str) { editor.insert(str); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "inserttext", exec: function(editor, args) { - editor.insertText(lang.stringRepeat(args.text || "", args.times || 1)); + editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); }, multiSelectAction: "forEach" }, { diff --git a/lib/ace/document.js b/lib/ace/document.js index 768182a4..a84d3bcc 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -62,7 +62,7 @@ var Document = function(textOrLines) { } else if (Array.isArray(textOrLines)) { this.insertMergedLines({row: 0, column: 0}, textOrLines); } else { - this.insertText({row: 0, column:0}, textOrLines); + this.insert({row: 0, column:0}, textOrLines); } }; @@ -78,7 +78,7 @@ var Document = function(textOrLines) { this.setValue = function(text) { var len = this.getLength(); this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insertText({row: 0, column:0}, text); + this.insert({row: 0, column:0}, text); }; /** @@ -265,10 +265,6 @@ var Document = function(textOrLines) { }; // Deprecated methods retained for backwards compatibility. - this.insert = function(position, text){ - console.warn('Use of document.insert is deprecated. Use the insertText method instead.'); - return this.insertText(position, text); - }; this.insertLines = function(row, lines) { console.warn('Use of document.insertLines is deprecated. Use the insertFullLines method instead.'); return this.insertFullLines(row, lines); @@ -282,8 +278,8 @@ var Document = function(textOrLines) { return this.insertMergedLines(position, ['', '']); }; this.insertInLine = function(position, text) { - console.warn('Use of document.insertInLine is deprecated. Use insertText instead.'); - return this.insertText(position, text); + console.warn('Use of document.insertInLine is deprecated. Use insert instead.'); + return this.insert(position, text); }; /** @@ -293,7 +289,7 @@ var Document = function(textOrLines) { * @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. * **/ - this.insertText = function(position, text) { + this.insert = function(position, text) { // Only detect new lines if the document has no line break yet. if (this.getLength() <= 1) @@ -509,7 +505,7 @@ var Document = function(textOrLines) { this.remove(range); var end; if (text) { - end = this.insertText(range.start, text); + end = this.insert(range.start, text); } else { end = range.start; diff --git a/lib/ace/document_test.js b/lib/ace/document_test.js index c29d6133..a91fccf2 100644 --- a/lib/ace/document_test.js +++ b/lib/ace/document_test.js @@ -48,7 +48,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertText({row: 0, column: 1}, "juhu"); + doc.insert({row: 0, column: 1}, "juhu"); assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); var d = deltas.concat(); @@ -126,7 +126,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertText({row: 0, column: 0}, "aa\nbb\ncc"); + doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); var d = deltas.concat(); @@ -143,7 +143,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertText({row: 1, column: 2}, "aa\nbb\ncc"); + doc.insert({row: 1, column: 2}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); var d = deltas.concat(); @@ -160,7 +160,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertText({row: 0, column: 1}, "aa\nbb\ncc"); + doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); var d = deltas.concat(); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 0d4df080..f140bdac 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1127,12 +1127,6 @@ var EditSession = function(text, mode) { this.getTextRange = function(range) { return this.doc.getTextRange(range || this.selection.getRange()); }; - - // Deprecated method retained for backwards compatibility. - this.insert = function(position, text){ - console.warn('Use of editsession.insert is deprecated. Use the insertText method instead.'); - return this.insertText(position, text); - }; /** * Inserts a block of `text` and the indicated `position`. @@ -1142,8 +1136,8 @@ var EditSession = function(text, mode) { * * **/ - this.insertText = function(position, text) { - return this.doc.insertText(position, text); + this.insert = function(position, text) { + return this.doc.insert(position, text); }; /** @@ -1356,7 +1350,7 @@ var EditSession = function(text, mode) { } } - toRange.end = this.insertText(toRange.start, text); + toRange.end = this.insert(toRange.start, text); if (folds.length) { var oldStart = fromRange.start; var newStart = toRange.start; @@ -1390,7 +1384,7 @@ var EditSession = function(text, mode) { this.indentRows = function(startRow, endRow, indentString) { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) - this.insertText({row: row, column:0}, indentString); + this.insert({row: row, column:0}, indentString); }; /** diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index fd20259c..75abf468 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -649,7 +649,7 @@ module.exports = { var foldLines = session.$foldData; function insert(row, column, text) { - session.insertText({row: row, column: column}, text); + session.insert({row: row, column: column}, text); // Force the session to store all changes made to the document NOW // on the undoManager's queue. Otherwise we can't undo in separate @@ -748,7 +748,7 @@ module.exports = { undoManager = session.getUndoManager(), foldLines = session.$foldData; function insert(row, column, text) { - session.insertText({row: row, column: column}, text); + session.insert({row: row, column: column}, text); // Force the session to store all changes made to the document NOW // on the undoManager's queue. Otherwise we can't undo in separate // steps later. diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 79f59e68..af991ef1 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -822,19 +822,13 @@ var Editor = function(renderer, session) { if (this.$readOnly) return; this._emit("paste", text); - this.insertText(text); + this.insert(text); }; this.execCommand = function(command, args) { this.commands.exec(command, this, args); }; - - // Deprecated method retained for backwards compatibility. - this.insert = function(text){ - console.warn('Use of editor.insert is deprecated. Use the insertText method instead.'); - return this.insertText(text); - }; /** * Inserts `text` into wherever the cursor is pointing. @@ -842,7 +836,7 @@ var Editor = function(renderer, session) { * * **/ - this.insertText = function(text) { + this.insert = function(text) { var session = this.session; var mode = session.getMode(); var cursor = this.getCursorPosition(); @@ -888,7 +882,7 @@ var Editor = function(renderer, session) { var lineState = session.getState(cursor.row); var line = session.getLine(cursor.row); var shouldOutdent = mode.checkOutdent(lineState, line, text); - var end = session.insertText(cursor, text); + var end = session.insert(cursor, text); if (transform && transform.selection) { if (transform.selection.length == 2) { // Transform relative to the current column @@ -907,7 +901,7 @@ var Editor = function(renderer, session) { if (session.getDocument().isNewLine(text)) { var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); - session.insertText({row: cursor.row+1, column: 0}, lineIndent); + session.insert({row: cursor.row+1, column: 0}, lineIndent); } if (shouldOutdent) mode.autoOutdent(lineState, session, cursor.row); @@ -1280,7 +1274,7 @@ var Editor = function(renderer, session) { } var cursor = this.getCursorPosition(); - this.insertText("\n"); + this.insert("\n"); this.moveCursorToPosition(cursor); }; @@ -1379,7 +1373,7 @@ var Editor = function(renderer, session) { this.selection.setSelectionRange(range); indentString = "\t"; } - return this.insertText(indentString); + return this.insert(indentString); }; /** @@ -1531,7 +1525,7 @@ var Editor = function(renderer, session) { doc.duplicateLines(row, row); } else { var point = reverse ? range.start : range.end; - var endPoint = doc.insertText(point, doc.getTextRange(range), false); + var endPoint = doc.insert(point, doc.getTextRange(range), false); range.start = point; range.end = endPoint; diff --git a/lib/ace/editor_change_document_test.js b/lib/ace/editor_change_document_test.js index 83fffeb3..a1fdaad9 100644 --- a/lib/ace/editor_change_document_test.js +++ b/lib/ace/editor_change_document_test.js @@ -172,7 +172,7 @@ module.exports = { self.session1.setMode(new HtmlMode()); // 5. Try to type valid HTML - self.session1.insertText({row: 0, column: 0}, ""); + self.session1.insert({row: 0, column: 0}, ""); setTimeout(function() { assert.equal(Object.keys(self.session1.getAnnotations()).length, 0); diff --git a/lib/ace/editor_navigation_test.js b/lib/ace/editor_navigation_test.js index b60d391d..ab348241 100644 --- a/lib/ace/editor_navigation_test.js +++ b/lib/ace/editor_navigation_test.js @@ -150,7 +150,7 @@ module.exports = { var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"])); editor.navigateTo(0, 3); - editor.insertText("juhu"); + editor.insert("juhu"); editor.navigateDown(); assert.position(editor.getCursorPosition(), 1, 7); diff --git a/lib/ace/ext/elastic_tabstops_lite.js b/lib/ace/ext/elastic_tabstops_lite.js index 4d3a40d4..a8c3570c 100644 --- a/lib/ace/ext/elastic_tabstops_lite.js +++ b/lib/ace/ext/elastic_tabstops_lite.js @@ -236,7 +236,7 @@ var ElasticTabstopsLite = function(editor) { if (difference > 0) { // put the spaces after the tab and then delete the tab, so any insertion // points behave as expected - this.$editor.session.getDocument().insertText({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); + this.$editor.session.getDocument().insert({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); this.$editor.session.getDocument().removeInLine(row, it, it + 1); bias += difference; diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index 736e991d..be0cde28 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -153,7 +153,7 @@ exports.convertIndentation = function(session, ch, len) { if (toInsert != match) { doc.removeInLine(i, 0, match.length); - doc.insertText({row: i, column: 0}, toInsert); + doc.insert({row: i, column: 0}, toInsert); } } } diff --git a/lib/ace/keyboard/vim/commands.js b/lib/ace/keyboard/vim/commands.js index defca037..dd3357d6 100644 --- a/lib/ace/keyboard/vim/commands.js +++ b/lib/ace/keyboard/vim/commands.js @@ -104,7 +104,7 @@ var actions = exports.actions = { if (param && param.length) { if (param.length > 1) param = param == "return" ? "\n" : param == "tab" ? "\t" : param; - repeat(function() { editor.insertText(param); }, count || 1); + repeat(function() { editor.insert(param); }, count || 1); editor.navigateLeft(); } } @@ -224,12 +224,12 @@ var actions = exports.actions = { var pos = editor.getCursorPosition(); pos.column = editor.session.getLine(pos.row).length; var text = lang.stringRepeat("\n" + defaultReg.text, count || 1); - editor.session.insertText(pos, text); + editor.session.insert(pos, text); editor.moveCursorTo(pos.row + 1, 0); } else { editor.navigateRight(); - editor.insertText(lang.stringRepeat(defaultReg.text, count || 1)); + editor.insert(lang.stringRepeat(defaultReg.text, count || 1)); editor.navigateLeft(); } editor.setOverwrite(true); @@ -245,11 +245,11 @@ var actions = exports.actions = { var pos = editor.getCursorPosition(); pos.column = 0; var text = lang.stringRepeat(defaultReg.text + "\n", count || 1); - editor.session.insertText(pos, text); + editor.session.insert(pos, text); editor.moveCursorToPosition(pos); } else { - editor.insertText(lang.stringRepeat(defaultReg.text, count || 1)); + editor.insert(lang.stringRepeat(defaultReg.text, count || 1)); } editor.setOverwrite(true); editor.selection.clearSelection(); diff --git a/lib/ace/keyboard/vim/maps/motions.js b/lib/ace/keyboard/vim/maps/motions.js index 2bf580b0..91c8b8af 100644 --- a/lib/ace/keyboard/vim/maps/motions.js +++ b/lib/ace/keyboard/vim/maps/motions.js @@ -545,7 +545,7 @@ module.exports = { if (content.length) { editor.navigateLineEnd() - editor.insertText(content); + editor.insert(content); util.insertMode(editor); } } @@ -562,9 +562,9 @@ module.exports = { if(row > 0) { editor.navigateUp(); editor.navigateLineEnd() - editor.insertText(content); + editor.insert(content); } else { - editor.session.insertText({row: 0, column: 0}, content); + editor.session.insert({row: 0, column: 0}, content); editor.navigateUp(); } util.insertMode(editor); diff --git a/lib/ace/mode/javascript_test.js b/lib/ace/mode/javascript_test.js index cc2b22d7..b413765a 100644 --- a/lib/ace/mode/javascript_test.js +++ b/lib/ace/mode/javascript_test.js @@ -131,7 +131,7 @@ module.exports = { this.mode.toggleCommentLines("start", session, 0, 2); assert.equal([" abc", " cde", " fg"].join("\n"), session.toString()); - session.insertText({row: 0, column: 0}, " "); + session.insert({row: 0, column: 0}, " "); this.mode.toggleCommentLines("start", session, 0, 2); assert.equal(["// abc", "// cde", "// fg"].join("\n"), session.toString()); }, diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 534ac03c..76ba15b5 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -92,8 +92,8 @@ var Mode = function() { if (testRemove(line, i)) return; if (!ignoreBlankLines || /\S/.test(line)) { - doc.insertText({row: i, column: line.length}, lineCommentEnd); - doc.insertText({row: i, column: minIndent}, lineCommentStart); + doc.insert({row: i, column: line.length}, lineCommentEnd); + doc.insert({row: i, column: minIndent}, lineCommentStart); } }; @@ -138,9 +138,9 @@ var Mode = function() { var comment = function(line, i) { if (!ignoreBlankLines || /\S/.test(line)) { if (shouldInsertSpace(line, minIndent, minIndent)) - doc.insertText({row: i, column: minIndent}, commentWithSpace); + doc.insert({row: i, column: minIndent}, commentWithSpace); else - doc.insertText({row: i, column: minIndent}, lineCommentStart); + doc.insert({row: i, column: minIndent}, lineCommentStart); } }; var testRemove = function(line, i) { @@ -244,8 +244,8 @@ var Mode = function() { } else { colDiff = comment.start.length startRow = range.start.row; - session.insertText(range.end, comment.end); - session.insertText(range.start, comment.start); + session.insert(range.end, comment.end); + session.insert(range.start, comment.start); } // todo: selection should have ended up in the right place automatically! if (initialRange.start.row == startRow) diff --git a/lib/ace/mouse/dragdrop_handler.js b/lib/ace/mouse/dragdrop_handler.js index 3ad54bb8..3a4bc188 100644 --- a/lib/ace/mouse/dragdrop_handler.js +++ b/lib/ace/mouse/dragdrop_handler.js @@ -176,7 +176,7 @@ function DragdropHandler(mouseHandler) { var dropData = dataTransfer.getData('Text'); range = { start: dragCursor, - end: editor.session.insertText(dragCursor, dropData) + end: editor.session.insert(dragCursor, dropData) }; editor.focus(); dragOperation = null; diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index 883d9a7c..965cd961 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -544,7 +544,7 @@ var Editor = require("./editor").Editor; this._signal("paste", text); if (!this.inMultiSelectMode || this.inVirtualSelectionMode) - return this.insertText(text); + return this.insert(text); var lines = text.split(/\r\n|\r|\n/); var ranges = this.selection.rangeList.ranges; @@ -557,7 +557,7 @@ var Editor = require("./editor").Editor; if (!range.isEmpty()) this.session.remove(range); - this.session.insertText(range.start, lines[i]); + this.session.insert(range.start, lines[i]); } }; @@ -742,7 +742,7 @@ var Editor = require("./editor").Editor; } var lines = this.session.removeFullLines(fr, lr); lines = this.$reAlignText(lines, guessRange); - this.session.insertText({row: fr, column: 0}, lines.join("\n") + "\n"); + this.session.insert({row: fr, column: 0}, lines.join("\n") + "\n"); if (!guessRange) { range.start.column = 0; range.end.column = lines[lines.length - 1].length; @@ -778,7 +778,7 @@ var Editor = require("./editor").Editor; var l = maxCol - p.column; var d = spaceOffsets[i] - minSpace; if (l > d) - session.insertText(p, lang.stringRepeat(" ", l - d)); + session.insert(p, lang.stringRepeat(" ", l - d)); else session.remove(new Range(p.row, p.column, p.row, p.column - l + d)); diff --git a/lib/ace/occur_test.js b/lib/ace/occur_test.js index a9b2c894..59fb8548 100644 --- a/lib/ace/occur_test.js +++ b/lib/ace/occur_test.js @@ -55,7 +55,7 @@ module.exports = { }, "test: find lines matching" : function() { - editor.session.insertText({row: 0, column: 0}, 'abc\ndef\nxyz\nbcxbc'); + editor.session.insert({row: 0, column: 0}, 'abc\ndef\nxyz\nbcxbc'); var result = occur.matchingLines(editor.session, {needle: 'bc'}), expected = [{row: 0, content: 'abc'}, {row: 3, content: 'bcxbc'}]; assert.deepEqual(result, expected); @@ -63,7 +63,7 @@ module.exports = { "test: display occurrences" : function() { var text = 'abc\ndef\nxyz\nbcx\n'; - editor.session.insertText({row: 0, column: 0}, text); + editor.session.insert({row: 0, column: 0}, text); occur.displayOccurContent(editor, {needle: 'bc'}); assert.equal(editor.getValue(), 'abc\nbcx'); occur.displayOriginalContent(editor); @@ -72,7 +72,7 @@ module.exports = { "test: original position from occur doc" : function() { var text = 'abc\ndef\nxyz\nbcx\n'; - editor.session.insertText({row: 0, column: 0}, text); + editor.session.insert({row: 0, column: 0}, text); occur.displayOccurContent(editor, {needle: 'bc'}); assert.equal(editor.getValue(), 'abc\nbcx'); var pos = occur.occurToOriginalPosition(editor.session, {row: 1, column: 2}); @@ -82,7 +82,7 @@ module.exports = { "test: occur command" : function() { // setup var text = 'hel\nlo\n\nwo\nrld\n'; - editor.session.insertText({row: 0, column: 0}, text); + editor.session.insert({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); // run occur for lines including 'o' @@ -106,7 +106,7 @@ module.exports = { "test: occur navigation" : function() { // setup var text = 'hel\nlo\n\nwo\nrld\n'; - editor.session.insertText({row: 0, column: 0}, text); + editor.session.insert({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); editor.moveCursorToPosition({row: 1, column: 1}); @@ -125,7 +125,7 @@ module.exports = { "test: recursive occur" : function() { // setup var text = 'x\nabc1\nx\nabc2\n'; - editor.session.insertText({row: 0, column: 0}, text); + editor.session.insert({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); // orig -> occur1 diff --git a/lib/ace/placeholder_test.js b/lib/ace/placeholder_test.js index dc7e4b23..97e561fd 100644 --- a/lib/ace/placeholder_test.js +++ b/lib/ace/placeholder_test.js @@ -53,9 +53,9 @@ module.exports = { new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insertText('b'); + editor.insert('b'); assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); - editor.insertText('cd'); + editor.insert('cd'); assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(abcd, abcd);"); editor.remove('left'); editor.remove('left'); @@ -70,7 +70,7 @@ module.exports = { new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(2, 0); - editor.insertText('b'); + editor.insert('b'); assert.equal(session.doc.getValue(), "var a = 10;\nconsole.log(a, a);\nb"); }, @@ -81,12 +81,12 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 4); - editor.insertText('$'); + editor.insert('$'); assert.equal(session.doc.getValue(), "var $a = 10;\nconsole.log($a, $a);"); editor.moveCursorTo(0, 4); // Have to put this in a setTimeout because the anchor is only fixed later. setTimeout(function() { - editor.insertText('v'); + editor.insert('v'); assert.equal(session.doc.getValue(), "var v$a = 10;\nconsole.log(v$a, v$a);"); next(); }, 10); @@ -99,10 +99,10 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insertText('b'); + editor.insert('b'); assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); p.detach(); - editor.insertText('cd'); + editor.insert('cd'); assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(ab, ab);"); }, @@ -136,8 +136,8 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insertText('b'); - editor.insertText('cd'); + editor.insert('b'); + editor.insert('cd'); editor.remove('left'); assert.equal(session.doc.getValue(), "var abc = 10;\nconsole.log(abc, abc);"); // Wait a little for the changes to enter the undo stack From f2a2e4e1a8ce7870824beea9c956ae2671aadc86 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 8 Jan 2014 22:18:05 -0600 Subject: [PATCH 010/545] Rename the 'delete' delta action to 'remove' Matches previous naming convention. --- lib/ace/anchor.js | 2 +- lib/ace/apply_delta.js | 8 ++++---- lib/ace/background_tokenizer.js | 2 +- lib/ace/document.js | 20 ++++++++++---------- lib/ace/edit_session.js | 4 ++-- lib/ace/edit_session/folding.js | 2 +- lib/ace/ext/chromevox.js | 2 +- lib/ace/layer/gutter.js | 2 +- lib/ace/line_widgets.js | 2 +- lib/ace/placeholder.js | 4 ++-- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index affb4f19..fee42bb5 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -133,7 +133,7 @@ var Anchor = exports.Anchor = function(doc, row, column) { } // DELTA ENVELOPS POINT (delete only): Move point to delta start. - if (delta.action != 'delete') + if (delta.action != 'remove') throw 'Delete action expected.'; return { diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 02c0a498..142d5e1c 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -53,8 +53,8 @@ function throwDeltaError(delta, errorText){ function validateDelta(lines, delta) { // Validate action. - if (delta.action != 'insert' && delta.action != 'delete') - fnThrow('Delta action must be "insert" or "delete".'); + if (delta.action != 'insert' && delta.action != 'remove') + fnThrow('Delta action must be "insert" or "remove".'); // Validate lines. if (!delta.lines instanceof Array) @@ -103,7 +103,7 @@ exports.applyDelta = function(lines, delta) { lines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); break; - case 'delete': + case 'remove': lines[row] = line.substring(0, startColumn) + line.substring(endColumn); break; } @@ -122,7 +122,7 @@ exports.applyDelta = function(lines, delta) { joinLineWithNext(lines, delta.range.end.row); break; - case 'delete': + case 'remove': splitLine(lines, delta.range.end); splitLine(lines, delta.range.start); lines.splice( diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index cb3ffe23..4d3d7034 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -183,7 +183,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { if (len === 0) { this.lines[startRow] = null; - } else if (delta.action == "delete") { + } else if (delta.action == 'remove') { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { diff --git a/lib/ace/document.js b/lib/ace/document.js index a84d3bcc..de77582e 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -306,7 +306,7 @@ var Document = function(textOrLines) { * * `"insert"` * * `range`: the [[Range]] of the change within the document * * `lines`: the lines being added - * * `"delete"` + * * `"remove"` * * `range`: the [[Range]] of the change within the document * * `lines`: the lines being removed * @@ -395,7 +395,7 @@ var Document = function(textOrLines) { // Apply delta (emits change). range = this.$getClippedRange(range); this.applyDelta({ - action: 'delete', + action: 'remove', range: range, lines: this.getLinesForRange(range), }); @@ -418,7 +418,7 @@ var Document = function(textOrLines) { // Apply delta (emits change). this.applyDelta({ - action: "delete", + action: 'remove', range: range, lines: this.getLinesForRange(range) }); @@ -455,7 +455,7 @@ var Document = function(textOrLines) { // Apply delta (emits change). this.applyDelta({ - action: "delete", + action: 'remove', range: range, lines: this.getLinesForRange(range) }); @@ -474,7 +474,7 @@ var Document = function(textOrLines) { if (row < this.getLength() - 1 && row >= 0) { // Apply delta (emits change). this.applyDelta({ - action: "delete", + action: 'remove', range: new Range(row, this.getLine(row).length, row + 1, 0), lines: ['', ''] }); @@ -516,7 +516,7 @@ var Document = function(textOrLines) { /** * Applies all changes in `deltas` to the document. - * @param {Array} deltas An array of delta objects (can include 'insert' and 'delete' actions) + * @param {Array} deltas An array of delta objects (can include 'insert' and 'remove' actions) **/ this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { @@ -536,7 +536,7 @@ var Document = function(textOrLines) { /** * Applies `delta` to the document. - * @param {Object} delta A delta object (can include 'insert' and 'delete' actions) + * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) **/ this.applyDelta = function(delta) { applyDelta(this.$lines, delta); @@ -545,12 +545,12 @@ var Document = function(textOrLines) { /** * Reverts `delta` from the document. - * @param {Object} delta A delta object (can include 'insert' and 'delete' actions) + * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) **/ this.revertDelta = function(delta) { this.applyDelta({ - action: (delta.action == 'insert' ? 'delete' : 'insert'), + action: (delta.action == 'insert' ? 'remove' : 'insert'), range: delta.range.clone(), lines: delta.lines.slice() }); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index f140bdac..7312f23b 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1685,7 +1685,7 @@ var EditSession = function(text, mode) { this.$updating = true; if (len != 0) { - if (action == "delete") { + if (action == 'remove') { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; @@ -1760,7 +1760,7 @@ var EditSession = function(text, mode) { // Realign folds. E.g. if you add some new chars before a fold, the // fold should "move" to the right. len = Math.abs(e.data.range.start.column - e.data.range.end.column); - if (action == "delete") { + if (action == 'remove') { // Get all the folds in the change range and remove them. removedFolds = this.getFoldsInRange(e.data.range); this.removeFolds(removedFolds); diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 9df35593..583dba0d 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -833,7 +833,7 @@ function Folding() { if (len === 0) { this.foldWidgets[firstRow] = null; - } else if (delta.action == "delete") { + } else if (delta.action == 'remove') { this.foldWidgets.splice(firstRow, len + 1, null); } else { var args = Array(len + 1); diff --git a/lib/ace/ext/chromevox.js b/lib/ace/ext/chromevox.js index 20bbb6c7..4abb8278 100644 --- a/lib/ace/ext/chromevox.js +++ b/lib/ace/ext/chromevox.js @@ -581,7 +581,7 @@ var onSelectionChange = function(evt) { var onChange = function(evt) { var data = evt.data; switch (data.action) { - case 'delete': + case 'remove': cvox.Api.speak(data.text, 0, DELETED_PROP); /* Let the future cursor change event know it's from text change. */ changed = true; diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 82dcf245..235425ab 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -108,7 +108,7 @@ var Gutter = function(parentEl) { var len = range.end.row - firstRow; if (len === 0) { // do nothing - } else if (delta.action == "delete") { + } else if (delta.action == 'remove') { this.$annotations.splice(firstRow, len + 1, null); } else { var args = new Array(len + 1); diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 4023bd55..d0c7581e 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -123,7 +123,7 @@ function LineWidgets(session) { if (len === 0) { // return - } else if (delta.action == "delete") { + } else if (delta.action == 'remove') { var removed = cells.splice(startRow + 1, len); removed.forEach(function(w) { w && this.removeLineWidget(w); diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index c9a44e50..df0bfa9e 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -169,7 +169,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) newPos.column += lengthDiff; this.doc.insertMergedLines(newPos, delta.lines); } - } else if(delta.action === "delete") { + } else if(delta.action === 'remove') { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; @@ -191,7 +191,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) } }.bind(this), 0); } - else if(range.start.column === this.pos.column && delta.action === "delete") { + else if(range.start.column === this.pos.column && delta.action === 'remove') { setTimeout(function() { for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; From 3a048cdf611b86151eb28a01af7db666bce39aca Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 8 Jan 2014 22:51:39 -0600 Subject: [PATCH 011/545] Bring back insertInLine Avoids an extra $split call. --- lib/ace/document.js | 37 +++++++++++++++++++++++++--- lib/ace/ext/elastic_tabstops_lite.js | 2 +- lib/ace/ext/whitespace.js | 2 +- lib/ace/mode/text.js | 4 +-- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index de77582e..6968e8f0 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -277,10 +277,6 @@ var Document = function(textOrLines) { console.warn('Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.'); return this.insertMergedLines(position, ['', '']); }; - this.insertInLine = function(position, text) { - console.warn('Use of document.insertInLine is deprecated. Use insert instead.'); - return this.insert(position, text); - }; /** * Inserts a block of `text` at the indicated `position`. @@ -298,6 +294,39 @@ var Document = function(textOrLines) { return this.insertMergedLines(position, this.$split(text)); }; + /** + * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event. + * + * This differs from the `insert` method in two ways: + * 1. This does NOT handle newline characters (single-line text only). + * 2. This is faster than the `insert` method for single-line text insertions. + * + * @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}` + * @param {String} text A chunk of text + * @returns {Object} Returns an object containing the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + **/ + this.insertInLine = function(position, text) { + + // Calculate insertion range end point. + this.$clipPosition(position); + var endPoint = { + row : position.row, + column : position.column + text.length + }; + + // Apply delta (emits change). + this.applyDelta({ + action: "insert", + range: Range.fromPoints(position, endPoint), + lines: [text] + }); + + return endPoint; + }; + /** * Fires whenever the document changes. * diff --git a/lib/ace/ext/elastic_tabstops_lite.js b/lib/ace/ext/elastic_tabstops_lite.js index a8c3570c..9901c5df 100644 --- a/lib/ace/ext/elastic_tabstops_lite.js +++ b/lib/ace/ext/elastic_tabstops_lite.js @@ -236,7 +236,7 @@ var ElasticTabstopsLite = function(editor) { if (difference > 0) { // put the spaces after the tab and then delete the tab, so any insertion // points behave as expected - this.$editor.session.getDocument().insert({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); + this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); this.$editor.session.getDocument().removeInLine(row, it, it + 1); bias += difference; diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index be0cde28..83486fb0 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -153,7 +153,7 @@ exports.convertIndentation = function(session, ch, len) { if (toInsert != match) { doc.removeInLine(i, 0, match.length); - doc.insert({row: i, column: 0}, toInsert); + doc.insertInLine({row: i, column: 0}, toInsert); } } } diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 76ba15b5..343fc271 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -92,8 +92,8 @@ var Mode = function() { if (testRemove(line, i)) return; if (!ignoreBlankLines || /\S/.test(line)) { - doc.insert({row: i, column: line.length}, lineCommentEnd); - doc.insert({row: i, column: minIndent}, lineCommentStart); + doc.insertInLine({row: i, column: line.length}, lineCommentEnd); + doc.insertInLine({row: i, column: minIndent}, lineCommentStart); } }; From 08edcdfc988fe8eacc40af4da464fb8ebde8c61c Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Fri, 10 Jan 2014 22:49:17 -0600 Subject: [PATCH 012/545] Stop doing a line-by-line splicing in applyDelta Also brings back the functionality where large deltas are split into smaller deltas so that .splice.apply() calls will work. --- lib/ace/apply_delta.js | 7 ++----- lib/ace/document.js | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 142d5e1c..380c3289 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -79,9 +79,9 @@ function validateDelta(lines, delta) { // TODO: // - Validate that the ending column offset matches the lines. // - Validate the deleted lines match the lines in the document. + // - Vaiidate that an insert delta does not contain more than 65001 entries. } - exports.applyDelta = function(lines, delta) { // Validate delta. @@ -114,10 +114,7 @@ exports.applyDelta = function(lines, delta) { case 'insert': splitLine(lines, delta.range.start); - for (var i = 0; i < delta.lines.length; i++) { - var row = delta.range.start.row + 1 + i; - lines.splice(row, 0, delta.lines[i]); - } + lines.splice.apply(lines, [delta.range.start.row + 1, 0].concat(delta.lines)); joinLineWithNext(lines, delta.range.start.row); joinLineWithNext(lines, delta.range.end.row); break; diff --git a/lib/ace/document.js b/lib/ace/document.js index 6968e8f0..cefaa136 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -568,8 +568,36 @@ var Document = function(textOrLines) { * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) **/ this.applyDelta = function(delta) { + + // Split large insert deltas. This is necessary because: + // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) + // 2. fn.apply() doesn't work for a large number of params. The mallest threshold is on safari 0xFFFF. + // + // To Do: Ideally we'd be consistent and also split 'delete' deltas. We don't do this now, because delete + // delta handling is too slow. If we make delete delta handling faster we can split all large deltas + // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js + // If we do this, update validateDelta() to limit the number of lines in a delete delta. + var bIsInsert = delta.action == 'insert'; + while (bIsInsert && delta.lines.length > 65001) + { + // Get split deltas. + var lines = delta.lines.splice(0, 65000); + lines.push(''); + this.applyDelta({ + action: delta.action, + lines: lines, + range: new Range(delta.range.start.row, delta.range.start.column, + delta.range.start.row + 65000, 0) + }); + + // Update remaining delta. + delta.range.start.row += 65000; + delta.range.start.column = 0; + } + + // Apply. applyDelta(this.$lines, delta); - this._emit("change", { data: delta }); + this._emit("change", { data: delta }); }; /** From ef0e8da5223884d4ff041ff59b1711488ca76a4a Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 11 Jan 2014 11:20:34 -0600 Subject: [PATCH 013/545] Fix / complete validateDelta This uncovered the fact that until now delta.range had not always been a Range object. This inconsistency has been resolved by my changes in mirror.js. --- lib/ace/apply_delta.js | 96 +++++++++++++++++++++------------------- lib/ace/worker/mirror.js | 13 +++++- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 380c3289..3d40d614 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -33,59 +33,63 @@ define(function(require, exports, module) { var Range = require("./range").Range; -function splitLine (lines, point) { - var text = lines[point.row]; - lines[point.row] = text.slice(0, point.column); - lines.splice(point.row + 1, 0, text.slice(point.column)); +function splitLine (docLines, position) { + var text = docLines[position.row]; + docLines[position.row] = text.slice(0, position.column); + docLines.splice(position.row + 1, 0, text.slice(position.column)); } -function joinLineWithNext(lines, row) { - lines[row] += lines[row + 1]; - lines.splice(row + 1, 1); +function joinLineWithNext(docLines, row) { + docLines[row] += docLines[row + 1]; + docLines.splice(row + 1, 1); } function throwDeltaError(delta, errorText){ - errorText = 'Invalid Delta: ' + errorText; - console.log(errorText, delta); - throw errorText; + console.log('Invalid Delta:', delta); + throw 'Invalid Delta: ' + errorText; } -function validateDelta(lines, delta) { +function positionInDocument(docLines, position) +{ + return position.row >= 0 && position.row < docLines.length && + position.column >= 0 && position.column <= docLines[position.row].length; +} - // Validate action. +function validateDelta(docLines, delta) { + + // Validate action string. if (delta.action != 'insert' && delta.action != 'remove') - fnThrow('Delta action must be "insert" or "remove".'); - - // Validate lines. - if (!delta.lines instanceof Array) - fnThrow('Delta lines must be an array'); + throwDeltaError(delta, 'delta.action must be "insert" or "remove"'); + // Validate lines type. + if (!(delta.lines instanceof Array)) + throwDeltaError(delta, 'delta.lines must be an Array'); + // Validate range type. - if (!delta.range instanceof Range) - fnThrow('Range object is not an instance of the Range class'); - - // Validate start point. + if (!(delta.range instanceof Range)) + throwDeltaError(delta, 'delta.range must be an instance of the Range class'); + + // Validate that the start point is contained in the document. var start = delta.range.start; - if (Math.min(Math.max(start.row, 0), lines.length - 1 ) != start.row || - Math.min(Math.max(start.column, 0), lines[start.row].length) != start.column) - { - fnThrow('Range start point not contained in document'); - } + if (!positionInDocument(docLines, delta.range.start)) + throwDeltaError(delta, 'delta.range.start must be contained in document'); - // Validate ending row offset. - if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row) - fnThrow('Range row offsets does not match delta lines'); + // Validate that the end point is contained in the document (remove deltas only). + var end = delta.range.end; + if (delta.action == 'remove' && !positionInDocument(docLines, end)) + throwDeltaError(delta, 'delta.range.end must contained in document for "remove" actions'); - // TODO: - // - Validate that the ending column offset matches the lines. - // - Validate the deleted lines match the lines in the document. - // - Vaiidate that an insert delta does not contain more than 65001 entries. + // Validate that the .range size matches the .lines size. + var numRangeRows = end.row - start.row; + var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); + if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) + throwDeltaError(delta, 'delta.range must match delta lines'); } -exports.applyDelta = function(lines, delta) { +exports.applyDelta = function(docLines, delta) { // Validate delta. - validateDelta(lines, delta); + validateDelta(docLines, delta); // Apply delta. if (delta.range.start.row == delta.range.end.row) @@ -96,15 +100,15 @@ exports.applyDelta = function(lines, delta) { var row = delta.range.start.row; var startColumn = delta.range.start.column; var endColumn = delta.range.end.column; - var line = lines[row]; + var line = docLines[row]; switch (delta.action) { case 'insert': - lines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); break; case 'remove': - lines[row] = line.substring(0, startColumn) + line.substring(endColumn); + docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); break; } } else { @@ -113,20 +117,20 @@ exports.applyDelta = function(lines, delta) { switch (delta.action) { case 'insert': - splitLine(lines, delta.range.start); - lines.splice.apply(lines, [delta.range.start.row + 1, 0].concat(delta.lines)); - joinLineWithNext(lines, delta.range.start.row); - joinLineWithNext(lines, delta.range.end.row); + splitLine(docLines, delta.range.start); + docLines.splice.apply(docLines, [delta.range.start.row + 1, 0].concat(delta.lines)); + joinLineWithNext(docLines, delta.range.start.row); + joinLineWithNext(docLines, delta.range.end.row); break; case 'remove': - splitLine(lines, delta.range.end); - splitLine(lines, delta.range.start); - lines.splice( + splitLine(docLines, delta.range.end); + splitLine(docLines, delta.range.start); + docLines.splice( delta.range.start.row + 1, // Where to start deleting delta.range.end.row - delta.range.start.row + 1 // Num lines to delete. ); - joinLineWithNext(lines, delta.range.start.row); + joinLineWithNext(docLines, delta.range.start.row); break; } } diff --git a/lib/ace/worker/mirror.js b/lib/ace/worker/mirror.js index 7a3318fb..d55e84f4 100644 --- a/lib/ace/worker/mirror.js +++ b/lib/ace/worker/mirror.js @@ -1,6 +1,7 @@ define(function(require, exports, module) { "use strict"; +var Range = require("../range").Range; var Document = require("../document").Document; var lang = require("../lib/lang"); @@ -12,7 +13,17 @@ var Mirror = exports.Mirror = function(sender) { var _self = this; sender.on("change", function(e) { - doc.applyDeltas(e.data); + + // Convert delta.range back into a Range instance since + // window.onMessage loses non-primitive data. See http://jsfiddle.net/nqJfw/1/. + var deltas = e.data; + for (var i in deltas) + { + var delta = deltas[i]; + delta.range = Range.fromPoints(delta.range.start, delta.range.end); + } + + doc.applyDeltas(deltas); if (_self.$timeout) return deferredUpdate.schedule(_self.$timeout); _self.onUpdate(); From f59708a5ba7b049271db9846ae8a71e88a9f6625 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 11 Jan 2014 12:00:10 -0600 Subject: [PATCH 014/545] Add a doNotValidate param to applyDelta Set it to true in insertInLine/removeInLine. Also sped up indent/dedent by using insertInLine and removeInLine. --- lib/ace/apply_delta.js | 5 +++-- lib/ace/document.js | 12 ++++++------ lib/ace/edit_session.js | 22 +++++++++++----------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 3d40d614..1317ce98 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -86,10 +86,11 @@ function validateDelta(docLines, delta) { throwDeltaError(delta, 'delta.range must match delta lines'); } -exports.applyDelta = function(docLines, delta) { +exports.applyDelta = function(docLines, delta, doNotValidate) { // Validate delta. - validateDelta(docLines, delta); + if (!doNotValidate) + validateDelta(docLines, delta); // Apply delta. if (delta.range.start.row == delta.range.end.row) diff --git a/lib/ace/document.js b/lib/ace/document.js index cefaa136..c4f8a9eb 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -322,7 +322,7 @@ var Document = function(textOrLines) { action: "insert", range: Range.fromPoints(position, endPoint), lines: [text] - }); + }, true /*doNotValidate*/); return endPoint; }; @@ -449,8 +449,8 @@ var Document = function(textOrLines) { this.applyDelta({ action: 'remove', range: range, - lines: this.getLinesForRange(range) - }); + lines: this.getLinesForRange(range), + }, true /*doNotValidate*/); return range.start; }; @@ -567,7 +567,7 @@ var Document = function(textOrLines) { * Applies `delta` to the document. * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) **/ - this.applyDelta = function(delta) { + this.applyDelta = function(delta, doNotValidate) { // Split large insert deltas. This is necessary because: // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) @@ -596,8 +596,8 @@ var Document = function(textOrLines) { } // Apply. - applyDelta(this.$lines, delta); - this._emit("change", { data: delta }); + applyDelta(this.$lines, delta, doNotValidate); + this._emit("change", { data: delta }); }; /** diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 7312f23b..414b68c1 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1384,7 +1384,7 @@ var EditSession = function(text, mode) { this.indentRows = function(startRow, endRow, indentString) { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) - this.insert({row: row, column:0}, indentString); + this.doc.insertInLine({row: row, column: 0}, indentString); }; /** @@ -1395,25 +1395,25 @@ var EditSession = function(text, mode) { **/ this.outdentRows = function (range) { var rowRange = range.collapseRows(); - var deleteRange = new Range(0, 0, 0, 0); var size = this.getTabSize(); - + for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) { var line = this.getLine(i); - - deleteRange.start.row = i; - deleteRange.end.row = i; + var row = i; + var startCol = 0; + var endCol = 0; + for (var j = 0; j < size; ++j) if (line.charAt(j) != ' ') break; if (j < size && line.charAt(j) == '\t') { - deleteRange.start.column = j; - deleteRange.end.column = j + 1; + startCol = j; + endCol = j + 1; } else { - deleteRange.start.column = 0; - deleteRange.end.column = j; + startCol = 0; + endCol = j; } - this.remove(deleteRange); + this.doc.removeInLine(row, startCol, endCol); } }; From ddd695ee3f2a1e851c842d4d17851341067d499b Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 11 Jan 2014 14:43:47 -0600 Subject: [PATCH 015/545] Store single-line deltas as .text instead of .lines in undo history Stores single-line delta content as .text instead of .lines in undo history. This is done without modifying the original delta object in case the caller still retains a handle to the original. --- lib/ace/undomanager.js | 80 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index 304dac23..4d978d46 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -61,14 +61,19 @@ var UndoManager = function() { * **/ this.execute = function(options) { - var deltas = options.args[0]; + + // Normalize deltas for storage. + var deltaSets = this.$serializeDeltas(options.args[0]); + + // Add deltas to undo stack. this.$doc = options.args[1]; if (options.merge && this.hasUndo()){ - deltas = this.$undoStack.pop().concat(deltas); + deltaSets = this.$undoStack.pop().concat(deltaSets); } - this.$undoStack.push(deltas); + this.$undoStack.push(deltaSets); + + // Reset redo stack. this.$redoStack = []; - if (this.dirtyCounter < 0) { // The user has made a change after undoing past the last clean state. // We can never get back to a clean state now until markClean() is called. @@ -85,12 +90,11 @@ var UndoManager = function() { * @returns {Range} The range of the undo. **/ this.undo = function(dontSelect) { - var deltas = this.$undoStack.pop(); + var deltaSets = this.$undoStack.pop(); var undoSelectionRange = null; - if (deltas) { - undoSelectionRange = - this.$doc.undoChanges(deltas, dontSelect); - this.$redoStack.push(deltas); + if (deltaSets) { + undoSelectionRange = this.$doc.undoChanges(this.$deserializeDeltas(deltaSets), dontSelect); + this.$redoStack.push(deltaSets); this.dirtyCounter--; } @@ -104,15 +108,14 @@ var UndoManager = function() { * **/ this.redo = function(dontSelect) { - var deltas = this.$redoStack.pop(); + var deltaSets = this.$redoStack.pop(); var redoSelectionRange = null; - if (deltas) { + if (deltaSets) { redoSelectionRange = - this.$doc.redoChanges(deltas, dontSelect); - this.$undoStack.push(deltas); + this.$doc.redoChanges(this.$deserializeDeltas(deltaSets), dontSelect); + this.$undoStack.push(deltaSets); this.dirtyCounter++; } - return redoSelectionRange; }; @@ -160,7 +163,54 @@ var UndoManager = function() { this.isClean = function() { return this.dirtyCounter === 0; }; - + + // Serializes deltaSets to reduce memory usage. + this.$serializeDeltas = function(deltaSets) + { + return this.$cloneDeltaSetsObj(deltaSets, $serializeDelta); + } + function $serializeDelta(delta){ + return { + action: delta.action, + range: delta.range, + lines: (delta.lines.length == 1 ? null : delta.lines), + text: (delta.lines.length == 1 ? delta.lines[0] : null ), + }; + } + + // Deserializes deltaSets to allow application to the document. + this.$deserializeDeltas = function(deltaSets) + { + return this.$cloneDeltaSetsObj(deltaSets, $deserializeDelta); + } + function $deserializeDelta(delta){ + return { + action: delta.action, + range: delta.range, + lines: (delta.text === null ? delta.lines : [delta.text]) + }; + } + + // Helper for delta serialization and deserialization. + this.$cloneDeltaSetsObj = function(deltaSets_old, fnGetModifiedDelta) + { + var deltaSets_new = new Array(deltaSets_old.length); + for (var i in deltaSets_old) + { + var deltaSet_old = deltaSets_old[i]; + var deltaSet_new = { group: deltaSet_old.group, deltas: new Array(deltaSet_old.length)}; + + for (var i_ in deltaSet_old.deltas) + { + var delta_old = deltaSet_old.deltas[i_]; + deltaSet_new.deltas[i_] = fnGetModifiedDelta(delta_old); + } + + deltaSets_new[i] = deltaSet_new; + } + return deltaSets_new; + } + }).call(UndoManager.prototype); exports.UndoManager = UndoManager; From 35a27fd1ba52cccb765f515f3924d9ba579a7eea Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 11 Jan 2014 14:45:08 -0600 Subject: [PATCH 016/545] Treat deltas with empty ranges as NOOPs --- lib/ace/document.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ace/document.js b/lib/ace/document.js index c4f8a9eb..e203d77c 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -569,6 +569,10 @@ var Document = function(textOrLines) { **/ this.applyDelta = function(delta, doNotValidate) { + // An empty range is a NOOP. + if (delta.range.isEmpty()) + return; + // Split large insert deltas. This is necessary because: // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) // 2. fn.apply() doesn't work for a large number of params. The mallest threshold is on safari 0xFFFF. From 6b280bf6bb48aa81fc73582f85877f5626f1eae0 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 11 Jan 2014 15:23:20 -0600 Subject: [PATCH 017/545] Code review fixes (mostly formatting) - Fix unconventional '{' formatting - Reformat `UndoManager` changes - Revert change from `insertInLine` to `insert` in text.js --- lib/ace/anchor.js | 7 +++---- lib/ace/apply_delta.js | 6 ++---- lib/ace/document.js | 12 ++++++------ lib/ace/mode/text.js | 4 ++-- lib/ace/placeholder.js | 4 ++-- lib/ace/undomanager.js | 32 ++++++++++++++------------------ lib/ace/worker/mirror.js | 3 +-- 7 files changed, 30 insertions(+), 38 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index fee42bb5..5622bf5c 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -101,14 +101,13 @@ var Anchor = exports.Anchor = function(doc, row, column) { **/ this.onChange = function(e) { - function _pointsInOrder(point1, point2, equalPointsInOrder) - { + function _pointsInOrder(point1, point2, equalPointsInOrder) { var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); } - function getTransformedPoint(delta, point, moveIfEqual) - { + function getTransformedPoint(delta, point, moveIfEqual) { + // Get delta info. var deltaIsInsert = (delta.action == 'insert') var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.row - delta.range.start.row); diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 1317ce98..86bc89c6 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -49,8 +49,7 @@ function throwDeltaError(delta, errorText){ throw 'Invalid Delta: ' + errorText; } -function positionInDocument(docLines, position) -{ +function positionInDocument(docLines, position) { return position.row >= 0 && position.row < docLines.length && position.column >= 0 && position.column <= docLines[position.row].length; } @@ -93,8 +92,7 @@ exports.applyDelta = function(docLines, delta, doNotValidate) { validateDelta(docLines, delta); // Apply delta. - if (delta.range.start.row == delta.range.end.row) - { + if (delta.range.start.row == delta.range.end.row) { // Apply single-line delta. // Note: The multi-line code below correctly handle single-line // deltas too, but we need to short-circuit for speed. diff --git a/lib/ace/document.js b/lib/ace/document.js index e203d77c..97d69968 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -108,14 +108,15 @@ var Document = function(textOrLines) { **/ // check for IE split bug - if ("aaa".split(/a/).length === 0) + if ("aaa".split(/a/).length === 0) { this.$split = function(text) { return text.replace(/\r\n|\r/g, "\n").split("\n"); }; - else + } else { this.$split = function(text) { return text.split(/\r\n|\r|\n/); }; + } this.$detectNewLine = function(text) { @@ -582,8 +583,8 @@ var Document = function(textOrLines) { // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js // If we do this, update validateDelta() to limit the number of lines in a delete delta. var bIsInsert = delta.action == 'insert'; - while (bIsInsert && delta.lines.length > 65001) - { + while (bIsInsert && delta.lines.length > 65001) { + // Get split deltas. var lines = delta.lines.splice(0, 65000); lines.push(''); @@ -608,8 +609,7 @@ var Document = function(textOrLines) { * Reverts `delta` from the document. * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) **/ - this.revertDelta = function(delta) - { + this.revertDelta = function(delta) { this.applyDelta({ action: (delta.action == 'insert' ? 'remove' : 'insert'), range: delta.range.clone(), diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 343fc271..d04fed78 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -138,9 +138,9 @@ var Mode = function() { var comment = function(line, i) { if (!ignoreBlankLines || /\S/.test(line)) { if (shouldInsertSpace(line, minIndent, minIndent)) - doc.insert({row: i, column: minIndent}, commentWithSpace); + doc.insertInLine({row: i, column: minIndent}, commentWithSpace); else - doc.insert({row: i, column: minIndent}, lineCommentStart); + doc.insertInLine({row: i, column: minIndent}, lineCommentStart); } }; var testRemove = function(line, i) { diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index df0bfa9e..1d345a24 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -161,7 +161,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) var distanceFromStart = range.start.column - this.pos.column; this.length += lengthDiff; if(!this.session.$fromUndo) { - if(delta.action === "insert") { + if(delta.action === 'insert') { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; @@ -179,7 +179,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) } } // Special case: insert in beginning - if(range.start.column === this.pos.column && delta.action === "insert") { + if(range.start.column === this.pos.column && delta.action === 'insert') { setTimeout(function() { this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff); for (var i = 0; i < this.others.length; i++) { diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index 4d978d46..209cf3db 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -165,10 +165,15 @@ var UndoManager = function() { }; // Serializes deltaSets to reduce memory usage. - this.$serializeDeltas = function(deltaSets) - { - return this.$cloneDeltaSetsObj(deltaSets, $serializeDelta); - } + this.$serializeDeltas = function(deltaSets) { + return cloneDeltaSetsObj(deltaSets, $serializeDelta); + }; + + // Deserializes deltaSets to allow application to the document. + this.$deserializeDeltas = function(deltaSets) { + return cloneDeltaSetsObj(deltaSets, $deserializeDelta); + }; + function $serializeDelta(delta){ return { action: delta.action, @@ -177,13 +182,8 @@ var UndoManager = function() { text: (delta.lines.length == 1 ? delta.lines[0] : null ), }; } - - // Deserializes deltaSets to allow application to the document. - this.$deserializeDeltas = function(deltaSets) - { - return this.$cloneDeltaSetsObj(deltaSets, $deserializeDelta); - } - function $deserializeDelta(delta){ + + function $deserializeDelta(delta) { return { action: delta.action, range: delta.range, @@ -191,17 +191,13 @@ var UndoManager = function() { }; } - // Helper for delta serialization and deserialization. - this.$cloneDeltaSetsObj = function(deltaSets_old, fnGetModifiedDelta) - { + function cloneDeltaSetsObj(deltaSets_old, fnGetModifiedDelta) { var deltaSets_new = new Array(deltaSets_old.length); - for (var i in deltaSets_old) - { + for (var i in deltaSets_old) { var deltaSet_old = deltaSets_old[i]; var deltaSet_new = { group: deltaSet_old.group, deltas: new Array(deltaSet_old.length)}; - for (var i_ in deltaSet_old.deltas) - { + for (var i_ in deltaSet_old.deltas) { var delta_old = deltaSet_old.deltas[i_]; deltaSet_new.deltas[i_] = fnGetModifiedDelta(delta_old); } diff --git a/lib/ace/worker/mirror.js b/lib/ace/worker/mirror.js index d55e84f4..2f33fea6 100644 --- a/lib/ace/worker/mirror.js +++ b/lib/ace/worker/mirror.js @@ -17,8 +17,7 @@ var Mirror = exports.Mirror = function(sender) { // Convert delta.range back into a Range instance since // window.onMessage loses non-primitive data. See http://jsfiddle.net/nqJfw/1/. var deltas = e.data; - for (var i in deltas) - { + for (var i in deltas) { var delta = deltas[i]; delta.range = Range.fromPoints(delta.range.start, delta.range.end); } From 7f1bc7af2fcc431241c2e8812588164394444df9 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Sat, 11 Jan 2014 15:48:38 -0600 Subject: [PATCH 018/545] Break out Anchor.onChange helper functions This should be faster since we don't have to re-initialize the helper functions each time Anchor.onChange is fired. --- lib/ace/anchor.js | 78 +++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 5622bf5c..c9c27dfe 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -100,50 +100,50 @@ var Anchor = exports.Anchor = function(doc, row, column) { * **/ this.onChange = function(e) { + var delta = e.data; + var point = this.$getTransformedPoint(delta, {row: this.row, column: this.column}); + this.setPosition(point.row, point.column, true); + }; + + function $pointsInOrder(point1, point2, equalPointsInOrder) { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); + } + + this.$getTransformedPoint = function (delta, point) { - function _pointsInOrder(point1, point2, equalPointsInOrder) { - var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; - return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); - } - - function getTransformedPoint(delta, point, moveIfEqual) { - - // Get delta info. - var deltaIsInsert = (delta.action == 'insert') - var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.row - delta.range.start.row); - var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.column - delta.range.start.column); - var deltaStart = delta.range.start; - var deltaEnd = (deltaIsInsert ? deltaStart : delta.range.end); // Collapse insert range. - - // DELTA AFTER POINT: No change needed. - if (_pointsInOrder(point, deltaStart, moveIfEqual)) { - return { - row: point.row, - column: point.column - }; - } - - // DELTA BEFORE POINT: Move point by delta shift. - if (_pointsInOrder(deltaEnd, point, !moveIfEqual)) { - return { - row: point.row + deltaRowShift, - column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) - }; - } - - // DELTA ENVELOPS POINT (delete only): Move point to delta start. - if (delta.action != 'remove') - throw 'Delete action expected.'; - + // Get delta info. + var moveIfEqual = this.$insertRight; + var deltaIsInsert = (delta.action == 'insert') + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.row - delta.range.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.column - delta.range.start.column); + var deltaStart = delta.range.start; + var deltaEnd = (deltaIsInsert ? deltaStart : delta.range.end); // Collapse insert range. + + // DELTA AFTER POINT: No change needed. + if ($pointsInOrder(point, deltaStart, moveIfEqual)) { return { - row: deltaStart.row, - column: deltaStart.column + row: point.row, + column: point.column }; } - var delta = e.data; - var point = getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); - this.setPosition(point.row, point.column, true); + // DELTA BEFORE POINT: Move point by delta shift. + if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) { + return { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }; + } + + // DELTA ENVELOPS POINT (delete only): Move point to delta start. + if (delta.action != 'remove') + throw 'Delete action expected.'; + + return { + row: deltaStart.row, + column: deltaStart.column + }; }; /** From 4299db01bdb4b6a578e8ed678fe82c32457d7601 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 18 Jan 2014 17:24:11 +0400 Subject: [PATCH 019/545] remove delta.range --- lib/ace/anchor.js | 17 ++-- lib/ace/apply_delta.js | 65 ++++++++------- lib/ace/background_tokenizer.js | 7 +- lib/ace/commands/command_manager.js | 4 +- lib/ace/document.js | 107 ++++++++++++------------- lib/ace/edit_session.js | 33 ++++---- lib/ace/edit_session/folding.js | 5 +- lib/ace/editor.js | 7 +- lib/ace/ext/elastic_tabstops_lite.js | 2 +- lib/ace/keyboard/vim/maps/operators.js | 2 - lib/ace/layer/gutter.js | 5 +- lib/ace/lib/lang.js | 1 - lib/ace/line_widgets.js | 5 +- lib/ace/undomanager.js | 20 ++--- lib/ace/worker/mirror.js | 11 +-- 15 files changed, 136 insertions(+), 155 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 421f9e5f..4511a4ce 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -111,14 +111,13 @@ var Anchor = exports.Anchor = function(doc, row, column) { } this.$getTransformedPoint = function (delta, point) { - // Get delta info. var moveIfEqual = this.$insertRight; - var deltaIsInsert = (delta.action == 'insert') - var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.row - delta.range.start.row); - var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.column - delta.range.start.column); - var deltaStart = delta.range.start; - var deltaEnd = (deltaIsInsert ? deltaStart : delta.range.end); // Collapse insert range. + var deltaIsInsert = (delta.action == "insert") + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column); + var deltaStart = delta.start; + var deltaEnd = (deltaIsInsert ? deltaStart : delta.end); // Collapse insert range. // DELTA AFTER POINT: No change needed. if ($pointsInOrder(point, deltaStart, moveIfEqual)) { @@ -137,8 +136,8 @@ var Anchor = exports.Anchor = function(doc, row, column) { } // DELTA ENVELOPS POINT (delete only): Move point to delta start. - if (delta.action != 'remove') - throw 'Delete action expected.'; + if (delta.action != "remove") + throw "Delete action expected."; return { row: deltaStart.row, @@ -181,7 +180,7 @@ var Anchor = exports.Anchor = function(doc, row, column) { }; /** - * When called, the `'change'` event listener is removed. + * When called, the `"change"` event listener is removed. * **/ this.detach = function() { diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 86bc89c6..3996920c 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -41,12 +41,12 @@ function splitLine (docLines, position) { function joinLineWithNext(docLines, row) { docLines[row] += docLines[row + 1]; - docLines.splice(row + 1, 1); + docLines.splice(row + 1, 1); } function throwDeltaError(delta, errorText){ - console.log('Invalid Delta:', delta); - throw 'Invalid Delta: ' + errorText; + console.log("Invalid Delta:", delta); + throw "Invalid Delta: " + errorText; } function positionInDocument(docLines, position) { @@ -57,32 +57,32 @@ function positionInDocument(docLines, position) { function validateDelta(docLines, delta) { // Validate action string. - if (delta.action != 'insert' && delta.action != 'remove') - throwDeltaError(delta, 'delta.action must be "insert" or "remove"'); + if (delta.action != "insert" && delta.action != "remove") + throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); // Validate lines type. if (!(delta.lines instanceof Array)) - throwDeltaError(delta, 'delta.lines must be an Array'); + throwDeltaError(delta, "delta.lines must be an Array"); // Validate range type. - if (!(delta.range instanceof Range)) - throwDeltaError(delta, 'delta.range must be an instance of the Range class'); + if (!delta.start || !delta.end) + throwDeltaError(delta, "delta.start/end must be an present"); // Validate that the start point is contained in the document. - var start = delta.range.start; - if (!positionInDocument(docLines, delta.range.start)) - throwDeltaError(delta, 'delta.range.start must be contained in document'); + var start = delta.start; + if (!positionInDocument(docLines, delta.start)) + throwDeltaError(delta, "delta.start must be contained in document"); // Validate that the end point is contained in the document (remove deltas only). - var end = delta.range.end; - if (delta.action == 'remove' && !positionInDocument(docLines, end)) - throwDeltaError(delta, 'delta.range.end must contained in document for "remove" actions'); + var end = delta.end; + if (delta.action == "remove" && !positionInDocument(docLines, end)) + throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); // Validate that the .range size matches the .lines size. var numRangeRows = end.row - start.row; var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) - throwDeltaError(delta, 'delta.range must match delta lines'); + throwDeltaError(delta, "delta.range must match delta lines"); } exports.applyDelta = function(docLines, delta, doNotValidate) { @@ -92,21 +92,21 @@ exports.applyDelta = function(docLines, delta, doNotValidate) { validateDelta(docLines, delta); // Apply delta. - if (delta.range.start.row == delta.range.end.row) { + if (delta.start.row == delta.end.row) { // Apply single-line delta. // Note: The multi-line code below correctly handle single-line // deltas too, but we need to short-circuit for speed. - var row = delta.range.start.row; - var startColumn = delta.range.start.column; - var endColumn = delta.range.end.column; + var row = delta.start.row; + var startColumn = delta.start.column; + var endColumn = delta.end.column; var line = docLines[row]; switch (delta.action) { - case 'insert': + case "insert": docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); break; - case 'remove': + case "remove": docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); break; } @@ -114,22 +114,21 @@ exports.applyDelta = function(docLines, delta, doNotValidate) { // Apply multi-line delta. switch (delta.action) { - - case 'insert': - splitLine(docLines, delta.range.start); - docLines.splice.apply(docLines, [delta.range.start.row + 1, 0].concat(delta.lines)); - joinLineWithNext(docLines, delta.range.start.row); - joinLineWithNext(docLines, delta.range.end.row); + case "insert": + splitLine(docLines, delta.start); + docLines.splice.apply(docLines, [delta.start.row + 1, 0].concat(delta.lines)); + joinLineWithNext(docLines, delta.start.row); + joinLineWithNext(docLines, delta.end.row); break; - case 'remove': - splitLine(docLines, delta.range.end); - splitLine(docLines, delta.range.start); + case "remove": + splitLine(docLines, delta.end); + splitLine(docLines, delta.start); docLines.splice( - delta.range.start.row + 1, // Where to start deleting - delta.range.end.row - delta.range.start.row + 1 // Num lines to delete. + delta.start.row + 1, // Where to start deleting + delta.end.row - delta.start.row + 1 // Num lines to delete. ); - joinLineWithNext(docLines, delta.range.start.row); + joinLineWithNext(docLines, delta.start.row); break; } } diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 81ea4a0f..07862188 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -177,13 +177,12 @@ var BackgroundTokenizer = function(tokenizer, editor) { } this.$updateOnChange = function(delta) { - var range = delta.range; - var startRow = range.start.row; - var len = range.end.row - startRow; + var startRow = delta.start.row; + var len = delta.end.row - startRow; if (len === 0) { this.lines[startRow] = null; - } else if (delta.action == 'remove') { + } else if (delta.action == "remove") { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { diff --git a/lib/ace/commands/command_manager.js b/lib/ace/commands/command_manager.js index 72a9942d..537942ab 100644 --- a/lib/ace/commands/command_manager.js +++ b/lib/ace/commands/command_manager.js @@ -13,7 +13,7 @@ var EventEmitter = require("../lib/event_emitter").EventEmitter; /** * new CommandManager(platform, commands) - * @param {String} platform Identifier for the platform; must be either `'mac'` or `'win'` + * @param {String} platform Identifier for the platform; must be either `"mac"` or `"win"` * @param {Array} commands A list of commands * **/ @@ -33,7 +33,7 @@ oop.inherits(CommandManager, HashHandler); oop.implement(this, EventEmitter); this.exec = function(command, editor, args) { - if (typeof command === 'string') + if (typeof command === "string") command = this.commands[command]; if (!command) diff --git a/lib/ace/document.js b/lib/ace/document.js index 97d69968..43d1a73c 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -53,7 +53,7 @@ var Anchor = require("./anchor").Anchor; **/ var Document = function(textOrLines) { - this.$lines = ['']; + this.$lines = [""]; // There has to be one line at least in the document. If you pass an empty // string to the insert function, nothing will happen. Workaround. @@ -99,7 +99,7 @@ var Document = function(textOrLines) { }; /** - * Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters. + * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters. * * @method $split * @param {String} text The text to work with @@ -225,12 +225,9 @@ var Document = function(textOrLines) { this.getLinesForRange = function(range) { var lines; if (range.start.row == range.end.row) { - // Handle a single-line range. - lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; - + lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; } else { - // Handle a multi-line range. lines = this.getLines(range.start.row, range.end.row); lines[0] = (lines[0] || "").substring(range.start.column); @@ -254,7 +251,6 @@ var Document = function(textOrLines) { }; this.$getClippedRange = function(range) { - // Get Range object. if (!range instanceof Range) range = Range.fromPoints(range.start, range.end); @@ -267,16 +263,16 @@ var Document = function(textOrLines) { // Deprecated methods retained for backwards compatibility. this.insertLines = function(row, lines) { - console.warn('Use of document.insertLines is deprecated. Use the insertFullLines method instead.'); + console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); return this.insertFullLines(row, lines); }; this.removeLines = function(firstRow, lastRow) { - console.warn('Use of document.removeLines is deprecated. Use the removeFullLines method instead.'); + console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); return this.removeFullLines(firstRow, lastRow); }; this.insertNewLine = function(position) { - console.warn('Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.'); - return this.insertMergedLines(position, ['', '']); + console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead."); + return this.insertMergedLines(position, ["", ""]); }; /** @@ -287,7 +283,6 @@ var Document = function(textOrLines) { * **/ this.insert = function(position, text) { - // Only detect new lines if the document has no line break yet. if (this.getLength() <= 1) this.$detectNewLine(text); @@ -296,7 +291,7 @@ var Document = function(textOrLines) { }; /** - * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event. + * Inserts `text` into the `position` at the current row. This method also triggers the `"change"` event. * * This differs from the `insert` method in two ways: * 1. This does NOT handle newline characters (single-line text only). @@ -310,7 +305,6 @@ var Document = function(textOrLines) { * ``` **/ this.insertInLine = function(position, text) { - // Calculate insertion range end point. this.$clipPosition(position); var endPoint = { @@ -318,10 +312,12 @@ var Document = function(textOrLines) { column : position.column + text.length }; + var range = Range.fromPoints(position, endPoint); // Apply delta (emits change). this.applyDelta({ action: "insert", - range: Range.fromPoints(position, endPoint), + start: range.start, + end: range.end, lines: [text] }, true /*doNotValidate*/); @@ -346,7 +342,7 @@ var Document = function(textOrLines) { **/ /** - * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `'change'` event. + * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `"change"` event. * @param {Number} row The index of the row to insert at * @param {Array} lines An array of strings * @returns {Object} Contains the final row and column, like this: @@ -368,11 +364,11 @@ var Document = function(textOrLines) { var column = 0; if (row < this.getLength()) { // Insert before the specified row. - lines = lines.concat(['']); + lines = lines.concat([""]); column = 0; } else { // Insert after the last row in the document. - lines = [''].concat(lines); + lines = [""].concat(lines); row--; column = this.$lines[row].length; } @@ -382,7 +378,7 @@ var Document = function(textOrLines) { }; /** - * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `'change'` event. + * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `"change"` event. * @param {Number} row The index of the row to insert at * @param {Array} lines An array of strings * @returns {Object} Contains the final row and column, like this: @@ -396,7 +392,6 @@ var Document = function(textOrLines) { * **/ this.insertMergedLines = function(position, lines) { - // Calculate insertion range end point. this.$clipPosition(position); var endPoint = { @@ -407,7 +402,8 @@ var Document = function(textOrLines) { // Apply delta (emits change). this.applyDelta({ action: "insert", - range: Range.fromPoints(position, endPoint), + start: position, + end: endPoint, lines: lines }); @@ -421,19 +417,19 @@ var Document = function(textOrLines) { * **/ this.remove = function(range) { - // Apply delta (emits change). range = this.$getClippedRange(range); this.applyDelta({ - action: 'remove', - range: range, + action: "remove", + start: range.start, + end: range.end, lines: this.getLinesForRange(range), }); - return range.start; + return range.start; }; /** - * Removes the specified columns from the `row`. This method also triggers the `'change'` event. + * Removes the specified columns from the `row`. This method also triggers the `"change"` event. * @param {Number} row The row to remove from * @param {Number} startColumn The column to start removing at * @param {Number} endColumn The column to stop removing at @@ -441,15 +437,15 @@ var Document = function(textOrLines) { * **/ this.removeInLine = function(row, startColumn, endColumn) { - // Calculate deleteion range. var range = new Range(row, startColumn, row, endColumn); range = this.$getClippedRange(range); // Apply delta (emits change). this.applyDelta({ - action: 'remove', - range: range, + action: "remove", + start: range.start, + end: range.end, lines: this.getLinesForRange(range), }, true /*doNotValidate*/); @@ -457,14 +453,13 @@ var Document = function(textOrLines) { }; /** - * Removes a range of full lines. This method also triggers the `'change'` event. + * Removes a range of full lines. This method also triggers the `"change"` event. * @param {Number} firstRow The first row to be removed * @param {Number} lastRow The last row to be removed * @returns {[String]} Returns all the removed lines. * **/ this.removeFullLines = function(firstRow, lastRow) { - // Clip to document. firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); @@ -485,8 +480,9 @@ var Document = function(textOrLines) { // Apply delta (emits change). this.applyDelta({ - action: 'remove', - range: range, + action: "remove", + start: range.start, + end: range.end, lines: this.getLinesForRange(range) }); @@ -495,18 +491,19 @@ var Document = function(textOrLines) { }; /** - * Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event. + * Removes the new line between `row` and the row immediately following it. This method also triggers the `"change"` event. * @param {Number} row The row to check * **/ this.removeNewLine = function(row) { - if (row < this.getLength() - 1 && row >= 0) { + var range = new Range(row, this.getLine(row).length, row + 1, 0); // Apply delta (emits change). this.applyDelta({ - action: 'remove', - range: new Range(row, this.getLine(row).length, row + 1, 0), - lines: ['', ''] + action: "remove", + start: range.start, + end: range.end, + lines: ["", ""] }); } }; @@ -546,7 +543,7 @@ var Document = function(textOrLines) { /** * Applies all changes in `deltas` to the document. - * @param {Array} deltas An array of delta objects (can include 'insert' and 'remove' actions) + * @param {Array} deltas An array of delta objects (can include "insert" and "remove" actions) **/ this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { @@ -566,12 +563,11 @@ var Document = function(textOrLines) { /** * Applies `delta` to the document. - * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) + * @param {Object} delta A delta object (can include "insert" and "remove" actions) **/ this.applyDelta = function(delta, doNotValidate) { - // An empty range is a NOOP. - if (delta.range.isEmpty()) + if (!Range.comparePoints(delta.start, delta.end)) return; // Split large insert deltas. This is necessary because: @@ -582,37 +578,40 @@ var Document = function(textOrLines) { // delta handling is too slow. If we make delete delta handling faster we can split all large deltas // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js // If we do this, update validateDelta() to limit the number of lines in a delete delta. - var bIsInsert = delta.action == 'insert'; + var bIsInsert = delta.action == "insert"; while (bIsInsert && delta.lines.length > 65001) { - // Get split deltas. var lines = delta.lines.splice(0, 65000); - lines.push(''); + lines.push(""); + var range = new Range(delta.start.row, delta.start.column, + delta.start.row + 65000, 0) this.applyDelta({ action: delta.action, lines: lines, - range: new Range(delta.range.start.row, delta.range.start.column, - delta.range.start.row + 65000, 0) + start: range.start, + end: range.end, }); // Update remaining delta. - delta.range.start.row += 65000; - delta.range.start.column = 0; + delta.start.row += 65000; + delta.start.column = 0; } // Apply. applyDelta(this.$lines, delta, doNotValidate); - this._emit("change", { data: delta }); + this._emit("change", { data: delta }); }; /** * Reverts `delta` from the document. - * @param {Object} delta A delta object (can include 'insert' and 'remove' actions) + * @param {Object} delta A delta object (can include "insert" and "remove" actions) **/ this.revertDelta = function(delta) { + var range = Range.fromPoints(delta.start, delta.end); this.applyDelta({ - action: (delta.action == 'insert' ? 'remove' : 'insert'), - range: delta.range.clone(), + action: (delta.action == "insert" ? "remove" : "insert"), + start: range.start, + end: range.end, lines: delta.lines.slice() }); }; diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 7cfa344c..4baa525f 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -253,7 +253,7 @@ var EditSession = function(text, mode) { var delta = e.data; this.$modified = true; - this.$resetRowCache(delta.range.start.row); + this.$resetRowCache(delta.start.row); var removedFolds = this.$updateInternalDataOnChange(e); if (!this.$fromUndo && this.$undoManager && !delta.ignore) { @@ -1247,30 +1247,29 @@ var EditSession = function(text, mode) { var range, point; var lastDeltaIsInsert = false; if (isInsert(delta)) { - range = Range.fromPoints(delta.range.start, delta.range.end); + range = Range.fromPoints(delta.start, delta.end); lastDeltaIsInsert = true; } else { - range = Range.fromPoints(delta.range.start, delta.range.start); + range = Range.fromPoints(delta.start, delta.start); lastDeltaIsInsert = false; } for (var i = 1; i < deltas.length; i++) { delta = deltas[i]; if (isInsert(delta)) { - point = delta.range.start; + point = delta.start; if (range.compare(point.row, point.column) == -1) { - range.setStart(delta.range.start); + range.setStart(point); } - point = delta.range.end; + point = delta.end; if (range.compare(point.row, point.column) == 1) { - range.setEnd(delta.range.end); + range.setEnd(point); } lastDeltaIsInsert = true; } else { - point = delta.range.start; + point = delta.start; if (range.compare(point.row, point.column) == -1) { - range = - Range.fromPoints(delta.range.start, delta.range.start); + range = Range.fromPoints(delta.start, delta.start); } lastDeltaIsInsert = false; } @@ -1676,8 +1675,8 @@ var EditSession = function(text, mode) { this.$updateInternalDataOnChange = function(e) { var useWrapMode = this.$useWrapMode; var action = e.data.action; - var start = e.data.range.start; - var end = e.data.range.end; + var start = e.data.start; + var end = e.data.end; var firstRow = start.row; var lastRow = end.row; var len = lastRow - firstRow; @@ -1685,11 +1684,11 @@ var EditSession = function(text, mode) { this.$updating = true; if (len != 0) { - if (action == 'remove') { + if (action == "remove") { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; - removedFolds = this.getFoldsInRange(e.data.range); + removedFolds = this.getFoldsInRange(e.data); this.removeFolds(removedFolds); var foldLine = this.getFoldLine(end.row); @@ -1759,10 +1758,10 @@ var EditSession = function(text, mode) { } else { // Realign folds. E.g. if you add some new chars before a fold, the // fold should "move" to the right. - len = Math.abs(e.data.range.start.column - e.data.range.end.column); - if (action == 'remove') { + len = Math.abs(e.data.start.column - e.data.end.column); + if (action == "remove") { // Get all the folds in the change range and remove them. - removedFolds = this.getFoldsInRange(e.data.range); + removedFolds = this.getFoldsInRange(e.data); this.removeFolds(removedFolds); len = -len; diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 25adc909..857382d8 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -830,9 +830,8 @@ function Folding() { this.updateFoldWidgets = function(e) { var delta = e.data; - var range = delta.range; - var firstRow = range.start.row; - var len = range.end.row - firstRow; + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; if (len === 0) { this.foldWidgets[firstRow] = null; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 6b046a89..16d79785 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -607,11 +607,10 @@ var Editor = function(renderer, session) { * **/ this.onDocumentChange = function(e) { - // Rerender and emit "change" event. - var range = e.data.range; - var lastRow = (range.start.row == range.end.row ? range.end.row : Infinity); - this.renderer.updateLines(range.start.row, lastRow); + var delta = e.data; + var lastRow = (delta.start.row == delta.end.row ? delta.end.row : Infinity); + this.renderer.updateLines(delta.start.row, lastRow); this._signal("change", e); // Update cursor because tab characters can influence the cursor position. diff --git a/lib/ace/ext/elastic_tabstops_lite.js b/lib/ace/ext/elastic_tabstops_lite.js index 9901c5df..ce5e55f9 100644 --- a/lib/ace/ext/elastic_tabstops_lite.js +++ b/lib/ace/ext/elastic_tabstops_lite.js @@ -45,7 +45,7 @@ var ElasticTabstopsLite = function(editor) { recordChanges = true; }; this.onChange = function(e) { - var range = e.data.range + var range = e.data; if (recordChanges) { if (changedRows.indexOf(range.start.row) == -1) changedRows.push(range.start.row); diff --git a/lib/ace/keyboard/vim/maps/operators.js b/lib/ace/keyboard/vim/maps/operators.js index 067562a0..73c6922e 100644 --- a/lib/ace/keyboard/vim/maps/operators.js +++ b/lib/ace/keyboard/vim/maps/operators.js @@ -94,11 +94,9 @@ module.exports = { editor.removeLines(); util.insertMode(editor); } - break; default: if (range) { - // range.end.column ++; editor.session.remove(range); util.insertMode(editor); diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 45c34565..59aa35fd 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -103,9 +103,8 @@ var Gutter = function(parentEl) { if (!this.$annotations.length) return; var delta = e.data; - var range = delta.range; - var firstRow = range.start.row; - var len = range.end.row - firstRow; + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; if (len === 0) { // do nothing } else if (delta.action == 'remove') { diff --git a/lib/ace/lib/lang.js b/lib/ace/lib/lang.js index d6a98149..863bbb55 100644 --- a/lib/ace/lib/lang.js +++ b/lib/ace/lib/lang.js @@ -150,7 +150,6 @@ exports.getMatchOffsets = function(string, regExp) { /* deprecated */ exports.deferredCall = function(fcn) { - var timer = null; var callback = function() { timer = null; diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 651f038d..185f6de4 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -119,9 +119,8 @@ function LineWidgets(session) { if (!lineWidgets) return; var delta = e.data; - var range = delta.range; - var startRow = range.start.row; - var len = range.end.row - startRow; + var startRow = delta.start.row; + var len = delta.end.row - startRow; if (len === 0) { // return diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index bd95bae9..71b4ba65 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -178,29 +178,31 @@ var UndoManager = function() { function $serializeDelta(delta){ return { action: delta.action, - range: delta.range, - lines: (delta.lines.length == 1 ? null : delta.lines), - text: (delta.lines.length == 1 ? delta.lines[0] : null ), + start: delta.start, + end: delta.end, + lines: delta.lines.length == 1 ? null : delta.lines, + text: delta.lines.length == 1 ? delta.lines[0] : null, }; } function $deserializeDelta(delta) { return { action: delta.action, - range: delta.range, - lines: (delta.text === null ? delta.lines : [delta.text]) + start: delta.start, + end: delta.end, + lines: delta.lines || [delta.text] }; } function cloneDeltaSetsObj(deltaSets_old, fnGetModifiedDelta) { var deltaSets_new = new Array(deltaSets_old.length); - for (var i in deltaSets_old) { + for (var i = 0; i < deltaSets_old.length; i++) { var deltaSet_old = deltaSets_old[i]; var deltaSet_new = { group: deltaSet_old.group, deltas: new Array(deltaSet_old.length)}; - for (var i_ in deltaSet_old.deltas) { - var delta_old = deltaSet_old.deltas[i_]; - deltaSet_new.deltas[i_] = fnGetModifiedDelta(delta_old); + for (var j = 0; j < deltaSet_old.deltas.length; j++) { + var delta_old = deltaSet_old.deltas[j]; + deltaSet_new.deltas[j] = fnGetModifiedDelta(delta_old); } deltaSets_new[i] = deltaSet_new; diff --git a/lib/ace/worker/mirror.js b/lib/ace/worker/mirror.js index 2f33fea6..8254f205 100644 --- a/lib/ace/worker/mirror.js +++ b/lib/ace/worker/mirror.js @@ -13,16 +13,7 @@ var Mirror = exports.Mirror = function(sender) { var _self = this; sender.on("change", function(e) { - - // Convert delta.range back into a Range instance since - // window.onMessage loses non-primitive data. See http://jsfiddle.net/nqJfw/1/. - var deltas = e.data; - for (var i in deltas) { - var delta = deltas[i]; - delta.range = Range.fromPoints(delta.range.start, delta.range.end); - } - - doc.applyDeltas(deltas); + doc.applyDeltas(e.data); if (_self.$timeout) return deferredUpdate.schedule(_self.$timeout); _self.onUpdate(); From c8d1df203ed8772805369c331f7c160f04af4bfc Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 19 Jan 2014 04:26:02 +0400 Subject: [PATCH 020/545] restore single line delta optimization in anchor.js --- lib/ace/anchor.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 4511a4ce..3431b3c4 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -101,6 +101,12 @@ var Anchor = exports.Anchor = function(doc, row, column) { **/ this.onChange = function(e) { var delta = e.data; + if (delta.start.row == delta.end.row && delta.start.row != this.row) + return; + + if (delta.start.row > this.row) + return; + var point = this.$getTransformedPoint(delta, {row: this.row, column: this.column}); this.setPosition(point.row, point.column, true); }; From 46f3d77068efbf8d1bfc3e0b3fb840c0bb90630d Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 19 Jan 2014 04:27:07 +0400 Subject: [PATCH 021/545] simplify apply_delta.js --- lib/ace/apply_delta.js | 45 +++++++++++++----------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 3996920c..ed019ccb 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -31,19 +31,6 @@ define(function(require, exports, module) { "use strict"; -var Range = require("./range").Range; - -function splitLine (docLines, position) { - var text = docLines[position.row]; - docLines[position.row] = text.slice(0, position.column); - docLines.splice(position.row + 1, 0, text.slice(position.column)); -} - -function joinLineWithNext(docLines, row) { - docLines[row] += docLines[row + 1]; - docLines.splice(row + 1, 1); -} - function throwDeltaError(delta, errorText){ console.log("Invalid Delta:", delta); throw "Invalid Delta: " + errorText; @@ -91,44 +78,40 @@ exports.applyDelta = function(docLines, delta, doNotValidate) { if (!doNotValidate) validateDelta(docLines, delta); + var row = delta.start.row; + var startColumn = delta.start.column; + var line = docLines[row]; // Apply delta. - if (delta.start.row == delta.end.row) { + if (row == delta.end.row) { // Apply single-line delta. // Note: The multi-line code below correctly handle single-line // deltas too, but we need to short-circuit for speed. - var row = delta.start.row; - var startColumn = delta.start.column; - var endColumn = delta.end.column; - var line = docLines[row]; + var endColumn = delta.end.column; switch (delta.action) { - case "insert": docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); break; - case "remove": docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); break; } } else { - // Apply multi-line delta. switch (delta.action) { case "insert": - splitLine(docLines, delta.start); - docLines.splice.apply(docLines, [delta.start.row + 1, 0].concat(delta.lines)); - joinLineWithNext(docLines, delta.start.row); - joinLineWithNext(docLines, delta.end.row); + var line = docLines[row]; + var args = [row, 1].concat(delta.lines); + docLines.splice.apply(docLines, args); + docLines[row] = line.substring(0, startColumn) + docLines[row]; + docLines[row + delta.lines.length - 1] += line.substring(startColumn); break; - case "remove": - splitLine(docLines, delta.end); - splitLine(docLines, delta.start); + var endRow docLines.splice( - delta.start.row + 1, // Where to start deleting - delta.end.row - delta.start.row + 1 // Num lines to delete. + row, // Where to start deleting + delta.end.row - delta.start.row + 1, // Num lines to delete. + line.substring(0, startColumn) + docLines[delta.end.row].substring(delta.end.column) ); - joinLineWithNext(docLines, delta.start.row); break; } } From 6b60bcbbd672aef1211ddcb58ca21225b3dba369 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 14 Feb 2014 22:35:22 +0400 Subject: [PATCH 022/545] continue refactoring --- lib/ace/apply_delta.js | 45 ++++------ lib/ace/document.js | 155 ++++++++++++++++---------------- lib/ace/edit_session.js | 24 ++--- lib/ace/range_list.js | 12 +-- lib/ace/undomanager.js | 7 +- lib/ace/worker/mirror.js | 14 ++- lib/ace/worker/worker_client.js | 12 ++- 7 files changed, 135 insertions(+), 134 deletions(-) diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index ed019ccb..98a1a857 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -42,7 +42,6 @@ function positionInDocument(docLines, position) { } function validateDelta(docLines, delta) { - // Validate action string. if (delta.action != "insert" && delta.action != "remove") throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); @@ -73,47 +72,37 @@ function validateDelta(docLines, delta) { } exports.applyDelta = function(docLines, delta, doNotValidate) { - - // Validate delta. if (!doNotValidate) validateDelta(docLines, delta); var row = delta.start.row; var startColumn = delta.start.column; var line = docLines[row]; - // Apply delta. - if (row == delta.end.row) { - // Apply single-line delta. - // Note: The multi-line code below correctly handle single-line - // deltas too, but we need to short-circuit for speed. - var endColumn = delta.end.column; - switch (delta.action) { - case "insert": + switch (delta.action) { + case "insert": + var lines = delta.lines; + if (lines.length === 1) { docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); - break; - case "remove": - docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); - break; - } - } else { - // Apply multi-line delta. - switch (delta.action) { - case "insert": + } else { var line = docLines[row]; var args = [row, 1].concat(delta.lines); docLines.splice.apply(docLines, args); docLines[row] = line.substring(0, startColumn) + docLines[row]; docLines[row + delta.lines.length - 1] += line.substring(startColumn); - break; - case "remove": - var endRow + } + break; + case "remove": + var endColumn = delta.end.column; + var endRow = delta.end.row; + if (row === endRow) { + docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); + } else { docLines.splice( - row, // Where to start deleting - delta.end.row - delta.start.row + 1, // Num lines to delete. - line.substring(0, startColumn) + docLines[delta.end.row].substring(delta.end.column) + row, endRow - row + 1, + line.substring(0, startColumn) + docLines[endRow].substring(endColumn) ); - break; - } + } + break; } } }); diff --git a/lib/ace/document.js b/lib/ace/document.js index 43d1a73c..1abb95a2 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -39,13 +39,12 @@ var Anchor = require("./anchor").Anchor; /** * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. - * * At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index. * * @class Document **/ - /** +/** * * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty. * @param {String | Array} text The starting text @@ -76,9 +75,9 @@ var Document = function(textOrLines) { * @param {String} text The text to use **/ this.setValue = function(text) { - var len = this.getLength(); - this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insert({row: 0, column:0}, text); + var len = this.getLength() - 1; + this.remove(new Range(0, 0, len, this.getLine(len).length)); + this.insert({row: 0, column: 0}, text); }; /** @@ -224,7 +223,7 @@ var Document = function(textOrLines) { **/ this.getLinesForRange = function(range) { var lines; - if (range.start.row == range.end.row) { + if (range.start.row === range.end.row) { // Handle a single-line range. lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; } else { @@ -238,29 +237,6 @@ var Document = function(textOrLines) { return lines; }; - this.$clipPosition = function(position) { - var length = this.getLength(); - if (position.row >= length) { - position.row = Math.max(0, length - 1); - position.column = this.getLine(length - 1).length; - } else { - position.row = Math.max(0, position.row); - position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); - } - return position; - }; - - this.$getClippedRange = function(range) { - // Get Range object. - if (!range instanceof Range) - range = Range.fromPoints(range.start, range.end); - - // Return clipped range. - this.$clipPosition(range.start); - this.$clipPosition(range.end); - return range; - }; - // Deprecated methods retained for backwards compatibility. this.insertLines = function(row, lines) { console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); @@ -305,25 +281,54 @@ var Document = function(textOrLines) { * ``` **/ this.insertInLine = function(position, text) { - // Calculate insertion range end point. - this.$clipPosition(position); - var endPoint = { - row : position.row, - column : position.column + text.length - }; + var start = this.clippedPos(position.row, position.column); + var end = this.pos(position.row, position.column + text.length); - var range = Range.fromPoints(position, endPoint); - // Apply delta (emits change). this.applyDelta({ action: "insert", - start: range.start, - end: range.end, + start: start, + end: end, lines: [text] - }, true /*doNotValidate*/); + }, true); - return endPoint; + return this.clonePos(end); }; + this.clippedPos = function(row, column) { + var length = this.getLength(); + if (row === undefined) { + row = length; + } else if (row < 0) { + row = 0; + } else if (row >= length) { + row = length - 1; + column = undefined + } + var line = this.getLine(row); + column = Math.min(Math.max(column, 0), line.length); + return {row: row, column: column}; + }; + + this.clonePos = function(pos) { + return {row: pos.row, column: pos.column}; + }; + + this.pos = function(row, column) { + return {row: row, column: column}; + }; + + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length - 1).length; + } else { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); + } + return position; + }; + /** * Fires whenever the document changes. * @@ -392,14 +397,12 @@ var Document = function(textOrLines) { * **/ this.insertMergedLines = function(position, lines) { - // Calculate insertion range end point. this.$clipPosition(position); var endPoint = { row : position.row + lines.length - 1, column : (lines.length == 1 ? position.column : 0) + lines[lines.length - 1].length }; - // Apply delta (emits change). this.applyDelta({ action: "insert", start: position, @@ -417,15 +420,14 @@ var Document = function(textOrLines) { * **/ this.remove = function(range) { - // Apply delta (emits change). - range = this.$getClippedRange(range); + var start = this.clippedPos(range.start.row, range.start.column); this.applyDelta({ action: "remove", - start: range.start, - end: range.end, + start: start, + end: this.clippedPos(range.end.row, range.end.column), lines: this.getLinesForRange(range), }); - return range.start; + return this.clonePos(start); }; /** @@ -437,19 +439,16 @@ var Document = function(textOrLines) { * **/ this.removeInLine = function(row, startColumn, endColumn) { - // Calculate deleteion range. - var range = new Range(row, startColumn, row, endColumn); - range = this.$getClippedRange(range); + var start = this.clippedPos(row, startColumn); - // Apply delta (emits change). this.applyDelta({ action: "remove", - start: range.start, - end: range.end, + start: start, + end: this.clippedPos(row, endColumn), lines: this.getLinesForRange(range), - }, true /*doNotValidate*/); + }, true); - return range.start; + return this.clonePos(start); }; /** @@ -478,7 +477,6 @@ var Document = function(textOrLines) { // Store delelted lines with bounding newlines ommitted (maintains previous behavior). var deletedLines = this.$lines.slice(firstRow, lastRow + 1); - // Apply delta (emits change). this.applyDelta({ action: "remove", start: range.start, @@ -496,13 +494,11 @@ var Document = function(textOrLines) { * **/ this.removeNewLine = function(row) { - if (row < this.getLength() - 1 && row >= 0) { - var range = new Range(row, this.getLine(row).length, row + 1, 0); - // Apply delta (emits change). + if (row < this.getLength() - 1 && row >= 0) { this.applyDelta({ action: "remove", - start: range.start, - end: range.end, + start: this.pos(row, this.getLine(row).length), + end: this.pos(row + 1, 0), lines: ["", ""] }); } @@ -566,10 +562,21 @@ var Document = function(textOrLines) { * @param {Object} delta A delta object (can include "insert" and "remove" actions) **/ this.applyDelta = function(delta, doNotValidate) { + var isInsert = delta.action == "insert"; // An empty range is a NOOP. - if (!Range.comparePoints(delta.start, delta.end)) + if (isInsert ? !delta.lines.length + : !Range.comparePoints(delta.start, delta.end)) return; + if (isInsert && delta.lines.length > 0xFFFF) + this.$splitAndapplyLargeDelta(delta); + + // Apply. + applyDelta(this.$lines, delta, doNotValidate); + this._signal("change", {data: delta}); + }; + + this.$splitAndapplyLargeDelta = function(delta) { // Split large insert deltas. This is necessary because: // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) // 2. fn.apply() doesn't work for a large number of params. The mallest threshold is on safari 0xFFFF. @@ -578,28 +585,18 @@ var Document = function(textOrLines) { // delta handling is too slow. If we make delete delta handling faster we can split all large deltas // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js // If we do this, update validateDelta() to limit the number of lines in a delete delta. - var bIsInsert = delta.action == "insert"; - while (bIsInsert && delta.lines.length > 65001) { + while (delta.lines.length > 0xFFFF) { // Get split deltas. - var lines = delta.lines.splice(0, 65000); + var lines = delta.lines.splice(0, 0xFFFF); lines.push(""); - var range = new Range(delta.start.row, delta.start.column, - delta.start.row + 65000, 0) + var start = delta.start; this.applyDelta({ action: delta.action, lines: lines, - start: range.start, - end: range.end, - }); - - // Update remaining delta. - delta.start.row += 65000; - delta.start.column = 0; + start: this.pos(start.row, start.column), + end: this.pos(start.row += 0xFFFF, start.column = 0) // Updates remaining delta. + }, true); } - - // Apply. - applyDelta(this.$lines, delta, doNotValidate); - this._emit("change", { data: delta }); }; /** diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 4baa525f..c9759fb1 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1394,25 +1394,25 @@ var EditSession = function(text, mode) { **/ this.outdentRows = function (range) { var rowRange = range.collapseRows(); + var deleteRange = new Range(0, 0, 0, 0); var size = this.getTabSize(); - + for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) { var line = this.getLine(i); - var row = i; - var startCol = 0; - var endCol = 0; - + + deleteRange.start.row = i; + deleteRange.end.row = i; for (var j = 0; j < size; ++j) if (line.charAt(j) != ' ') break; if (j < size && line.charAt(j) == '\t') { - startCol = j; - endCol = j + 1; + deleteRange.start.column = j; + deleteRange.end.column = j + 1; } else { - startCol = 0; - endCol = j; + deleteRange.start.column = 0; + deleteRange.end.column = j; } - this.doc.removeInLine(row, startCol, endCol); + this.remove(deleteRange); } }; @@ -1684,7 +1684,7 @@ var EditSession = function(text, mode) { this.$updating = true; if (len != 0) { - if (action == "remove") { + if (action === "remove") { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; @@ -1759,7 +1759,7 @@ var EditSession = function(text, mode) { // Realign folds. E.g. if you add some new chars before a fold, the // fold should "move" to the right. len = Math.abs(e.data.start.column - e.data.end.column); - if (action == "remove") { + if (action === "remove") { // Get all the folds in the change range and remove them. removedFolds = this.getFoldsInRange(e.data); this.removeFolds(removedFolds); diff --git a/lib/ace/range_list.js b/lib/ace/range_list.js index 0cbcc394..a112139a 100644 --- a/lib/ace/range_list.js +++ b/lib/ace/range_list.js @@ -181,13 +181,13 @@ var RangeList = function() { }; this.$onChange = function(e) { - var changeRange = e.data.range; - if (e.data.action[0] == "i"){ - var start = changeRange.start; - var end = changeRange.end; + var delta = e.data; + if (delta.action == "insert"){ + var start = delta.start; + var end = delta.end; } else { - var end = changeRange.start; - var start = changeRange.end; + var end = delta.start; + var start = delta.end; } var startRow = start.row; var endRow = end.row; diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index 71b4ba65..6da50a8b 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -61,10 +61,9 @@ var UndoManager = function() { * **/ this.execute = function(options) { - // Normalize deltas for storage. - var deltaSets = this.$serializeDeltas(options.args[0]); - + // var deltaSets = this.$serializeDeltas(options.args[0]); + var deltaSets = options.args[0]; // Add deltas to undo stack. this.$doc = options.args[1]; if (options.merge && this.hasUndo()){ @@ -207,7 +206,7 @@ var UndoManager = function() { deltaSets_new[i] = deltaSet_new; } - return deltaSets_new; + return deltaSets_new; } }).call(UndoManager.prototype); diff --git a/lib/ace/worker/mirror.js b/lib/ace/worker/mirror.js index 8254f205..514d377f 100644 --- a/lib/ace/worker/mirror.js +++ b/lib/ace/worker/mirror.js @@ -13,7 +13,19 @@ var Mirror = exports.Mirror = function(sender) { var _self = this; sender.on("change", function(e) { - doc.applyDeltas(e.data); + var data = e.data; + if (data[0].start) { + doc.applyDeltas(data); + } else { + for (var i = 0; i < data.length; i += 2) { + if (Array.isArray(data[i+1])) + var d = {action: "insert", start: data[i], lines: data[i+1]}; + else + var d = {action: "remove", start: data[i],end: data[i+1]}; + + doc.applyDelta(d, true); + } + } if (_self.$timeout) return deferredUpdate.schedule(_self.$timeout); _self.onUpdate(); diff --git a/lib/ace/worker/worker_client.js b/lib/ace/worker/worker_client.js index cb18998f..f5902f90 100644 --- a/lib/ace/worker/worker_client.js +++ b/lib/ace/worker/worker_client.js @@ -162,17 +162,21 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) { this.changeListener = function(e) { if (!this.deltaQueue) { - this.deltaQueue = [e.data]; + this.deltaQueue = []; setTimeout(this.$sendDeltaQueue, 0); - } else - this.deltaQueue.push(e.data); + } + var delta = e.data; + if (delta.action == "insert") + this.deltaQueue.push(delta.start, delta.lines); + else + this.deltaQueue.push(delta.start, delta.end); }; this.$sendDeltaQueue = function() { var q = this.deltaQueue; if (!q) return; this.deltaQueue = null; - if (q.length > 20 && q.length > this.$doc.getLength() >> 1) { + if (q.length > 50 && q.length > this.$doc.getLength() >> 1) { this.call("setValue", [this.$doc.getValue()]); } else this.emit("change", {data: q}); From 27b6d6dcd38557b2836a71d3933db8270ee7a343 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 00:01:30 +0400 Subject: [PATCH 023/545] apply arguments max length also includes actual call stack --- lib/ace/document.js | 45 +++++++++++++++++++++++------------------- lib/ace/placeholder.js | 2 +- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index 1abb95a2..99b7bb2d 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -302,9 +302,11 @@ var Document = function(textOrLines) { row = 0; } else if (row >= length) { row = length - 1; - column = undefined - } + column = undefined; + } var line = this.getLine(row); + if (column == undefined) + column = line.length; column = Math.min(Math.max(column, 0), line.length); return {row: row, column: column}; }; @@ -421,31 +423,33 @@ var Document = function(textOrLines) { **/ this.remove = function(range) { var start = this.clippedPos(range.start.row, range.start.column); + var end = this.clippedPos(range.end.row, range.end.column); this.applyDelta({ action: "remove", start: start, - end: this.clippedPos(range.end.row, range.end.column), - lines: this.getLinesForRange(range), + end: end, + lines: this.getLinesForRange({start: start, end: end}), }); return this.clonePos(start); }; /** - * Removes the specified columns from the `row`. This method also triggers the `"change"` event. - * @param {Number} row The row to remove from - * @param {Number} startColumn The column to start removing at - * @param {Number} endColumn The column to stop removing at - * @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
If `startColumn` is equal to `endColumn`, this function returns nothing. - * - **/ + * Removes the specified columns from the `row`. This method also triggers a `"change"` event. + * @param {Number} row The row to remove from + * @param {Number} startColumn The column to start removing at + * @param {Number} endColumn The column to stop removing at + * @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
If `startColumn` is equal to `endColumn`, this function returns nothing. + * + **/ this.removeInLine = function(row, startColumn, endColumn) { - var start = this.clippedPos(row, startColumn); + var start = this.clippedPos(row, startColumn); + var end = this.clippedPos(row, endColumn); this.applyDelta({ action: "remove", start: start, - end: this.clippedPos(row, endColumn), - lines: this.getLinesForRange(range), + end: end, + lines: this.getLinesForRange({start: start, end: end}), }, true); return this.clonePos(start); @@ -568,7 +572,7 @@ var Document = function(textOrLines) { : !Range.comparePoints(delta.start, delta.end)) return; - if (isInsert && delta.lines.length > 0xFFFF) + if (isInsert && delta.lines.length > 0xF000) this.$splitAndapplyLargeDelta(delta); // Apply. @@ -579,22 +583,23 @@ var Document = function(textOrLines) { this.$splitAndapplyLargeDelta = function(delta) { // Split large insert deltas. This is necessary because: // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) - // 2. fn.apply() doesn't work for a large number of params. The mallest threshold is on safari 0xFFFF. + // 2. fn.apply() doesn't work for a large number of params. The smallest threshold is on safari 0xFFFF. + // we use 0xF000 to leave some space for actual stack // // To Do: Ideally we'd be consistent and also split 'delete' deltas. We don't do this now, because delete // delta handling is too slow. If we make delete delta handling faster we can split all large deltas // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js // If we do this, update validateDelta() to limit the number of lines in a delete delta. - while (delta.lines.length > 0xFFFF) { + while (delta.lines.length > 0xF000) { // Get split deltas. - var lines = delta.lines.splice(0, 0xFFFF); + var lines = delta.lines.splice(0, 0xF000); lines.push(""); var start = delta.start; this.applyDelta({ action: delta.action, lines: lines, - start: this.pos(start.row, start.column), - end: this.pos(start.row += 0xFFFF, start.column = 0) // Updates remaining delta. + start: this.pos(start.row, start.column), + end: this.pos(start.row += 0xF000, start.column = 0) // Updates remaining delta. }, true); } }; diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index 1d345a24..d7a2d6e9 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -150,7 +150,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) **/ this.onUpdate = function(event) { var delta = event.data; - var range = delta.range; + var range = delta; if(range.start.row !== range.end.row) return; if(range.start.row !== this.pos.row) return; if (this.$updating) return; From 4e2d7a41f51494706a2c6d78ea28ffbebf6cc0ac Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 18:15:59 +0400 Subject: [PATCH 024/545] update jshint --- lib/ace/mode/javascript/jshint.js | 542 ++++++++++++++++++++---------- tool/update_deps.js | 2 +- 2 files changed, 365 insertions(+), 179 deletions(-) diff --git a/lib/ace/mode/javascript/jshint.js b/lib/ace/mode/javascript/jshint.js index fb2039b6..12590467 100644 --- a/lib/ace/mode/javascript/jshint.js +++ b/lib/ace/mode/javascript/jshint.js @@ -27,9 +27,9 @@ module.exports = { }, {}], 2:[function(_dereq_,module,exports){ -// Underscore.js 1.4.4 +// Underscore.js 1.6.0 // http://underscorejs.org -// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. +// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. (function() { @@ -37,7 +37,7 @@ module.exports = { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. + // Establish the root object, `window` in the browser, or `exports` on the server. var root = this; // Save the previous value of the `_` variable. @@ -50,11 +50,12 @@ module.exports = { var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; // Create quick reference variables for speed access to core prototypes. - var push = ArrayProto.push, - slice = ArrayProto.slice, - concat = ArrayProto.concat, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; + var + push = ArrayProto.push, + slice = ArrayProto.slice, + concat = ArrayProto.concat, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. @@ -93,7 +94,7 @@ module.exports = { } // Current version. - _.VERSION = '1.4.4'; + _.VERSION = '1.6.0'; // Collection Functions // -------------------- @@ -102,20 +103,20 @@ module.exports = { // Handles objects with the built-in `forEach`, arrays, and raw objects. // Delegates to **ECMAScript 5**'s native `forEach` if available. var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; + if (obj == null) return obj; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { + for (var i = 0, length = obj.length; i < length; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { - for (var key in obj) { - if (_.has(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; } } + return obj; }; // Return the results of applying the iterator to each element. @@ -125,7 +126,7 @@ module.exports = { if (obj == null) return results; if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); + results.push(iterator.call(context, value, index, list)); }); return results; }; @@ -181,10 +182,10 @@ module.exports = { }; // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { + _.find = _.detect = function(obj, predicate, context) { var result; any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { + if (predicate.call(context, value, index, list)) { result = value; return true; } @@ -195,33 +196,33 @@ module.exports = { // Return all the elements that pass a truth test. // Delegates to **ECMAScript 5**'s native `filter` if available. // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { + _.filter = _.select = function(obj, predicate, context) { var results = []; if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; + if (predicate.call(context, value, index, list)) results.push(value); }); return results; }; // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { + _.reject = function(obj, predicate, context) { return _.filter(obj, function(value, index, list) { - return !iterator.call(context, value, index, list); + return !predicate.call(context, value, index, list); }, context); }; // Determine whether all of the elements match a truth test. // Delegates to **ECMAScript 5**'s native `every` if available. // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - iterator || (iterator = _.identity); + _.every = _.all = function(obj, predicate, context) { + predicate || (predicate = _.identity); var result = true; if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context); each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; + if (!(result = result && predicate.call(context, value, index, list))) return breaker; }); return !!result; }; @@ -229,13 +230,13 @@ module.exports = { // Determine if at least one element in the object matches a truth test. // Delegates to **ECMAScript 5**'s native `some` if available. // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); + var any = _.some = _.any = function(obj, predicate, context) { + predicate || (predicate = _.identity); var result = false; if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context); each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; + if (result || (result = predicate.call(context, value, index, list))) return breaker; }); return !!result; }; @@ -261,41 +262,37 @@ module.exports = { // Convenience version of a common use case of `map`: fetching a property. _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); + return _.map(obj, _.property(key)); }; // Convenience version of a common use case of `filter`: selecting only objects // containing specific `key:value` pairs. - _.where = function(obj, attrs, first) { - if (_.isEmpty(attrs)) return first ? null : []; - return _[first ? 'find' : 'filter'](obj, function(value) { - for (var key in attrs) { - if (attrs[key] !== value[key]) return false; - } - return true; - }); + _.where = function(obj, attrs) { + return _.filter(obj, _.matches(attrs)); }; // Convenience version of a common use case of `find`: getting the first object // containing specific `key:value` pairs. _.findWhere = function(obj, attrs) { - return _.where(obj, attrs, true); + return _.find(obj, _.matches(attrs)); }; // Return the maximum element or (element-based computation). // Can't optimize arrays of integers longer than 65,535 elements. - // See: https://bugs.webkit.org/show_bug.cgi?id=80797 + // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) _.max = function(obj, iterator, context) { if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { return Math.max.apply(Math, obj); } - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity, value: -Infinity}; + var result = -Infinity, lastComputed = -Infinity; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); + if (computed > lastComputed) { + result = value; + lastComputed = computed; + } }); - return result.value; + return result; }; // Return the minimum element (or element-based computation). @@ -303,16 +300,19 @@ module.exports = { if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { return Math.min.apply(Math, obj); } - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity, value: Infinity}; + var result = Infinity, lastComputed = Infinity; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); + if (computed < lastComputed) { + result = value; + lastComputed = computed; + } }); - return result.value; + return result; }; - // Shuffle an array. + // Shuffle an array, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). _.shuffle = function(obj) { var rand; var index = 0; @@ -325,19 +325,32 @@ module.exports = { return shuffled; }; + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (obj.length !== +obj.length) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + // An internal function to generate lookup iterators. var lookupIterator = function(value) { - return _.isFunction(value) ? value : function(obj){ return obj[value]; }; + if (value == null) return _.identity; + if (_.isFunction(value)) return value; + return _.property(value); }; // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, value, context) { - var iterator = lookupIterator(value); + _.sortBy = function(obj, iterator, context) { + iterator = lookupIterator(iterator); return _.pluck(_.map(obj, function(value, index, list) { return { - value : value, - index : index, - criteria : iterator.call(context, value, index, list) + value: value, + index: index, + criteria: iterator.call(context, value, index, list) }; }).sort(function(left, right) { var a = left.criteria; @@ -346,43 +359,46 @@ module.exports = { if (a > b || a === void 0) return 1; if (a < b || b === void 0) return -1; } - return left.index < right.index ? -1 : 1; + return left.index - right.index; }), 'value'); }; // An internal function used for aggregate "group by" operations. - var group = function(obj, value, context, behavior) { - var result = {}; - var iterator = lookupIterator(value || _.identity); - each(obj, function(value, index) { - var key = iterator.call(context, value, index, obj); - behavior(result, key, value); - }); - return result; + var group = function(behavior) { + return function(obj, iterator, context) { + var result = {}; + iterator = lookupIterator(iterator); + each(obj, function(value, index) { + var key = iterator.call(context, value, index, obj); + behavior(result, key, value); + }); + return result; + }; }; // Groups the object's values by a criterion. Pass either a string attribute // to group by, or a function that returns the criterion. - _.groupBy = function(obj, value, context) { - return group(obj, value, context, function(result, key, value) { - (_.has(result, key) ? result[key] : (result[key] = [])).push(value); - }); - }; + _.groupBy = group(function(result, key, value) { + _.has(result, key) ? result[key].push(value) : result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, key, value) { + result[key] = value; + }); // Counts instances of an object that group by a certain criterion. Pass // either a string attribute to count by, or a function that returns the // criterion. - _.countBy = function(obj, value, context) { - return group(obj, value, context, function(result, key) { - if (!_.has(result, key)) result[key] = 0; - result[key]++; - }); - }; + _.countBy = group(function(result, key) { + _.has(result, key) ? result[key]++ : result[key] = 1; + }); // Use a comparator function to figure out the smallest index at which // an object should be inserted so as to maintain order. Uses binary search. _.sortedIndex = function(array, obj, iterator, context) { - iterator = iterator == null ? _.identity : lookupIterator(iterator); + iterator = lookupIterator(iterator); var value = iterator.call(context, obj); var low = 0, high = array.length; while (low < high) { @@ -392,7 +408,7 @@ module.exports = { return low; }; - // Safely convert anything iterable into a real, live array. + // Safely create a real, live array from anything iterable. _.toArray = function(obj) { if (!obj) return []; if (_.isArray(obj)) return slice.call(obj); @@ -414,7 +430,9 @@ module.exports = { // allows it to work with `_.map`. _.first = _.head = _.take = function(array, n, guard) { if (array == null) return void 0; - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + if ((n == null) || guard) return array[0]; + if (n < 0) return []; + return slice.call(array, 0, n); }; // Returns everything but the last entry of the array. Especially useful on @@ -429,11 +447,8 @@ module.exports = { // values in the array. The **guard** check allows it to work with `_.map`. _.last = function(array, n, guard) { if (array == null) return void 0; - if ((n != null) && !guard) { - return slice.call(array, Math.max(array.length - n, 0)); - } else { - return array[array.length - 1]; - } + if ((n == null) || guard) return array[array.length - 1]; + return slice.call(array, Math.max(array.length - n, 0)); }; // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. @@ -451,8 +466,11 @@ module.exports = { // Internal implementation of a recursive `flatten` function. var flatten = function(input, shallow, output) { + if (shallow && _.every(input, _.isArray)) { + return concat.apply(output, input); + } each(input, function(value) { - if (_.isArray(value)) { + if (_.isArray(value) || _.isArguments(value)) { shallow ? push.apply(output, value) : flatten(value, shallow, output); } else { output.push(value); @@ -461,7 +479,7 @@ module.exports = { return output; }; - // Return a completely flattened version of an array. + // Flatten out an array, either recursively (by default), or just one level. _.flatten = function(array, shallow) { return flatten(array, shallow, []); }; @@ -471,6 +489,16 @@ module.exports = { return _.difference(array, slice.call(arguments, 1)); }; + // Split an array into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(array, predicate) { + var pass = [], fail = []; + each(array, function(elem) { + (predicate(elem) ? pass : fail).push(elem); + }); + return [pass, fail]; + }; + // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. @@ -495,7 +523,7 @@ module.exports = { // Produce an array that contains the union: each distinct element from all of // the passed-in arrays. _.union = function() { - return _.uniq(concat.apply(ArrayProto, arguments)); + return _.uniq(_.flatten(arguments, true)); }; // Produce an array that contains every item shared between all the @@ -504,7 +532,7 @@ module.exports = { var rest = slice.call(arguments, 1); return _.filter(_.uniq(array), function(item) { return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; + return _.contains(other, item); }); }); }; @@ -519,11 +547,10 @@ module.exports = { // Zip together multiple lists into a single array -- elements that share // an index go together. _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); + var length = _.max(_.pluck(arguments, 'length').concat(0)); var results = new Array(length); for (var i = 0; i < length; i++) { - results[i] = _.pluck(args, "" + i); + results[i] = _.pluck(arguments, '' + i); } return results; }; @@ -534,7 +561,7 @@ module.exports = { _.object = function(list, values) { if (list == null) return {}; var result = {}; - for (var i = 0, l = list.length; i < l; i++) { + for (var i = 0, length = list.length; i < length; i++) { if (values) { result[list[i]] = values[i]; } else { @@ -552,17 +579,17 @@ module.exports = { // for **isSorted** to use binary search. _.indexOf = function(array, item, isSorted) { if (array == null) return -1; - var i = 0, l = array.length; + var i = 0, length = array.length; if (isSorted) { if (typeof isSorted == 'number') { - i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); + i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted); } else { i = _.sortedIndex(array, item); return array[i] === item ? i : -1; } } if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); - for (; i < l; i++) if (array[i] === item) return i; + for (; i < length; i++) if (array[i] === item) return i; return -1; }; @@ -588,11 +615,11 @@ module.exports = { } step = arguments[2] || 1; - var len = Math.max(Math.ceil((stop - start) / step), 0); + var length = Math.max(Math.ceil((stop - start) / step), 0); var idx = 0; - var range = new Array(len); + var range = new Array(length); - while(idx < len) { + while(idx < length) { range[idx++] = start; start += step; } @@ -603,31 +630,50 @@ module.exports = { // Function (ahem) Functions // ------------------ + // Reusable constructor function for prototype setting. + var ctor = function(){}; + // Create a function bound to a given object (assigning `this`, and arguments, // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if // available. _.bind = function(func, context) { - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - var args = slice.call(arguments, 2); - return function() { - return func.apply(context, args.concat(slice.call(arguments))); + var args, bound; + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + ctor.prototype = null; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; }; }; // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. _.partial = function(func) { - var args = slice.call(arguments, 1); + var boundArgs = slice.call(arguments, 1); return function() { - return func.apply(this, args.concat(slice.call(arguments))); + var position = 0; + var args = boundArgs.slice(); + for (var i = 0, length = args.length; i < length; i++) { + if (args[i] === _) args[i] = arguments[position++]; + } + while (position < arguments.length) args.push(arguments[position++]); + return func.apply(this, args); }; }; - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. _.bindAll = function(obj) { var funcs = slice.call(arguments, 1); - if (funcs.length === 0) funcs = _.functions(obj); + if (funcs.length === 0) throw new Error('bindAll must be passed function names'); each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); return obj; }; @@ -656,17 +702,24 @@ module.exports = { }; // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - var context, args, timeout, result; + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; var previous = 0; + options || (options = {}); var later = function() { - previous = new Date; + previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); + context = args = null; }; return function() { - var now = new Date; + var now = _.now(); + if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; @@ -675,7 +728,8 @@ module.exports = { timeout = null; previous = now; result = func.apply(context, args); - } else if (!timeout) { + context = args = null; + } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; @@ -687,17 +741,34 @@ module.exports = { // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { - var timeout, result; - return function() { - var context = this, args = arguments; - var later = function() { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + if (last < wait) { + timeout = setTimeout(later, wait - last); + } else { timeout = null; - if (!immediate) result = func.apply(context, args); - }; + if (!immediate) { + result = func.apply(context, args); + context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) result = func.apply(context, args); + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + return result; }; }; @@ -719,11 +790,7 @@ module.exports = { // allowing you to adjust arguments, run code before and after, and // conditionally execute the original function. _.wrap = function(func, wrapper) { - return function() { - var args = [func]; - push.apply(args, arguments); - return wrapper.apply(this, args); - }; + return _.partial(wrapper, func); }; // Returns a function that is the composition of a list of functions, each @@ -741,7 +808,6 @@ module.exports = { // Returns a function that will only be executed after being called N times. _.after = function(times, func) { - if (times <= 0) return func(); return function() { if (--times < 1) { return func.apply(this, arguments); @@ -754,31 +820,43 @@ module.exports = { // Retrieve the names of an object's properties. // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); var keys = []; - for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + for (var key in obj) if (_.has(obj, key)) keys.push(key); return keys; }; // Retrieve the values of an object's properties. _.values = function(obj) { - var values = []; - for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); + var keys = _.keys(obj); + var length = keys.length; + var values = new Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } return values; }; // Convert an object into a list of `[key, value]` pairs. _.pairs = function(obj) { - var pairs = []; - for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); + var keys = _.keys(obj); + var length = keys.length; + var pairs = new Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } return pairs; }; // Invert the keys and values of an object. The values must be serializable. _.invert = function(obj) { var result = {}; - for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } return result; }; @@ -829,7 +907,7 @@ module.exports = { each(slice.call(arguments, 1), function(source) { if (source) { for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; + if (obj[prop] === void 0) obj[prop] = source[prop]; } } }); @@ -853,7 +931,7 @@ module.exports = { // Internal recursive comparison function for `isEqual`. var eq = function(a, b, aStack, bStack) { // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) return a !== 0 || 1 / a == 1 / b; // A strict comparison is necessary because `null == undefined`. if (a == null || b == null) return a === b; @@ -895,6 +973,14 @@ module.exports = { // unique nested structures. if (aStack[length] == a) return bStack[length] == b; } + // Objects with different constructors are not equivalent, but `Object`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && + _.isFunction(bCtor) && (bCtor instanceof bCtor)) + && ('constructor' in a && 'constructor' in b)) { + return false; + } // Add the first object to the stack of traversed objects. aStack.push(a); bStack.push(b); @@ -911,13 +997,6 @@ module.exports = { } } } else { - // Objects with different constructors are not equivalent, but `Object`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && - _.isFunction(bCtor) && (bCtor instanceof bCtor))) { - return false; - } // Deep compare objects. for (var key in a) { if (_.has(a, key)) { @@ -1039,9 +1118,33 @@ module.exports = { return value; }; + _.constant = function(value) { + return function () { + return value; + }; + }; + + _.property = function(key) { + return function(obj) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of `key:value` pairs. + _.matches = function(attrs) { + return function(obj) { + if (obj === attrs) return true; //avoid comparing an object to itself. + for (var key in attrs) { + if (attrs[key] !== obj[key]) + return false; + } + return true; + } + }; + // Run a function **n** times. _.times = function(n, iterator, context) { - var accum = Array(n); + var accum = Array(Math.max(0, n)); for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); return accum; }; @@ -1055,6 +1158,9 @@ module.exports = { return min + Math.floor(Math.random() * (max - min + 1)); }; + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { return new Date().getTime(); }; + // List of HTML entities for escaping. var entityMap = { escape: { @@ -1062,8 +1168,7 @@ module.exports = { '<': '<', '>': '>', '"': '"', - "'": ''', - '/': '/' + "'": ''' } }; entityMap.unescape = _.invert(entityMap.escape); @@ -1084,17 +1189,17 @@ module.exports = { }; }); - // If the value of the named property is a function then invoke it; - // otherwise, return it. + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. _.result = function(object, property) { - if (object == null) return null; + if (object == null) return void 0; var value = object[property]; return _.isFunction(value) ? value.call(object) : value; }; // Add your own custom functions to the Underscore object. _.mixin = function(obj) { - each(_.functions(obj), function(name){ + each(_.functions(obj), function(name) { var func = _[name] = obj[name]; _.prototype[name] = function() { var args = [this._wrapped]; @@ -1252,6 +1357,18 @@ module.exports = { }); + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } }).call(this); }, @@ -1353,6 +1470,7 @@ var JSHINT = (function () { globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') immed : true, // if immediate invocations must be wrapped in parens iterator : true, // if the `__iterator__` property should be allowed + jasmine : true, // Jasmine functions should be predefined jquery : true, // if jQuery globals should be predefined lastsemic : true, // if semicolons may be ommitted for the trailing // statements inside of a one-line blocks. @@ -1378,6 +1496,7 @@ var JSHINT = (function () { proto : true, // if the `__proto__` property should be allowed prototypejs : true, // if Prototype and Scriptaculous globals should be // predefined + qunit : true, // if the QUnit environment globals should be predefined rhino : true, // if the Rhino environment globals should be predefined shelljs : true, // if ShellJS globals should be predefined typed : true, // if typed array globals should be predefined @@ -1570,7 +1689,7 @@ var JSHINT = (function () { function combine(dest, src) { Object.keys(src).forEach(function (name) { - if (JSHINT.blacklist.hasOwnProperty(name)) return; + if (_.has(JSHINT.blacklist, name)) return; dest[name] = src[name]; }); } @@ -1584,6 +1703,10 @@ var JSHINT = (function () { combine(predefined, vars.couch); } + if (state.option.qunit) { + combine(predefined, vars.qunit); + } + if (state.option.rhino) { combine(predefined, vars.rhino); } @@ -1626,6 +1749,10 @@ var JSHINT = (function () { combine(predefined, vars.nonstandard); } + if (state.option.jasmine) { + combine(predefined, vars.jasmine); + } + if (state.option.jquery) { combine(predefined, vars.jquery); } @@ -2208,11 +2335,13 @@ var JSHINT = (function () { if (state.tokens.next.id === "(end)") error("E006", state.tokens.curr); - if (state.option.asi && - (state.tokens.curr.id === "[" || - state.tokens.curr.id === "(" || - state.tokens.curr.id === "/") && - state.tokens.prev.line < state.tokens.curr.line) + var isDangerous = + state.option.asi && + state.tokens.prev.line < state.tokens.curr.line && + _.contains(["]", ")"], state.tokens.prev.id) && + _.contains(["[", "("], state.tokens.curr.id); + + if (isDangerous) warning("W014", state.tokens.curr, state.tokens.curr.id); advance(); @@ -2792,6 +2921,21 @@ var JSHINT = (function () { } } + function parseFinalSemicolon() { + if (state.tokens.next.id !== ";") { + if (!state.option.asi) { + // If this is the last statement in a block that ends on + // the same line *and* option lastsemic is on, ignore the warning. + // Otherwise, complain about missing semicolon. + if (!state.option.lastsemic || state.tokens.next.id !== "}" || + state.tokens.next.line !== state.tokens.curr.line) { + warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); + } + } + } else { + advance(";"); + } + } function statement() { var values; @@ -2814,6 +2958,23 @@ var JSHINT = (function () { res = false; } + // detect a module import declaration + if (t.value === "module" && t.type === "(identifier)") { + if (peek().type === "(identifier)") { + if (!state.option.inESNext()) { + warning("W119", state.tokens.curr, "module"); + } + + advance("module"); + var name = identifier(); + addlabel(name, { type: "unused", token: state.tokens.curr }); + advance("from"); + advance("(string)"); + parseFinalSemicolon(); + return; + } + } + // detect a destructuring assignment if (_.has(["[", "{"], t.value)) { if (lookupBlockType().isDestAssign) { @@ -2879,22 +3040,10 @@ var JSHINT = (function () { } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { warning("W031", t); } - - if (state.tokens.next.id !== ";") { - if (!state.option.asi) { - // If this is the last statement in a block that ends on - // the same line *and* option lastsemic is on, ignore the warning. - // Otherwise, complain about missing semicolon. - if (!state.option.lastsemic || state.tokens.next.id !== "}" || - state.tokens.next.line !== state.tokens.curr.line) { - warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); - } - } - } else { - advance(";"); - } + parseFinalSemicolon(); } + // Restore the indentation. indent = i; @@ -5432,7 +5581,6 @@ var JSHINT = (function () { FutureReservedWord("static", { es5: true, strictOnly: true }); FutureReservedWord("super", { es5: true }); FutureReservedWord("synchronized"); - FutureReservedWord("throws"); FutureReservedWord("transient"); FutureReservedWord("volatile"); @@ -8150,7 +8298,7 @@ exports.starSlash = /\*\//; exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; // JavaScript URL (jx) -exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; +exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i; // Catches /* falls through */ comments (ft) exports.fallsThrough = /^\s*\/\*\s*falls?\sthrough\s*\*\/\s*$/; @@ -8323,7 +8471,7 @@ exports.register = function (linter) { // Warn about script URLs. linter.on("String", function style_scanJavaScriptURLs(data) { - var re = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; + var re = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i; if (linter.getOption("scripturl")) { return; @@ -8756,6 +8904,27 @@ exports.phantom = { exports : true // v1.7+ }; +exports.qunit = { + asyncTest : false, + deepEqual : false, + equal : false, + expect : false, + module : false, + notDeepEqual : false, + notEqual : false, + notPropEqual : false, + notStrictEqual : false, + ok : false, + propEqual : false, + QUnit : false, + raises : false, + start : false, + stop : false, + strictEqual : false, + test : false, + "throws" : false +}; + exports.rhino = { defineClass : false, deserialize : false, @@ -8875,7 +9044,7 @@ exports.mootools = { Group : false, Hash : false, HtmlTable : false, - Iframe : false, + IFrame : false, IframeShim : false, InputValidator: false, instanceOf : false, @@ -8962,6 +9131,23 @@ exports.mocha = { teardown : false }; +exports.jasmine = { + jasmine : false, + describe : false, + it : false, + xit : false, + beforeEach : false, + afterEach : false, + setFixtures : false, + loadFixtures: false, + spyOn : false, + expect : false, + // Jasmine 1.3 + runs : false, + waitsFor : false, + waits : false +}; + }, {}], 10:[function(_dereq_,module,exports){ diff --git a/tool/update_deps.js b/tool/update_deps.js index 99e2a9bd..249083c8 100644 --- a/tool/update_deps.js +++ b/tool/update_deps.js @@ -85,7 +85,7 @@ var deps = { jshint: { path: "mode/javascript/jshint.js", browserify: { - npmModule: "git+https://github.com/nightwing/jshint.git#master", + npmModule: "git+https://github.com/ajaxorg/jshint.git#master", path: "jshint/src/jshint.js", exports: "jshint" }, From 9ab12a6ed37eeec01c46bee8f75cfb02999817d7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 20:07:07 +0400 Subject: [PATCH 025/545] fix ctrl-shift-mousedown --- lib/ace/autocomplete.js | 8 +--- lib/ace/lib/event.js | 4 +- lib/ace/mouse/mouse_handler.js | 11 +++++ lib/ace/mouse/multi_select_handler.js | 47 +++++++++++++++++--- lib/ace/multi_select.js | 62 ++++++++++++++++++--------- lib/ace/selection.js | 11 +---- 6 files changed, 99 insertions(+), 44 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index a2fea74f..adf9bd73 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -306,13 +306,7 @@ var Autocomplete = function() { }; this.cancelContextMenu = function() { - var stop = function(e) { - this.editor.off("nativecontextmenu", stop); - if (e && e.domEvent) - event.stopEvent(e.domEvent); - }.bind(this); - setTimeout(stop, 10); - this.editor.on("nativecontextmenu", stop); + this.editor.$mouseHandler.cancelContextMenu(); }; }).call(Autocomplete.prototype); diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 39d115b4..612b6a34 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -85,7 +85,7 @@ exports.preventDefault = function(e) { exports.getButton = function(e) { if (e.type == "dblclick") return 0; - if (e.type == "contextmenu" || (e.ctrlKey && useragent.isMac)) + if (e.type == "contextmenu" || (useragent.isMac && (e.ctrlKey && !e.altKey && !e.shiftKey))) return 2; // DOM Event @@ -183,7 +183,7 @@ exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbac if (!timer || isNewClick) clicks = 1; if (timer) - clearTimeout(timer) + clearTimeout(timer); timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); if (clicks == 1) { diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index c7573e94..a991a849 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -157,6 +157,17 @@ var MouseHandler = function(editor) { var timerId = setInterval(onCaptureInterval, 20); }; this.releaseMouse = null; + this.cancelContextMenu = function() { + var stop = function(e) { + if (e && e.domEvent && e.domEvent.type != "contextmenu") + return; + this.editor.off("nativecontextmenu", stop); + if (e && e.domEvent) + event.stopEvent(e.domEvent); + }.bind(this); + setTimeout(stop, 10); + this.editor.on("nativecontextmenu", stop); + }; }).call(MouseHandler.prototype); config.defineOptions(MouseHandler.prototype, "mouseHandler", { diff --git a/lib/ace/mouse/multi_select_handler.js b/lib/ace/mouse/multi_select_handler.js index 88dc6668..0620f8f5 100644 --- a/lib/ace/mouse/multi_select_handler.js +++ b/lib/ace/mouse/multi_select_handler.js @@ -31,6 +31,7 @@ define(function(require, exports, module) { var event = require("../lib/event"); +var useragent = require("../lib/useragent"); // mouse function isSamePoint(p1, p2) { @@ -41,8 +42,12 @@ function onMouseDown(e) { var ev = e.domEvent; var alt = ev.altKey; var shift = ev.shiftKey; - var ctrl = e.getAccelKey(); + var ctrl = ev.ctrlKey; + var accel = e.getAccelKey(); var button = e.getButton(); + + if (ctrl && useragent.isMac) + button = ev.button; if (e.editor.inMultiSelectMode && button == 2) { e.editor.textInput.onContextMenu(e.domEvent); @@ -54,6 +59,9 @@ function onMouseDown(e) { e.editor.exitMultiSelectMode(); return; } + + if (button !== 0) + return; var editor = e.editor; var selection = editor.selection; @@ -90,10 +98,28 @@ function onMouseDown(e) { var session = editor.session; var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY); var screenCursor = screenAnchor; - + var selectionMode; + if (editor.$mouseHandler.$enableJumpToDef) { + if (ctrl && alt || accel && alt) + selectionMode = "add"; + else if (alt) + selectionMode = "block"; + } else { + if (accel && !alt) { + selectionMode = "add"; + if (!isMultiSelect && shift) + return; + } else if (alt) { + selectionMode = "block"; + } + } + + if (selectionMode && useragent.isMac && ev.ctrlKey) { + editor.$mouseHandler.cancelContextMenu(); + } - if (ctrl && !alt && !shift && button === 0) { + if (selectionMode == "add") { if (!isMultiSelect && inSelection) return; // dragging @@ -104,23 +130,34 @@ function onMouseDown(e) { var oldRange = selection.rangeList.rangeAtPoint(pos); + editor.$blockScrolling++; + editor.inVirtualSelectionMode = true; + + if (shift) { + oldRange = null; + range = selection.ranges[0]; + editor.removeSelectionMarker(range); + } editor.once("mouseup", function() { var tmpSel = selection.toOrientedRange(); if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor)) selection.substractPoint(tmpSel.cursor); else { - if (range) { + if (shift) { + selection.substractPoint(range.cursor); + } else if (range) { editor.removeSelectionMarker(range); selection.addRange(range); } selection.addRange(tmpSel); } editor.$blockScrolling--; + editor.inVirtualSelectionMode = false; }); - } else if (alt && button === 0) { + } else if (selectionMode == "block") { e.stop(); if (isMultiSelect && !ctrl) diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index b079e387..ef0f7a2e 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -76,7 +76,7 @@ var EditSession = require("./edit_session").EditSession; if (!range) return; - if (!this.inMultiSelectMode && this.rangeCount == 0) { + if (!this.inMultiSelectMode && this.rangeCount === 0) { var oldRange = this.toOrientedRange(); this.rangeList.add(oldRange); this.rangeList.add(range); @@ -168,7 +168,7 @@ var EditSession = require("./edit_session").EditSession; this._signal("removeRange", {ranges: removed}); - if (this.rangeCount == 0 && this.inMultiSelectMode) { + if (this.rangeCount === 0 && this.inMultiSelectMode) { this.inMultiSelectMode = false; this._signal("singleSelect"); this.session.$undoSelect = true; @@ -543,6 +543,19 @@ var Editor = require("./editor").Editor; } return text; }; + + this.$checkMultiselectChange = function(e, anchor) { + if (this.inMultiSelectMode && !this.inVirtualSelectionMode) { + var range = this.multiSelect.ranges[0]; + if (this.multiSelect.isEmpty() && anchor == this.multiSelect.anchor) + return; + var pos = anchor == this.multiSelect.anchor + ? range.cursor == range.start ? range.end : range.start + : range.cursor; + if (!isSamePoint(pos, anchor)) + this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange()); + } + }; // todo this should change when paste becomes a command this.onPaste = function(text) { @@ -742,8 +755,15 @@ var Editor = require("./editor").Editor; var session = this.session; var sel = session.multiSelect; var ranges = sel.ranges; - - if (!ranges.length) { + // filter out ranges on same row + var row = -1; + var sameRowRanges = ranges.filter(function(r) { + if (r.cursor.row == row) + return true; + row = r.cursor.row; + }); + + if (!ranges.length || sameRowRanges.length == ranges.length - 1) { var range = this.selection.getRange(); var fr = range.start.row, lr = range.end.row; var guessRange = fr == lr; @@ -769,14 +789,9 @@ var Editor = require("./editor").Editor; } this.selection.setRange(range); } else { - // filter out ranges on same row - var row = -1; - var sameRowRanges = ranges.filter(function(r) { - if (r.cursor.row == row) - return true; - row = r.cursor.row; + sameRowRanges.forEach(function(r) { + sel.substractPoint(r.cursor); }); - sel.$onRemoveRange(sameRowRanges); var maxCol = 0; var minSpace = Infinity; @@ -851,19 +866,19 @@ var Editor = require("./editor").Editor; function alignLeft(m) { return !m[2] ? m[0] : spaces(startW) + m[2] + spaces(textW - m[2].length + endW) - + m[4].replace(/^([=:])\s+/, "$1 ") + + m[4].replace(/^([=:])\s+/, "$1 "); } function alignRight(m) { return !m[2] ? m[0] : spaces(startW + textW - m[2].length) + m[2] + spaces(endW, " ") - + m[4].replace(/^([=:])\s+/, "$1 ") + + m[4].replace(/^([=:])\s+/, "$1 "); } function unAlign(m) { return !m[2] ? m[0] : spaces(startW) + m[2] + spaces(endW) - + m[4].replace(/^([=:])\s+/, "$1 ") + + m[4].replace(/^([=:])\s+/, "$1 "); } - } + }; }).call(Editor.prototype); @@ -884,17 +899,21 @@ exports.onSessionChange = function(e) { var oldSession = e.oldSession; if (oldSession) { - oldSession.multiSelect.removeEventListener("addRange", this.$onAddRange); - oldSession.multiSelect.removeEventListener("removeRange", this.$onRemoveRange); - oldSession.multiSelect.removeEventListener("multiSelect", this.$onMultiSelect); - oldSession.multiSelect.removeEventListener("singleSelect", this.$onSingleSelect); + oldSession.multiSelect.off("addRange", this.$onAddRange); + oldSession.multiSelect.off("removeRange", this.$onRemoveRange); + oldSession.multiSelect.off("multiSelect", this.$onMultiSelect); + oldSession.multiSelect.off("singleSelect", this.$onSingleSelect); + oldSession.multiSelect.lead.off("change", this.$checkMultiselectChange); + oldSession.multiSelect.anchor.off("change", this.$checkMultiselectChange); } session.multiSelect.on("addRange", this.$onAddRange); session.multiSelect.on("removeRange", this.$onRemoveRange); session.multiSelect.on("multiSelect", this.$onMultiSelect); session.multiSelect.on("singleSelect", this.$onSingleSelect); - + session.multiSelect.lead.on("change", this.$checkMultiselectChange); + session.multiSelect.anchor.on("change", this.$checkMultiselectChange); + // this.$onSelectionChange = this.onSelectionChange.bind(this); if (this.inMultiSelectMode != session.selection.inMultiSelectMode) { @@ -916,6 +935,7 @@ function MultiSelect(editor) { editor.$onMultiSelect = editor.$onMultiSelect.bind(editor); editor.$onSingleSelect = editor.$onSingleSelect.bind(editor); editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor); + editor.$checkMultiselectChange = editor.$checkMultiselectChange.bind(editor); editor.$multiselectOnSessionChange(editor); editor.on("changeSession", editor.$multiselectOnSessionChange); @@ -969,7 +989,7 @@ require("./config").defineOptions(Editor.prototype, "editor", { }, value: true } -}) +}); diff --git a/lib/ace/selection.js b/lib/ace/selection.js index e113d8ad..63bc9668 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -37,7 +37,6 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; /** - * * Contains the cursor position and the text selection of an edit session. * * The row/columns used in the selection are in document coordinates representing ths coordinates as thez appear in the document before applying soft wrap and folding. @@ -49,22 +48,16 @@ var Range = require("./range").Range; * Emitted when the cursor position changes. * @event changeCursor * - * - * **/ /** * Emitted when the cursor selection changes. + * * @event changeSelection - * - * - * **/ /** * Creates a new `Selection` object. * @param {EditSession} session The session to use - * - * - * + * * @constructor **/ var Selection = function(session) { From 88aed652124ed2210e08db358c83dfc03dbf2134 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 20:26:13 +0400 Subject: [PATCH 026/545] fix home key on folded line --- lib/ace/edit_session/folding.js | 10 +++++----- lib/ace/ext/modelist.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 09d67b95..a727b15a 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -485,15 +485,15 @@ function Folding() { }; this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) { - if (startRow == null) { + if (startRow == null) startRow = foldLine.start.row; + if (startColumn == null) startColumn = 0; - } - - if (endRow == null) { + if (endRow == null) endRow = foldLine.end.row; + if (endColumn == null) endColumn = this.getLine(endRow).length; - } + // Build the textline using the FoldLine walker. var doc = this.doc; diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 66fe3de8..77b5b127 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -53,7 +53,7 @@ var supportedModes = { C9Search: ["c9search_results"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp"], Cirru: ["cirru|cr"], - Clojure: ["clj"], + Clojure: ["clj|cljs"], Cobol: ["CBL|COB"], coffee: ["coffee|cf|cson|^Cakefile"], ColdFusion: ["cfm"], From ba93cc6dfad98d4a20ddff0ed09c7396cd38c0ee Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 20:30:47 +0400 Subject: [PATCH 027/545] fix tab detection --- lib/ace/ext/whitespace.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index a3c179f3..fdbf7360 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -46,7 +46,6 @@ exports.$detectIndentation = function(lines, fallback) { if (!/^\s*[^*+\-\s]/.test(line)) continue; - var tabs = line.match(/^\t*/)[0].length; if (line[0] == "\t") tabIndents++; @@ -65,9 +64,6 @@ exports.$detectIndentation = function(lines, fallback) { line = lines[i++]; } - if (!stats.length) - return; - function getScore(indent) { var score = 0; for (var i = indent; i < stats.length; i += indent) @@ -82,7 +78,7 @@ exports.$detectIndentation = function(lines, fallback) { for (var i = 1; i < 12; i++) { if (i == 1) { spaceIndents = getScore(i); - var score = 1; + var score = stats.length && 1; } else var score = getScore(i) / spaceIndents; @@ -99,7 +95,7 @@ exports.$detectIndentation = function(lines, fallback) { if (tabIndents > spaceIndents + 1) return {ch: "\t", length: tabLength}; - if (spaceIndents + 1 > tabIndents) + if (spaceIndents > tabIndents + 1) return {ch: " ", length: tabLength}; }; From 4872441bc6126665bcbdb507f31a7dac7a72d13a Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 20:32:08 +0400 Subject: [PATCH 028/545] fix vim cc --- lib/ace/keyboard/vim/maps/operators.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/ace/keyboard/vim/maps/operators.js b/lib/ace/keyboard/vim/maps/operators.js index 350bbd05..6df55b0f 100644 --- a/lib/ace/keyboard/vim/maps/operators.js +++ b/lib/ace/keyboard/vim/maps/operators.js @@ -34,6 +34,7 @@ define(function(require, exports, module) { var util = require("./util"); var registers = require("../registers"); +var Range = require("../../../range").Range; module.exports = { "d": { @@ -90,15 +91,18 @@ module.exports = { count = count || 1; switch (param) { case "c": - for (var i = 0; i < count; i++) { - editor.removeLines(); - util.insertMode(editor); - } - + editor.$blockScrolling++; + editor.selection.$moveSelection(function() { + editor.selection.moveCursorBy(count - 1, 0); + }); + var rows = editor.$getSelectedRows(); + range = new Range(rows.first, 0, rows.last, Infinity); + editor.session.remove(range); + editor.$blockScrolling--; + util.insertMode(editor); break; default: if (range) { - // range.end.column ++; editor.session.remove(range); util.insertMode(editor); From 72a509e5422b39d4712fee46b3b4b2161999f202 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 20:32:34 +0400 Subject: [PATCH 029/545] improve ruby outdent --- lib/ace/mode/ruby.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/ace/mode/ruby.js b/lib/ace/mode/ruby.js index 27bc6c38..76bc2d6f 100644 --- a/lib/ace/mode/ruby.js +++ b/lib/ace/mode/ruby.js @@ -74,14 +74,21 @@ oop.inherits(Mode, TextMode); }; this.checkOutdent = function(state, line, input) { - return /^\s+end$/.test(line + input) || /^\s+}$/.test(line + input) || /^\s+else$/.test(line + input); + return /^\s+(end|else)$/.test(line + input) || this.$outdent.checkOutdent(line, input); }; - this.autoOutdent = function(state, doc, row) { - var indent = this.$getIndent(doc.getLine(row)); - var tab = doc.getTabString(); - if (indent.slice(-tab.length) == tab) - doc.remove(new Range(row, indent.length-tab.length, row, indent.length)); + this.autoOutdent = function(state, session, row) { + var line = session.getLine(row); + if (/}/.test(line)) + return this.$outdent.autoOutdent(session, row); + var indent = this.$getIndent(line); + var prevLine = session.getLine(row - 1); + var prevIndent = this.$getIndent(prevLine); + var tab = session.getTabString(); + if (prevIndent.length <= indent.length) { + if (indent.slice(-tab.length) == tab) + session.remove(new Range(row, indent.length-tab.length, row, indent.length)); + } }; this.$id = "ace/mode/ruby"; From 7e2dda1e185d76d9044afada55a1a6d0585f8448 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 21 May 2014 20:38:07 +0400 Subject: [PATCH 030/545] allow tokenizer states with only defaultToken --- lib/ace/mode/text.js | 2 +- lib/ace/tokenizer.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 34a2a511..f04f1722 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -62,7 +62,7 @@ var Mode = function() { this.getTokenizer = function() { if (!this.$tokenizer) { - this.$highlightRules = new this.HighlightRules(); + this.$highlightRules = this.$highlightRules || new this.HighlightRules(); this.$tokenizer = new Tokenizer(this.$highlightRules.getRules()); } return this.$tokenizer; diff --git a/lib/ace/tokenizer.js b/lib/ace/tokenizer.js index 72989766..64bf59e8 100644 --- a/lib/ace/tokenizer.js +++ b/lib/ace/tokenizer.js @@ -116,6 +116,11 @@ var Tokenizer = function(rules) { rule.onMatch = null; } + if (!ruleRegExps.length) { + mapping[0] = 0; + ruleRegExps.push("$"); + } + splitterRurles.forEach(function(rule) { rule.splitRegex = this.createSplitterRegexp(rule.regex, flag); }, this); From d0acc15e67bbe1b9ef51703644b1e30abae75659 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 23 May 2014 00:16:31 +0400 Subject: [PATCH 031/545] fix #1973 custom array of autocompleters never used --- lib/ace/ext/language_tools.js | 39 +++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index 651835d4..f8c00047 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -120,40 +120,45 @@ var loadSnippetFile = function(id) { }); }; -var doLiveAutocomplete = function(e) { - var editor = e.editor; - var text = e.args || ""; +function getCompletionPrefix(editor) { var pos = editor.getCursorPosition(); var line = editor.session.getLine(pos.row); - var hasCompleter = editor.completer && editor.completer.activated; var prefix = util.retrievePrecedingIdentifier(line, pos.column); - - //Try to find custom prefixes on the completers - completers.forEach(function(completer) { + // Try to find custom prefixes on the completers + editor.completers.forEach(function(completer) { if (completer.identifierRegexps) { completer.identifierRegexps.forEach(function(identifierRegex) { - if (!prefix) { + if (!prefix && identifierRegex) prefix = util.retrievePrecedingIdentifier(line, pos.column, identifierRegex); - } }); } }); + return prefix; +} + +var doLiveAutocomplete = function(e) { + var editor = e.editor; + var text = e.args || ""; + var hasCompleter = editor.completer && editor.completer.activated; + + // We don't want to autocomplete with no prefix - if (e.command.name === "backspace" && !prefix) { - if (hasCompleter) + if (e.command.name === "backspace") { + if (hasCompleter && !getCompletionPrefix(editor)) editor.completer.detach(); } else if (e.command.name === "insertstring") { + var prefix = getCompletionPrefix(editor); // Only autocomplete if there's a prefix that can be matched if (prefix && !hasCompleter) { if (!editor.completer) { // Create new autocompleter editor.completer = new Autocomplete(); - // Disable autoInsert - editor.completer.autoSelect = false; - editor.completer.autoInsert = false; } + // Disable autoInsert + editor.completer.autoSelect = false; + editor.completer.autoInsert = false; editor.completer.showPopup(editor); } else if (!prefix && hasCompleter) { // When the prefix is empty @@ -168,7 +173,8 @@ require("../config").defineOptions(Editor.prototype, "editor", { enableBasicAutocompletion: { set: function(val) { if (val) { - this.completers = Array.isArray(val)? val: completers; + if (!this.completers) + this.completers = Array.isArray(val)? val: completers; this.commands.addCommand(Autocomplete.startCommand); } else { this.commands.removeCommand(Autocomplete.startCommand); @@ -183,7 +189,8 @@ require("../config").defineOptions(Editor.prototype, "editor", { enableLiveAutocompletion: { set: function(val) { if (val) { - this.completers = Array.isArray(val)? val: completers; + if (!this.completers) + this.completers = Array.isArray(val)? val: completers; // On each change automatically trigger the autocomplete this.commands.on('afterExec', doLiveAutocomplete); } else { From 66866121e9ae1015148d0ac6ee0af375a46f30c1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 23 May 2014 14:13:23 +0400 Subject: [PATCH 032/545] fix issue with scrolling into view on focus --- demo/autoresize.html | 40 +++++++++++++++++++--------------- lib/ace/mouse/mouse_handler.js | 6 ++++- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/demo/autoresize.html b/demo/autoresize.html index 2b64d96a..73a87599 100644 --- a/demo/autoresize.html +++ b/demo/autoresize.html @@ -26,28 +26,32 @@

 
-
+
 
 
 
diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js
index c7573e94..a69a672c 100644
--- a/lib/ace/mouse/mouse_handler.js
+++ b/lib/ace/mouse/mouse_handler.js
@@ -46,7 +46,11 @@ var MouseHandler = function(editor) {
     new DefaultGutterHandler(this);
     new DragdropHandler(this);
     
-    var focusEditor = function(e) { editor.focus() };
+    var focusEditor = function(e) { 
+        if (!editor.isFocused() && editor.textInput)
+            editor.textInput.onContextMenu(e);
+        editor.focus() 
+    };
     
     var mouseTarget = editor.renderer.getMouseEventTarget();
     event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click"));

From 1c2bc2942436b2f7ad998bcf7059671a592f8768 Mon Sep 17 00:00:00 2001
From: nightwing 
Date: Wed, 28 May 2014 01:25:18 +0400
Subject: [PATCH 033/545] fix selecting with ctrl-alt click

---
 lib/ace/mouse/default_handlers.js     | 24 +++++----
 lib/ace/mouse/multi_select_handler.js | 76 ++++++++++++++++-----------
 2 files changed, 59 insertions(+), 41 deletions(-)

diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js
index 8a9adcf7..7bb701a8 100644
--- a/lib/ace/mouse/default_handlers.js
+++ b/lib/ace/mouse/default_handlers.js
@@ -109,12 +109,14 @@ function DefaultHandlers(mouseHandler) {
         var editor = this.editor;
         // allow double/triple click handlers to change selection
         var shiftPressed = this.mousedownEvent.getShiftKey();
-        if (shiftPressed) {
-            editor.selection.selectToPosition(pos);
-        }
-        else if (!this.$clickSelection) {
-            editor.selection.moveToPosition(pos);
-        }
+        setTimeout(function(){
+            if (shiftPressed) {
+                editor.selection.selectToPosition(pos);
+            }
+            else if (!this.$clickSelection) {
+                editor.selection.moveToPosition(pos);
+            }
+        }.bind(this), 0);
         if (editor.renderer.scroller.setCapture) {
             editor.renderer.scroller.setCapture();
         }
@@ -213,7 +215,6 @@ function DefaultHandlers(mouseHandler) {
             this.setState("selectByWords");
         }
         this.$clickSelection = range;
-        this[this.state] && this[this.state](ev);
     };
 
     this.onTripleClick = function(ev) {
@@ -221,8 +222,13 @@ function DefaultHandlers(mouseHandler) {
         var editor = this.editor;
 
         this.setState("selectByLines");
-        this.$clickSelection = editor.selection.getLineRange(pos.row);
-        this[this.state] && this[this.state](ev);
+        var range = editor.getSelectionRange();
+        if (range.isMultiLine() && range.contains(pos.row, pos.column)) {
+            this.$clickSelection = editor.selection.getLineRange(range.start.row);
+            this.$clickSelection.end = editor.selection.getLineRange(range.end.row).end;
+        } else {
+            this.$clickSelection = editor.selection.getLineRange(pos.row);
+        }
     };
 
     this.onQuadClick = function(ev) {
diff --git a/lib/ace/mouse/multi_select_handler.js b/lib/ace/mouse/multi_select_handler.js
index 0620f8f5..8d6af6b5 100644
--- a/lib/ace/mouse/multi_select_handler.js
+++ b/lib/ace/mouse/multi_select_handler.js
@@ -54,7 +54,7 @@ function onMouseDown(e) {
         return;
     }
     
-    if (!ctrl && !alt) {
+    if (!ctrl && !alt && !accel) {
         if (button === 0 && e.editor.inMultiSelectMode)
             e.editor.exitMultiSelectMode();
         return;
@@ -70,30 +70,11 @@ function onMouseDown(e) {
     var cursor = selection.getCursor();
     var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
 
-
     var mouseX = e.x, mouseY = e.y;
     var onMouseSelection = function(e) {
         mouseX = e.clientX;
         mouseY = e.clientY;
     };
-
-    var blockSelect = function() {
-        var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
-        var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column);
-
-        if (isSamePoint(screenCursor, newCursor)
-            && isSamePoint(cursor, selection.selectionLead))
-            return;
-        screenCursor = newCursor;
-
-        editor.selection.moveToPosition(cursor);
-        editor.renderer.scrollCursorIntoView();
-
-        editor.removeSelectionMarkers(rectSel);
-        rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor);
-        rectSel.forEach(editor.addSelectionMarker, editor);
-        editor.updateSelectionMarkers();
-    };
     
     var session = editor.session;
     var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
@@ -159,26 +140,57 @@ function onMouseDown(e) {
 
     } else if (selectionMode == "block") {
         e.stop();
-
-        if (isMultiSelect && !ctrl)
-            selection.toSingleRange();
-        else if (!isMultiSelect && ctrl)
-            selection.addRange();
-
+        editor.inVirtualSelectionMode = true;        
+        var initialRange;
         var rectSel = [];
-        if (shift) {
-            screenAnchor = session.documentToScreenPosition(selection.lead);
-            blockSelect();
-        } else {
-            selection.moveToPosition(pos);
-        }
+        var blockSelect = function() {
+            var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
+            var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column);
 
+            if (isSamePoint(screenCursor, newCursor) && isSamePoint(cursor, selection.lead))
+                return;
+            screenCursor = newCursor;
+
+            editor.selection.moveToPosition(cursor);
+            editor.renderer.scrollCursorIntoView();
+
+            editor.removeSelectionMarkers(rectSel);
+            rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor);
+            if (editor.$mouseHandler.$clickSelection && rectSel.length == 1 && rectSel[0].isEmpty())
+                rectSel[0] = editor.$mouseHandler.$clickSelection.clone();
+            rectSel.forEach(editor.addSelectionMarker, editor);
+            editor.updateSelectionMarkers();
+        };
+        
+        if (isMultiSelect && !accel) {
+            selection.toSingleRange();
+        } else if (!isMultiSelect && accel) {
+            initialRange = selection.toOrientedRange();
+            editor.addSelectionMarker(initialRange);
+        }
+        
+        if (shift)
+            screenAnchor = session.documentToScreenPosition(selection.lead);            
+        else
+            selection.moveToPosition(pos);
+        
+        screenCursor = {row: -1, column: -1};
 
         var onMouseSelectionEnd = function(e) {
             clearInterval(timerId);
             editor.removeSelectionMarkers(rectSel);
+            if (!rectSel.length)
+                rectSel = [selection.toOrientedRange()];
+            editor.$blockScrolling++;
+            if (initialRange) {
+                editor.removeSelectionMarker(initialRange);
+                selection.toSingleRange(initialRange);
+            }
             for (var i = 0; i < rectSel.length; i++)
                 selection.addRange(rectSel[i]);
+            editor.inVirtualSelectionMode = false;
+            editor.$mouseHandler.$clickSelection = null;
+            editor.$blockScrolling--;
         };
 
         var onSelectionInterval = blockSelect;

From e4355adae7f8fc6c7279bd7a22ed5caec1fd1848 Mon Sep 17 00:00:00 2001
From: baboso 
Date: Sat, 31 May 2014 19:51:41 -0400
Subject: [PATCH 034/545] Initial commit for praat highlighting: based on Perl

---
 lib/ace/mode/praat.js                 |  90 ++++++++++++++
 lib/ace/mode/praat_highlight_rules.js | 165 ++++++++++++++++++++++++++
 2 files changed, 255 insertions(+)
 create mode 100644 lib/ace/mode/praat.js
 create mode 100644 lib/ace/mode/praat_highlight_rules.js

diff --git a/lib/ace/mode/praat.js b/lib/ace/mode/praat.js
new file mode 100644
index 00000000..69c4d27e
--- /dev/null
+++ b/lib/ace/mode/praat.js
@@ -0,0 +1,90 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Ajax.org B.V. nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var TextMode = require("./text").Mode;
+var PerlHighlightRules = require("./perl_highlight_rules").PerlHighlightRules;
+var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
+var Range = require("../range").Range;
+var CStyleFoldMode = require("./folding/cstyle").FoldMode;
+
+var Mode = function() {
+    this.HighlightRules = PerlHighlightRules;
+    
+    this.$outdent = new MatchingBraceOutdent();
+    this.foldingRules = new CStyleFoldMode({start: "^=(begin|item)\\b", end: "^=(cut)\\b"});
+};
+oop.inherits(Mode, TextMode);
+
+(function() {
+
+    this.lineCommentStart = "#";
+    this.blockComment = [
+        {start: "=begin", end: "=cut"},
+        {start: "=item", end: "=cut"}
+    ];
+
+
+    this.getNextLineIndent = function(state, line, tab) {
+        var indent = this.$getIndent(line);
+
+        var tokenizedLine = this.getTokenizer().getLineTokens(line, state);
+        var tokens = tokenizedLine.tokens;
+
+        if (tokens.length && tokens[tokens.length-1].type == "comment") {
+            return indent;
+        }
+
+        if (state == "start") {
+            var match = line.match(/^.*[\{\(\[\:]\s*$/);
+            if (match) {
+                indent += tab;
+            }
+        }
+
+        return indent;
+    };
+
+    this.checkOutdent = function(state, line, input) {
+        return this.$outdent.checkOutdent(line, input);
+    };
+
+    this.autoOutdent = function(state, doc, row) {
+        this.$outdent.autoOutdent(doc, row);
+    };
+
+    this.$id = "ace/mode/perl";
+}).call(Mode.prototype);
+
+exports.Mode = Mode;
+});
diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
new file mode 100644
index 00000000..7c183fe3
--- /dev/null
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -0,0 +1,165 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Ajax.org B.V. nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
+
+var PerlHighlightRules = function() {
+
+    var keywords = (
+        "base|constant|continue|else|elsif|for|foreach|format|goto|if|last|local|my|next|" +
+         "no|package|parent|redo|require|scalar|sub|unless|until|while|use|vars"
+    );
+
+    var buildinConstants = ("ARGV|ENV|INC|SIG");
+
+    var builtinFunctions = (
+        "getprotobynumber|getprotobyname|getservbyname|gethostbyaddr|" +
+         "gethostbyname|getservbyport|getnetbyaddr|getnetbyname|getsockname|" +
+         "getpeername|setpriority|getprotoent|setprotoent|getpriority|" +
+         "endprotoent|getservent|setservent|endservent|sethostent|socketpair|" +
+         "getsockopt|gethostent|endhostent|setsockopt|setnetent|quotemeta|" +
+         "localtime|prototype|getnetent|endnetent|rewinddir|wantarray|getpwuid|" +
+         "closedir|getlogin|readlink|endgrent|getgrgid|getgrnam|shmwrite|" +
+         "shutdown|readline|endpwent|setgrent|readpipe|formline|truncate|" +
+         "dbmclose|syswrite|setpwent|getpwnam|getgrent|getpwent|ucfirst|sysread|" +
+         "setpgrp|shmread|sysseek|sysopen|telldir|defined|opendir|connect|" +
+         "lcfirst|getppid|binmode|syscall|sprintf|getpgrp|readdir|seekdir|" +
+         "waitpid|reverse|unshift|symlink|dbmopen|semget|msgrcv|rename|listen|" +
+         "chroot|msgsnd|shmctl|accept|unpack|exists|fileno|shmget|system|" +
+         "unlink|printf|gmtime|msgctl|semctl|values|rindex|substr|splice|" +
+         "length|msgget|select|socket|return|caller|delete|alarm|ioctl|index|" +
+         "undef|lstat|times|srand|chown|fcntl|close|write|umask|rmdir|study|" +
+         "sleep|chomp|untie|print|utime|mkdir|atan2|split|crypt|flock|chmod|" +
+         "BEGIN|bless|chdir|semop|shift|reset|link|stat|chop|grep|fork|dump|" +
+         "join|open|tell|pipe|exit|glob|warn|each|bind|sort|pack|eval|push|" +
+         "keys|getc|kill|seek|sqrt|send|wait|rand|tied|read|time|exec|recv|" +
+         "eof|chr|int|ord|exp|pos|pop|sin|log|abs|oct|hex|tie|cos|vec|END|ref|" +
+         "map|die|uc|lc|do"
+    );
+
+    var keywordMapper = this.createKeywordMapper({
+        "keyword": keywords,
+        "constant.language": buildinConstants,
+        "support.function": builtinFunctions
+    }, "identifier");
+
+    // regexp must not have capturing parentheses. Use (?:) instead.
+    // regexps are ordered -> the first match is used
+
+    this.$rules = {
+        "start" : [
+            {
+                token : "comment.doc",
+                regex : "^=(?:begin|item)\\b",
+                next : "block_comment"
+            }, {
+                token : "string.regexp",
+                regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
+            }, {
+                token : "string", // single line
+                regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
+            }, {
+                token : "string", // multi line string start
+                regex : '["].*\\\\$',
+                next : "qqstring"
+            }, {
+                token : "string", // single line
+                regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
+            }, {
+                token : "string", // multi line string start
+                regex : "['].*\\\\$",
+                next : "qstring"
+            }, {
+                token : "constant.numeric", // hex
+                regex : "0x[0-9a-fA-F]+\\b"
+            }, {
+                token : "constant.numeric", // float
+                regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
+            }, {
+                token : keywordMapper,
+                regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
+            }, {
+                token : "keyword.operator",
+                regex : "%#|\\$#|\\.\\.\\.|\\|\\|=|>>=|<<=|<=>|&&=|=>|!~|\\^=|&=|\\|=|\\.=|x=|%=|\\/=|\\*=|\\-=|\\+=|=~|\\*\\*|\\-\\-|\\.\\.|\\|\\||&&|\\+\\+|\\->|!=|==|>=|<=|>>|<<|,|=|\\?\\:|\\^|\\||x|%|\\/|\\*|<|&|\\\\|~|!|>|\\.|\\-|\\+|\\-C|\\-b|\\-S|\\-u|\\-t|\\-p|\\-l|\\-d|\\-f|\\-g|\\-s|\\-z|\\-k|\\-e|\\-O|\\-T|\\-B|\\-M|\\-A|\\-X|\\-W|\\-c|\\-R|\\-o|\\-x|\\-w|\\-r|\\b(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|xor)"
+            }, {
+                token : "comment",
+                regex : "#.*$"
+            }, {
+                token : "lparen",
+                regex : "[[({]"
+            }, {
+                token : "rparen",
+                regex : "[\\])}]"
+            }, {
+                token : "text",
+                regex : "\\s+"
+            }
+        ],
+        "qqstring" : [
+            {
+                token : "string",
+                regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
+                next : "start"
+            }, {
+                token : "string",
+                regex : '.+'
+            }
+        ],
+        "qstring" : [
+            {
+                token : "string",
+                regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
+                next : "start"
+            }, {
+                token : "string",
+                regex : '.+'
+            }
+        ],
+        "block_comment": [
+            {
+                token: "comment.doc", 
+                regex: "^=cut\\b",
+                next: "start"
+            },
+            {
+                defaultToken: "comment.doc"
+            }
+        ]
+    };
+};
+
+oop.inherits(PerlHighlightRules, TextHighlightRules);
+
+exports.PerlHighlightRules = PerlHighlightRules;
+});

From df92a99e93c57439c6870466c111ef985085e4a4 Mon Sep 17 00:00:00 2001
From: baboso 
Date: Sun, 1 Jun 2014 18:25:27 -0400
Subject: [PATCH 035/545] Praat syntax highlighter, first release

---
 demo/kitchen-sink/docs/praat.praat    | 115 ++++++++++
 lib/ace/ext/modelist.js               |   1 +
 lib/ace/mode/praat.js                 |  11 +-
 lib/ace/mode/praat_highlight_rules.js | 288 +++++++++++++++-----------
 4 files changed, 290 insertions(+), 125 deletions(-)
 create mode 100644 demo/kitchen-sink/docs/praat.praat

diff --git a/demo/kitchen-sink/docs/praat.praat b/demo/kitchen-sink/docs/praat.praat
new file mode 100644
index 00000000..48a649a2
--- /dev/null
+++ b/demo/kitchen-sink/docs/praat.praat
@@ -0,0 +1,115 @@
+form Highlighter test
+  sentence My_sentence This should all be a string
+  text My_text This should also all be a string
+  word My_word Only the first word is a string, the rest is invalid
+  boolean Binary 1
+  boolean Text no
+  boolean Quoted "yes"
+  comment This should be a string
+  real left_Range -123.6
+  positive right_Range_max 3.3
+  integer Int 4
+  natural Nat 4
+endform
+
+# old-style procedure call
+call oldStyle "quoted" 2 unquoted string
+assert oldStyle.local = 1
+
+# New-style procedure call with parens
+@newStyle("quoted", 2, "quoted string")
+if praatVersion >= 5364 
+  # New-style procedure call with colon
+  @newStyle: "quoted", 2, "quoted string"
+endif
+assert newStyle.local = 1
+
+# if-block with built-in variables
+if windows
+  # We are on Windows
+elsif unix = 1 or !macintosh
+  # We are on Linux
+else macintosh == 1
+  # We are on Mac
+endif
+
+# inline if with inline comment
+var = if macintosh = 1 then 0 else 1 fi ; This is an inline comment
+
+# for-loop with explicit from using local variable
+# and paren-style function calls and variable interpolation
+n = numberOfSelected("Sound")
+for i from newStyle.local to n
+  sound'i' = selected("Sound", i)
+  sound[i] = sound'i'
+endfor
+
+for i from 1 to n
+  # Different styles of object selection
+  select sound'i'
+  sound = selected()
+  sound$ = selected$("Sound")
+  select Sound 'sound$'
+  selectObject(sound[i])
+  selectObject: sound
+  
+  # New-style standalone command call
+  Rename: "SomeName"
+
+  # Command call with assignment
+  duration = Get total duration
+  
+  # Multi-line command with modifier
+  pitch = noprogress To Pitch (ac): 0, 75, 15, "no",
+    ...0.03, 0.45, 0.01, 0.35, 0.14, 600
+    
+  # Old-style command with assignment
+  minimum = Get minimum... 0 0 "Hertz" Parabolic
+
+  # New-style multi-line command call with broken strings
+  table = Create Table with column names: "table", 0,
+    ..."file subject speaker
+    ...f0 f1 f2 f3 " +
+    ..."duration response"
+  
+  removeObject: pitch, table
+    
+  # Picture window commands
+  selectObject: sound
+  Select inner viewport: 1, 6, 0.5, 1.5
+  Black
+  Draw... 0 0 0 0 "no" Curve
+  Draw inner box
+  Text bottom: "yes", sound$
+  Erase all
+  
+  # Demo window commands
+  demo Erase all
+  demo Select inner viewport... 0 100 0 100
+  demo Axes... 0 100 0 100
+  demo Paint rectangle... white 0 100 0 100
+  demo Purple
+  demo Times
+  demo 24
+  # The "to" in "Click to finish" should not be a keyword
+  demo Text... 50 centre 50 half Click to finish
+  demoWaitForInput ( )
+  demo Erase all
+  demo Select inner viewport... 0 100 0 100
+  demo Axes... 0 100 0 100
+  demo Paint rectangle... purple 0 100 0 100
+  demo Yellow
+  demo Times
+  demo 24
+  demo Text... 50 centre 50 half Finished
+endfor
+
+# Old-style procedure declaration
+procedure oldStyle .str1$ .num .str2$
+  .local = 1
+endproc
+
+# New-style procedure declaration
+procedure newStyle (.str1$, .num, .str2$)
+  .local = 1
+endproc
diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js
index 66fe3de8..b4fbd0da 100644
--- a/lib/ace/ext/modelist.js
+++ b/lib/ace/ext/modelist.js
@@ -113,6 +113,7 @@ var supportedModes = {
     pgSQL:       ["pgsql"],
     PHP:         ["php|phtml"],
     Powershell:  ["ps1"],
+    Praat:      ["praat"],
     Prolog:      ["plg|prolog"],
     Properties:  ["properties"],
     Protobuf:    ["proto"],
diff --git a/lib/ace/mode/praat.js b/lib/ace/mode/praat.js
index 69c4d27e..01d18c9a 100644
--- a/lib/ace/mode/praat.js
+++ b/lib/ace/mode/praat.js
@@ -33,13 +33,13 @@ define(function(require, exports, module) {
 
 var oop = require("../lib/oop");
 var TextMode = require("./text").Mode;
-var PerlHighlightRules = require("./perl_highlight_rules").PerlHighlightRules;
+var PraatHighlightRules = require("./praat_highlight_rules").PraatHighlightRules;
 var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
 var Range = require("../range").Range;
 var CStyleFoldMode = require("./folding/cstyle").FoldMode;
 
 var Mode = function() {
-    this.HighlightRules = PerlHighlightRules;
+    this.HighlightRules = PraatHighlightRules;
     
     this.$outdent = new MatchingBraceOutdent();
     this.foldingRules = new CStyleFoldMode({start: "^=(begin|item)\\b", end: "^=(cut)\\b"});
@@ -49,11 +49,6 @@ oop.inherits(Mode, TextMode);
 (function() {
 
     this.lineCommentStart = "#";
-    this.blockComment = [
-        {start: "=begin", end: "=cut"},
-        {start: "=item", end: "=cut"}
-    ];
-
 
     this.getNextLineIndent = function(state, line, tab) {
         var indent = this.$getIndent(line);
@@ -83,7 +78,7 @@ oop.inherits(Mode, TextMode);
         this.$outdent.autoOutdent(doc, row);
     };
 
-    this.$id = "ace/mode/perl";
+    this.$id = "ace/mode/praat";
 }).call(Mode.prototype);
 
 exports.Mode = Mode;
diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
index 7c183fe3..693a6572 100644
--- a/lib/ace/mode/praat_highlight_rules.js
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -1,77 +1,106 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Distributed under the BSD license:
- *
- * Copyright (c) 2010, Ajax.org B.V.
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Ajax.org B.V. nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ***** END LICENSE BLOCK ***** */
-
 define(function(require, exports, module) {
 "use strict";
 
 var oop = require("../lib/oop");
 var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
 
-var PerlHighlightRules = function() {
+var PraatHighlightRules = function() {
 
     var keywords = (
-        "base|constant|continue|else|elsif|for|foreach|format|goto|if|last|local|my|next|" +
-         "no|package|parent|redo|require|scalar|sub|unless|until|while|use|vars"
+        "if|then|else|elsif|elif|endif|fi|" +
+        "endfor|" + // other for-related keywords are specified below
+        "while|endwhile|" +
+        "repeat|until|" +
+        "select|plus|minus|" +
+        "assert"
     );
 
-    var buildinConstants = ("ARGV|ENV|INC|SIG");
+//     var buildinConstants = ("ARGV|ENV|INC|SIG");
 
-    var builtinFunctions = (
-        "getprotobynumber|getprotobyname|getservbyname|gethostbyaddr|" +
-         "gethostbyname|getservbyport|getnetbyaddr|getnetbyname|getsockname|" +
-         "getpeername|setpriority|getprotoent|setprotoent|getpriority|" +
-         "endprotoent|getservent|setservent|endservent|sethostent|socketpair|" +
-         "getsockopt|gethostent|endhostent|setsockopt|setnetent|quotemeta|" +
-         "localtime|prototype|getnetent|endnetent|rewinddir|wantarray|getpwuid|" +
-         "closedir|getlogin|readlink|endgrent|getgrgid|getgrnam|shmwrite|" +
-         "shutdown|readline|endpwent|setgrent|readpipe|formline|truncate|" +
-         "dbmclose|syswrite|setpwent|getpwnam|getgrent|getpwent|ucfirst|sysread|" +
-         "setpgrp|shmread|sysseek|sysopen|telldir|defined|opendir|connect|" +
-         "lcfirst|getppid|binmode|syscall|sprintf|getpgrp|readdir|seekdir|" +
-         "waitpid|reverse|unshift|symlink|dbmopen|semget|msgrcv|rename|listen|" +
-         "chroot|msgsnd|shmctl|accept|unpack|exists|fileno|shmget|system|" +
-         "unlink|printf|gmtime|msgctl|semctl|values|rindex|substr|splice|" +
-         "length|msgget|select|socket|return|caller|delete|alarm|ioctl|index|" +
-         "undef|lstat|times|srand|chown|fcntl|close|write|umask|rmdir|study|" +
-         "sleep|chomp|untie|print|utime|mkdir|atan2|split|crypt|flock|chmod|" +
-         "BEGIN|bless|chdir|semop|shift|reset|link|stat|chop|grep|fork|dump|" +
-         "join|open|tell|pipe|exit|glob|warn|each|bind|sort|pack|eval|push|" +
-         "keys|getc|kill|seek|sqrt|send|wait|rand|tied|read|time|exec|recv|" +
-         "eof|chr|int|ord|exp|pos|pop|sin|log|abs|oct|hex|tie|cos|vec|END|ref|" +
-         "map|die|uc|lc|do"
+    var predefinedVariables = (
+        "macintosh|windows|unix|" +
+        "praatVersion|praatVersion\\$" +
+        "pi|undefined|" +
+        "newline\\$|tab\\$|" +
+        "shellDirectory\\$|homeDirectory\\$|preferencesDirectory\\$|" +
+        "temporaryDirectory\\$|defaultDirectory\\$"
+    );
+    
+    var functions = (
+//      Math functions
+        "writeInfo|writeInfoLine|appendInfo|appendInfoLine|" +
+        "writeFile|writeFileLine|appendFile|appendFileLine|" +
+        "abs|round|floor|ceiling|min|max|imin|imax|" +
+        "sqrt|sin|cos|tan|arcsin|arccos|arctan|arctan2|sinc|sincpi|" +
+        "exp|ln|log10|log2|" +
+        "sinh|cosh|tanh|arcsinh|arccosh|actanh|" +
+        "sigmoid|invSigmoid|erf|erfc|" +
+        "randomUniform|randomInteger|randomGauss|randomPoisson|" +
+        "lnGamma|gaussP|gaussQ|invGaussQ|" +
+        "chiSquareP|chiSquareQ|invChiSquareQ|studentP|studentQ|invStudentQ|" +
+        "fisherP|fisherQ|invFisherQ|" +
+        "binomialP|binomialQ|invBinomialP|invBinomialQ|" +
+        "hertzToBark|barkToHerz|" +
+        "hertzToMel|melToHertz|" +
+        "hertzToSemitones|semitonesToHerz|" +
+        "erb|hertzToErb|erbToHertz|" +
+        "phonToDifferenceLimens|differenceLimensToPhon|" +
+        "beta|besselI|besselK|" +
+//      String functions
+        "selected|selected$|numberOfSelected|variableExists|"+
+        "index|rindex|startsWith|endsWith|"+
+        "index_regex|rindex_regex|replace_regex$|"+
+        "length|extractWord$|extractLine$|extractNumber|" +
+        "left$|right$|mid$|replace$|" +
+//      Pause functions
+        "beginPause|endPause|" +
+//      Demo functions
+        "demoShow|demoWindowTitle|demoInput|demoWaitForInput|" +
+        "demoClicked|demoClickedIn|demoX|demoY|" +
+        "demoKeyPressed|demoKey$|" +
+        "demoExtraControlKeyPressed|demoShiftKeyPressed|"+
+        "demoCommandKeyPressed|demoOptionKeyPressed|" +
+//      File functions
+        "environment$|" +
+        "chooseDirectory$|createDirectory|fileReadable|deleteFile|" +
+        "selectObject|removeObject|plusObject|minusObject|" +
+        "runScript|exitScript"
     );
 
+    var objectTypes = (
+        "Collection|Strings|ManPages|SortedSetOfString|Sound|Matrix|Polygon|" +
+        "PointProcess|ParamCurve|Spectrum|Ltas|Spectrogram|Formant|" +
+        "Excitation|Cochleagram|VocalTract|FormantPoint|FormantTier|" +
+        "FormantGrid|Label|Tier|Autosegment|Intensity|Pitch|Harmonicity|" +
+        "Transition|RealPoint|RealTier|PitchTier|IntensityTier|DurationTier|" +
+        "AmplitudeTier|SpectrumTier|Manipulation|TextPoint|TextInterval|" +
+        "TextTier|IntervalTier|TextGrid|LongSound|WordList|SpellingChecker|" +
+        "Movie|Corpus|TableOfReal|Distributions|PairDistribution|Table|" +
+        "LinearRegression|LogisticRegression|Art|Artword|Speaker|Activation|" +
+        "BarkFilter|Categories|Cepstrum|CCA|ChebyshevSeries|" +
+        "ClassificationTable|Confusion|Correlation|Covariance|Discriminant|" +
+        "DTW|Eigen|Excitations|FormantFilter|Index|KlattTable|Permutation|" +
+        "ISpline|LegendreSeries|MelFilter|MSpline|Pattern|PCA|Polynomial|" +
+        "Roots|SimpleString|StringsIndex|SpeechSynthesizer|SPINET|SSCP|SVD|" +
+        "AffineTransform|Procrustes|ContingencyTable|Dissimilarity|" +
+        "Similarity|Configuration|Distance|Salience|ScalarProduct|Weight|" +
+        "KlattGrid|HMM|HMM_State|HMM_Observation|HMM_ObservationSequence|" +
+        "HMM_StateSequence|GaussianMixture|Diagonalizer|MixingMatrix|" +
+        "CrossCorrelationTable|CrossCorrelationTables|Network|OTGrammar|" +
+        "OTHistory|OTMulti|FFNet|Cepstrumc|LPC|LFCC|MFCC|ExperimentMFC|" +
+        "ResultsMFC|EEG|ERPTier|ERP|KNN|FeatureWeights"
+    );
+    
     var keywordMapper = this.createKeywordMapper({
         "keyword": keywords,
-        "constant.language": buildinConstants,
-        "support.function": builtinFunctions
+//         "constant.language": buildinConstants,
+        "support.function": functions
+    }, "identifier");
+    
+    var inlineIf = this.createKeywordMapper({
+        "keyword": "(if|then|else|fi)",
+//         "constant.language": buildinConstants,
+        "support.function": functions
     }, "identifier");
 
     // regexp must not have capturing parentheses. Use (?:) instead.
@@ -80,86 +109,111 @@ var PerlHighlightRules = function() {
     this.$rules = {
         "start" : [
             {
-                token : "comment.doc",
-                regex : "^=(?:begin|item)\\b",
-                next : "block_comment"
+                token : "entity.name.type",
+                regex : "(" + objectTypes + ")"
             }, {
-                token : "string.regexp",
-                regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
+                token : "variable.language",
+                regex : "(" + predefinedVariables + ")"
             }, {
-                token : "string", // single line
-                regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
+                token : ["support.function", "text"],
+                regex : "((?:" + functions + ")\\$?)(\\s*(?::|\\())"
             }, {
-                token : "string", // multi line string start
-                regex : '["].*\\\\$',
-                next : "qqstring"
+//                 token : ["keyword", "text", "keyword", "text", "keyword", "text"],
+//                 regex : /\b(for)(\s+\S+\s*)(?:(from)(\s+[a-z][a-zA-Z0-9_.]*\$?\s*))?(?:(to)(\s+\S+\s*))?/,
+//             }, {
+                token : "keyword",
+                regex : /(\bfor\b)/,
+                next : "for"
             }, {
-                token : "string", // single line
-                regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
+                token : "keyword",
+                regex : "(\\b(?:" + keywords + ")\\b)"
             }, {
-                token : "string", // multi line string start
-                regex : "['].*\\\\$",
-                next : "qstring"
+                token : "string.interpolated",
+                regex : /'((?:[a-z][a-zA-Z0-9_]*)(?:\$|#|:[0-9]+)?)'/
             }, {
-                token : "constant.numeric", // hex
-                regex : "0x[0-9a-fA-F]+\\b"
+                token : "string",
+                regex : /"[^"]*"/
             }, {
-                token : "constant.numeric", // float
-                regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
+                token : ["text", "keyword", "text", "entity.name.section"], // multi line string start
+                regex : /(^\s*)(\bform\b)(\s+)(.*)/,
+                next : "form"
             }, {
-                token : keywordMapper,
-                regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
+                token : "constant.numeric",
+                regex : /\b[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
+            }, {
+                token : ["entity.name.function", "text"],
+                regex : /(@\S+)(:|\s*\()/
+            }, {
+                token : ["text", "keyword", "text", "entity.name.function"],
+                regex : /(^\s*)(call)(\s+)(\S+)/
+            }, {
+                token : ["text", "text", "keyword.operator", "text", "keyword", "text", "keyword"],
+                regex : /(^\s*)(?:([a-z][a-zA-Z0-9_]*\$?\s+)(=)(\s+))?(?:((?:no)?warn|nocheck|noprogress)(\s+))?((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
+            }, {
+                token : ["text", "keyword", "text", "keyword"],
+                regex : /(^\s*)(?:(demo)?(\s+))((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
+            }, {
+                token : ["text", "keyword"],
+                regex : /(^\s*)(demo\b)/
             }, {
                 token : "keyword.operator",
-                regex : "%#|\\$#|\\.\\.\\.|\\|\\|=|>>=|<<=|<=>|&&=|=>|!~|\\^=|&=|\\|=|\\.=|x=|%=|\\/=|\\*=|\\-=|\\+=|=~|\\*\\*|\\-\\-|\\.\\.|\\|\\||&&|\\+\\+|\\->|!=|==|>=|<=|>>|<<|,|=|\\?\\:|\\^|\\||x|%|\\/|\\*|<|&|\\\\|~|!|>|\\.|\\-|\\+|\\-C|\\-b|\\-S|\\-u|\\-t|\\-p|\\-l|\\-d|\\-f|\\-g|\\-s|\\-z|\\-k|\\-e|\\-O|\\-T|\\-B|\\-M|\\-A|\\-X|\\-W|\\-c|\\-R|\\-o|\\-x|\\-w|\\-r|\\b(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|xor)"
+                regex : /(?:\b((?:\+|-|\/|\*|<|>)=?|==?|!=|%|\^|\||and|or|not)\b)/
             }, {
                 token : "comment",
                 regex : "#.*$"
             }, {
-                token : "lparen",
-                regex : "[[({]"
+                token : "text",
+                regex : /\s+/
+            }
+        ],
+        "form" : [
+            {
+                token : ["keyword", "text", "constant.numeric"],
+                regex : /((?:optionmenu|choice)\s+)(\S+:\s+)([0-9]+)/
             }, {
-                token : "rparen",
-                regex : "[\\])}]"
+                token : ["keyword", "constant.numeric"],
+                regex : /((?:option|button)\s+)([+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b)/
+            }, {
+                token : ["keyword", "string"],
+                regex : /((?:option|button)\s+)(.*)/
+            }, {
+                token : ["keyword", "text", "string"],
+                regex : /((?:sentence|text)\s+)(\S+\s*)(.*)/
+            }, {
+                token : ["keyword", "text", "string", "invalid.illegal"],
+                regex : /(word\s+)(\S+\s*)(\S+)?(\s.*)?/
+            }, {
+                token : ["keyword", "text", "constant.language"],
+                regex : /(boolean\s+)(\S+\s*)(0|1|"?(?:yes|no)"?)/
+            }, {
+                token : ["keyword", "text", "constant.numeric"],
+                regex : /((?:real|natural|positive|integer)\s+)(\S+\s*)([+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b)/
+            }, {
+                token : ["keyword", "string"],
+                regex : /(comment\s+)(.*)/
+            }, {
+                token : "keyword",
+                regex : 'endform',
+                next : "start"
+            }
+        ],
+        "for" : [
+            {
+                token : ["keyword", "text", "constant.numeric", "text"],
+                regex : /(from|to)(\s+)([+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?)(\s*)/
+            }, {
+                token : ["keyword", "text"],
+                regex : /(from|to)(\s+\S+\s*)/
             }, {
                 token : "text",
-                regex : "\\s+"
-            }
-        ],
-        "qqstring" : [
-            {
-                token : "string",
-                regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
+                regex : /$/,
                 next : "start"
-            }, {
-                token : "string",
-                regex : '.+'
             }
         ],
-        "qstring" : [
-            {
-                token : "string",
-                regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
-                next : "start"
-            }, {
-                token : "string",
-                regex : '.+'
-            }
-        ],
-        "block_comment": [
-            {
-                token: "comment.doc", 
-                regex: "^=cut\\b",
-                next: "start"
-            },
-            {
-                defaultToken: "comment.doc"
-            }
-        ]
     };
 };
 
-oop.inherits(PerlHighlightRules, TextHighlightRules);
+oop.inherits(PraatHighlightRules, TextHighlightRules);
 
-exports.PerlHighlightRules = PerlHighlightRules;
+exports.PraatHighlightRules = PraatHighlightRules;
 });

From 08afa03cb9c140ffe7ca86e3b5edb038b9433a22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Joaqu=C3=ADn=20Atria?= 
Date: Tue, 3 Jun 2014 14:32:55 -0400
Subject: [PATCH 036/545] Fixed operators and introduced broken lines

---
 lib/ace/mode/praat_highlight_rules.js | 47 ++++++++++++++++++---------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
index 693a6572..0ce8a802 100644
--- a/lib/ace/mode/praat_highlight_rules.js
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -8,7 +8,7 @@ var PraatHighlightRules = function() {
 
     var keywords = (
         "if|then|else|elsif|elif|endif|fi|" +
-        "endfor|" + // other for-related keywords are specified below
+        "endfor|endproc|" + // other for-related keywords are specified below
         "while|endwhile|" +
         "repeat|until|" +
         "select|plus|minus|" +
@@ -109,6 +109,18 @@ var PraatHighlightRules = function() {
     this.$rules = {
         "start" : [
             {
+                token : ["text", "keyword.operator", "text"],
+                regex : /(\s+)((?:\+|-|\/|\*|<|>)=?|==?|!=|%|\^|\||and|or|not)(\s+)/
+            }, {
+                token : ["text", "text", "keyword.operator", "text", "keyword", "text", "keyword"],
+                regex : /(^\s*)(?:([a-z][a-zA-Z0-9_]*\$?\s+)(=)(\s+))?(?:((?:no)?warn|nocheck|noprogress)(\s+))?((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
+            }, {
+                token : ["text", "keyword", "text", "keyword"],
+                regex : /(^\s*)(?:(demo)?(\s+))((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
+            }, {
+                token : ["text", "keyword"],
+                regex : /(^\s*)(demo\b)/
+            }, {
                 token : "entity.name.type",
                 regex : "(" + objectTypes + ")"
             }, {
@@ -118,9 +130,6 @@ var PraatHighlightRules = function() {
                 token : ["support.function", "text"],
                 regex : "((?:" + functions + ")\\$?)(\\s*(?::|\\())"
             }, {
-//                 token : ["keyword", "text", "keyword", "text", "keyword", "text"],
-//                 regex : /\b(for)(\s+\S+\s*)(?:(from)(\s+[a-z][a-zA-Z0-9_.]*\$?\s*))?(?:(to)(\s+\S+\s*))?/,
-//             }, {
                 token : "keyword",
                 regex : /(\bfor\b)/,
                 next : "for"
@@ -133,6 +142,10 @@ var PraatHighlightRules = function() {
             }, {
                 token : "string",
                 regex : /"[^"]*"/
+            }, {
+                token : "string",
+                regex : /"[^"]*$/,
+                next : "brokenstring"
             }, {
                 token : ["text", "keyword", "text", "entity.name.section"], // multi line string start
                 regex : /(^\s*)(\bform\b)(\s+)(.*)/,
@@ -140,6 +153,9 @@ var PraatHighlightRules = function() {
             }, {
                 token : "constant.numeric",
                 regex : /\b[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
+            }, {
+                token : ["keyword", "text", "entity.name.function"],
+                regex : /(procedure)(\s+)(\S+)/
             }, {
                 token : ["entity.name.function", "text"],
                 regex : /(@\S+)(:|\s*\()/
@@ -147,17 +163,8 @@ var PraatHighlightRules = function() {
                 token : ["text", "keyword", "text", "entity.name.function"],
                 regex : /(^\s*)(call)(\s+)(\S+)/
             }, {
-                token : ["text", "text", "keyword.operator", "text", "keyword", "text", "keyword"],
-                regex : /(^\s*)(?:([a-z][a-zA-Z0-9_]*\$?\s+)(=)(\s+))?(?:((?:no)?warn|nocheck|noprogress)(\s+))?((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
-            }, {
-                token : ["text", "keyword", "text", "keyword"],
-                regex : /(^\s*)(?:(demo)?(\s+))((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
-            }, {
-                token : ["text", "keyword"],
-                regex : /(^\s*)(demo\b)/
-            }, {
-                token : "keyword.operator",
-                regex : /(?:\b((?:\+|-|\/|\*|<|>)=?|==?|!=|%|\^|\||and|or|not)\b)/
+                token : "comment",
+                regex : ";.*$"
             }, {
                 token : "comment",
                 regex : "#.*$"
@@ -210,6 +217,16 @@ var PraatHighlightRules = function() {
                 next : "start"
             }
         ],
+        "brokenstring" : [
+            {
+                token : ["text", "string"],
+                regex : /(\s*\.{3})([^"]*)/
+            }, {
+                token : "string",
+                regex : /"/,
+                next : "start"
+            }
+        ],
     };
 };
 

From d57e010ca3c3bbb77a2b7104bd1837fdf3a4af9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Joaqu=C3=ADn=20Atria?= 
Date: Tue, 3 Jun 2014 15:10:31 -0400
Subject: [PATCH 037/545] Added single number font size changing commands
 (praat)

---
 lib/ace/mode/praat_highlight_rules.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
index 0ce8a802..9ba554ec 100644
--- a/lib/ace/mode/praat_highlight_rules.js
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -118,9 +118,13 @@ var PraatHighlightRules = function() {
                 token : ["text", "keyword", "text", "keyword"],
                 regex : /(^\s*)(?:(demo)?(\s+))((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
             }, {
-                token : ["text", "keyword"],
-                regex : /(^\s*)(demo\b)/
+                token : ["text", "keyword", "text", "keyword"],
+                regex : /^(\s*)(?:(demo)(\s+))?(10|12|14|16|24)$/
             }, {
+            // Is this rule necessary?
+            //     token : ["text", "keyword"],
+            //     regex : /(^\s*)(demo\b)/
+            // }, {
                 token : "entity.name.type",
                 regex : "(" + objectTypes + ")"
             }, {

From a519520ae7cf18abd7a97c88665b40f4c7d962e2 Mon Sep 17 00:00:00 2001
From: baboso 
Date: Wed, 4 Jun 2014 18:03:55 -0400
Subject: [PATCH 038/545] Removed useless rules, added support for do() syntax

---
 demo/kitchen-sink/docs/praat.praat    |  7 ++++---
 lib/ace/mode/praat_highlight_rules.js | 19 ++++---------------
 2 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/demo/kitchen-sink/docs/praat.praat b/demo/kitchen-sink/docs/praat.praat
index 48a649a2..f15e4058 100644
--- a/demo/kitchen-sink/docs/praat.praat
+++ b/demo/kitchen-sink/docs/praat.praat
@@ -63,8 +63,8 @@ for i from 1 to n
   pitch = noprogress To Pitch (ac): 0, 75, 15, "no",
     ...0.03, 0.45, 0.01, 0.35, 0.14, 600
     
-  # Old-style command with assignment
-  minimum = Get minimum... 0 0 "Hertz" Parabolic
+  # do-style command with assignment
+  minimum = do("Get minimum...", 0, 0, "Hertz", "Parabolic")
 
   # New-style multi-line command call with broken strings
   table = Create Table with column names: "table", 0,
@@ -76,7 +76,8 @@ for i from 1 to n
     
   # Picture window commands
   selectObject: sound
-  Select inner viewport: 1, 6, 0.5, 1.5
+  # do-style command
+  do("Select inner viewport...", 1, 6, 0.5, 1.5)
   Black
   Draw... 0 0 0 0 "no" Curve
   Draw inner box
diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
index 9ba554ec..1e53b94c 100644
--- a/lib/ace/mode/praat_highlight_rules.js
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -15,8 +15,6 @@ var PraatHighlightRules = function() {
         "assert"
     );
 
-//     var buildinConstants = ("ARGV|ENV|INC|SIG");
-
     var predefinedVariables = (
         "macintosh|windows|unix|" +
         "praatVersion|praatVersion\\$" +
@@ -91,18 +89,6 @@ var PraatHighlightRules = function() {
         "ResultsMFC|EEG|ERPTier|ERP|KNN|FeatureWeights"
     );
     
-    var keywordMapper = this.createKeywordMapper({
-        "keyword": keywords,
-//         "constant.language": buildinConstants,
-        "support.function": functions
-    }, "identifier");
-    
-    var inlineIf = this.createKeywordMapper({
-        "keyword": "(if|then|else|fi)",
-//         "constant.language": buildinConstants,
-        "support.function": functions
-    }, "identifier");
-
     // regexp must not have capturing parentheses. Use (?:) instead.
     // regexps are ordered -> the first match is used
 
@@ -120,6 +106,9 @@ var PraatHighlightRules = function() {
             }, {
                 token : ["text", "keyword", "text", "keyword"],
                 regex : /^(\s*)(?:(demo)(\s+))?(10|12|14|16|24)$/
+            }, {
+                token : ["text", "support.function", "text"],
+                regex : /(\s*)(do\$?)(\s*:\s*|\s*\(\s*)/
             }, {
             // Is this rule necessary?
             //     token : ["text", "keyword"],
@@ -151,7 +140,7 @@ var PraatHighlightRules = function() {
                 regex : /"[^"]*$/,
                 next : "brokenstring"
             }, {
-                token : ["text", "keyword", "text", "entity.name.section"], // multi line string start
+                token : ["text", "keyword", "text", "entity.name.section"],
                 regex : /(^\s*)(\bform\b)(\s+)(.*)/,
                 next : "form"
             }, {

From 17c75da27b040310cf1aa06a92c14fbb0d893ec1 Mon Sep 17 00:00:00 2001
From: baboso 
Date: Thu, 5 Jun 2014 00:45:20 -0400
Subject: [PATCH 039/545] Added sendpraat and unquoted string directives,
 simplified demo example, added some other missing functions/directives

---
 demo/kitchen-sink/docs/praat.praat    | 44 ++++++++++++------
 lib/ace/ext/modelist.js               |  2 +-
 lib/ace/mode/praat.js                 |  1 -
 lib/ace/mode/praat_highlight_rules.js | 64 +++++++++++++++++++++------
 4 files changed, 81 insertions(+), 30 deletions(-)

diff --git a/demo/kitchen-sink/docs/praat.praat b/demo/kitchen-sink/docs/praat.praat
index f15e4058..c5dde785 100644
--- a/demo/kitchen-sink/docs/praat.praat
+++ b/demo/kitchen-sink/docs/praat.praat
@@ -12,6 +12,13 @@ form Highlighter test
   natural Nat 4
 endform
 
+# External scripts
+include /path/to/file
+runScript: "/path/to/file"
+execute /path/to/file
+
+stopwatch
+
 # old-style procedure call
 call oldStyle "quoted" 2 unquoted string
 assert oldStyle.local = 1
@@ -22,15 +29,14 @@ if praatVersion >= 5364
   # New-style procedure call with colon
   @newStyle: "quoted", 2, "quoted string"
 endif
-assert newStyle.local = 1
 
 # if-block with built-in variables
 if windows
   # We are on Windows
 elsif unix = 1 or !macintosh
-  # We are on Linux
+  exitScript: "We are on Linux"
 else macintosh == 1
-  # We are on Mac
+  exit We are on Mac
 endif
 
 # inline if with inline comment
@@ -89,22 +95,32 @@ for i from 1 to n
   demo Select inner viewport... 0 100 0 100
   demo Axes... 0 100 0 100
   demo Paint rectangle... white 0 100 0 100
-  demo Purple
-  demo Times
-  demo 24
-  # The "to" in "Click to finish" should not be a keyword
   demo Text... 50 centre 50 half Click to finish
   demoWaitForInput ( )
   demo Erase all
-  demo Select inner viewport... 0 100 0 100
-  demo Axes... 0 100 0 100
-  demo Paint rectangle... purple 0 100 0 100
-  demo Yellow
-  demo Times
-  demo 24
-  demo Text... 50 centre 50 half Finished
+  demo Text: 50, "centre", 50, "half", "Finished"
 endfor
 
+# An old-style sendpraat block
+sendpraat Praat
+  ...'newline$' Create Sound as pure tone... "tone" 1 0 0.4 44100 440 0.2 0.01 0.01
+  ...'newline$' Play
+  ...'newline$' Remove
+
+# A new-style sendpraat block
+beginSendPraat: "Praat"
+  Create Sound as pure tone: "tone", 1, 0, 0.4, 44100, 440, 0.2, 0.01, 0.01
+  duration = Get total duration
+  Remove
+endSendPraat: "duration"
+appendInfoLine: "The generated sound lasted for ", duration, "seconds"
+
+time = stopwatch
+clearinfo
+echo This script took 
+print 'time' seconds to 
+printline execute.
+
 # Old-style procedure declaration
 procedure oldStyle .str1$ .num .str2$
   .local = 1
diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js
index b4fbd0da..5c5552b4 100644
--- a/lib/ace/ext/modelist.js
+++ b/lib/ace/ext/modelist.js
@@ -113,7 +113,7 @@ var supportedModes = {
     pgSQL:       ["pgsql"],
     PHP:         ["php|phtml"],
     Powershell:  ["ps1"],
-    Praat:      ["praat"],
+    Praat:       ["praat|praatscript|psc|proc"],
     Prolog:      ["plg|prolog"],
     Properties:  ["properties"],
     Protobuf:    ["proto"],
diff --git a/lib/ace/mode/praat.js b/lib/ace/mode/praat.js
index 01d18c9a..7b100ef0 100644
--- a/lib/ace/mode/praat.js
+++ b/lib/ace/mode/praat.js
@@ -42,7 +42,6 @@ var Mode = function() {
     this.HighlightRules = PraatHighlightRules;
     
     this.$outdent = new MatchingBraceOutdent();
-    this.foldingRules = new CStyleFoldMode({start: "^=(begin|item)\\b", end: "^=(cut)\\b"});
 };
 oop.inherits(Mode, TextMode);
 
diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
index 1e53b94c..39220a52 100644
--- a/lib/ace/mode/praat_highlight_rules.js
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -8,7 +8,7 @@ var PraatHighlightRules = function() {
 
     var keywords = (
         "if|then|else|elsif|elif|endif|fi|" +
-        "endfor|endproc|" + // other for-related keywords are specified below
+        "endfor|endproc|" + // related keywords specified below
         "while|endwhile|" +
         "repeat|until|" +
         "select|plus|minus|" +
@@ -24,10 +24,16 @@ var PraatHighlightRules = function() {
         "temporaryDirectory\\$|defaultDirectory\\$"
     );
     
+    // What is "endSendPraat"? Function? Directive?
+    var directives = (
+        "clearinfo|endSendPraat"
+    );
+      
     var functions = (
-//      Math functions
+//      Info functions
         "writeInfo|writeInfoLine|appendInfo|appendInfoLine|" +
         "writeFile|writeFileLine|appendFile|appendFileLine|" +
+//      Math functions
         "abs|round|floor|ceiling|min|max|imin|imax|" +
         "sqrt|sin|cos|tan|arcsin|arccos|arctan|arctan2|sinc|sincpi|" +
         "exp|ln|log10|log2|" +
@@ -45,24 +51,26 @@ var PraatHighlightRules = function() {
         "phonToDifferenceLimens|differenceLimensToPhon|" +
         "beta|besselI|besselK|" +
 //      String functions
-        "selected|selected$|numberOfSelected|variableExists|"+
+        "selected|selected\\$|numberOfSelected|variableExists|"+
         "index|rindex|startsWith|endsWith|"+
-        "index_regex|rindex_regex|replace_regex$|"+
-        "length|extractWord$|extractLine$|extractNumber|" +
-        "left$|right$|mid$|replace$|" +
+        "index_regex|rindex_regex|replace_regex\\$|"+
+        "length|extractWord\\$|extractLine\\$|extractNumber|" +
+        "left\\$|right\\$|mid\\$|replace\\$|" +
 //      Pause functions
         "beginPause|endPause|" +
 //      Demo functions
         "demoShow|demoWindowTitle|demoInput|demoWaitForInput|" +
         "demoClicked|demoClickedIn|demoX|demoY|" +
-        "demoKeyPressed|demoKey$|" +
+        "demoKeyPressed|demoKey\\$|" +
         "demoExtraControlKeyPressed|demoShiftKeyPressed|"+
         "demoCommandKeyPressed|demoOptionKeyPressed|" +
 //      File functions
-        "environment$|" +
-        "chooseDirectory$|createDirectory|fileReadable|deleteFile|" +
+        "environment\\$|chooseReadFile\\$|" +
+        "chooseDirectory\\$|createDirectory|fileReadable|deleteFile|" +
         "selectObject|removeObject|plusObject|minusObject|" +
-        "runScript|exitScript"
+        "runScript|exitScript|" +
+//      sendpraat functions
+        "beginSendPraat|endSendPraat"
     );
 
     var objectTypes = (
@@ -95,18 +103,35 @@ var PraatHighlightRules = function() {
     this.$rules = {
         "start" : [
             {
+            // stopwatch
+                token : ["text", "text", "keyword.operator", "text", "keyword"],
+                regex : /(^\s*)(?:([a-z][a-zA-Z0-9_]*\$?\s+)(=)(\s+))?(stopwatch)/
+            }, {
+            // Directives which introduce unquoted strings
+                token : ["text", "keyword", "text", "string"],
+                regex : /(^\s*)(print(?:line)?|echo|exit|pause|sendpraat|include|execute)(\s+)(.*)/
+            }, {
+            // Directives with no arguments 
+                token : ["text", "keyword"],
+                regex : "(^\\s*)(" + directives + ")$"
+            }, {
+            // Operators
                 token : ["text", "keyword.operator", "text"],
                 regex : /(\s+)((?:\+|-|\/|\*|<|>)=?|==?|!=|%|\^|\||and|or|not)(\s+)/
             }, {
+            // Commands
                 token : ["text", "text", "keyword.operator", "text", "keyword", "text", "keyword"],
                 regex : /(^\s*)(?:([a-z][a-zA-Z0-9_]*\$?\s+)(=)(\s+))?(?:((?:no)?warn|nocheck|noprogress)(\s+))?((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
             }, {
+            // Demo commands
                 token : ["text", "keyword", "text", "keyword"],
                 regex : /(^\s*)(?:(demo)?(\s+))((?:[A-Z][^.:"]+)(?:$|(?:\.{3}|:)))/
             }, {
+            // Font-sizing commands
                 token : ["text", "keyword", "text", "keyword"],
                 regex : /^(\s*)(?:(demo)(\s+))?(10|12|14|16|24)$/
             }, {
+            // do-style command calls
                 token : ["text", "support.function", "text"],
                 regex : /(\s*)(do\$?)(\s*:\s*|\s*\(\s*)/
             }, {
@@ -114,53 +139,64 @@ var PraatHighlightRules = function() {
             //     token : ["text", "keyword"],
             //     regex : /(^\s*)(demo\b)/
             // }, {
+            // Object types
                 token : "entity.name.type",
                 regex : "(" + objectTypes + ")"
             }, {
+            // Predefined variables
                 token : "variable.language",
                 regex : "(" + predefinedVariables + ")"
             }, {
+            // Functions
                 token : ["support.function", "text"],
                 regex : "((?:" + functions + ")\\$?)(\\s*(?::|\\())"
             }, {
+            // For-loop declarations
                 token : "keyword",
                 regex : /(\bfor\b)/,
                 next : "for"
             }, {
+            // Generic keywords
                 token : "keyword",
                 regex : "(\\b(?:" + keywords + ")\\b)"
             }, {
+            // Interpolated strings
                 token : "string.interpolated",
                 regex : /'((?:[a-z][a-zA-Z0-9_]*)(?:\$|#|:[0-9]+)?)'/
             }, {
+            // Generic strings
                 token : "string",
                 regex : /"[^"]*"/
             }, {
+            // Multiline quoted strings
                 token : "string",
                 regex : /"[^"]*$/,
                 next : "brokenstring"
             }, {
+            // Form declarations
                 token : ["text", "keyword", "text", "entity.name.section"],
                 regex : /(^\s*)(\bform\b)(\s+)(.*)/,
                 next : "form"
             }, {
+            // Numeric constants
                 token : "constant.numeric",
                 regex : /\b[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
             }, {
+            // Procedure declarations
                 token : ["keyword", "text", "entity.name.function"],
                 regex : /(procedure)(\s+)(\S+)/
             }, {
+            // New-style procedure calls
                 token : ["entity.name.function", "text"],
                 regex : /(@\S+)(:|\s*\()/
             }, {
+            // Old-style procedure calls
                 token : ["text", "keyword", "text", "entity.name.function"],
                 regex : /(^\s*)(call)(\s+)(\S+)/
             }, {
+            // Comments
                 token : "comment",
-                regex : ";.*$"
-            }, {
-                token : "comment",
-                regex : "#.*$"
+                regex : /(^\s*#|;).*$/
             }, {
                 token : "text",
                 regex : /\s+/

From 84abfa5ff89ded60a99c8d9809291115c639fd16 Mon Sep 17 00:00:00 2001
From: hitode909 
Date: Thu, 5 Jun 2014 14:10:25 +0900
Subject: [PATCH 040/545] window.controllers was renamed to window.Controllers
 in Firefox 29

useragent.isGecko was false on Firefox 29
---
 lib/ace/lib/useragent.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/ace/lib/useragent.js b/lib/ace/lib/useragent.js
index e539dae3..0d1d9f4d 100644
--- a/lib/ace/lib/useragent.js
+++ b/lib/ace/lib/useragent.js
@@ -82,7 +82,7 @@ exports.isIE =
 exports.isOldIE = exports.isIE && exports.isIE < 9;
 
 // Is this Firefox or related?
-exports.isGecko = exports.isMozilla = window.controllers && window.navigator.product === "Gecko";
+exports.isGecko = exports.isMozilla = (window.Controllers || window.controllers) && window.navigator.product === "Gecko";
 
 // oldGecko == rev < 2.0 
 exports.isOldGecko = exports.isGecko && parseInt((ua.match(/rv\:(\d+)/)||[])[1], 10) < 4;

From 84a8201dfd71b191a75140fa2b1f07a12be5d47d Mon Sep 17 00:00:00 2001
From: baboso 
Date: Thu, 5 Jun 2014 18:44:20 -0400
Subject: [PATCH 041/545] Removed useless rule

---
 lib/ace/mode/praat_highlight_rules.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js
index 39220a52..9cf98bcb 100644
--- a/lib/ace/mode/praat_highlight_rules.js
+++ b/lib/ace/mode/praat_highlight_rules.js
@@ -135,10 +135,6 @@ var PraatHighlightRules = function() {
                 token : ["text", "support.function", "text"],
                 regex : /(\s*)(do\$?)(\s*:\s*|\s*\(\s*)/
             }, {
-            // Is this rule necessary?
-            //     token : ["text", "keyword"],
-            //     regex : /(^\s*)(demo\b)/
-            // }, {
             // Object types
                 token : "entity.name.type",
                 regex : "(" + objectTypes + ")"

From c5031db61c77d9273dcfd77340462fa1d3124662 Mon Sep 17 00:00:00 2001
From: nightwing 
Date: Mon, 9 Jun 2014 23:44:27 +0400
Subject: [PATCH 042/545] fix tests

---
 lib/ace/mouse/default_handlers.js   | 1 +
 lib/ace/mouse/mouse_handler_test.js | 8 +++++---
 lib/ace/test/all_browser.js         | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js
index 7bb701a8..e7a31540 100644
--- a/lib/ace/mouse/default_handlers.js
+++ b/lib/ace/mouse/default_handlers.js
@@ -116,6 +116,7 @@ function DefaultHandlers(mouseHandler) {
             else if (!this.$clickSelection) {
                 editor.selection.moveToPosition(pos);
             }
+            this.select();
         }.bind(this), 0);
         if (editor.renderer.scroller.setCapture) {
             editor.renderer.scroller.setCapture();
diff --git a/lib/ace/mouse/mouse_handler_test.js b/lib/ace/mouse/mouse_handler_test.js
index 96374d71..571acdac 100644
--- a/lib/ace/mouse/mouse_handler_test.js
+++ b/lib/ace/mouse/mouse_handler_test.js
@@ -58,15 +58,17 @@ module.exports = {
         next();
     },
 
-    "test: double tap. issue #956" : function() {
+    "test: double tap. issue #956" : function(done) {
         // mouse up fired immediately after mouse down
         var target = this.editor.renderer.getMouseEventTarget();
         target.dispatchEvent(MouseEvent("down", {x: 1, y: 1}));
         target.dispatchEvent(MouseEvent("up", {x: 1, y: 1}));
         target.dispatchEvent(MouseEvent("down", {x: 1, y: 1, detail: 2}));
         target.dispatchEvent(MouseEvent("up", {x: 1, y: 1, detail: 2}));
-        
-        assert.equal(this.editor.getSelectedText(), "Juhu");
+        setTimeout(function() {
+            assert.equal(this.editor.getSelectedText(), "Juhu");
+            done();
+        }.bind(this));
     }
 };
 
diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js
index db56517c..3b7bf5d9 100644
--- a/lib/ace/test/all_browser.js
+++ b/lib/ace/test/all_browser.js
@@ -44,6 +44,7 @@ var testNames = [
     "ace/mode/folding/xml_test",
     "ace/mode/folding/coffee_test",
     "ace/multi_select_test",
+    "ace/mouse/mouse_handler_test",
     "ace/occur_test",
     "ace/range_test",
     "ace/range_list_test",

From bcba9bea6e7049abd04e29595ab4686a967d0137 Mon Sep 17 00:00:00 2001
From: Brion Vibber 
Date: Sun, 15 Sep 2013 11:09:23 -0700
Subject: [PATCH 043/545] Support variable-width text

Updated from 2011 patch by fjakobs:
https://github.com/ajaxorg/ace/commit/36ebe6c49632f7a2955ce9933a7432f238a389b7

* removes old double-width CJK handling
* replaces monospace assumptions with measurements of actual text
* appears to work for Latin, CJK, Thai, Malayalam in ad-hoc testing
* does NOT fully handle RTL text issues (Hebrew, Arabic)

Conflicts:
	demo/kitchen-sink/doclist.js
	lib/ace/edit_session.js
	lib/ace/layer/text.js
	lib/ace/virtual_renderer.js
---
 demo/kitchen-sink/doclist.js            |   1 +
 demo/kitchen-sink/docs/international.md |   7 ++
 lib/ace/edit_session.js                 |  16 +---
 lib/ace/layer/cursor.js                 |  12 ++-
 lib/ace/layer/marker.js                 |  13 +--
 lib/ace/layer/text.js                   | 110 +++++++++++++++++++++---
 lib/ace/virtual_renderer.js             |  40 ++++++++-
 7 files changed, 159 insertions(+), 40 deletions(-)
 create mode 100644 demo/kitchen-sink/docs/international.md

diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js
index d003da8e..0b700d19 100644
--- a/demo/kitchen-sink/doclist.js
+++ b/demo/kitchen-sink/doclist.js
@@ -67,6 +67,7 @@ function makeHuge(txt) {
 
 var docs = {
     "docs/javascript.js": {order: 1, name: "JavaScript"},
+    "docs/international.md": "International Text",
 
     "docs/latex.tex": {name: "LaTeX", wrapped: true},
     "docs/markdown.md": {name: "Markdown", wrapped: true},
diff --git a/demo/kitchen-sink/docs/international.md b/demo/kitchen-sink/docs/international.md
new file mode 100644
index 00000000..1170ab12
--- /dev/null
+++ b/demo/kitchen-sink/docs/international.md
@@ -0,0 +1,7 @@
+Pinyin Simplified
+-----------------
+反对方山东队但是上
+
+Thai
+----
+อักษรไทย
diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js
index 9689ea5c..fb066434 100644
--- a/lib/ace/edit_session.js
+++ b/lib/ace/edit_session.js
@@ -1832,7 +1832,6 @@ var EditSession = function(text, mode) {
 
     // "Tokens"
     var CHAR = 1,
-        CHAR_EXT = 2,
         PLACEHOLDER_START = 3,
         PLACEHOLDER_BODY =  4,
         PUNCTUATION = 9,
@@ -1862,10 +1861,6 @@ var EditSession = function(text, mode) {
                 // Get all the TAB_SPACEs.
                 replace(/12/g, function() {
                     len -= 1;
-                }).
-                // Get all the CHAR_EXT/multipleWidth characters.
-                replace(/2/g, function() {
-                    len -= 1;
                 });
 
             lastDocSplit += len;
@@ -1959,7 +1954,7 @@ var EditSession = function(text, mode) {
 
             // === ELSE ===
             split = lastSplit + wrapLimit;
-            // The split is inside of a CHAR or CHAR_EXT token and no space
+            // The split is inside of a CHAR token and no space
             // around -> force a split.
             addSplit(split);
         }
@@ -1993,10 +1988,6 @@ var EditSession = function(text, mode) {
                 arr.push(SPACE);
             } else if((c > 39 && c < 48) || (c > 57 && c < 64)) {
                 arr.push(PUNCTUATION);
-            }
-            // full width characters
-            else if (c >= 0x1100 && isFullWidth(c)) {
-                arr.push(CHAR, CHAR_EXT);
             } else {
                 arr.push(CHAR);
             }
@@ -2028,12 +2019,7 @@ var EditSession = function(text, mode) {
             if (c == 9) {
                 screenColumn += this.getScreenTabSize(screenColumn);
             }
-            // full width characters
-            else if (c >= 0x1100 && isFullWidth(c)) {
-                screenColumn += 2;
-            } else {
                 screenColumn += 1;
-            }
             if (screenColumn > maxScreenColumn) {
                 break;
             }
diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js
index 4578482a..e6b8e19c 100644
--- a/lib/ace/layer/cursor.js
+++ b/lib/ace/layer/cursor.js
@@ -170,11 +170,17 @@ var Cursor = function(parentEl) {
         if (!position)
             position = this.session.selection.getCursor();
         var pos = this.session.documentToScreenPosition(position);
-        var cursorLeft = this.$padding + pos.column * this.config.characterWidth;
+        var textWidth = this.config.textWidth(pos.row, pos.column);
+        var cursorLeft = this.$padding + textWidth;
         var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
             this.config.lineHeight;
+        var cursorWidth = (this.config.textWidth(pos.row, pos.column + 1) - textWidth) || this.config.characterWidth;
 
-        return {left : cursorLeft, top : cursorTop};
+        return {
+            left : cursorLeft,
+        	top : cursorTop,
+        	width: cursorWidth
+        };
     };
 
     this.update = function(config) {
@@ -198,7 +204,7 @@ var Cursor = function(parentEl) {
 
             style.left = pixelPos.left + "px";
             style.top = pixelPos.top + "px";
-            style.width = config.characterWidth + "px";
+            style.width = pixelPos.width + "px";
             style.height = config.lineHeight + "px";
         }
         while (this.cursors.length > cursorIndex)
diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js
index cd1b992d..7238bedf 100644
--- a/lib/ace/layer/marker.js
+++ b/lib/ace/layer/marker.js
@@ -78,7 +78,7 @@ var Marker = function(parentEl) {
             range = range.toScreenRange(this.session);
             if (marker.renderer) {
                 var top = this.$getTop(range.start.row, config);
-                var left = this.$padding + range.start.column * config.characterWidth;
+                var left = this.$padding + config.textWidth(range.start.row, range.start.column);
                 marker.renderer(html, range, left, top, config);
             } else if (marker.type == "fullLine") {
                 this.drawFullLineMarker(html, range, marker.clazz, config);
@@ -129,8 +129,10 @@ var Marker = function(parentEl) {
         // from selection start to the end of the line
         var padding = this.$padding;
         var height = config.lineHeight;
+        var textWidth = config.textWidth(range.start.row, range.start.column);
+        var left = padding + textWidth;
+        var width = config.width - textWidth;
         var top = this.$getTop(range.start.row, config);
-        var left = padding + range.start.column * config.characterWidth;
         extraStyle = extraStyle || "";
 
         stringBuilder.push(
@@ -143,7 +145,7 @@ var Marker = function(parentEl) {
 
         // from start of the last line to the selection end
         top = this.$getTop(range.end.row, config);
-        var width = range.end.column * config.characterWidth;
+        var width = config.textWidth(range.end.row, range.end.column);
 
         stringBuilder.push(
             "
" + space + ""; } else if (b) { return "" + self.SPACE_CHAR + ""; - } else { - screenColumn += 1; - return "" + c + ""; } }; @@ -367,6 +354,101 @@ var Text = function(parentEl) { } return screenColumn + value.length; }; + + this.$measureText = function(tokens, column) { + // build HTML for tokens + var stringBuilder = []; + var len = 0; + var i = 0; + var screenColumn = 0; // TODO + while (len < column && i < tokens.length) { + var token = tokens[i++]; + + var self = this; + var replaceReg = /\t|&|<|( +)|([\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000])/g; + var replaceFunc = function(c, a, b, tabIdx, idx4) { + if (c.charCodeAt(0) == 32) { + return new Array(c.length+1).join(" "); + } else if (c == "\t") { + var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx); + screenColumn += tabSize - 1; + return self.$tabStrings[tabSize]; + } else if (c == "&") { + if (useragent.isOldGecko) + return "&"; + else + return "&"; + } else if (c == "<") { + return "<"; + } else if (c.match(/[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]/)) { + if (self.showInvisibles) { + var space = new Array(c.length+1).join(self.SPACE_CHAR); + return "" + space + ""; + } else { + return " "; + } + } + }; + + var value = token.value; + + // truncate once length is larger than 'column' + len += value.length; + if (len > column) + value = value.substring(0, value.length - (len - column)); + + var output = value.replace(replaceReg, replaceFunc); + + + if (!this.$textToken[token.type]) { + var classes = "ace_" + token.type.replace(/\./g, " ace_"); + stringBuilder.push("", output, ""); + } + else { + stringBuilder.push(output); + } + } + + // render line off screen + var el = document.createElement("div"); + var style = el.style; + style.position = "absolute"; + style.top = "-1000px"; + el.className = "ace_line"; + el.innerHTML = stringBuilder.join(""); + this.element.appendChild(el); + + // measure pixel length + var width = el.offsetWidth; + this.element.removeChild(el); + + return width; + } + + this.textWidth = function(row, column) { + //return this.$characterSize.width * column; + var line = this.session.getTokens(row); + + // cache in tokens object + // this way the cache gets invalidated automatically when the tokens change + if (line.widthCache && line.widthCache[column]) { + // invalidate if font size has changed + if (line.widthCache.rowHeight == this.getLineHeight()) { + return line.widthCache[column]; + } + else + delete line.widthCache; + } + + var width = this.$measureText(line, column); + + if (!line.widthCache) + line.widthCache = { rowHeight: this.getLineHeight() }; + + line.widthCache[column] = width; + + return width; + }; this.renderIndentGuide = function(stringBuilder, value, max) { var cols = value.search(this.$indentGuideRe); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 33f3a906..199225ea 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -150,6 +150,7 @@ var VirtualRenderer = function(container, theme) { lastRow : 0, lineHeight : 0, characterWidth : 0, + textWidth: function() { return 1; }, minHeight : 1, maxHeight : 1, offset : 0, @@ -997,6 +998,7 @@ var VirtualRenderer = function(container, theme) { lastRow : lastRow, lineHeight : lineHeight, characterWidth : this.characterWidth, + textWidth: this.$textLayer.textWidth.bind(this.$textLayer), minHeight : minHeight, maxHeight : maxHeight, offset : offset, @@ -1389,12 +1391,44 @@ var VirtualRenderer = function(container, theme) { return {row: row, column: col, side: offset - col > 0 ? 1 : -1}; }; + this.$findColumn = function(row, width) { + // binary search to find the screen column + var min = 0; + var max = this.session.getLine(row).length; + + while (true) { + if (max <= 0) + return null; + + // if the range has length one pick the closes characte + if (max-min == 1) { + var wMin = this.$textLayer.textWidth(row, min); + var wMax = this.$textLayer.textWidth(row, max); + + if (Math.abs(wMin-width) < Math.abs(wMax-width)) + return min; + else + return max; + } + else { + // same as Math.floor((max-min)/2) but faster + var pivot = min + ((max - min) >> 1); + var w = this.$textLayer.textWidth(row, pivot); + if (w == width) + return pivot; + else if (w > width) + max = pivot; + else + min = pivot; + } + } + }; + this.screenToTextCoordinates = function(x, y) { var canvasPos = this.scroller.getBoundingClientRect(); - var col = Math.round( - (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth - ); + var width = x + this.scroller.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft(); + var col = this.$findColumn(row, width); var row = (y + this.scrollTop - canvasPos.top) / this.lineHeight; From 6d2fbb3ed535e0f8bc792a842094c6b273e55950 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 27 May 2014 04:19:23 +0400 Subject: [PATCH 044/545] fix cursor on lines with tab --- lib/ace/layer/cursor.js | 8 ++----- lib/ace/layer/marker.js | 3 +++ lib/ace/layer/text.js | 44 ++++--------------------------------- lib/ace/virtual_renderer.js | 15 ++++++++----- 4 files changed, 18 insertions(+), 52 deletions(-) diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js index e6b8e19c..2d4a720e 100644 --- a/lib/ace/layer/cursor.js +++ b/lib/ace/layer/cursor.js @@ -170,17 +170,13 @@ var Cursor = function(parentEl) { if (!position) position = this.session.selection.getCursor(); var pos = this.session.documentToScreenPosition(position); - var textWidth = this.config.textWidth(pos.row, pos.column); + var textWidth = this.config.textWidth(pos.row, position.column); var cursorLeft = this.$padding + textWidth; var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) * this.config.lineHeight; var cursorWidth = (this.config.textWidth(pos.row, pos.column + 1) - textWidth) || this.config.characterWidth; - return { - left : cursorLeft, - top : cursorTop, - width: cursorWidth - }; + return {left : cursorLeft, top : cursorTop, width: cursorWidth}; }; this.update = function(config) { diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js index 7238bedf..af21fcd4 100644 --- a/lib/ace/layer/marker.js +++ b/lib/ace/layer/marker.js @@ -75,7 +75,10 @@ var Marker = function(parentEl) { var range = marker.range.clipRows(config.firstRow, config.lastRow); if (range.isEmpty()) continue; + var docRange = range; range = range.toScreenRange(this.session); + range.start.column = docRange.start.column; + range.end.column = docRange.end.column; if (marker.renderer) { var top = this.$getTop(range.start.row, config); var left = this.$padding + config.textWidth(range.start.row, range.start.column); diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 6ca804d0..add0dc5f 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -346,7 +346,7 @@ var Text = function(parentEl) { var classes = "ace_" + token.type.replace(/\./g, " ace_"); var style = ""; if (token.type == "fold") - style = " style='width:" + (token.value.length * this.config.characterWidth) + "px;' "; + style = " style='width:" + (value.length * this.config.characterWidth) + "px;' "; stringBuilder.push("", output, ""); } else { @@ -360,53 +360,17 @@ var Text = function(parentEl) { var stringBuilder = []; var len = 0; var i = 0; - var screenColumn = 0; // TODO + var screenColumn = 0; while (len < column && i < tokens.length) { var token = tokens[i++]; - - var self = this; - var replaceReg = /\t|&|<|( +)|([\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000])/g; - var replaceFunc = function(c, a, b, tabIdx, idx4) { - if (c.charCodeAt(0) == 32) { - return new Array(c.length+1).join(" "); - } else if (c == "\t") { - var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx); - screenColumn += tabSize - 1; - return self.$tabStrings[tabSize]; - } else if (c == "&") { - if (useragent.isOldGecko) - return "&"; - else - return "&"; - } else if (c == "<") { - return "<"; - } else if (c.match(/[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]/)) { - if (self.showInvisibles) { - var space = new Array(c.length+1).join(self.SPACE_CHAR); - return "" + space + ""; - } else { - return " "; - } - } - }; - var value = token.value; - + // truncate once length is larger than 'column' len += value.length; if (len > column) value = value.substring(0, value.length - (len - column)); - var output = value.replace(replaceReg, replaceFunc); - - - if (!this.$textToken[token.type]) { - var classes = "ace_" + token.type.replace(/\./g, " ace_"); - stringBuilder.push("", output, ""); - } - else { - stringBuilder.push(output); - } + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); } // render line off screen diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 199225ea..1e4746e1 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1413,7 +1413,7 @@ var VirtualRenderer = function(container, theme) { else { // same as Math.floor((max-min)/2) but faster var pivot = min + ((max - min) >> 1); - var w = this.$textLayer.textWidth(row, pivot); + var w = this.$textLayer.textWidth(row, pivot, true); if (w == width) return pivot; else if (w > width) @@ -1426,13 +1426,16 @@ var VirtualRenderer = function(container, theme) { this.screenToTextCoordinates = function(x, y) { var canvasPos = this.scroller.getBoundingClientRect(); - - var width = x + this.scroller.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft(); - var col = this.$findColumn(row, width); - var row = (y + this.scrollTop - canvasPos.top) / this.lineHeight; - return this.session.screenToDocumentPosition(row, Math.max(col, 0)); + var width = x + this.scroller.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft(); + + + var pos = this.session.screenToDocumentPosition(row, Math.max(col, 0)); + + var col = this.$findColumn(pos.row, width); + pos.column = col + return pos }; /** From b8c21d4c6fa961aa0c7012105a6c008d84ce26c0 Mon Sep 17 00:00:00 2001 From: Tomek Wytrebowicz Date: Fri, 13 Jun 2014 01:58:05 +0200 Subject: [PATCH 045/545] Use current document to process ')} - scripts.forEach(function(s) { - s = s.replace(/"/g, ""); - if (s == "ace/ace") { - comment("load ace") - script("ace") - } else { - var extName = s.match(/[^/]*$/)[0]; - comment("load ace " + extName + " extension"); - script("ext-" + extName); - } - }); - result.push("')} + scripts.forEach(function(s) { + s = s.replace(/"/g, ""); + if (s == "ace/ace") { + comment("load ace"); + script("ace"); + } else { + var extName = s.match(/[^/]*$/)[0]; + comment("load ace " + extName + " extension"); + script("ext-" + extName); + } + }); + result.push(" - diff --git a/package.json b/package.json index cbabb3a0..58aabdf9 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "asyncjs": "0.0.x", "jsdom": "0.2.x", "amd-loader": "~0.0.4", - "dryice": "0.4.10" + "dryice": "0.4.11" }, "mappings": { "ace": "." From b42108a2c993b684036620e606201f6989ff91b4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 20 Jun 2014 10:37:23 +0400 Subject: [PATCH 051/545] remove unnecessary use of async --- Makefile.dryice.js | 104 ++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 8bf54562..5f5d69bc 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -33,7 +33,6 @@ var fs = require("fs"); var path = require("path"); var copy = require('architect-build/copy'); var build = require('architect-build/build'); -var async = require("asyncjs"); var ACE_HOME = __dirname; var BUILD_DIR = ACE_HOME + "/build"; @@ -346,58 +345,57 @@ function buildSubmodule(options, extra, file, callback) { function buildAce(options) { var snippetFiles = jsFileList("lib/ace/snippets"); var modeNames = modeList(); - async.forEach([ - buildCore.bind(null, options, {outputFile: "ace.js"}), - // modes - async.forEach.bind(null, modeNames, function(name, next) { - buildSubmodule(options, { - projectType: "mode", - require: ["ace/mode/" + name] - }, "mode-" + name, next); - }), - // snippets - async.forEach.bind(null, modeNames, function(name, next) { - if (snippetFiles.indexOf(name + ".js") == -1) - addSnippetFile(name); - - buildSubmodule(options, { - require: ["ace/snippets/" + name], - }, "snippets/" + name, next); - }), - // themes - async.forEach.bind(null, jsFileList("lib/ace/theme"), function(name, next) { - buildSubmodule(options, { - projectType: "theme", - require: ["ace/theme/" + name] - }, "theme-" + name.replace("_theme", ""), next); - }), - // keybindings - async.forEach.bind(null, ["vim", "emacs"], function(name, next) { - buildSubmodule(options, { - projectType: "keybinding", - require: ["ace/keyboard/" + name ] - }, "keybinding-" + name, next); - }), - // extensions - async.forEach.bind(null, jsFileList("lib/ace/ext"), function(name, next) { - buildSubmodule(options, { - projectType: "ext", - require: ["ace/ext/" + name] - }, "ext-" + name, next); - }), - // workers - async.forEach.bind(null, workers("lib/ace/mode"), function(name, next) { - buildSubmodule(options, { - projectType: "worker", - require: ["ace/mode/" + name + "_worker"], - additional: [{ - id: "ace/worker/worker", - loaderModule: true, - order: -1000 - }], - }, "worker-" + name, next); - }), - ], function(f, next) { f(next); }); + + buildCore(options, {outputFile: "ace.js"}), + // modes + modeNames.forEach(function(name) { + buildSubmodule(options, { + projectType: "mode", + require: ["ace/mode/" + name] + }, "mode-" + name); + }); + // snippets + modeNames.forEach(function(name) { + if (snippetFiles.indexOf(name + ".js") == -1) + addSnippetFile(name); + + buildSubmodule(options, { + require: ["ace/snippets/" + name], + }, "snippets/" + name); + }); + // themes + jsFileList("lib/ace/theme").forEach(function(name) { + buildSubmodule(options, { + projectType: "theme", + require: ["ace/theme/" + name] + }, "theme-" + name.replace("_theme", "")); + }); + // keybindings + ["vim", "emacs"].forEach(function(name) { + buildSubmodule(options, { + projectType: "keybinding", + require: ["ace/keyboard/" + name ] + }, "keybinding-" + name); + }); + // extensions + jsFileList("lib/ace/ext").forEach(function(name) { + buildSubmodule(options, { + projectType: "ext", + require: ["ace/ext/" + name] + }, "ext-" + name); + }); + // workers + workers("lib/ace/mode").forEach(function(name) { + buildSubmodule(options, { + projectType: "worker", + require: ["ace/mode/" + name + "_worker"], + additional: [{ + id: "ace/worker/worker", + loaderModule: true, + order: -1000 + }], + }, "worker-" + name); + }); } function getLoadedFileList(options, callback, result) { From e52884761d447c85e6a597732abfcfae4874e00a Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 20 Jun 2014 10:38:05 +0400 Subject: [PATCH 052/545] keep demo/kitchein-sink folders location in the build --- Makefile.dryice.js | 15 +++++---------- kitchen-sink.html | 10 ++-------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 5f5d69bc..a0982577 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -132,25 +132,20 @@ function demo() { ); } - function fixDocPaths(data) { - return data.replace(/"(demo|build)\//g, "\""); - } - - copy(ACE_HOME + "/demo/kitchen-sink", BUILD_DIR + "/kitchen-sink", { + copy(ACE_HOME + "/demo/kitchen-sink", BUILD_DIR + "/demo/kitchen-sink", { shallow: true, - replace: [changeComments, fixDocPaths], + replace: [changeComments], include: /\.(css|html)$/ }); - copy(ACE_HOME +"/demo/kitchen-sink/docs/", BUILD_DIR + "/kitchen-sink/docs/"); + copy(ACE_HOME +"/demo/kitchen-sink/docs/", BUILD_DIR + "/demo/kitchen-sink/docs/"); - copy.file(ACE_HOME + "/demo/kitchen-sink/logo.png", BUILD_DIR + "/kitchen-sink/logo.png"); + copy.file(ACE_HOME + "/demo/kitchen-sink/logo.png", BUILD_DIR + "/demo/kitchen-sink/logo.png"); buildSubmodule({}, { require: ["kitchen-sink/demo"], - filters: [fixDocPaths], projectType: "demo" - }, BUILD_DIR + "/kitchen-sink/demo"); + }, BUILD_DIR + "/demo/kitchen-sink/demo"); copy(ACE_HOME + "/demo/", BUILD_DIR + "/demo/", { shallow: true, diff --git a/kitchen-sink.html b/kitchen-sink.html index f55cfa14..d32b98b5 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -11,16 +11,10 @@ commit %commit% --> - - - - + + -
From e5b2eed5c58425c3ae3db35da9328320a57582f2 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 20 Jun 2014 20:54:08 +0400 Subject: [PATCH 053/545] add architect build to package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 58aabdf9..31a4dec9 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "asyncjs": "0.0.x", "jsdom": "0.2.x", "amd-loader": "~0.0.4", - "dryice": "0.4.11" + "dryice": "0.4.11", + "architect-build": "https://github.com/c9/architect-build/tarball/42723e152bb" }, "mappings": { "ace": "." From 67143599981cadec7b9898d0fdd028f73ff8d7ba Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 21 Jun 2014 00:45:50 +0400 Subject: [PATCH 054/545] tweak --- Makefile | 1 - Makefile.dryice.js | 61 +++++++++++++++++----------------------------- kitchen-sink.html | 2 +- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 95dcf964..29cf0495 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,6 @@ pre_build: build: pre_build ./Makefile.dryice.js normal ./Makefile.dryice.js demo - ./Makefile.dryice.js bm # Minimal build: call Makefile.dryice.js only if our sources changed basic: build/src/ace.js diff --git a/Makefile.dryice.js b/Makefile.dryice.js index a0982577..2bc36f8b 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -112,14 +112,11 @@ function ace() { function demo() { console.log('# kitchen sink ---------'); - var version, ref; + var version = "", ref = ""; try { version = JSON.parse(fs.readFileSync(ACE_HOME + "/package.json")).version; ref = fs.readFileSync(ACE_HOME + "/.git-ref").toString(); - } catch(e) { - ref = ""; - version = ""; - } + } catch(e) {} function changeComments(data) { return (data @@ -131,16 +128,12 @@ function demo() { .replace("%commit%", ref) ); } - - copy(ACE_HOME + "/demo/kitchen-sink", BUILD_DIR + "/demo/kitchen-sink", { - shallow: true, - replace: [changeComments], - include: /\.(css|html)$/ - }); copy(ACE_HOME +"/demo/kitchen-sink/docs/", BUILD_DIR + "/demo/kitchen-sink/docs/"); copy.file(ACE_HOME + "/demo/kitchen-sink/logo.png", BUILD_DIR + "/demo/kitchen-sink/logo.png"); + copy.file(ACE_HOME + "/demo/kitchen-sink/styles.css", BUILD_DIR + "/demo/kitchen-sink/styles.css"); + copy.file(ACE_HOME + "/kitchen-sink.html", BUILD_DIR + "/kitchen-sink.html", changeComments); buildSubmodule({}, { require: ["kitchen-sink/demo"], @@ -214,9 +207,9 @@ function buildAceModule(opts, callback) { buildAceModule.dequeue = function() { if (buildAceModule.running) return; var call = buildAceModule.queue.shift(); + buildAceModule.running = call; if (call) buildAceModuleInternal.apply(null, call); - buildAceModule.running = call; }; } @@ -235,7 +228,7 @@ function buildAceModule(opts, callback) { function buildAceModuleInternal(opts, callback) { var cache = opts.cache == undefined ? CACHE : opts.cache; - var key = opts.require + "|" + opts.compress + "|" + opts.projectType; + var key = opts.require + "|" + opts.projectType; if (cache && cache.configs && cache.configs[key]) return write(null, cache.configs[key]); @@ -249,19 +242,23 @@ function buildAceModuleInternal(opts, callback) { }; function write(err, result) { - if (opts.compress) - result.code = compress(result.code); - - if (cache && key) { + if (cache && key && !(cache.configs && cache.configs[key])) { cache.configs = cache.configs || Object.create(null); cache.configs[key] = result; result.sources = result.sources.map(function(pkg) { return {deps: pkg.deps}; }); - } + } if (!opts.outputFile) return callback(err, result); + + var code = result.code; + if (opts.compress) { + if (!result.codeMin) + result.codeMin = compress(result.code); + code = result.codeMin; + } var targetDir = BUILD_DIR + "/src"; if (opts.compress) @@ -287,7 +284,6 @@ function buildAceModuleInternal(opts, callback) { opts.noconflict ? ns : "", projectType == "ext")); } - var code = result.code; filters.forEach(function(f) { code = f(code); }); build.writeToFile({code: code}, { @@ -331,7 +327,7 @@ function buildSubmodule(options, extra, file, callback) { options = extend(extra, options); getLoadedFileList(options, function(coreFiles) { options.outputFile = file + ".js"; - options.ignore = coreFiles; + options.ignore = options.ignore || coreFiles; options.quiet = true; buildAceModule(options, callback); }); @@ -384,9 +380,10 @@ function buildAce(options) { buildSubmodule(options, { projectType: "worker", require: ["ace/mode/" + name + "_worker"], + ignore: [], additional: [{ id: "ace/worker/worker", - loaderModule: true, + transforms: [], order: -1000 }], }, "worker-" + name); @@ -467,9 +464,7 @@ function namespace(ns) { return function(text) { text = text .toString() - .replace('var ACE_NAMESPACE = "";', 'var ACE_NAMESPACE = "' + ns +'";') - // .replace(/(\.define)|([,;\n]|^\s*?)define\(/g, function(_, a, b) { - // return a || b + ns + ".define("; + .replace(/ACE_NAMESPACE\s*=\s*""/, 'ACE_NAMESPACE = "' + ns +'"') .replace(/(\.define)|\bdefine\(/g, function(_, a) { return a || ns + ".define("; }); @@ -551,20 +546,10 @@ function addSnippetFile(modeName) { } function compress(text) { - return asciify(require("dryice").copy.filter.uglifyjs(text)); - // copy.filter.uglifyjs.options.ascii_only = true; doesn't work with some uglify.js versions - function asciify(text) { - return text.replace(/[\x00-\x08\x0b\x0c\x0e\x19\x80-\uffff]/g, function(c) { - c = c.charCodeAt(0).toString(16); - if (c.length == 1) - return "\\x0" + c; - if (c.length == 2) - return "\\x" + c; - if (c.length == 3) - return "\\u0" + c; - return "\\u" + c; - }); - } + var ujs = require("dryice").copy.filter.uglifyjs; + ujs.options.mangle_toplevel = {except: ["ACE_NAMESPACE", "requirejs"]}; + ujs.options.beautify = {ascii_only: true, inline_script: true} + return ujs(text); } function extend(base, extra) { diff --git a/kitchen-sink.html b/kitchen-sink.html index d32b98b5..65fe2a2a 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -281,7 +281,7 @@ - + From 739e86cde7eacd303246afe5a6d80ab49f7d5375 Mon Sep 17 00:00:00 2001 From: rmsmith Date: Sat, 21 Jun 2014 19:15:52 +0300 Subject: [PATCH 055/545] mode/applescript : set the `$id` to the correct value This brings the new applescript mode into alignment with the other modes per #1778 --- lib/ace/mode/applescript.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/mode/applescript.js b/lib/ace/mode/applescript.js index 121b73eb..81bc3533 100644 --- a/lib/ace/mode/applescript.js +++ b/lib/ace/mode/applescript.js @@ -47,6 +47,7 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "--"; this.blockComment = {start: "(*", end: "*)"}; + this.$id = "ace/mode/applescript"; // Extra logic goes here. }).call(Mode.prototype); From 6aaede1a2e15ed246bc75f76e5d74fb90e1c74ce Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 22 Jun 2014 23:33:45 +0400 Subject: [PATCH 056/545] keep mac line movement keybindings (still overridden by jumptomatching) --- lib/ace/commands/default_commands.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 9d1720e3..b1c0b5f0 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -208,7 +208,7 @@ exports.commands = [{ readOnly: true }, { name: "golineup", - bindKey: bindKey("Up", "Up"), + bindKey: bindKey("Up", "Up|Ctrl-P"), exec: function(editor, args) { editor.navigateUp(args.times); }, multiSelectAction: "forEach", readOnly: true @@ -237,7 +237,7 @@ exports.commands = [{ readOnly: true }, { name: "golinedown", - bindKey: bindKey("Down", "Down"), + bindKey: bindKey("Down", "Down|Ctrl-N"), exec: function(editor, args) { editor.navigateDown(args.times); }, multiSelectAction: "forEach", scrollIntoView: "cursor", From 3ebc2828e608c9c0847d5fa45b9ed4a37a108f38 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 10 Jun 2014 22:11:55 +0400 Subject: [PATCH 057/545] add textarea keybinding (probably fixes #36) --- lib/ace/commands/default_commands.js | 8 +- .../ext/menu_tools/add_editor_menu_options.js | 46 ++++++----- lib/ace/keyboard/textarea.js | 82 +++++++++++++++++++ 3 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 lib/ace/keyboard/textarea.js diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index b1c0b5f0..a150a76f 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -402,7 +402,13 @@ exports.commands = [{ exec: function(editor) { editor.jumpToMatching(true); }, multiSelectAction: "forEach", readOnly: true -}, +}, { + name: "passKeysToBrowser", + bindKey: bindKey("null", "null"), + exec: function() {}, + passEvent: true, + readOnly: true +}, // commands disabled in readOnly mode { diff --git a/lib/ace/ext/menu_tools/add_editor_menu_options.js b/lib/ace/ext/menu_tools/add_editor_menu_options.js index 0c95e790..eb90e31d 100644 --- a/lib/ace/ext/menu_tools/add_editor_menu_options.js +++ b/lib/ace/ext/menu_tools/add_editor_menu_options.js @@ -60,41 +60,47 @@ module.exports.addEditorMenuOptions = function addEditorMenuOptions (editor) { var modelist = require('../modelist'); var themelist = require('../themelist'); editor.menuOptions = { - "setNewLineMode" : [{ - "textContent" : "unix", - "value" : "unix" + setNewLineMode: [{ + textContent: "unix", + value: "unix" }, { - "textContent" : "windows", - "value" : "windows" + textContent: "windows", + value: "windows" }, { - "textContent" : "auto", - "value" : "auto" + textContent: "auto", + value: "auto" }], - "setTheme" : [], - "setMode" : [], - "setKeyboardHandler": [{ - "textContent" : "ace", - "value" : "" + setTheme: [], + setMode: [], + setKeyboardHandler: [{ + textContent: "ace", + value: "" }, { - "textContent" : "vim", - "value" : "ace/keyboard/vim" + textContent: "vim", + value: "ace/keyboard/vim" }, { - "textContent" : "emacs", - "value" : "ace/keyboard/emacs" + textContent: "emacs", + value: "ace/keyboard/emacs" + }, { + textContent: "textarea", + value: "ace/keyboard/textarea" + }, { + textContent: "sublime", + value: "ace/keyboard/sublime" }] }; editor.menuOptions.setTheme = themelist.themes.map(function(theme) { return { - 'textContent' : theme.caption, - 'value' : theme.theme + textContent: theme.caption, + value: theme.theme }; }); editor.menuOptions.setMode = modelist.modes.map(function(mode) { return { - 'textContent' : mode.name, - 'value' : mode.mode + textContent: mode.name, + value: mode.mode }; }); }; diff --git a/lib/ace/keyboard/textarea.js b/lib/ace/keyboard/textarea.js new file mode 100644 index 00000000..470b2940 --- /dev/null +++ b/lib/ace/keyboard/textarea.js @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var HashHandler = require("./hash_handler").HashHandler; +exports.handler = new HashHandler(); + +[{ + bindKey: "Shift-Tab|Tab", + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-L", mac: "Cmd-L"}, + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-G", mac: "Cmd-G"}, + command: "gotoline" +}, { + bindKey: {win: "Ctrl-T|Ctrl-Shift-T", mac: "Cmd-T|Cmd-Shift-T"}, + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-G", mac: "Cmd-G"}, + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-G", mac: "Cmd-G"}, + command: "passKeysToBrowser" +}, { + name: "golineup", + bindKey: {win: null, mac: "Ctrl-P"}, +}, { + name: "golinedown", + bindKey: {win: null, mac: "Ctrl-N"}, +}, { + name: "gotoleft", + bindKey: {win: null, mac: "Ctrl-B"}, +}, { + name: "gotoright", + bindKey: {win: null, mac: "Ctrl-F"}, +}, { + name: "gotolineend", + bindKey: {win: null, mac: "Ctrl-E"}, +}, { + name: "gotolinestart", + bindKey: {win: null, mac: "Ctrl-A"}, +} +].forEach(function(k) { + var bindKey = k.bindKey; + if (typeof bindKey == "object") + bindKey = bindKey[exports.handler.platform]; + exports.handler.bindKey(bindKey, k.command); +}); +exports.handler.$id = "ace/keyboard/textarea"; + +}); From 1dd41ea75dfa90d2eed246659c7638efc91d7ae2 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Fri, 13 Jun 2014 16:17:17 +0200 Subject: [PATCH 058/545] Make mergeable commands (for undo history) overridable. --- lib/ace/editor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 7552a17a..6a68e5de 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -211,13 +211,14 @@ var Editor = function(renderer, session) { } }; + // TODO use property on commands instead of this + this.$mergeableCommands = ["backspace", "del", "insertstring"]; this.$historyTracker = function(e) { if (!this.$mergeUndoDeltas) return; - var prev = this.prevOp; - var mergeableCommands = ["backspace", "del", "insertstring"]; + var mergeableCommands = this.$mergeableCommands; // previous command was the same var shouldMerge = prev.command && (e.command.name == prev.command.name); if (e.command.name == "insertstring") { From 0450a1a539e5944f2514eb8a6eeca6fdb192c9d8 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 25 Jun 2014 19:01:06 +0400 Subject: [PATCH 059/545] remove unneeded setOption call --- lib/ace/line_widgets.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 94ad9ddf..9e384e0e 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -87,7 +87,6 @@ function LineWidgets(session) { editor.widgetManager = this; - editor.setOption("enableLineWidgets", true); editor.renderer.on("beforeRender", this.measureWidgets); editor.renderer.on("afterRender", this.renderWidgets); }; From 2dcc4a3f04c01157b1a56b0703c5bd2ff430f9e5 Mon Sep 17 00:00:00 2001 From: Derk-Jan Hartman Date: Sat, 21 Jun 2014 16:28:10 +0200 Subject: [PATCH 060/545] Match platform specifics for dragDelay of text On Mac we keep it at 150ms. On other platforms it either does not exist or at most it's very small. This fixes issue #1879 --- lib/ace/mouse/mouse_handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index 9897290c..ce88eb81 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -192,7 +192,7 @@ var MouseHandler = function(editor) { config.defineOptions(MouseHandler.prototype, "mouseHandler", { scrollSpeed: {initialValue: 2}, - dragDelay: {initialValue: 150}, + dragDelay: {initialValue: (useragent.isMac ? 150 : 0)}, dragEnabled: {initialValue: true}, focusTimout: {initialValue: 0}, tooltipFollowsMouse: {initialValue: true} From f8b7dce3e05a507e7bf34adc4b97ec6efebf08af Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Sat, 28 Jun 2014 22:21:52 -0700 Subject: [PATCH 061/545] remove the invalid rule from the go syntax file --- lib/ace/mode/golang_highlight_rules.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/ace/mode/golang_highlight_rules.js b/lib/ace/mode/golang_highlight_rules.js index 5bd40b44..2369c8cb 100644 --- a/lib/ace/mode/golang_highlight_rules.js +++ b/lib/ace/mode/golang_highlight_rules.js @@ -72,9 +72,6 @@ define(function(require, exports, module) { }, { token : "paren.rparen", regex : "[\\])}]" - }, { - token: "invalid", - regex: "\\s+$" }, { token : "text", regex : "\\s+" From 299d174dc77c98566dacd547f0c3bfb72c91cbc3 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 22 May 2014 20:26:11 +0400 Subject: [PATCH 062/545] do not use setInnerHTML since it isn't faster on new browsers --- demo/kitchen-sink/demo.js | 2 +- lib/ace/layer/marker.js | 2 +- lib/ace/layer/text.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 0b35ca74..552b1e65 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -592,7 +592,7 @@ env.editSnippets = function() { require("ace/ext/language_tools"); env.editor.setOptions({ enableBasicAutocompletion: true, - enableLiveAutocompletion: true, + enableLiveAutocompletion: false, enableSnippets: true }); diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js index cd1b992d..37e038b5 100644 --- a/lib/ace/layer/marker.js +++ b/lib/ace/layer/marker.js @@ -93,7 +93,7 @@ var Marker = function(parentEl) { this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config); } } - this.element = dom.setInnerHtml(this.element, html.join("")); + this.element.innerHTML = html.join(""); }; this.$getTop = function(row, layerConfig) { diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 140700aa..748d2231 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -203,7 +203,7 @@ var Text = function(parentEl) { html, row, !this.$useLineGroups(), row == foldStart ? foldLine : false ); lineElement.style.height = config.lineHeight * this.session.getRowLength(row) + "px"; - dom.setInnerHtml(lineElement, html.join("")); + lineElement.innerHTML = html.join(""); } row++; } @@ -310,7 +310,7 @@ var Text = function(parentEl) { row++; } - this.element = dom.setInnerHtml(this.element, html.join("")); + this.element.innerHTML = html.join(""); }; this.$textToken = { From b5eda22bfc0bf8519ccbb03d1442b6b5b9f05844 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 1 Jul 2014 00:29:18 +0400 Subject: [PATCH 063/545] update changelog --- ChangeLog.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 2b1f88bb..224f9326 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,13 @@ +2014.07.01 Version 1.1.4 + +* New Features + - Highlight matching tags (Adam Jimenez) + - Improved jump to matching command (Adam Jimenez) + +* new language modes + - AppleScript (Yaogang Lian) + - Vala + 2014.03.08 Version 1.1.3 * New Features From ccfb820418034c5974191451ce71ac5ec59cc845 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 10 Jun 2014 22:12:34 +0400 Subject: [PATCH 064/545] add test for whitespace extension --- build | 2 +- lib/ace/ext/whitespace_test.js | 116 +++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 lib/ace/ext/whitespace_test.js diff --git a/build b/build index fc9d2cae..b85b38c1 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit fc9d2cae9fe8e6e95e74c86a31d21caadd8f9f39 +Subproject commit b85b38c1e33e161826f4dd7774ef73aac55e0d14 diff --git a/lib/ace/ext/whitespace_test.js b/lib/ace/ext/whitespace_test.js new file mode 100644 index 00000000..be4f360f --- /dev/null +++ b/lib/ace/ext/whitespace_test.js @@ -0,0 +1,116 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("assert"); +var EditSession = require("../edit_session").EditSession; +var whitespace = require("./whitespace"); + +// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite +module.exports = { + timeout: 10000, + + "test tab detection": function(next) { + var s = new EditSession([ + "define({", + "\tfoo:1,", + "\tbar:2,", + "\tbaz:{,", + "\t\tx:3", + "\t}", + "})" + ]); + + var indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, "\t"); + assert.equal(indent.length, undefined); + + s.insert({row: 0, column: 0}, " "); + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, "\t"); + assert.equal(indent.length, 4); + + s.setValue(""); + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.ok(!indent); + + next(); + }, + + "test empty session": function(next) { + var s = new EditSession([ + "define({", + "foo:1,", + "})" + ]); + var indent = whitespace.$detectIndentation(s.doc.$lines); + assert.ok(!indent); + s.insert({row: 1, column: 0}, " x\n "); + + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, " "); + assert.equal(indent.length, 4); + + next(); + }, + + "!test one line": function(next) { + var s = new EditSession([ + "define({", + " foo:1,", + "})" + ]); + var indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, " "); + assert.equal(indent.length, 4); + + next(); + }, + + "test 1 width indents": function(next) { + var s = new EditSession([ + "define({", + " foo:1,", + "})", + "define({", + " bar:1,", + "})", + " t", + " t", + " t", + " t", + " t", + " t", + " t", + " t" + ]); + var indent = whitespace.$detectIndentation(s.doc.$lines); + // assert.equal(indent.ch, " "); + // assert.equal(indent.length, 4); + + s = new EditSession([ + "{", + " foo:1,", + " bar: {", + " baz:2", + " }", + "}" + ]); + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, " "); + assert.equal(indent.length, 1); + + next(); + }, + +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} From 2ce7ed0f44e50dc1d89e7599f2767982686fc0cd Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Tue, 1 Jul 2014 16:15:45 -0700 Subject: [PATCH 065/545] add the export keyword to dart --- lib/ace/mode/dart_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/dart_highlight_rules.js b/lib/ace/mode/dart_highlight_rules.js index 311acd90..750392f7 100644 --- a/lib/ace/mode/dart_highlight_rules.js +++ b/lib/ace/mode/dart_highlight_rules.js @@ -54,7 +54,7 @@ var DartHighlightRules = function() { }, { token: "keyword.other.import.dart", - regex: "(?:\\b)(?:library|import|part|of)(?:\\b)" + regex: "(?:\\b)(?:library|import|export|part|of)(?:\\b)" }, { token : ["keyword.other.import.dart", "text"], From 109923873ad91ad590a59662c9c4f513db974aec Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 11 Oct 2013 16:30:02 +0400 Subject: [PATCH 066/545] do not hang the browser when edit is called for textarea --- lib/ace/ace.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/ace/ace.js b/lib/ace/ace.js index d7da2fb7..500b458f 100644 --- a/lib/ace/ace.js +++ b/lib/ace/ace.js @@ -79,11 +79,21 @@ exports.edit = function(el) { throw new Error("ace.edit can't find div #" + _id); } - if (el.env && el.env.editor instanceof Editor) + if (el && el.env && el.env.editor instanceof Editor) return el.env.editor; - var doc = exports.createEditSession(dom.getInnerText(el)); - el.innerHTML = ''; + var value = ""; + if (el && /input|textarea/i.test(el.tagName)) { + var oldNode = el; + value = oldNode.value; + el = dom.createElement("pre"); + oldNode.parentNode.replaceChild(el, oldNode); + } else { + value = dom.getInnerText(el); + el.innerHTML = ''; + } + + var doc = exports.createEditSession(value); var editor = new Editor(new Renderer(el)); editor.setSession(doc); @@ -93,11 +103,12 @@ exports.edit = function(el) { editor: editor, onResize: editor.resize.bind(editor, null) }; + if (oldNode) env.textarea = oldNode; event.addListener(window, "resize", env.onResize); editor.on("destroy", function() { event.removeListener(window, "resize", env.onResize); }); - el.env = editor.env = env; + editor.container.env = editor.env = env; return editor; }; From ad54d2c46cb8b161295ec215d4495c4b69adb661 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 2 Jul 2014 22:00:51 +0400 Subject: [PATCH 067/545] disabled validateDelta since it breaks autocompletion popup --- lib/ace/apply_delta.js | 10 +++++----- lib/ace/autocomplete/popup.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ace/apply_delta.js b/lib/ace/apply_delta.js index 98a1a857..98bfe148 100644 --- a/lib/ace/apply_delta.js +++ b/lib/ace/apply_delta.js @@ -52,7 +52,7 @@ function validateDelta(docLines, delta) { // Validate range type. if (!delta.start || !delta.end) - throwDeltaError(delta, "delta.start/end must be an present"); + throwDeltaError(delta, "delta.start/end must be an present"); // Validate that the start point is contained in the document. var start = delta.start; @@ -72,19 +72,19 @@ function validateDelta(docLines, delta) { } exports.applyDelta = function(docLines, delta, doNotValidate) { - if (!doNotValidate) - validateDelta(docLines, delta); + // disabled validation since it breaks autocompletion popup + // if (!doNotValidate) + // validateDelta(docLines, delta); var row = delta.start.row; var startColumn = delta.start.column; - var line = docLines[row]; + var line = docLines[row] || ""; switch (delta.action) { case "insert": var lines = delta.lines; if (lines.length === 1) { docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); } else { - var line = docLines[row]; var args = [row, 1].concat(delta.lines); docLines.splice.apply(docLines, args); docLines[row] = line.substring(0, startColumn) + docLines[row]; diff --git a/lib/ace/autocomplete/popup.js b/lib/ace/autocomplete/popup.js index a0ab7604..471cdb90 100644 --- a/lib/ace/autocomplete/popup.js +++ b/lib/ace/autocomplete/popup.js @@ -213,8 +213,8 @@ var AcePopup = function(parentNode) { popup.data = []; popup.setData = function(list) { - popup.data = list || []; popup.setValue(lang.stringRepeat("\n", list.length), -1); + popup.data = list || []; popup.setRow(0); }; popup.getData = function(row) { From f9b3655c943dee63b7aba01610bd1ee1d88e6878 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 2 Jul 2014 22:24:20 +0400 Subject: [PATCH 068/545] fix autocomplete popup click regression --- lib/ace/autocomplete/popup.js | 1 + lib/ace/keyboard/textinput.js | 14 +++++++++----- lib/ace/mouse/mouse_handler.js | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/ace/autocomplete/popup.js b/lib/ace/autocomplete/popup.js index a0ab7604..c8d168a6 100644 --- a/lib/ace/autocomplete/popup.js +++ b/lib/ace/autocomplete/popup.js @@ -67,6 +67,7 @@ var AcePopup = function(parentNode) { popup.renderer.setStyle("ace_autocomplete"); popup.setOption("displayIndentGuides", false); + popup.setOption("dragDelay", 150); var noop = function(){}; diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index fbf37786..ed213d70 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -428,13 +428,17 @@ var TextInput = function(parentNode, host) { this.onContextMenu = function(e) { afterContextMenu = true; - if (!tempStyle) - tempStyle = text.style.cssText; - - text.style.cssText = "z-index:100000;" + (useragent.isIE ? "opacity:0.1;" : ""); - resetSelection(host.selection.isEmpty()); host._emit("nativecontextmenu", {target: host, domEvent: e}); + this.moveToMouse(e, true); + }; + + this.moveToMouse = function(e, bringToFront) { + if (!tempStyle) + tempStyle = text.style.cssText; + text.style.cssText = (bringToFront ? "z-index:100000;" : "") + + (useragent.isIE ? "opacity:0.1;" : ""); + var rect = host.container.getBoundingClientRect(); var style = dom.computedStyle(host.container); var top = rect.top + (parseInt(style.borderTopWidth) || 0); diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index ce88eb81..9cf26721 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -49,7 +49,7 @@ var MouseHandler = function(editor) { var focusEditor = function(e) { if (!editor.isFocused() && editor.textInput) - editor.textInput.onContextMenu(e); + editor.textInput.moveToMouse(e); editor.focus() }; From f8be5072ac0d3ea6befade28a53c4e4c8fbbab96 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 2 Jul 2014 23:56:24 +0400 Subject: [PATCH 069/545] allow using name instead of caption --- lib/ace/autocomplete/popup.js | 2 +- lib/ace/autocomplete/text_completer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/autocomplete/popup.js b/lib/ace/autocomplete/popup.js index c8d168a6..a34ebf09 100644 --- a/lib/ace/autocomplete/popup.js +++ b/lib/ace/autocomplete/popup.js @@ -179,7 +179,7 @@ var AcePopup = function(parentNode) { if (typeof data == "string") data = {value: data}; if (!data.caption) - data.caption = data.value; + data.caption = data.value || data.name; var last = -1; var flag, c; diff --git a/lib/ace/autocomplete/text_completer.js b/lib/ace/autocomplete/text_completer.js index 6eebfc61..17a4bdad 100644 --- a/lib/ace/autocomplete/text_completer.js +++ b/lib/ace/autocomplete/text_completer.js @@ -68,7 +68,7 @@ define(function(require, exports, module) { var wordList = Object.keys(wordScore); callback(null, wordList.map(function(word) { return { - name: word, + caption: word, value: word, score: wordScore[word], meta: "local" From 8ed27996207ed25e1e0a4b9ce7394b805ee7ce40 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 3 Jul 2014 00:12:27 +0400 Subject: [PATCH 070/545] do not close the popup if there are matching completions --- lib/ace/autocomplete.js | 13 ++++++------- lib/ace/ext/language_tools.js | 4 ---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index adf9bd73..13d140d9 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -101,12 +101,12 @@ var Autocomplete = function() { this.changeTimer.cancel(); if (this.popup && this.popup.isOpen) { - this.gatherCompletionsId = this.gatherCompletionsId + 1; - } - - if (this.popup) + this.gatherCompletionsId += 1; this.popup.hide(); - + } + + if (this.base) + this.base.detach(); this.activated = false; this.completions = this.base = null; }; @@ -205,8 +205,7 @@ var Autocomplete = function() { var line = session.getLine(pos.row); var prefix = util.retrievePrecedingIdentifier(line, pos.column); - this.base = editor.getCursorPosition(); - this.base.column -= prefix.length; + this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length); var matches = []; var total = editor.completers.length; diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index dc56e6e0..d8b2a1dd 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -161,10 +161,6 @@ var doLiveAutocomplete = function(e) { editor.completer.autoSelect = false; editor.completer.autoInsert = false; editor.completer.showPopup(editor); - } else if (!prefix && hasCompleter) { - // When the prefix is empty - // close the autocomplete dialog - editor.completer.detach(); } } }; From bf72097811c2285a4999b527c79b24ef5d3ea070 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Fri, 4 Jul 2014 11:25:53 -0700 Subject: [PATCH 071/545] add a gitignore mode --- demo/kitchen-sink/docs/gitignore.gitignore | 8 +++++++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/gitignore.js | 19 +++++++++++++++ lib/ace/mode/gitignore_highlight_rules.js | 28 ++++++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 demo/kitchen-sink/docs/gitignore.gitignore create mode 100644 lib/ace/mode/gitignore.js create mode 100644 lib/ace/mode/gitignore_highlight_rules.js diff --git a/demo/kitchen-sink/docs/gitignore.gitignore b/demo/kitchen-sink/docs/gitignore.gitignore new file mode 100644 index 00000000..80f4f386 --- /dev/null +++ b/demo/kitchen-sink/docs/gitignore.gitignore @@ -0,0 +1,8 @@ +# A sample .gitiignore file. + +.buildlog +.DS_Store +.svn + +# Also ignore user settings... +/.settings diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 57470ed0..15a31610 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -70,6 +70,7 @@ var supportedModes = { Forth: ["frt|fs|ldr"], FTL: ["ftl"], Gherkin: ["feature"], + Gitignore: ["^.gitignore"], Glsl: ["glsl|frag|vert"], golang: ["go"], Groovy: ["groovy"], diff --git a/lib/ace/mode/gitignore.js b/lib/ace/mode/gitignore.js new file mode 100644 index 00000000..fd9b04f4 --- /dev/null +++ b/lib/ace/mode/gitignore.js @@ -0,0 +1,19 @@ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var GitignoreHighlightRules = require("./gitignore_highlight_rules").GitignoreHighlightRules; + +var Mode = function() { + this.HighlightRules = GitignoreHighlightRules; +}; +oop.inherits(Mode, TextMode); + +(function() { + this.$id = "ace/mode/gitignore"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/gitignore_highlight_rules.js b/lib/ace/mode/gitignore_highlight_rules.js new file mode 100644 index 00000000..8889511d --- /dev/null +++ b/lib/ace/mode/gitignore_highlight_rules.js @@ -0,0 +1,28 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var GitignoreHighlightRules = function() { + this.$rules = { + "start" : [ + { + token : "comment", + regex : /[#].*$/ + } + ] + }; + + this.normalizeRules(); +}; + +GitignoreHighlightRules.metaData = { + fileTypes: ['gitignore'], + name: 'Gitignore' +}; + +oop.inherits(GitignoreHighlightRules, TextHighlightRules); + +exports.GitignoreHighlightRules = GitignoreHighlightRules; +}); From e6f01878d7a6f800bbf62ffc5f3a459bd9d75bbf Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Fri, 4 Jul 2014 11:35:07 -0700 Subject: [PATCH 072/545] add snippets; fix the kitchensink demo --- demo/kitchen-sink/docs/{gitignore.gitignore => .gitignore} | 2 +- lib/ace/snippets/gitignore.js | 7 +++++++ lib/ace/snippets/gitignore.snippets | 0 3 files changed, 8 insertions(+), 1 deletion(-) rename demo/kitchen-sink/docs/{gitignore.gitignore => .gitignore} (70%) create mode 100644 lib/ace/snippets/gitignore.js create mode 100644 lib/ace/snippets/gitignore.snippets diff --git a/demo/kitchen-sink/docs/gitignore.gitignore b/demo/kitchen-sink/docs/.gitignore similarity index 70% rename from demo/kitchen-sink/docs/gitignore.gitignore rename to demo/kitchen-sink/docs/.gitignore index 80f4f386..17e256b1 100644 --- a/demo/kitchen-sink/docs/gitignore.gitignore +++ b/demo/kitchen-sink/docs/.gitignore @@ -1,4 +1,4 @@ -# A sample .gitiignore file. +# A sample .gitignore file. .buildlog .DS_Store diff --git a/lib/ace/snippets/gitignore.js b/lib/ace/snippets/gitignore.js new file mode 100644 index 00000000..0a632c99 --- /dev/null +++ b/lib/ace/snippets/gitignore.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./gitignore.snippets"); +exports.scope = "gitignore"; + +}); diff --git a/lib/ace/snippets/gitignore.snippets b/lib/ace/snippets/gitignore.snippets new file mode 100644 index 00000000..e69de29b From cc03e77327fc7c83ed4983974b49105628d65039 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 7 Jul 2014 08:17:25 -0700 Subject: [PATCH 073/545] review comments --- demo/kitchen-sink/docs/.gitignore | 3 +++ lib/ace/mode/gitignore_highlight_rules.js | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/demo/kitchen-sink/docs/.gitignore b/demo/kitchen-sink/docs/.gitignore index 17e256b1..56ec8fd9 100644 --- a/demo/kitchen-sink/docs/.gitignore +++ b/demo/kitchen-sink/docs/.gitignore @@ -4,5 +4,8 @@ .DS_Store .svn +# Negated patterns: +!foo.bar + # Also ignore user settings... /.settings diff --git a/lib/ace/mode/gitignore_highlight_rules.js b/lib/ace/mode/gitignore_highlight_rules.js index 8889511d..cfa42afa 100644 --- a/lib/ace/mode/gitignore_highlight_rules.js +++ b/lib/ace/mode/gitignore_highlight_rules.js @@ -9,7 +9,10 @@ var GitignoreHighlightRules = function() { "start" : [ { token : "comment", - regex : /[#].*$/ + regex : /^\s*#.*$/ + }, { + token : "keyword", // negated patterns + regex : /^\s*!.*$/ } ] }; From 4904f74dbdcc21a0a58852f55194a81864ebf8cf Mon Sep 17 00:00:00 2001 From: baboso Date: Tue, 8 Jul 2014 15:18:57 -0400 Subject: [PATCH 074/545] Minor changes to Praat syntax files --- demo/kitchen-sink/docs/praat.praat | 16 +++++++++ lib/ace/mode/praat_highlight_rules.js | 51 ++++++++++++++------------- lib/ace/snippets/praat.js | 7 ++++ lib/ace/snippets/praat.snippets | 0 4 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 lib/ace/snippets/praat.js create mode 100644 lib/ace/snippets/praat.snippets diff --git a/demo/kitchen-sink/docs/praat.praat b/demo/kitchen-sink/docs/praat.praat index c5dde785..3700ae6f 100644 --- a/demo/kitchen-sink/docs/praat.praat +++ b/demo/kitchen-sink/docs/praat.praat @@ -59,6 +59,22 @@ for i from 1 to n selectObject(sound[i]) selectObject: sound + # Pause commands + beginPause("Viewing " + sound$) + if i > 1 + button = endPause("Stop", "Previous", + ...if i = total_sounds then "Finish" else "Next" fi, + ...3, 1) + else + button = endPause("Stop", + ...if i = total_sounds then "Finish" else "Next" fi, + ...2, 1) + endif + editor_name$ = if total_textgrids then "TextGrid " else "Sound " fi + name$ + nocheck editor 'editor_name$' + nocheck Close + nocheck endeditor + # New-style standalone command call Rename: "SomeName" diff --git a/lib/ace/mode/praat_highlight_rules.js b/lib/ace/mode/praat_highlight_rules.js index 9cf98bcb..8b826487 100644 --- a/lib/ace/mode/praat_highlight_rules.js +++ b/lib/ace/mode/praat_highlight_rules.js @@ -74,27 +74,28 @@ var PraatHighlightRules = function() { ); var objectTypes = ( - "Collection|Strings|ManPages|SortedSetOfString|Sound|Matrix|Polygon|" + - "PointProcess|ParamCurve|Spectrum|Ltas|Spectrogram|Formant|" + - "Excitation|Cochleagram|VocalTract|FormantPoint|FormantTier|" + - "FormantGrid|Label|Tier|Autosegment|Intensity|Pitch|Harmonicity|" + - "Transition|RealPoint|RealTier|PitchTier|IntensityTier|DurationTier|" + - "AmplitudeTier|SpectrumTier|Manipulation|TextPoint|TextInterval|" + - "TextTier|IntervalTier|TextGrid|LongSound|WordList|SpellingChecker|" + - "Movie|Corpus|TableOfReal|Distributions|PairDistribution|Table|" + - "LinearRegression|LogisticRegression|Art|Artword|Speaker|Activation|" + - "BarkFilter|Categories|Cepstrum|CCA|ChebyshevSeries|" + - "ClassificationTable|Confusion|Correlation|Covariance|Discriminant|" + - "DTW|Eigen|Excitations|FormantFilter|Index|KlattTable|Permutation|" + - "ISpline|LegendreSeries|MelFilter|MSpline|Pattern|PCA|Polynomial|" + - "Roots|SimpleString|StringsIndex|SpeechSynthesizer|SPINET|SSCP|SVD|" + - "AffineTransform|Procrustes|ContingencyTable|Dissimilarity|" + - "Similarity|Configuration|Distance|Salience|ScalarProduct|Weight|" + - "KlattGrid|HMM|HMM_State|HMM_Observation|HMM_ObservationSequence|" + - "HMM_StateSequence|GaussianMixture|Diagonalizer|MixingMatrix|" + - "CrossCorrelationTable|CrossCorrelationTables|Network|OTGrammar|" + - "OTHistory|OTMulti|FFNet|Cepstrumc|LPC|LFCC|MFCC|ExperimentMFC|" + - "ResultsMFC|EEG|ERPTier|ERP|KNN|FeatureWeights" + "Activation|AffineTransform|AmplitudeTier|Art|Artword|Autosegment|" + + "BarkFilter|CCA|Categories|Cepstrum|Cepstrumc|ChebyshevSeries|" + + "ClassificationTable|Cochleagram|Collection|Configuration|" + + "Confusion|ContingencyTable|Corpus|Correlation|Covariance|" + + "CrossCorrelationTable|CrossCorrelationTables|DTW|Diagonalizer|" + + "Discriminant|Dissimilarity|Distance|Distributions|DurationTier|" + + "EEG|ERP|ERPTier|Eigen|Excitation|Excitations|ExperimentMFC|FFNet|" + + "FeatureWeights|Formant|FormantFilter|FormantGrid|FormantPoint|" + + "FormantTier|GaussianMixture|HMM|HMM_Observation|" + + "HMM_ObservationSequence|HMM_State|HMM_StateSequence|Harmonicity|" + + "ISpline|Index|Intensity|IntensityTier|IntervalTier|KNN|KlattGrid|" + + "KlattTable|LFCC|LPC|Label|LegendreSeries|LinearRegression|" + + "LogisticRegression|LongSound|Ltas|MFCC|MSpline|ManPages|" + + "Manipulation|Matrix|MelFilter|MixingMatrix|Movie|Network|" + + "OTGrammar|OTHistory|OTMulti|PCA|PairDistribution|ParamCurve|" + + "Pattern|Permutation|Pitch|PitchTier|PointProcess|Polygon|" + + "Polynomial|Procrustes|RealPoint|RealTier|ResultsMFC|Roots|SPINET|" + + "SSCP|SVD|Salience|ScalarProduct|Similarity|SimpleString|" + + "SortedSetOfString|Sound|Speaker|Spectrogram|Spectrum|SpectrumTier|" + + "SpeechSynthesizer|SpellingChecker|Strings|StringsIndex|Table|" + + "TableOfReal|TextGrid|TextInterval|TextPoint|TextTier|Tier|" + + "Transition|VocalTract|Weight|WordList" ); // regexp must not have capturing parentheses. Use (?:) instead. @@ -103,6 +104,10 @@ var PraatHighlightRules = function() { this.$rules = { "start" : [ { + // Interpolated strings + token : "string.interpolated", + regex : /'((?:[a-z][a-zA-Z0-9_]*)(?:\$|#|:[0-9]+)?)'/ + }, { // stopwatch token : ["text", "text", "keyword.operator", "text", "keyword"], regex : /(^\s*)(?:([a-z][a-zA-Z0-9_]*\$?\s+)(=)(\s+))?(stopwatch)/ @@ -156,10 +161,6 @@ var PraatHighlightRules = function() { token : "keyword", regex : "(\\b(?:" + keywords + ")\\b)" }, { - // Interpolated strings - token : "string.interpolated", - regex : /'((?:[a-z][a-zA-Z0-9_]*)(?:\$|#|:[0-9]+)?)'/ - }, { // Generic strings token : "string", regex : /"[^"]*"/ diff --git a/lib/ace/snippets/praat.js b/lib/ace/snippets/praat.js new file mode 100644 index 00000000..18afa87f --- /dev/null +++ b/lib/ace/snippets/praat.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./praat.snippets"); +exports.scope = "praat"; + +}); diff --git a/lib/ace/snippets/praat.snippets b/lib/ace/snippets/praat.snippets new file mode 100644 index 00000000..e69de29b From a3bb907f46b7c8c1d939ad2cf4f0d4ed543f18d3 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 9 Jul 2014 18:32:00 +0400 Subject: [PATCH 075/545] v1.1.5 --- ChangeLog.txt | 8 ++++++++ build | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 224f9326..589d9a46 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,11 @@ +2014.07.09 Version 1.1.5 + +* Bugfixes + - fix regression in autocomplete popup + +* new language modes + - gitignore (Devon Carew) + 2014.07.01 Version 1.1.4 * New Features diff --git a/build b/build index b85b38c1..cbc08e4e 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit b85b38c1e33e161826f4dd7774ef73aac55e0d14 +Subproject commit cbc08e4ebc4843eebec8dcd213751cb0d64c955b From a885aea2f0300fc74cc672cf63dbbb3544ae3793 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Wed, 9 Jul 2014 16:22:24 -0700 Subject: [PATCH 076/545] add the show and hide keywords to the dart mode --- lib/ace/mode/dart_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/dart_highlight_rules.js b/lib/ace/mode/dart_highlight_rules.js index 750392f7..0cd5811b 100644 --- a/lib/ace/mode/dart_highlight_rules.js +++ b/lib/ace/mode/dart_highlight_rules.js @@ -54,7 +54,7 @@ var DartHighlightRules = function() { }, { token: "keyword.other.import.dart", - regex: "(?:\\b)(?:library|import|export|part|of)(?:\\b)" + regex: "(?:\\b)(?:library|import|export|part|of|show|hide)(?:\\b)" }, { token : ["keyword.other.import.dart", "text"], From fd182ea76f370b31482e508c97ab8b8a45adb73a Mon Sep 17 00:00:00 2001 From: James Allen Date: Thu, 10 Jul 2014 12:56:11 +0100 Subject: [PATCH 077/545] Redraw lines and active line highlight when offscreen updates are made When setUseWrapMode is true, if some text is inserted into a line which is above the cursor and offscreen, then the renderer did not previously redraw the lines or active line highlight. However, if this insert causes the line to wrap onto another line then everything is shifted down by one visual line, leaving the onscreen lines in an out of date state. With this commit, the onscreen lines and active line highlight are now redrawn when this happens. --- lib/ace/editor.js | 1 + lib/ace/virtual_renderer.js | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 6a68e5de..e198ecaa 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -708,6 +708,7 @@ var Editor = function(renderer, session) { // update cursor because tab characters can influence the cursor position this.$cursorChange(); + this.$updateHighlightActiveLine(); }; this.onTokenizerUpdate = function(e) { diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 33f3a906..dfb435be 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -276,8 +276,13 @@ var VirtualRenderer = function(container, theme) { this.$changedLines.lastRow = lastRow; } - if (this.$changedLines.firstRow > this.layerConfig.lastRow || - this.$changedLines.lastRow < this.layerConfig.firstRow) + // If the change happened offscreen above us then it's possible + // that a new line wrap will affect the position of the lines on our + // screen so they need redrawn. + if (this.$changedLines.lastRow < this.layerConfig.firstRow) + this.$changedLines.lastRow = this.layerConfig.lastRow + + if (this.$changedLines.firstRow > this.layerConfig.lastRow) return; this.$loop.schedule(this.CHANGE_LINES); }; From 0afb5f6da6921be6ff41407deb3b14bec6ac6df1 Mon Sep 17 00:00:00 2001 From: Daniel Felder Date: Tue, 15 Jul 2014 01:38:50 +0200 Subject: [PATCH 078/545] Update latex.js Most of LaTeX is text. Word wrapping etc. should behave accordingly. --- lib/ace/mode/latex.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ace/mode/latex.js b/lib/ace/mode/latex.js index 1f8c07cb..24048d5e 100644 --- a/lib/ace/mode/latex.js +++ b/lib/ace/mode/latex.js @@ -14,6 +14,8 @@ var Mode = function() { oop.inherits(Mode, TextMode); (function() { + this.type = "text"; + this.lineCommentStart = "%"; this.$id = "ace/mode/latex"; From d3d2e0823ba25a53a244338cf2466c2b786b572c Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 11 Jul 2014 16:07:12 +0400 Subject: [PATCH 079/545] fix Double tapping to select words doesn't work reliably --- demo/kitchen-sink/demo.js | 21 ++---------------- lib/ace/lib/event.js | 2 ++ lib/ace/mouse/default_handlers.js | 34 +++++++++++------------------ lib/ace/mouse/mouse_handler_test.js | 8 +++---- 4 files changed, 20 insertions(+), 45 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 552b1e65..c7beb3d0 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -415,28 +415,11 @@ bindDropdown("folding", function(value) { }); bindDropdown("soft_wrap", function(value) { - var session = env.editor.session; - var renderer = env.editor.renderer; - switch (value) { - case "off": - session.setUseWrapMode(false); - renderer.setPrintMarginColumn(80); - break; - case "free": - session.setUseWrapMode(true); - session.setWrapLimitRange(null, null); - renderer.setPrintMarginColumn(80); - break; - default: - session.setUseWrapMode(true); - var col = parseInt(value, 10); - session.setWrapLimitRange(col, col); - renderer.setPrintMarginColumn(col); - } + env.editor.setOption("wrap", value); }); bindCheckbox("select_style", function(checked) { - env.editor.setSelectionStyle(checked ? "line" : "text"); + env.editor.setOption("selectionStyle", checked ? "line" : "text"); }); bindCheckbox("highlight_active", function(checked) { diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 612b6a34..b8e2199d 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -191,6 +191,8 @@ exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbac startY = e.clientY; } } + + e._clicks = clicks; eventHandler[callbackName]("mousedown", e); diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js index e7a31540..48d09ee4 100644 --- a/lib/ace/mouse/default_handlers.js +++ b/lib/ace/mouse/default_handlers.js @@ -71,21 +71,20 @@ function DefaultHandlers(mouseHandler) { var selectionRange = editor.getSelectionRange(); var selectionEmpty = selectionRange.isEmpty(); - if (selectionEmpty) { + if (selectionEmpty) editor.selection.moveToPosition(pos); - } // 2: contextmenu, 1: linux paste editor.textInput.onContextMenu(ev.domEvent); return; // stopping event here breaks contextmenu on ff mac } + this.mousedownEvent.time = Date.now(); // if this click caused the editor to be focused should not clear the // selection if (inSelection && !editor.isFocused()) { editor.focus(); if (this.$focusTimout && !this.$clickSelection && !editor.inMultiSelectMode) { - this.mousedownEvent.time = Date.now(); this.setState("focusWait"); this.captureMouse(ev); return; @@ -93,31 +92,21 @@ function DefaultHandlers(mouseHandler) { } this.captureMouse(ev); - if (!inSelection || this.$clickSelection || ev.getShiftKey() || editor.inMultiSelectMode) { - // Directly pick STATE_SELECT, since the user is not clicking inside - // a selection. - this.startSelect(pos); - } else if (inSelection) { - this.mousedownEvent.time = Date.now(); - this.startSelect(pos); - } + this.startSelect(pos, ev.domEvent._clicks > 1); return ev.preventDefault(); }; - this.startSelect = function(pos) { + this.startSelect = function(pos, waitForClickSelection) { pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y); var editor = this.editor; // allow double/triple click handlers to change selection - var shiftPressed = this.mousedownEvent.getShiftKey(); - setTimeout(function(){ - if (shiftPressed) { - editor.selection.selectToPosition(pos); - } - else if (!this.$clickSelection) { - editor.selection.moveToPosition(pos); - } + + if (this.mousedownEvent.getShiftKey()) + editor.selection.selectToPosition(pos); + else if (!waitForClickSelection) + editor.selection.moveToPosition(pos); + if (!waitForClickSelection) this.select(); - }.bind(this), 0); if (editor.renderer.scroller.setCapture) { editor.renderer.scroller.setCapture(); } @@ -216,6 +205,7 @@ function DefaultHandlers(mouseHandler) { this.setState("selectByWords"); } this.$clickSelection = range; + this.select(); }; this.onTripleClick = function(ev) { @@ -230,6 +220,7 @@ function DefaultHandlers(mouseHandler) { } else { this.$clickSelection = editor.selection.getLineRange(pos.row); } + this.select(); }; this.onQuadClick = function(ev) { @@ -238,6 +229,7 @@ function DefaultHandlers(mouseHandler) { editor.selectAll(); this.$clickSelection = editor.getSelectionRange(); this.setState("selectAll"); + this.select(); }; this.onMouseWheel = function(ev) { diff --git a/lib/ace/mouse/mouse_handler_test.js b/lib/ace/mouse/mouse_handler_test.js index 571acdac..96374d71 100644 --- a/lib/ace/mouse/mouse_handler_test.js +++ b/lib/ace/mouse/mouse_handler_test.js @@ -58,17 +58,15 @@ module.exports = { next(); }, - "test: double tap. issue #956" : function(done) { + "test: double tap. issue #956" : function() { // mouse up fired immediately after mouse down var target = this.editor.renderer.getMouseEventTarget(); target.dispatchEvent(MouseEvent("down", {x: 1, y: 1})); target.dispatchEvent(MouseEvent("up", {x: 1, y: 1})); target.dispatchEvent(MouseEvent("down", {x: 1, y: 1, detail: 2})); target.dispatchEvent(MouseEvent("up", {x: 1, y: 1, detail: 2})); - setTimeout(function() { - assert.equal(this.editor.getSelectedText(), "Juhu"); - done(); - }.bind(this)); + + assert.equal(this.editor.getSelectedText(), "Juhu"); } }; From c1c08945b23682eff67752ac0bc58d8b2efe813f Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 16 Jul 2014 22:46:35 +0400 Subject: [PATCH 080/545] do not scroll cursor into view after quad click --- lib/ace/mouse/default_handlers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js index 48d09ee4..bbd85484 100644 --- a/lib/ace/mouse/default_handlers.js +++ b/lib/ace/mouse/default_handlers.js @@ -229,7 +229,6 @@ function DefaultHandlers(mouseHandler) { editor.selectAll(); this.$clickSelection = editor.getSelectionRange(); this.setState("selectAll"); - this.select(); }; this.onMouseWheel = function(ev) { From a52b30317ba665d81df1c7e1a1b48399504917d5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 11 Jul 2014 17:03:34 +0400 Subject: [PATCH 081/545] add heredoc support for sh mode --- lib/ace/mode/sh_highlight_rules.js | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/lib/ace/mode/sh_highlight_rules.js b/lib/ace/mode/sh_highlight_rules.js index 73ece2f8..43f536f4 100644 --- a/lib/ace/mode/sh_highlight_rules.js +++ b/lib/ace/mode/sh_highlight_rules.js @@ -99,6 +99,62 @@ var ShHighlightRules = function() { }, { defaultToken: "string" }] + }, { + stateName: "heredoc", + onMatch : function(value, currentState, stack) { + var next = value[2] == '-' ? "indentedHeredoc" : "heredoc"; + var tokens = value.split(this.splitRegex); + stack.push(next, tokens[4]); + return [ + {type:"constant", value: tokens[1]}, + {type:"text", value: tokens[2]}, + {type:"string", value: tokens[3]}, + {type:"support.class", value: tokens[4]}, + {type:"string", value: tokens[5]} + ]; + }, + regex : "(<<-?)(\\s*)(['\"`]?)([\\w\-]+)(['\"`]?)", + rules: { + heredoc: [{ + onMatch: function(value, currentState, stack) { + if (value === stack[1]) { + stack.shift(); + stack.shift(); + this.next = stack[0] || "start"; + return "support.class"; + } + this.next = ""; + return "string"; + }, + regex: ".*$", + next: "start" + }], + indentedHeredoc: [{ + token: "string", + regex: "^ +" + }, { + onMatch: function(value, currentState, stack) { + if (value === stack[1]) { + stack.shift(); + stack.shift(); + this.next = stack[0] || "start"; + return "support.class"; + } + this.next = ""; + return "string"; + }, + regex: ".*$", + next: "start" + }] + } + }, { + regex : "$", + token : "empty", + next : function(currentState, stack) { + if (stack[0] === "heredoc" || stack[0] === "indentedHeredoc") + return stack[0]; + return currentState; + } }, { token : "variable.language", regex : builtinVariable From 1ad5e66be0f022c14f2fcc1153d301421299fa4c Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 16 Jul 2014 23:27:20 +0400 Subject: [PATCH 082/545] fix #2051 highlighting php string in script tag --- lib/ace/tokenizer.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/ace/tokenizer.js b/lib/ace/tokenizer.js index 64bf59e8..85fa6c7b 100644 --- a/lib/ace/tokenizer.js +++ b/lib/ace/tokenizer.js @@ -268,11 +268,14 @@ var Tokenizer = function(rules) { type = rule.token; if (rule.next) { - if (typeof rule.next == "string") + if (typeof rule.next == "string") { + if (stack.length && stack[0] == currentState && stack[1] == rule.next) + stack.shift(); currentState = rule.next; - else + } else { currentState = rule.next(currentState, stack); - + } + state = this.states[currentState]; if (!state) { window.console && console.error && console.error(currentState, "doesn't exist"); From d53c91e41a05b2b32886a58e2d627a8f3a8a2fd7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 16 Jul 2014 23:29:37 +0400 Subject: [PATCH 083/545] update mode tests --- lib/ace/mode/_test/text_php.txt | 24 ++++ lib/ace/mode/_test/tokens_gitignore.json | 33 +++++ lib/ace/mode/_test/tokens_lsl.json | 2 +- lib/ace/mode/_test/tokens_lua.json | 2 +- lib/ace/mode/_test/tokens_php.json | 39 +++++- lib/ace/mode/_test/tokens_vala.json | 158 +++++++++++++++++++++++ lib/ace/mode/_test/tokens_xquery.json | 44 ------- 7 files changed, 255 insertions(+), 47 deletions(-) create mode 100644 lib/ace/mode/_test/text_php.txt create mode 100644 lib/ace/mode/_test/tokens_gitignore.json create mode 100644 lib/ace/mode/_test/tokens_vala.json delete mode 100644 lib/ace/mode/_test/tokens_xquery.json diff --git a/lib/ace/mode/_test/text_php.txt b/lib/ace/mode/_test/text_php.txt new file mode 100644 index 00000000..b76aa8a5 --- /dev/null +++ b/lib/ace/mode/_test/text_php.txt @@ -0,0 +1,24 @@ + not &js; diff --git a/lib/ace/mode/_test/tokens_gitignore.json b/lib/ace/mode/_test/tokens_gitignore.json new file mode 100644 index 00000000..8689a724 --- /dev/null +++ b/lib/ace/mode/_test/tokens_gitignore.json @@ -0,0 +1,33 @@ +[[ + "start", + ["comment","# A sample .gitignore file."] +],[ + "start" +],[ + "start", + ["text",".buildlog"] +],[ + "start", + ["text",".DS_Store"] +],[ + "start", + ["text",".svn"] +],[ + "start" +],[ + "start", + ["comment","# Negated patterns:"] +],[ + "start", + ["keyword","!foo.bar"] +],[ + "start" +],[ + "start", + ["comment","# Also ignore user settings..."] +],[ + "start", + ["text","/.settings"] +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_lsl.json b/lib/ace/mode/_test/tokens_lsl.json index 93575a2c..2248a607 100644 --- a/lib/ace/mode/_test/tokens_lsl.json +++ b/lib/ace/mode/_test/tokens_lsl.json @@ -500,4 +500,4 @@ ["paren.rparen.lsl","}"] ],[ "start" -]] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_lua.json b/lib/ace/mode/_test/tokens_lua.json index 3fde966d..b60c7cb1 100644 --- a/lib/ace/mode/_test/tokens_lua.json +++ b/lib/ace/mode/_test/tokens_lua.json @@ -345,4 +345,4 @@ ["text"," "], ["comment","--[[ blah ]]"], ["paren.rparen",")"] -]] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_php.json b/lib/ace/mode/_test/tokens_php.json index d8a41eec..d1458a65 100644 --- a/lib/ace/mode/_test/tokens_php.json +++ b/lib/ace/mode/_test/tokens_php.json @@ -129,6 +129,43 @@ ],[ "php-start" ],[ - "start", + ["php-start","js-start"], + ["support.php_tag","?>"], + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text"," "], + ["support.php_tag",""] +],[ + "js-comment_regex_allowed", + ["comment","/*this is js "], + ["support.php_tag",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," not "], + ["constant.language.escape.reference.xml","&js;"] +],[ + "start" ]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_vala.json b/lib/ace/mode/_test/tokens_vala.json new file mode 100644 index 00000000..efe6e7c8 --- /dev/null +++ b/lib/ace/mode/_test/tokens_vala.json @@ -0,0 +1,158 @@ +[[ + "start", + ["meta.using.vala",""], + ["keyword.other.using.vala","using"], + ["meta.using.vala"," "], + ["storage.modifier.using.vala","Gtk"], + ["punctuation.terminator.vala",";"] +],[ + "start", + ["text"," "] +],[ + "text0", + ["storage.type.primitive.array.vala","int"], + ["text"," main ("], + ["storage.type.primitive.array.vala","string"], + ["text","[] args) {"] +],[ + "text0", + ["text"," "], + ["storage.type.vala","Gtk"], + ["keyword.operator.dereference.vala","."], + ["text","init ("], + ["storage.modifier.vala","ref"], + ["text"," args)"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "], + ["storage.type.primitive.vala","var"], + ["text"," foo "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["keyword.control.new.vala","new"], + ["text"," "], + ["storage.type.generic.vala","MyFoo>"], + ["text","()"], + ["punctuation.terminator.vala",";"] +],[ + "text0" +],[ + "text0", + ["text"," "], + ["storage.type.primitive.vala","var"], + ["text"," window "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["keyword.control.new.vala","new"], + ["text"," "], + ["storage.type.vala","Window"], + ["text","()"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","title "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["punctuation.definition.string.begin.vala","\""], + ["string.quoted.double.vala","Hello, World!"], + ["punctuation.definition.string.end.vala","\""], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","border_width "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["constant.numeric.vala","10"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","window_position "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["storage.type.vala","WindowPosition"], + ["keyword.operator.dereference.vala","."], + ["constant.other.vala","CENTER"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","set_default_size("], + ["constant.numeric.vala","350"], + ["text",", "], + ["constant.numeric.vala","70"], + ["text",")"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","destroy"], + ["keyword.operator.dereference.vala","."], + ["text","connect("], + ["storage.type.vala","Gtk"], + ["keyword.operator.dereference.vala","."], + ["text","main_quit)"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "] +],[ + "text0", + ["text"," "], + ["storage.type.primitive.vala","var"], + ["text"," label "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["keyword.control.new.vala","new"], + ["text"," "], + ["storage.type.vala","Label"], + ["text","("], + ["punctuation.definition.string.begin.vala","\""], + ["string.quoted.double.vala","Hello, World!"], + ["punctuation.definition.string.end.vala","\""], + ["text",")"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","add(label)"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","show_all()"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "] +],[ + "text0", + ["text"," "], + ["storage.type.vala","Gtk"], + ["keyword.operator.dereference.vala","."], + ["text","main()"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "], + ["keyword.control.vala","return"], + ["text"," "], + ["constant.numeric.vala","0"], + ["punctuation.terminator.vala",";"] +],[ + "start", + ["text","}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_xquery.json b/lib/ace/mode/_test/tokens_xquery.json deleted file mode 100644 index aaf9ab9b..00000000 --- a/lib/ace/mode/_test/tokens_xquery.json +++ /dev/null @@ -1,44 +0,0 @@ -[[ - "[\"start\"]", - ["keyword","xquery"], - ["text"," "], - ["keyword","version"], - ["text"," "], - ["string","\""], - ["string","1.0"], - ["string","\""], - ["text",";"] -],[ - "[\"start\"]" -],[ - "[\"start\"]", - ["keyword","let"], - ["text"," "], - ["variable","$message"], - ["text"," "], - ["keyword.operator",":="], - ["text"," "], - ["string","\""], - ["string","Hello World!"], - ["string","\""] -],[ - "[\"start\",\"StartTag\",\"TagContent\"]", - ["keyword","return"], - ["text"," "], - ["meta.tag",""] -],[ - "[\"start\",\"StartTag\",\"TagContent\"]", - ["text"," "], - ["meta.tag",""], - ["text","{"], - ["variable","$message"], - ["text","}"], - ["meta.tag",""] -],[ - "[\"start\"]", - ["meta.tag",""] -],[ - "[\"start\"]" -]] \ No newline at end of file From fcd1dbb98d5ee96b8615577334e585645114f01a Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 17:22:21 +0200 Subject: [PATCH 084/545] Adding Eiffel language mode. - Adding Eiffel highlight rules and Eiffel mode - Use Sudoku grid example of Eiffel Rosetta Code project as Eiffel example --- demo/kitchen-sink/docs/eiffel.e | 246 +++++++++++++++++++++++++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/eiffel.js | 51 +++++ lib/ace/mode/eiffel_highlight_rules.js | 143 ++++++++++++++ 4 files changed, 441 insertions(+) create mode 100644 demo/kitchen-sink/docs/eiffel.e create mode 100644 lib/ace/mode/eiffel.js create mode 100644 lib/ace/mode/eiffel_highlight_rules.js diff --git a/demo/kitchen-sink/docs/eiffel.e b/demo/kitchen-sink/docs/eiffel.e new file mode 100644 index 00000000..4b349566 --- /dev/null +++ b/demo/kitchen-sink/docs/eiffel.e @@ -0,0 +1,246 @@ +note + description: "[ + Sudoku grid and simple resolution facilities. + ]" + author: "Victorien ELVINGER" + date: "22 August 2013" + revision: "3" + libraries: "Relies on ARRAY2 from EiffelBase" + +class + SUDOKU_GRID + +inherit + + ANY + redefine + default_create, + out + end + +create + default_create + +feature {NONE} -- Creation + + default_create + -- Create an empty grid. + do + create grid.make_filled (Default_value, 9, 9) + ensure then + unsolved: not solved + end + +feature -- Access + + item alias "[]" (a_row, a_column: INTEGER): INTEGER assign put + -- Value at coordinates (`a_row', `a_column'). + require + valid_row (a_row) + valid_column (a_column) + do + Result := grid [a_row, a_column] + end + + out: STRING + -- Printable representation. + do + Result := "" + across column_range as column_ic loop + across row_range as row_ic loop + Result := Result + grid [row_ic.item, column_ic.item].out + " " + end + Result := Result + "%N" + end + end + + column_range: INTEGER_INTERVAL + -- Column interval. + do + Result := 1 |..| grid.width + end + + row_range: INTEGER_INTERVAL + -- Row interval. + do + Result := 1 |..| grid.height + end + + subgrid_column_range (a_column: INTEGER): INTEGER_INTERVAL + -- Colum interval of the subgrids including `a_column'. + require + valid_column (a_column) + local + l_column: like a_column + do + l_column := ((a_column - 1) // 3)*3 + 1 + Result := l_column |..| (l_column + 2) + ensure + lower_bound: (<<1, 4, 7>>).has (Result.lower) + upper_bound: (<<3, 6, 9>>).has (Result.upper) + end + + subgrid_row_range (a_row: INTEGER): INTEGER_INTERVAL + -- Row interval of the subgrids including `a_row'. + require + valid_row (a_row) + local + l_row: like a_row + do + l_row := ((a_row - 1) // 3) * 3 + 1 + Result := l_row |..| (l_row + 2) + ensure + lower_bound: (<<1, 4, 7>>).has (Result.lower) + upper_bound: (<<3, 6, 9>>).has (Result.upper) + end + +feature -- Status report + + solved: BOOLEAN + -- Is completed? + + valid_column (a_column: INTEGER): BOOLEAN + -- Is `a_column' a valid coordinate? + do + Result := 1 <= a_column and a_column <= grid.width + end + + valid_row (a_row: INTEGER): BOOLEAN + -- Is `a_row' a valid coordinate? + do + Result := 1 <= a_row and a_row <= grid.height + end + + valid_value (a_value: INTEGER): BOOLEAN + -- Is `a_value' a valid item? + do + Result := 1 <= a_value and a_value <= 9 + end + + valid (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN + -- Can `a_value' be inserted at coordinates (`a_row', `a_column')? + require + valid_value (a_value) + valid_row (a_row) + valid_column (a_column) + do + Result := not (subgrid_has (a_value, a_row, a_column) or row_has (a_value, a_row) or column_has (a_value, a_column)) + end + + subgrid_has (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN + -- Is there `a_value' in the subgrid containing coordinates (`a_row', `a_column')? + require + valid_row (a_row) + valid_column (a_column) + do + across + subgrid_row_range (a_row) as row_ic + until + Result + loop + across + subgrid_column_range (a_column) as column_ic + until + Result + loop + Result := grid [row_ic.item, column_ic.item] = a_value + end + end + end + + row_has (a_value: INTEGER; a_row: INTEGER): BOOLEAN + -- Exist there an item `a_value' at coordinates (`a_row', ?)? + require + valid_row (a_row) + do + Result := across column_range as ic some grid [a_row, ic.item] = a_value end + end + + column_has (a_value: INTEGER; a_column: INTEGER): BOOLEAN + -- Exist there an item `a_value' at coordinates (?, `a_column')? + require + valid_column (a_column) + do + Result := across row_range as ic some grid [ic.item, a_column] = a_value end + end + +feature -- Extension + + put (a_value: INTEGER; a_row, a_column: INTEGER) + -- Assign item `a_value' at coordinates (`a_row', `a_column'). + require + valid_value (a_value) + valid_row (a_row) + valid_column (a_column) + valid (a_value, a_row, a_column) + do + grid [a_row, a_column] := a_value + ensure + item_inserted: grid [a_row, a_column] = a_value + end + +feature -- Change + + solve + -- Try to solve grid. + do + sub_solve (1, 1) + end + +feature {NONE} -- Implementation + + grid: ARRAY2 [INTEGER] + -- Board. + + Default_value: INTEGER = 0 + -- Empty cell content. + + sub_solve (a_row, a_column: INTEGER) + -- Solve grid from row `a_row' and column `a_column'. + require + valid_row (a_row) + valid_column (a_column) + do + if valid_value (grid [a_row, a_column]) then + solve_after (a_row, a_column) + else + across + 1 |..| 9 as ic + until + solved + loop + if valid (ic.item, a_row, a_column) then + put (ic.item, a_row, a_column) + solve_after (a_row, a_column) + + if not solved then + grid [a_row, a_column] := Default_value + end + end + end + end + end + + solve_after (a_row, a_column: INTEGER) + -- Solve the next cell. + require + valid_row (a_row) + valid_column (a_column) + do + if a_column = grid.width then + if a_row = grid.height then + solved := True + else + sub_solve (a_row + 1, 1) + end + else + sub_solve (a_row, a_column + 1) + end + end + +invariant + valid_numbers: solved implies across grid as ic all valid_value (ic.item) end + nine_columns: grid.width = 9 + nine_rows: grid.height = 9 + +end diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 2028386e..53b78f00 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -65,6 +65,7 @@ var supportedModes = { Diff: ["diff|patch"], Dockerfile: ["^Dockerfile"], Dot: ["dot"], + Eiffel: ["e"], Erlang: ["erl|hrl"], EJS: ["ejs"], Forth: ["frt|fs|ldr"], diff --git a/lib/ace/mode/eiffel.js b/lib/ace/mode/eiffel.js new file mode 100644 index 00000000..2ef84ff8 --- /dev/null +++ b/lib/ace/mode/eiffel.js @@ -0,0 +1,51 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var EiffelHighlightRules = require("./eiffel_highlight_rules").EiffelHighlightRules; +var Range = require("../range").Range; + +var Mode = function() { + this.HighlightRules = EiffelHighlightRules; +}; +oop.inherits(Mode, TextMode); + +(function() { + this.$id = "ace/mode/eiffel"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); + diff --git a/lib/ace/mode/eiffel_highlight_rules.js b/lib/ace/mode/eiffel_highlight_rules.js new file mode 100644 index 00000000..f2cc8bd6 --- /dev/null +++ b/lib/ace/mode/eiffel_highlight_rules.js @@ -0,0 +1,143 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var EiffelHighlightRules = function() { + var keywords = "across|agent|alias|all|attached|as|assign|attribute|check|" + + "class|convert|create|debug|deferred|detachable|do|else|elseif|end|" + + "ensure|expanded|export|external|feature|from|frozen|if|inherit|" + + "inspect|invariant|like|local|loop|not|note|obsolete|old|once|" + + "Precursor|redefine|rename|require|rescue|retry|select|separate|" + + "some|then|undefine|until|variant|when"; + + var operatorKeywords = "and|implies|or|xor"; + + var languageConstants = "Void"; + + var booleanConstants = "True|False"; + + var languageVariables = "Current|Result"; + + var keywordMapper = this.createKeywordMapper({ + "constant.language": languageConstants, + "constant.language.boolean": booleanConstants, + "variable.language": languageVariables, + "keyword.operator": operatorKeywords, + "keyword": keywords + }, "identifier", true); + + this.$rules = { + "start": [{ + token : "comment.line.double-dash", + regex : /--.*$/ + }, { + token : "string.quoted.double", + regex : /"(?:%"|[^%])*?"/ + }, { + token : "string.quoted.other", // "[ ]" aligned verbatim string + regex : /"\[/, + next: "aligned_verbatim_string" + }, { + token : "string.quoted.other", // "{ }" non-aligned verbatim string + regex : /"\{/, + next: "non-aligned_verbatim_string" + }, { + token : "constant.character", + regex : /'(?:%%|%T|%R|%N|%F|%'|[^%])'/ + }, { + token : "constant.numeric", // real + regex : /(?:\d(?:_?\d)*\.|\.\d)(?:\d*[eE][+-]?\d+)?\b/ + }, { + token : "constant.numeric", // integer + regex : /\d(?:_?\d)*\b/ + }, { + token : "constant.numeric", // hex + regex : /0[xX][a-fA-F\d](?:_?[a-fA-F\d])*\b/ + }, { + token : "constant.numeric", // octal + regex : /0[cC][0-7](?:_?[0-7])*\b/ + },{ + token : "constant.numeric", // bin + regex : /0[bB][01](?:_?[01])*\b/ + }, { + token : "keyword.operator", + regex : /\+|\-|\*|\/|\\\\|\/\/|\^|~|\/~|<|>|<=|>=|\/=|=|:=|\|\.\.\||\.\./ + }, { + token : "keyword.operator", // punctuation + regex : /\.|:|,|;\b/ + }, { + token : function (v) { + var result = keywordMapper (v); + if (result === "identifier" && v === v.toUpperCase ()) { + result = "entity.name.type"; + } + return result; + }, + regex : /[a-zA-Z][a-zA-Z\d_]*\b/ + }, { + token : "paren.lparen", + regex : /[\[({]/ + }, { + token : "paren.rparen", + regex : /[\])}]/ + }, { + token : "text", + regex : /\s+/ + } + ], + "aligned_verbatim_string" : [{ + token : "string", // closing multi-line comment + regex : /]"/, + next : "start" + }, { + token : "string", // comment spanning whole line + regex : /[^(?:\]")]+/ + } + ], + "non-aligned_verbatim_string" : [{ + token : "string.quoted.other", // closing multi-line comment + regex : /}"/, + next : "start" + }, { + token : "string.quoted.other", // comment spanning whole line + regex : /[^(?:\}")]+/ + } + ]}; +}; + +oop.inherits(EiffelHighlightRules, TextHighlightRules); + +exports.EiffelHighlightRules = EiffelHighlightRules; +}); From 7e55724c522598378c9d16f8893cf222ad5bf202 Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 19:10:50 +0200 Subject: [PATCH 085/545] Add comment mark in Eiffel mode. --- lib/ace/mode/eiffel.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/mode/eiffel.js b/lib/ace/mode/eiffel.js index 2ef84ff8..f8ba173b 100644 --- a/lib/ace/mode/eiffel.js +++ b/lib/ace/mode/eiffel.js @@ -42,6 +42,7 @@ var Mode = function() { oop.inherits(Mode, TextMode); (function() { + this.lineCommentStart = "--"; this.$id = "ace/mode/eiffel"; }).call(Mode.prototype); From 9284732a28f727b3185cec56e4f0d236b221d1bc Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 19:12:03 +0200 Subject: [PATCH 086/545] Remove eiffel example. Current example is too large. --- demo/kitchen-sink/docs/eiffel.e | 246 -------------------------------- 1 file changed, 246 deletions(-) delete mode 100644 demo/kitchen-sink/docs/eiffel.e diff --git a/demo/kitchen-sink/docs/eiffel.e b/demo/kitchen-sink/docs/eiffel.e deleted file mode 100644 index 4b349566..00000000 --- a/demo/kitchen-sink/docs/eiffel.e +++ /dev/null @@ -1,246 +0,0 @@ -note - description: "[ - Sudoku grid and simple resolution facilities. - ]" - author: "Victorien ELVINGER" - date: "22 August 2013" - revision: "3" - libraries: "Relies on ARRAY2 from EiffelBase" - -class - SUDOKU_GRID - -inherit - - ANY - redefine - default_create, - out - end - -create - default_create - -feature {NONE} -- Creation - - default_create - -- Create an empty grid. - do - create grid.make_filled (Default_value, 9, 9) - ensure then - unsolved: not solved - end - -feature -- Access - - item alias "[]" (a_row, a_column: INTEGER): INTEGER assign put - -- Value at coordinates (`a_row', `a_column'). - require - valid_row (a_row) - valid_column (a_column) - do - Result := grid [a_row, a_column] - end - - out: STRING - -- Printable representation. - do - Result := "" - across column_range as column_ic loop - across row_range as row_ic loop - Result := Result + grid [row_ic.item, column_ic.item].out + " " - end - Result := Result + "%N" - end - end - - column_range: INTEGER_INTERVAL - -- Column interval. - do - Result := 1 |..| grid.width - end - - row_range: INTEGER_INTERVAL - -- Row interval. - do - Result := 1 |..| grid.height - end - - subgrid_column_range (a_column: INTEGER): INTEGER_INTERVAL - -- Colum interval of the subgrids including `a_column'. - require - valid_column (a_column) - local - l_column: like a_column - do - l_column := ((a_column - 1) // 3)*3 + 1 - Result := l_column |..| (l_column + 2) - ensure - lower_bound: (<<1, 4, 7>>).has (Result.lower) - upper_bound: (<<3, 6, 9>>).has (Result.upper) - end - - subgrid_row_range (a_row: INTEGER): INTEGER_INTERVAL - -- Row interval of the subgrids including `a_row'. - require - valid_row (a_row) - local - l_row: like a_row - do - l_row := ((a_row - 1) // 3) * 3 + 1 - Result := l_row |..| (l_row + 2) - ensure - lower_bound: (<<1, 4, 7>>).has (Result.lower) - upper_bound: (<<3, 6, 9>>).has (Result.upper) - end - -feature -- Status report - - solved: BOOLEAN - -- Is completed? - - valid_column (a_column: INTEGER): BOOLEAN - -- Is `a_column' a valid coordinate? - do - Result := 1 <= a_column and a_column <= grid.width - end - - valid_row (a_row: INTEGER): BOOLEAN - -- Is `a_row' a valid coordinate? - do - Result := 1 <= a_row and a_row <= grid.height - end - - valid_value (a_value: INTEGER): BOOLEAN - -- Is `a_value' a valid item? - do - Result := 1 <= a_value and a_value <= 9 - end - - valid (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN - -- Can `a_value' be inserted at coordinates (`a_row', `a_column')? - require - valid_value (a_value) - valid_row (a_row) - valid_column (a_column) - do - Result := not (subgrid_has (a_value, a_row, a_column) or row_has (a_value, a_row) or column_has (a_value, a_column)) - end - - subgrid_has (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN - -- Is there `a_value' in the subgrid containing coordinates (`a_row', `a_column')? - require - valid_row (a_row) - valid_column (a_column) - do - across - subgrid_row_range (a_row) as row_ic - until - Result - loop - across - subgrid_column_range (a_column) as column_ic - until - Result - loop - Result := grid [row_ic.item, column_ic.item] = a_value - end - end - end - - row_has (a_value: INTEGER; a_row: INTEGER): BOOLEAN - -- Exist there an item `a_value' at coordinates (`a_row', ?)? - require - valid_row (a_row) - do - Result := across column_range as ic some grid [a_row, ic.item] = a_value end - end - - column_has (a_value: INTEGER; a_column: INTEGER): BOOLEAN - -- Exist there an item `a_value' at coordinates (?, `a_column')? - require - valid_column (a_column) - do - Result := across row_range as ic some grid [ic.item, a_column] = a_value end - end - -feature -- Extension - - put (a_value: INTEGER; a_row, a_column: INTEGER) - -- Assign item `a_value' at coordinates (`a_row', `a_column'). - require - valid_value (a_value) - valid_row (a_row) - valid_column (a_column) - valid (a_value, a_row, a_column) - do - grid [a_row, a_column] := a_value - ensure - item_inserted: grid [a_row, a_column] = a_value - end - -feature -- Change - - solve - -- Try to solve grid. - do - sub_solve (1, 1) - end - -feature {NONE} -- Implementation - - grid: ARRAY2 [INTEGER] - -- Board. - - Default_value: INTEGER = 0 - -- Empty cell content. - - sub_solve (a_row, a_column: INTEGER) - -- Solve grid from row `a_row' and column `a_column'. - require - valid_row (a_row) - valid_column (a_column) - do - if valid_value (grid [a_row, a_column]) then - solve_after (a_row, a_column) - else - across - 1 |..| 9 as ic - until - solved - loop - if valid (ic.item, a_row, a_column) then - put (ic.item, a_row, a_column) - solve_after (a_row, a_column) - - if not solved then - grid [a_row, a_column] := Default_value - end - end - end - end - end - - solve_after (a_row, a_column: INTEGER) - -- Solve the next cell. - require - valid_row (a_row) - valid_column (a_column) - do - if a_column = grid.width then - if a_row = grid.height then - solved := True - else - sub_solve (a_row + 1, 1) - end - else - sub_solve (a_row, a_column + 1) - end - end - -invariant - valid_numbers: solved implies across grid as ic all valid_value (ic.item) end - nine_columns: grid.width = 9 - nine_rows: grid.height = 9 - -end From b651a424f101f1f448c085ac2828757d7b6bb9ab Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 19:12:34 +0200 Subject: [PATCH 087/545] Adding the new Eiffel example. --- demo/kitchen-sink/docs/eiffel.e | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 demo/kitchen-sink/docs/eiffel.e diff --git a/demo/kitchen-sink/docs/eiffel.e b/demo/kitchen-sink/docs/eiffel.e new file mode 100644 index 00000000..943cdb35 --- /dev/null +++ b/demo/kitchen-sink/docs/eiffel.e @@ -0,0 +1,30 @@ +note + description: "Represents a person." + +class + PERSON + +create + make, make_unknown + +feature {NONE} -- Creation + + make (a_name: like name) + -- Create a person with `a_name' as `name'. + do + name := a_name + ensure + name = a_name + end + + make_unknown + do ensure + name = Void + end + +feature -- Access + + name: detachable STRING + -- Full name or Void if unknown. + +end \ No newline at end of file From 0eaae8712e4e52e03ffc3165f86cff0b8dc92c39 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 22 Jul 2014 16:32:40 +0400 Subject: [PATCH 088/545] do not rename kr_theme to kr during the build --- Makefile.dryice.js | 2 +- lib/ace/config.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 2bc36f8b..bac090f7 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -359,7 +359,7 @@ function buildAce(options) { buildSubmodule(options, { projectType: "theme", require: ["ace/theme/" + name] - }, "theme-" + name.replace("_theme", "")); + }, "theme-" + name); }); // keybindings ["vim", "emacs"].forEach(function(name) { diff --git a/lib/ace/config.js b/lib/ace/config.js index f4e4c89a..94e9465f 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -80,11 +80,7 @@ exports.moduleUrl = function(name, component) { // todo make this configurable or get rid of '-' var sep = component == "snippets" ? "/" : "-"; - var base = parts[parts.length - 1]; - if (sep == "-") { - var re = new RegExp("^" + component + "[\\-_]|[\\-_]" + component + "$", "g"); - base = base.replace(re, ""); - } + var base = parts[parts.length - 1]; if ((!base || base == component) && parts.length > 1) base = parts[parts.length - 2]; From 23f678229aaad720b8f82d98743bece56114a2de Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 22 Jul 2014 16:57:14 +0400 Subject: [PATCH 089/545] update config_test.js --- lib/ace/config_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/config_test.js b/lib/ace/config_test.js index d09a2801..ac664fae 100644 --- a/lib/ace/config_test.js +++ b/lib/ace/config_test.js @@ -43,7 +43,7 @@ module.exports = { "test: path resolution" : function() { config.set("packaged", "true"); var url = config.moduleUrl("kr_theme", "theme"); - assert.equal(url, "theme-kr.js"); + assert.equal(url, "theme-kr_theme.js"); config.set("basePath", "a/b"); url = config.moduleUrl("m/theme", "theme"); From d40bec839dc58e2e7c6f5484a350666b8a29731b Mon Sep 17 00:00:00 2001 From: Diego Ferreyra Date: Thu, 24 Jul 2014 17:14:40 -0300 Subject: [PATCH 090/545] ie11 fix getBoundingClientRect() error --- lib/ace/layer/font_metrics.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ace/layer/font_metrics.js b/lib/ace/layer/font_metrics.js index a1423732..a89ed9db 100644 --- a/lib/ace/layer/font_metrics.js +++ b/lib/ace/layer/font_metrics.js @@ -128,7 +128,12 @@ var FontMetrics = exports.FontMetrics = function(parentEl, interval) { this.$measureSizes = function() { if (CHAR_COUNT === 1) { - var rect = this.$measureNode.getBoundingClientRect(); + var rect = null; + try { + rect = this.$measureNode.getBoundingClientRect(); + } catch(e) { + rect = { top : this.$measureNode.offsetTop, left : this.$measureNode.offsetLeft } + }; var size = { height: rect.height, width: rect.width From 80f42e13ffe424ea5ac1f4f68b7e2173a9c39778 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 28 Jul 2014 19:10:41 +0400 Subject: [PATCH 091/545] accept mode options object in static highlight extension --- lib/ace/ext/static_highlight.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/ace/ext/static_highlight.js b/lib/ace/ext/static_highlight.js index 1d69a9bb..9116467b 100644 --- a/lib/ace/ext/static_highlight.js +++ b/lib/ace/ext/static_highlight.js @@ -98,7 +98,6 @@ var highlight = function(el, opts, callback) { * and `css`. * @returns {object} An object containing the properties `html` and `css`. */ - highlight.render = function(input, mode, theme, lineStart, disableGutter, callback) { var waiting = 1; var modeCache = EditSession.prototype.$modes; @@ -112,11 +111,17 @@ highlight.render = function(input, mode, theme, lineStart, disableGutter, callba --waiting || done(); }); } - + // allow setting mode options e.h {path: "ace/mode/php", inline:true} + var modeOptions; + if (mode && typeof mode === "object" && !mode.getTokenizer) { + modeOptions = mode; + mode = modeOptions.path; + } if (typeof mode == "string") { waiting++; config.loadModule(['mode', mode], function(m) { - if (!modeCache[mode]) modeCache[mode] = new m.Mode(); + if (!modeCache[mode] || modeOptions) + modeCache[mode] = new m.Mode(modeOptions); mode = modeCache[mode]; --waiting || done(); }); @@ -130,14 +135,13 @@ highlight.render = function(input, mode, theme, lineStart, disableGutter, callba return --waiting || done(); }; -/* +/** * Transforms a given input code snippet into HTML using the given mode * @param {string} input Code snippet * @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode') * @param {string} r Code snippet * @returns {object} An object containing: html, css */ - highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) { lineStart = parseInt(lineStart || 1, 10); From 7ab9ce686f41fecbe9c95ee993b84b4bcb0a2110 Mon Sep 17 00:00:00 2001 From: Diego Ferreyra Date: Mon, 28 Jul 2014 14:34:39 -0300 Subject: [PATCH 092/545] ie11 fix getBoundingClientRect() error --- lib/ace/layer/font_metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/layer/font_metrics.js b/lib/ace/layer/font_metrics.js index a89ed9db..9100a0f6 100644 --- a/lib/ace/layer/font_metrics.js +++ b/lib/ace/layer/font_metrics.js @@ -132,7 +132,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, interval) { try { rect = this.$measureNode.getBoundingClientRect(); } catch(e) { - rect = { top : this.$measureNode.offsetTop, left : this.$measureNode.offsetLeft } + rect = {width: 0, height:0 } }; var size = { height: rect.height, From b0babd3f255788fdefe5c928a64fe08d8badcb38 Mon Sep 17 00:00:00 2001 From: Diego Ferreyra Date: Mon, 28 Jul 2014 14:37:15 -0300 Subject: [PATCH 093/545] ie11 fix getBoundingClientRect() error missing ";" --- lib/ace/layer/font_metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/layer/font_metrics.js b/lib/ace/layer/font_metrics.js index 9100a0f6..06bd4b0d 100644 --- a/lib/ace/layer/font_metrics.js +++ b/lib/ace/layer/font_metrics.js @@ -132,7 +132,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, interval) { try { rect = this.$measureNode.getBoundingClientRect(); } catch(e) { - rect = {width: 0, height:0 } + rect = {width: 0, height:0 }; }; var size = { height: rect.height, From c673190bf79d1e6c04aa372f0b39e31445031f17 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 22 Jul 2014 03:20:43 +0400 Subject: [PATCH 094/545] allow binding multiple commands to same key --- lib/ace/commands/command_manager.js | 18 ++-- lib/ace/editor.js | 49 +++------ lib/ace/ext/language_tools.js | 4 +- lib/ace/keyboard/emacs.js | 4 +- lib/ace/keyboard/hash_handler.js | 149 +++++++++++++++++----------- lib/ace/lib/keys.js | 3 + 6 files changed, 122 insertions(+), 105 deletions(-) diff --git a/lib/ace/commands/command_manager.js b/lib/ace/commands/command_manager.js index 72a9942d..7b017ed2 100644 --- a/lib/ace/commands/command_manager.js +++ b/lib/ace/commands/command_manager.js @@ -2,13 +2,12 @@ define(function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); -var HashHandler = require("../keyboard/hash_handler").HashHandler; +var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler; var EventEmitter = require("../lib/event_emitter").EventEmitter; /** * @class CommandManager * - * **/ /** @@ -19,20 +18,27 @@ var EventEmitter = require("../lib/event_emitter").EventEmitter; **/ var CommandManager = function(platform, commands) { - HashHandler.call(this, commands, platform); + MultiHashHandler.call(this, commands, platform); this.byName = this.commands; this.setDefaultHandler("exec", function(e) { return e.command.exec(e.editor, e.args || {}); }); }; -oop.inherits(CommandManager, HashHandler); +oop.inherits(CommandManager, MultiHashHandler); (function() { oop.implement(this, EventEmitter); this.exec = function(command, editor, args) { + if (Array.isArray(command)) { + for (var i = command.length; i--; ) { + if (this.exec(command[i], editor, args)) return true; + } + return false; + } + if (typeof command === 'string') command = this.commands[command]; @@ -43,10 +49,10 @@ oop.inherits(CommandManager, HashHandler); return false; var e = {editor: editor, command: command, args: args}; - var retvalue = this._emit("exec", e); + e.returnValue = this._emit("exec", e); this._signal("afterExec", e); - return retvalue === false ? false : true; + return e.returnValue === false ? false : true; }; this.toggleRecording = function(editor) { diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 6a68e5de..6c1a9200 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -114,30 +114,8 @@ var Editor = function(renderer, session) { function last(a) {return a[a.length - 1]} this.selections = []; - this.commands.on("exec", function(e) { - this.startOperation(e); - - var command = e.command; - if (command.aceCommandGroup == "fileJump") { - var prev = this.prevOp; - if (!prev || prev.command.aceCommandGroup != "fileJump") { - this.lastFileJumpPos = last(this.selections); - } - } else { - this.lastFileJumpPos = null; - } - }.bind(this), true); - - this.commands.on("afterExec", function(e) { - var command = e.command; - - if (command.aceCommandGroup == "fileJump") { - if (this.lastFileJumpPos && !this.curOp.selectionChanged) { - this.selection.fromJSON(this.lastFileJumpPos); - } - } - this.endOperation(e); - }.bind(this), true); + this.commands.on("exec", this.startOperation.bind(this), true); + this.commands.on("afterExec", this.endOperation.bind(this), true); this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this)); @@ -172,18 +150,16 @@ var Editor = function(renderer, session) { scrollTop: this.renderer.scrollTop }; - var command = this.curOp.command; - if (command && command.scrollIntoView) - this.$blockScrolling++; - - this.selections.push(this.selection.toJSON()); + // this.selections.push(this.selection.toJSON()); }; - this.endOperation = function() { + this.endOperation = function(e) { if (this.curOp) { + if (e && e.returnValue === false) + return this.curOp = null; + var command = this.curOp.command; if (command && command.scrollIntoView) { - this.$blockScrolling--; switch (command.scrollIntoView) { case "center": this.renderer.scrollCursorIntoView(null, 0.5); @@ -254,19 +230,19 @@ var Editor = function(renderer, session) { * @param {String} keyboardHandler The new key handler * **/ - this.setKeyboardHandler = function(keyboardHandler) { - if (!keyboardHandler) { - this.keyBinding.setKeyboardHandler(null); - } else if (typeof keyboardHandler === "string") { + this.setKeyboardHandler = function(keyboardHandler, cb) { + if (keyboardHandler && typeof keyboardHandler === "string") { this.$keybindingId = keyboardHandler; var _self = this; config.loadModule(["keybinding", keyboardHandler], function(module) { if (_self.$keybindingId == keyboardHandler) _self.keyBinding.setKeyboardHandler(module && module.handler); + cb && cb(); }); } else { this.$keybindingId = null; this.keyBinding.setKeyboardHandler(keyboardHandler); + cb && cb(); } }; @@ -925,9 +901,8 @@ var Editor = function(renderer, session) { this.insert(e.text, true); }; - this.execCommand = function(command, args) { - this.commands.exec(command, this, args); + return this.commands.exec(command, this, args); }; /** diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index d8b2a1dd..9d10695d 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -80,9 +80,7 @@ exports.snippetCompleter = snippetCompleter; var expandSnippet = { name: "expandSnippet", exec: function(editor) { - var success = snippetManager.expandWithTab(editor); - if (!success) - editor.execCommand("indent"); + return snippetManager.expandWithTab(editor); }, bindKey: "Tab" }; diff --git a/lib/ace/keyboard/emacs.js b/lib/ace/keyboard/emacs.js index f1adb9ef..c15f07d0 100644 --- a/lib/ace/keyboard/emacs.js +++ b/lib/ace/keyboard/emacs.js @@ -64,7 +64,7 @@ exports.handler.attach = function(editor) { initialized = true; dom.importCssString('\ .emacs-mode .ace_cursor{\ - border: 2px rgba(50,250,50,0.8) solid!important;\ + border: 1px rgba(50,250,50,0.8) solid!important;\ -moz-box-sizing: border-box!important;\ -webkit-box-sizing: border-box!important;\ box-sizing: border-box!important;\ @@ -195,6 +195,8 @@ exports.handler.onPaste = function(e, editor) { }; exports.handler.bindKey = function(key, command) { + if (typeof key == "object") + key = key[this.platform]; if (!key) return; diff --git a/lib/ace/keyboard/hash_handler.js b/lib/ace/keyboard/hash_handler.js index cb02f170..06badccd 100644 --- a/lib/ace/keyboard/hash_handler.js +++ b/lib/ace/keyboard/hash_handler.js @@ -33,37 +33,25 @@ define(function(require, exports, module) { var keyUtil = require("../lib/keys"); var useragent = require("../lib/useragent"); +var KEY_MODS = keyUtil.KEY_MODS; function HashHandler(config, platform) { this.platform = platform || (useragent.isMac ? "mac" : "win"); this.commands = {}; this.commandKeyBinding = {}; - - // todo remove this after a while - if (this.__defineGetter__ && this.__defineSetter__ && typeof console != "undefined" && console.error) { - var warned = false; - var warn = function() { - if (!warned) { - warned = true; - console.error("commmandKeyBinding has too many m's. use commandKeyBinding"); - } - }; - this.__defineGetter__("commmandKeyBinding", function() { - warn(); - return this.commandKeyBinding; - }); - this.__defineSetter__("commmandKeyBinding", function(val) { - warn(); - return this.commandKeyBinding = val; - }); - } else { - this.commmandKeyBinding = this.commandKeyBinding; - } - this.addCommands(config); -}; + this.$singleCommand = true; +} + +function MultiHashHandler(config, platform) { + HashHandler.call(this, config, platform); + this.$singleCommand = false; +} + +MultiHashHandler.prototype = HashHandler.prototype; (function() { + this.addCommand = function(command) { if (this.commands[command.name]) @@ -75,37 +63,76 @@ function HashHandler(config, platform) { this._buildKeyHash(command); }; - this.removeCommand = function(command) { - var name = (typeof command === 'string' ? command : command.name); + this.removeCommand = function(command, keepCommand) { + var name = command && (typeof command === 'string' ? command : command.name); command = this.commands[name]; - delete this.commands[name]; + if (!keepCommand) + delete this.commands[name]; // exhaustive search is brute force but since removeCommand is // not a performance critical operation this should be OK var ckb = this.commandKeyBinding; - for (var hashId in ckb) { - for (var key in ckb[hashId]) { - if (ckb[hashId][key] == command) - delete ckb[hashId][key]; + for (var keyId in ckb) { + var cmdGroup = ckb[keyId]; + if (cmdGroup == command) { + delete ckb[keyId]; + } else if (Array.isArray(cmdGroup)) { + var i = cmdGroup.indexOf(command); + if (i != -1) { + cmdGroup.splice(i, 1); + if (cmdGroup.length == 1) + ckb[keyId] = cmdGroup[0]; + } } } }; - this.bindKey = function(key, command) { - if(!key) + this.bindKey = function(key, command, asDefault) { + if (typeof key == "object") + key = key[this.platform]; + if (!key) return; - if (typeof command == "function") { - this.addCommand({exec: command, bindKey: key, name: command.name || key}); - return; - } - - var ckb = this.commandKeyBinding; + if (typeof command == "function") + return this.addCommand({exec: command, bindKey: key, name: command.name || key}); + key.split("|").forEach(function(keyPart) { - var binding = this.parseKeys(keyPart, command); - var hashId = binding.hashId; - (ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command; + var chain = ""; + if (keyPart.indexOf(" ") != -1) { + var parts = keyPart.split(/\s+/); + keyPart = parts.pop(); + parts.forEach(function(keyPart) { + var binding = this.parseKeys(keyPart); + var id = KEY_MODS[binding.hashId] + binding.key; + chain += (chain ? " " : "") + id; + this._addCommandToBinding(chain, "chainKeys"); + }, this); + chain += " "; + } + var binding = this.parseKeys(keyPart); + var id = KEY_MODS[binding.hashId] + binding.key; + this._addCommandToBinding(chain + id, command, asDefault); }, this); }; + + this._addCommandToBinding = function(keyId, command, asDefault) { + var ckb = this.commandKeyBinding, i; + if (!command) { + delete ckb[keyId]; + } else if (!ckb[keyId] || this.$singleCommand) { + ckb[keyId] = command; + } else { + if (!Array.isArray(ckb[keyId])) { + ckb[keyId] = [ckb[keyId]]; + } else if ((i = ckb[keyId].indexOf(command)) != -1) { + ckb[keyId].splice(i, 1); + } + + if (asDefault || command.isDefault) + ckb[keyId].unshift(command); + else + ckb[keyId].push(command); + } + }; this.addCommands = function(commands) { commands && Object.keys(commands).forEach(function(name) { @@ -142,21 +169,12 @@ function HashHandler(config, platform) { }; this._buildKeyHash = function(command) { - var binding = command.bindKey; - if (!binding) - return; - - var key = typeof binding == "string" ? binding: binding[this.platform]; - this.bindKey(key, command); + this.bindKey(command.bindKey, command); }; // accepts keys in the form ctrl+Enter or ctrl-Enter // keys without modifiers or shift only this.parseKeys = function(keys) { - // todo support keychains - if (keys.indexOf(" ") != -1) - keys = keys.split(/\s+/).pop(); - var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x}); var key = parts.pop(); @@ -173,7 +191,7 @@ function HashHandler(config, platform) { var modifier = keyUtil.KEY_MODS[parts[i]]; if (modifier == null) { if (typeof console != "undefined") - console.error("invalid modifier " + parts[i] + " in " + keys); + console.error("invalid modifier " + parts[i] + " in " + keys); return false; } hashId |= modifier; @@ -182,17 +200,32 @@ function HashHandler(config, platform) { }; this.findKeyCommand = function findKeyCommand(hashId, keyString) { - var ckbr = this.commandKeyBinding; - return ckbr[hashId] && ckbr[hashId][keyString]; + var key = KEY_MODS[hashId] + keyString; + return this.commandKeyBinding[key]; }; this.handleKeyboard = function(data, hashId, keyString, keyCode) { - return { - command: this.findKeyCommand(hashId, keyString) - }; + var key = KEY_MODS[hashId] + keyString; + var command = this.commandKeyBinding[key]; + if (data.$keyChain) { + data.$keyChain += " " + key; + command = this.commandKeyBinding[data.$keyChain] || command; + } + + if (command) { + if (command == "chainKeys" || command[command.length - 1] == "chainKeys") { + data.$keyChain = data.$keyChain || key; + return {command: "null"}; + } + } + + if (data.$keyChain && keyCode > 0) + data.$keyChain = ""; + return {command: command}; }; -}).call(HashHandler.prototype) +}).call(HashHandler.prototype); exports.HashHandler = HashHandler; +exports.MultiHashHandler = MultiHashHandler; }); diff --git a/lib/ace/lib/keys.js b/lib/ace/lib/keys.js index e708a5d4..e3c19214 100644 --- a/lib/ace/lib/keys.js +++ b/lib/ace/lib/keys.js @@ -143,6 +143,9 @@ var Keys = (function() { } })(); + ret.KEY_MODS[0] = ""; + ret.KEY_MODS[-1] = "input"; + return ret; })(); oop.mixin(exports, Keys); From b2612c6039e74972cff414eb17f2346993609fed Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 29 Jul 2014 17:40:43 +0400 Subject: [PATCH 095/545] cleanup emmet extension --- lib/ace/ext/emmet.js | 82 +++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/lib/ace/ext/emmet.js b/lib/ace/ext/emmet.js index e547ae4d..75eefa3f 100644 --- a/lib/ace/ext/emmet.js +++ b/lib/ace/ext/emmet.js @@ -34,15 +34,7 @@ var HashHandler = require("ace/keyboard/hash_handler").HashHandler; var Editor = require("ace/editor").Editor; var snippetManager = require("ace/snippets").snippetManager; var Range = require("ace/range").Range; -var emmet; - -Editor.prototype.indexToPosition = function(index) { - return this.session.doc.indexToPosition(index); -}; - -Editor.prototype.positionToIndex = function(pos) { - return this.session.doc.positionToIndex(pos); -}; +var emmet, emmetPath; /** * Implementation of {@link IEmmetEditor} interface for Ace @@ -72,9 +64,10 @@ AceEmmetEditor.prototype = { getSelectionRange: function() { // TODO should start be caret position instead? var range = this.ace.getSelectionRange(); + var doc = this.ace.session.doc; return { - start: this.ace.positionToIndex(range.start), - end: this.ace.positionToIndex(range.end) + start: doc.positionToIndex(range.start), + end: doc.positionToIndex(range.end) }; }, @@ -91,9 +84,10 @@ AceEmmetEditor.prototype = { * editor.createSelection(15); */ createSelection: function(start, end) { + var doc = this.ace.session.doc; this.ace.selection.setRange({ - start: this.ace.indexToPosition(start), - end: this.ace.indexToPosition(end) + start: doc.indexToPosition(start), + end: doc.indexToPosition(end) }); }, @@ -106,9 +100,10 @@ AceEmmetEditor.prototype = { * alert(range.start + ', ' + range.end); */ getCurrentLineRange: function() { - var row = this.ace.getCursorPosition().row; - var lineLength = this.ace.session.getLine(row).length; - var index = this.ace.positionToIndex({row: row, column: 0}); + var ace = this.ace; + var row = ace.getCursorPosition().row; + var lineLength = ace.session.getLine(row).length; + var index = ace.session.doc.positionToIndex({row: row, column: 0}); return { start: index, end: index + lineLength @@ -121,7 +116,7 @@ AceEmmetEditor.prototype = { */ getCaretPos: function(){ var pos = this.ace.getCursorPosition(); - return this.ace.positionToIndex(pos); + return this.ace.session.doc.positionToIndex(pos); }, /** @@ -129,7 +124,7 @@ AceEmmetEditor.prototype = { * @param {Number} index Caret position */ setCaretPos: function(index){ - var pos = this.ace.indexToPosition(index); + var pos = this.ace.session.doc.indexToPosition(index); this.ace.selection.moveToPosition(pos); }, @@ -169,14 +164,15 @@ AceEmmetEditor.prototype = { start = 0; var editor = this.ace; - var range = Range.fromPoints(editor.indexToPosition(start), editor.indexToPosition(end)); + var doc = editor.session.doc; + var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end)); editor.session.remove(range); range.end = range.start; //editor.selection.setRange(range); value = this.$updateTabstops(value); - snippetManager.insertSnippet(editor, value) + snippetManager.insertSnippet(editor, value); }, /** @@ -292,7 +288,7 @@ AceEmmetEditor.prototype = { lastZero = range.create(data.start, result); } - return result + return result; }, escape: function(ch) { if (ch == '$') return '\\$'; @@ -363,12 +359,17 @@ exports.runEmmetCommand = function(editor) { }, 0); } + var pos = editor.selection.lead; + var token = editor.session.getTokenAt(pos.row, pos.column); + if (token && /\btag\b/.test(token.type)) + return false; + try { var result = actions.run(this.action, editorProxy); } catch(e) { editor._signal("changeStatus", typeof e == "string" ? e : e.message); console.log(e); - result = false + result = false; } return result; }; @@ -383,21 +384,36 @@ for (var command in keymap) { }); } +exports.updateCommands = function(editor, enabled) { + if (enabled) { + editor.keyBinding.addKeyboardHandler(exports.commands); + } else { + editor.keyBinding.removeKeyboardHandler(exports.commands); + } +}; + +exports.isSupportedMode = function(modeId) { + return modeId && /css|less|scss|sass|stylus|html|php|twig/.test(modeId); +}; + var onChangeMode = function(e, target) { var editor = target; if (!editor) return; - var modeId = editor.session.$modeId; - var enabled = modeId && /css|less|scss|sass|stylus|html|php/.test(modeId); + var enabled = exports.isSupportedMode(editor.session.$modeId); if (e.enableEmmet === false) enabled = false; - if (enabled) - editor.keyBinding.addKeyboardHandler(exports.commands); - else - editor.keyBinding.removeKeyboardHandler(exports.commands); + if (enabled) { + if (typeof emmetPath == "string") { + require("ace/config").loadModule(emmetPath, function() { + + }); + emmetPath = null; + } + } + exports.updateCommands(editor, enabled); }; - exports.AceEmmetEditor = AceEmmetEditor; require("ace/config").defineOptions(Editor.prototype, "editor", { enableEmmet: { @@ -409,7 +425,11 @@ require("ace/config").defineOptions(Editor.prototype, "editor", { } }); - -exports.setCore = function(e) {emmet = e;}; +exports.setCore = function(e) { + if (typeof e == "string") + emmetPath = e; + else + emmet = e; +}; }); From a00ce9cd72d5b2f417fb8ed5d9282bfaa5a54182 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 1 Aug 2014 20:47:49 +0400 Subject: [PATCH 096/545] update keyboard shortcuts extension --- .../get_editor_keyboard_shortcuts.js | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js b/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js index e412bfba..99e006b0 100644 --- a/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js +++ b/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js @@ -69,29 +69,20 @@ module.exports.getEditorKeybordShortcuts = function(editor) { editor.keyBinding.$handlers.forEach(function(handler) { var ckb = handler.commandKeyBinding; for (var i in ckb) { - var modifier = parseInt(i); - if (modifier == -1) { - modifier = ""; - } else if(isNaN(modifier)) { - modifier = i; - } else { - modifier = "" + - (modifier & KEY_MODS.command ? "Cmd-" : "") + - (modifier & KEY_MODS.ctrl ? "Ctrl-" : "") + - (modifier & KEY_MODS.alt ? "Alt-" : "") + - (modifier & KEY_MODS.shift ? "Shift-" : ""); - } - for (var key in ckb[i]) { - var command = ckb[i][key] + var key = i.replace(/(^|-)\w/g, function(x) { return x.toUpperCase(); }); + var commands = ckb[i]; + if (!Array.isArray(commands)) + commands = [commands]; + commands.forEach(function(command) { if (typeof command != "string") command = command.name if (commandMap[command]) { - commandMap[command].key += "|" + modifier + key; + commandMap[command].key += "|" + key; } else { - commandMap[command] = {key: modifier+key, command: command}; + commandMap[command] = {key: key, command: command}; keybindings.push(commandMap[command]); - } - } + } + }); } }); return keybindings; From f4990b3a56d04b8245ad4b57199e56907b40c98d Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 1 Aug 2014 21:45:43 +0400 Subject: [PATCH 097/545] make sure text redraw isn't missed when bgTokenizer state changes --- lib/ace/background_tokenizer.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index b2ba3733..da8008bd 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -36,8 +36,6 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter; /** - * - * * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. * * If a certain row is changed, everything below that row is re-tokenized. @@ -50,8 +48,6 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter; * @param {Tokenizer} tokenizer The tokenizer to use * @param {Editor} editor The editor to associate with * - * - * * @constructor **/ @@ -89,10 +85,9 @@ var BackgroundTokenizer = function(tokenizer, editor) { // only check every 5 lines processedLines ++; - if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) { + if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) { self.running = setTimeout(self.$worker, 20); - self.currentLine = currentLine; - return; + break; } } self.currentLine = currentLine; From 72dcd289050f0d129139906960dbe822e06eaedc Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 1 Aug 2014 22:06:43 +0400 Subject: [PATCH 098/545] trigger redraw less often --- lib/ace/editor.js | 2 +- lib/ace/virtual_renderer.js | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index e198ecaa..83782f06 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -702,7 +702,7 @@ var Editor = function(renderer, session) { lastRow = range.end.row; else lastRow = Infinity; - this.renderer.updateLines(range.start.row, lastRow); + this.renderer.updateLines(range.start.row, lastRow, this.session.$useWrapMode); this._signal("change", e); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index dfb435be..d3e26758 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -258,7 +258,7 @@ var VirtualRenderer = function(container, theme) { * * **/ - this.updateLines = function(firstRow, lastRow) { + this.updateLines = function(firstRow, lastRow, force) { if (lastRow === undefined) lastRow = Infinity; @@ -279,9 +279,13 @@ var VirtualRenderer = function(container, theme) { // If the change happened offscreen above us then it's possible // that a new line wrap will affect the position of the lines on our // screen so they need redrawn. - if (this.$changedLines.lastRow < this.layerConfig.firstRow) - this.$changedLines.lastRow = this.layerConfig.lastRow - + // TODO: better solution is to not change scroll position when text is changed outside of visible area + if (this.$changedLines.lastRow < this.layerConfig.firstRow) { + if (force) + this.$changedLines.lastRow = this.layerConfig.lastRow; + else + return; + } if (this.$changedLines.firstRow > this.layerConfig.lastRow) return; this.$loop.schedule(this.CHANGE_LINES); From 5744a3c6e3fc0c15b4fb22803db339e690f38f7f Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 1 Aug 2014 20:53:08 +0400 Subject: [PATCH 099/545] fix bracket matching in vala mode --- lib/ace/mode/vala_highlight_rules.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ace/mode/vala_highlight_rules.js b/lib/ace/mode/vala_highlight_rules.js index f199426d..b4a96a3d 100644 --- a/lib/ace/mode/vala_highlight_rules.js +++ b/lib/ace/mode/vala_highlight_rules.js @@ -136,7 +136,7 @@ var ValaHighlightRules = function() { [ { token: 'meta.class.vala', regex: '(?=\\w?[\\w\\s]*(?:class|(?:@)?interface|enum|struct|namespace)\\s+\\w+)', push: - [ { token: 'punctuation.section.class.end.vala', + [ { token: 'paren.vala', regex: '}', next: 'pop' }, { include: '#storage-modifiers' }, @@ -166,10 +166,10 @@ var ValaHighlightRules = function() { { include: '#object-types-inherited' }, { include: '#comments' }, { defaultToken: 'meta.definition.class.implemented.interfaces.vala' } ] }, - { token: 'meta.class.body.vala', + { token: 'paren.vala', regex: '{', push: - [ { token: 'meta.class.body.vala', regex: '(?=})', next: 'pop' }, + [ { token: 'paren.vala', regex: '(?=})', next: 'pop' }, { include: '#class-body' }, { defaultToken: 'meta.class.body.vala' } ] }, { defaultToken: 'meta.class.vala' } ], @@ -266,7 +266,7 @@ var ValaHighlightRules = function() { [ { token: 'meta.method.vala', regex: '(?!new)(?=\\w.*\\s+)(?=[^=]+\\()', push: - [ { token: 'meta.method.vala', regex: '}|(?=;)', next: 'pop' }, + [ { token: 'paren.vala', regex: '}|(?=;)', next: 'pop' }, { include: '#storage-modifiers' }, { token: [ 'entity.name.function.vala', 'meta.method.identifier.vala' ], regex: '([\\~\\w\\.]+)(\\s*\\()', @@ -285,10 +285,10 @@ var ValaHighlightRules = function() { { include: '#all-types' }, { defaultToken: 'meta.method.return-type.vala' } ] }, { include: '#throws' }, - { token: 'meta.method.body.vala', + { token: 'paren.vala', regex: '{', push: - [ { token: 'meta.method.body.vala', regex: '(?=})', next: 'pop' }, + [ { token: 'paren.vala', regex: '(?=})', next: 'pop' }, { include: '#code' }, { defaultToken: 'meta.method.body.vala' } ] }, { defaultToken: 'meta.method.vala' } ] } ], From dfee7408020c6c86b41983d78b10b856720202df Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 1 Aug 2014 22:33:32 +0400 Subject: [PATCH 100/545] update command_manager test --- lib/ace/commands/command_manager_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/commands/command_manager_test.js b/lib/ace/commands/command_manager_test.js index 76d973bb..902600be 100644 --- a/lib/ace/commands/command_manager_test.js +++ b/lib/ace/commands/command_manager_test.js @@ -188,7 +188,7 @@ module.exports = { assert.equal(command, "cm2"); var command = this.cm.findKeyCommand(0, "return"); - assert.equal(command, "cm3"); + assert.equal(command + "", ["cm4", "cm3"] + ""); } }; From b990ad3f90f14f99cfbe8bcb2a807027cfee7228 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 2 Aug 2014 00:56:34 +0400 Subject: [PATCH 101/545] update csslint --- lib/ace/mode/css/csslint.js | 968 ++++++++++++++++++++++++------------ lib/ace/mode/css_worker.js | 7 +- 2 files changed, 647 insertions(+), 328 deletions(-) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index a3a7a9bd..c3c79a80 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -4,7 +4,7 @@ CSSLint Copyright (c) 2014 Nicole Sullivan and Nicholas C. Zakas. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal +of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is @@ -13,7 +13,7 @@ furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* Build: v0.10.0 31-March-2014 08:16:48 */ +/* Build: v0.10.0 22-July-2014 01:17:52 */ /*! Parser-Lib Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. @@ -46,11 +46,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* Version v0.2.4, Build time: 7-January-2014 07:32:49 */ +/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */ var parserlib = {}; (function(){ - /** * A generic base to inherit from for any object * that needs event handling. @@ -506,7 +505,7 @@ SyntaxUnit.prototype = { * @method valueOf */ valueOf: function(){ - return this.toString(); + return this.text; }, /** @@ -921,8 +920,6 @@ TokenStreamBase.prototype = { }; - - parserlib.util = { StringReader: StringReader, SyntaxError : SyntaxError, @@ -931,8 +928,6 @@ EventTarget : EventTarget, TokenStreamBase : TokenStreamBase }; })(); - - /* Parser-Lib Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. @@ -956,7 +951,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* Version v0.2.4, Build time: 7-January-2014 07:32:49 */ +/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */ (function(){ var EventTarget = parserlib.util.EventTarget, TokenStreamBase = parserlib.util.TokenStreamBase, @@ -964,7 +959,6 @@ StringReader = parserlib.util.StringReader, SyntaxError = parserlib.util.SyntaxError, SyntaxUnit = parserlib.util.SyntaxUnit; - var Colors = { aliceblue :"#f0f8ff", antiquewhite :"#faebd7", @@ -1182,7 +1176,6 @@ function Combinator(text, line, col){ Combinator.prototype = new SyntaxUnit(); Combinator.prototype.constructor = Combinator; - /*global SyntaxUnit, Parser*/ /** * Represents a media feature, such as max-width:500. @@ -1215,7 +1208,6 @@ function MediaFeature(name, value){ MediaFeature.prototype = new SyntaxUnit(); MediaFeature.prototype.constructor = MediaFeature; - /*global SyntaxUnit, Parser*/ /** * Represents an individual media query. @@ -1259,7 +1251,6 @@ function MediaQuery(modifier, mediaType, features, line, col){ MediaQuery.prototype = new SyntaxUnit(); MediaQuery.prototype.constructor = MediaQuery; - /*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit, PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector, PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */ @@ -1521,7 +1512,7 @@ Parser.prototype = function(){ tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); //grab the URI value - uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); this._readWhitespace(); @@ -1626,8 +1617,10 @@ Parser.prototype = function(){ while(true) { if (tokenStream.peek() == Tokens.PAGE_SYM){ this._page(); - } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ + } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ this._font_face(); + } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ + this._viewport(); } else if (!this._ruleset()){ break; } @@ -2823,7 +2816,7 @@ Parser.prototype = function(){ value = null, operator = null; - value = this._term(); + value = this._term(inFunction); if (value !== null){ values.push(value); @@ -2840,7 +2833,7 @@ Parser.prototype = function(){ valueParts = []; }*/ - value = this._term(); + value = this._term(inFunction); if (value === null){ break; @@ -2858,7 +2851,7 @@ Parser.prototype = function(){ return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; }, - _term: function(){ + _term: function(inFunction){ /* * term @@ -2872,6 +2865,7 @@ Parser.prototype = function(){ var tokenStream = this._tokenStream, unary = null, value = null, + endChar = null, token, line, col; @@ -2892,6 +2886,20 @@ Parser.prototype = function(){ col = tokenStream.token().startCol; } + //see if it's a simple block + } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ + + token = tokenStream.token(); + endChar = token.endChar; + value = token.value + this._expr(inFunction).text; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + tokenStream.mustMatch(Tokens.type(endChar)); + value += endChar; + this._readWhitespace(); + //see if there's a simple match } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, Tokens.ANGLE, Tokens.TIME, @@ -3536,7 +3544,6 @@ nth ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* ; */ - /*global Validation, ValidationTypes, ValidationError*/ var Properties = { @@ -3553,6 +3560,7 @@ var Properties = { "animation-delay" : { multi: "
diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 78c7c18d..f487b49e 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1655,9 +1655,7 @@ var Editor = function(renderer, session) { * @related EditSession.moveLinesUp **/ this.moveLinesDown = function() { - this.$moveLines(function(firstRow, lastRow) { - return this.session.moveLinesDown(firstRow, lastRow); - }); + this.$moveLines(1, false); }; /** @@ -1666,9 +1664,7 @@ var Editor = function(renderer, session) { * @related EditSession.moveLinesDown **/ this.moveLinesUp = function() { - this.$moveLines(function(firstRow, lastRow) { - return this.session.moveLinesUp(firstRow, lastRow); - }); + this.$moveLines(-1, false); }; /** @@ -1692,10 +1688,7 @@ var Editor = function(renderer, session) { * **/ this.copyLinesUp = function() { - this.$moveLines(function(firstRow, lastRow) { - this.session.duplicateLines(firstRow, lastRow); - return 0; - }); + this.$moveLines(-1, true); }; /** @@ -1705,51 +1698,61 @@ var Editor = function(renderer, session) { * **/ this.copyLinesDown = function() { - this.$moveLines(function(firstRow, lastRow) { - return this.session.duplicateLines(firstRow, lastRow); - }); + this.$moveLines(1, true); }; /** - * Executes a specific function, which can be anything that manipulates selected lines, such as copying them, duplicating them, or shifting them. - * @param {Function} mover A method to call on each selected row - * + * for internal use + * @ignore * **/ - this.$moveLines = function(mover) { + this.$moveLines = function(dir, copy) { + var rows, moved; var selection = this.selection; if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) { var range = selection.toOrientedRange(); - var rows = this.$getSelectedRows(range); - var linesMoved = mover.call(this, rows.first, rows.last); - range.moveBy(linesMoved, 0); + rows = this.$getSelectedRows(range); + moved = this.session.$moveLines(rows.first, rows.last, copy ? 0 : dir); + if (copy && dir == -1) moved = 0; + range.moveBy(moved, 0); selection.fromOrientedRange(range); } else { var ranges = selection.rangeList.ranges; selection.rangeList.detach(this.session); - - for (var i = ranges.length; i--; ) { + this.inVirtualSelectionMode = true; + + var diff = 0; + var totalDiff = 0; + var l = ranges.length; + for (var i = 0; i < l; i++) { var rangeIndex = i; - var rows = ranges[i].collapseRows(); - var last = rows.end.row; - var first = rows.start.row; - while (i--) { - rows = ranges[i].collapseRows(); - if (first - rows.end.row <= 1) - first = rows.end.row; - else + ranges[i].moveBy(diff, 0); + rows = this.$getSelectedRows(ranges[i]); + var first = rows.first; + var last = rows.last; + while (++i < l) { + if (totalDiff) ranges[i].moveBy(totalDiff, 0); + var subRows = this.$getSelectedRows(ranges[i]); + if (copy && subRows.first != last) break; + else if (!copy && subRows.first > last + 1) + break; + last = subRows.last; } - i++; - - var linesMoved = mover.call(this, first, last); - while (rangeIndex >= i) { - ranges[rangeIndex].moveBy(linesMoved, 0); - rangeIndex--; + i--; + diff = this.session.$moveLines(first, last, copy ? 0 : dir); + if (copy && dir == -1) rangeIndex = i + 1; + while (rangeIndex <= i) { + ranges[rangeIndex].moveBy(diff, 0); + rangeIndex++; } + if (!copy) diff = 0; + totalDiff += diff; } + selection.fromOrientedRange(selection.ranges[0]); selection.rangeList.attach(this.session); + this.inVirtualSelectionMode = false; } }; @@ -1762,8 +1765,8 @@ var Editor = function(renderer, session) { * * @returns {Object} **/ - this.$getSelectedRows = function() { - var range = this.getSelectionRange().collapseRows(); + this.$getSelectedRows = function(range) { + range = (range || this.getSelectionRange()).collapseRows(); return { first: this.session.getRowFoldStart(range.start.row), diff --git a/lib/ace/multi_select_test.js b/lib/ace/multi_select_test.js index 2e71aefa..1eccc4ce 100644 --- a/lib/ace/multi_select_test.js +++ b/lib/ace/multi_select_test.js @@ -51,6 +51,45 @@ var exec = function(name, times, args) { var testRanges = function(str) { assert.equal(editor.selection.getAllRanges() + "", str + ""); }; +function getSelection(editor) { + var data = editor.multiSelect.toJSON(); + if (!data.length) data = [data]; + data = data.map(function(x) { + var a, c; + if (x.isBackwards) { + a = x.end; + c = x.start; + } else { + c = x.end; + a = x.start; + } + return Range.comparePoints(a, c) + ? [a.row, a.column, c.row, c.column] + : [a.row, a.column]; + }); + return data.length > 1 ? data : data[0]; +} +function testSelection(editor, data) { + assert.equal(getSelection(editor) + "", data + ""); +} +function setSelection(editor, data) { + if (typeof data[0] == "number") + data = [data]; + editor.selection.fromJSON(data.map(function(x) { + var start = {row: x[0], column: x[1]}; + var end = x.length == 2 ? start : {row: x[2], column: x[3]}; + var isBackwards = Range.comparePoints(start, end) > 0; + return isBackwards ? { + start: end, + end: start, + isBackwards: true + } : { + start: start, + end: end, + isBackwards: true + }; + })); +} module.exports = { @@ -167,6 +206,37 @@ module.exports = { editor.execCommand('insertfoo'); assert.equal('l1foo\nl2foo', editor.getValue()); }, + + "test multiselect move lines": function() { + editor = new Editor(new MockRenderer()); + + editor.setValue("l1\nl2\nl3\nl4", -1); + setSelection(editor, [[0,2],[1,2],[2,2],[3,2]]); + + exec("copylinesdown"); + assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4"); + testSelection(editor, [[1,2],[3,2],[5,2],[7,2]]); + exec("copylinesup"); + assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4"); + testSelection(editor, [[1,2],[4,2],[7,2],[10,2]]); + exec("removeline"); + assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4"); + testSelection(editor, [[1,0],[3,0],[5,0],[7,0]]); + + setSelection(editor, [[1,2],[1,0,1,1],[3,0,3,1],[5,0,5,1],[7,0,7,1]]); + exec("copylinesdown"); + exec("copylinesup"); + assert.equal(editor.getValue(),"l1\nl1\nl1\nl1\nl2\nl2\nl2\nl2\nl3\nl3\nl3\nl3\nl4\nl4\nl4\nl4"); + testSelection(editor, [[2,2],[2,0,2,1],[6,0,6,1],[10,0,10,1],[14,0,14,1]]); + + exec("movelinesdown", 12); + assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4\nl1\nl2\nl3\nl4"); + testSelection(editor, [[12,2],[12,0,12,1],[13,0,13,1],[14,0,14,1],[15,0,15,1]]); + + exec("movelinesup", 12); + assert.equal(editor.getValue(),"l1\nl2\nl3\nl4\nl1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4"); + testSelection(editor, [[0,2],[0,0,0,1],[1,0,1,1],[2,0,2,1],[3,0,3,1]]); + }, "test multiselect fromJSON/toJSON": function() { var doc = new EditSession(["l1", "l2"]); From ec18d9493d89805f702e66854f84c687ac0d6f89 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 21 Nov 2014 01:04:11 +0400 Subject: [PATCH 327/545] fix toggleComment command in php mode --- lib/ace/mode/php.js | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/lib/ace/mode/php.js b/lib/ace/mode/php.js index 2754ef51..c7688d43 100644 --- a/lib/ace/mode/php.js +++ b/lib/ace/mode/php.js @@ -55,6 +55,24 @@ oop.inherits(PhpMode, TextMode); (function() { + this.tokenRe = new RegExp("^[" + + unicode.packages.L + + unicode.packages.Mn + unicode.packages.Mc + + unicode.packages.Nd + + unicode.packages.Pc + "\_]+", "g" + ); + + this.nonTokenRe = new RegExp("^(?:[^" + + unicode.packages.L + + unicode.packages.Mn + unicode.packages.Mc + + unicode.packages.Nd + + unicode.packages.Pc + "\_]|\s])+", "g" + ); + + + this.lineCommentStart = ["//", "#"]; + this.blockComment = {start: "/*", end: "*/"}; + this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); @@ -100,8 +118,10 @@ oop.inherits(PhpMode, TextMode); var Mode = function(opts) { if (opts && opts.inline) { - PhpMode.call(this); - return; + var mode = new PhpMode(); + mode.createWorker = this.createWorker; + mode.inlinePhp = true; + return mode; } HtmlMode.call(this); this.HighlightRules = PhpHighlightRules; @@ -116,24 +136,6 @@ oop.inherits(Mode, HtmlMode); (function() { - this.tokenRe = new RegExp("^[" - + unicode.packages.L - + unicode.packages.Mn + unicode.packages.Mc - + unicode.packages.Nd - + unicode.packages.Pc + "\_]+", "g" - ); - - this.nonTokenRe = new RegExp("^(?:[^" - + unicode.packages.L - + unicode.packages.Mn + unicode.packages.Mc - + unicode.packages.Nd - + unicode.packages.Pc + "\_]|\s])+", "g" - ); - - - this.lineCommentStart = ["//", "#"]; - this.blockComment = {start: "/*", end: "*/"}; - this.createWorker = function(session) { var worker = new WorkerClient(["ace"], "ace/mode/php_worker", "PhpWorker"); worker.attachToDocument(session.getDocument()); From 6b13aedf5f45fad451dea7a0bb2431ea9737ce53 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 4 Dec 2014 14:47:17 +0400 Subject: [PATCH 328/545] do not pair quotes inside strings --- lib/ace/mode/behaviour/behaviour_test.js | 9 +++++++++ lib/ace/mode/behaviour/cstyle.js | 2 ++ 2 files changed, 11 insertions(+) diff --git a/lib/ace/mode/behaviour/behaviour_test.js b/lib/ace/mode/behaviour/behaviour_test.js index ded22ccb..ba0a5041 100644 --- a/lib/ace/mode/behaviour/behaviour_test.js +++ b/lib/ace/mode/behaviour/behaviour_test.js @@ -120,6 +120,15 @@ module.exports = { assert.equal(editor.getValue(), "{") exec("insertstring", 1, "\n"); assert.equal(editor.getValue(), "{\n \n}") + + editor.setValue(""); + exec("insertstring", 1, "("); + exec("insertstring", 1, '"'); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '("")'); + exec("backspace", 1); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '("")'); } }; diff --git a/lib/ace/mode/behaviour/cstyle.js b/lib/ace/mode/behaviour/cstyle.js index db8f4a36..5abf08fd 100644 --- a/lib/ace/mode/behaviour/cstyle.js +++ b/lib/ace/mode/behaviour/cstyle.js @@ -277,6 +277,8 @@ var CstyleBehaviour = function() { } else { if (stringBefore && !stringAfter) return null; // wrap string with different quote + if (stringBefore && stringAfter) + return null; // do not pair quotes inside strings var wordRe = session.$mode.tokenRe; wordRe.lastIndex = 0; var isWordBefore = wordRe.test(leftChar); From 5a03993f65a2a347c6f2d2da4fb9513999f1c8f3 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 13 Dec 2014 00:43:30 +0400 Subject: [PATCH 329/545] update vim.js --- lib/ace/keyboard/vim.js | 326 ++++++++++++++++++++--------------- lib/ace/keyboard/vim_test.js | 74 ++++++++ 2 files changed, 264 insertions(+), 136 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index cbf3dda3..d3a01ebc 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -167,7 +167,7 @@ define(function(require, exports, module) { this.removeOverlay(); }; this.virtualSelectionMode = function() { - return this.ace.inVirtualSelectionMode && this.ace.selection.index + return this.ace.inVirtualSelectionMode && this.ace.selection.index; }; this.onChange = function(delta) { var oldDelta = delta.data; @@ -356,7 +356,7 @@ define(function(require, exports, module) { point.row = start.row; point.column = start.column; if (cmp2 === 0) - point.bias = 1 + point.bias = 1; } } }; @@ -421,9 +421,6 @@ define(function(require, exports, module) { throw "not implemented"; } }; - this.openDialog = function() { - debugger - }; this.getSearchCursor = function(query, pos, caseFold) { var caseSensitive = false; var isRegexp = false; @@ -566,12 +563,11 @@ define(function(require, exports, module) { var row = delta.start.row; if (row == delta.end.row) highlight.cache[row] = undefined; else highlight.cache.splice(row, highlight.cache.length); - } + }; highlight.session.on("changeEditor", highlight.destroy); highlight.session.on("change", highlight.updateOnChange); } var re = new RegExp(o.query.source, "gmi"); - console.log(re) this.$searchHighlight = o.highlight = highlight; this.$searchHighlight.setRegexp(re); this.ace.renderer.updateBackMarkers(); @@ -866,11 +862,11 @@ dom.importCssString(".normal-mode .ace_cursor{\ { keys: '', type: 'keyToKey', toKeys: 'k' }, { keys: '', type: 'keyToKey', toKeys: 'j' }, { keys: '', type: 'keyToKey', toKeys: 'l' }, - { keys: '', type: 'keyToKey', toKeys: 'h' }, + { keys: '', type: 'keyToKey', toKeys: 'h', context: 'normal'}, { keys: '', type: 'keyToKey', toKeys: 'W' }, - { keys: '', type: 'keyToKey', toKeys: 'B' }, + { keys: '', type: 'keyToKey', toKeys: 'B', context: 'normal' }, { keys: '', type: 'keyToKey', toKeys: 'w' }, - { keys: '', type: 'keyToKey', toKeys: 'b' }, + { keys: '', type: 'keyToKey', toKeys: 'b', context: 'normal' }, { keys: '', type: 'keyToKey', toKeys: 'j' }, { keys: '', type: 'keyToKey', toKeys: 'k' }, { keys: '', type: 'keyToKey', toKeys: '' }, @@ -1018,55 +1014,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ var Pos = CodeMirror.Pos; - var modifierCodes = [16, 17, 18, 91]; - var specialKey = {Enter:'CR',Backspace:'BS',Delete:'Del'}; - var mac = /Mac/.test(navigator.platform); var Vim = function() { return vimApi; } //{ - function lookupKey(e) { - var keyCode = e.keyCode; - if (modifierCodes.indexOf(keyCode) != -1) { return; } - var hasModifier = e.ctrlKey || e.metaKey; - var key = CodeMirror.keyNames[keyCode]; - key = specialKey[key] || key; - var name = ''; - if (e.ctrlKey) { name += 'C-'; } - if (e.altKey) { name += 'A-'; } - if (mac && e.metaKey || (!hasModifier && e.shiftKey) && key.length < 2) { - // Shift key bindings can only specified for special characters. - return; - } else if (e.shiftKey && !/^[A-Za-z]$/.test(key)) { - name += 'S-'; - } - if (key.length == 1) { key = key.toLowerCase(); } - name += key; - if (name.length > 1) { name = '<' + name + '>'; } - return name; - } - // Keys with modifiers are handled using keydown due to limitations of - // keypress event. - function handleKeyDown(cm, e) { - var name = lookupKey(e); - if (!name) { return; } - - CodeMirror.signal(cm, 'vim-keypress', name); - if (CodeMirror.Vim.handleKey(cm, name, 'user')) { - CodeMirror.e_stop(e); - } - } - // Keys without modifiers are handled using keypress to work best with - // non-standard keyboard layouts. - function handleKeyPress(cm, e) { - var code = e.charCode || e.keyCode; - if (e.ctrlKey || e.metaKey || e.altKey || - e.shiftKey && code < 32) { return; } - var name = String.fromCharCode(code); - - CodeMirror.signal(cm, 'vim-keypress', name); - if (CodeMirror.Vim.handleKey(cm, name, 'user')) { - CodeMirror.e_stop(e); - } - } - function enterVimMode(cm) { cm.setOption('disableInput', true); cm.setOption('showCursorWhenSelecting', false); @@ -1074,8 +1022,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ cm.on('cursorActivity', onCursorActivity); maybeInitVimState(cm); CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm)); - cm.on('keypress', handleKeyPress); - cm.on('keydown', handleKeyDown); } function leaveVimMode(cm) { @@ -1083,8 +1029,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ cm.off('cursorActivity', onCursorActivity); CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm)); cm.state.vim = null; - cm.off('keypress', handleKeyPress); - cm.off('keydown', handleKeyDown); } function detachVimMap(cm, next) { @@ -1109,6 +1053,60 @@ dom.importCssString(".normal-mode .ace_cursor{\ else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap"))) cm.setOption("keyMap", "default"); }); + + function cmKey(key, cm) { + if (!cm) { return undefined; } + var vimKey = cmKeyToVimKey(key); + if (!vimKey) { + return false; + } + var cmd = CodeMirror.Vim.findKey(cm, vimKey); + if (typeof cmd == 'function') { + CodeMirror.signal(cm, 'vim-keypress', vimKey); + } + return cmd; + } + + var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'}; + var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del'}; + function cmKeyToVimKey(key) { + if (key.charAt(0) == '\'') { + // Keypress character binding of format "'a'" + return key.charAt(1); + } + var pieces = key.split('-'); + if (/-$/.test(key)) { + // If the - key was typed, split will result in 2 extra empty strings + // in the array. Replace them with 1 '-'. + pieces.splice(-2, 2, '-'); + } + var lastPiece = pieces[pieces.length - 1]; + if (pieces.length == 1 && pieces[0].length == 1) { + // No-modifier bindings use literal character bindings above. Skip. + return false; + } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) { + // Ignore Shift+char bindings as they should be handled by literal character. + return false; + } + var hasCharacter = false; + for (var i = 0; i < pieces.length; i++) { + var piece = pieces[i]; + if (piece in modifiers) { pieces[i] = modifiers[piece]; } + else { hasCharacter = true; } + if (piece in specialKeys) { pieces[i] = specialKeys[piece]; } + } + if (!hasCharacter) { + // Vim does not support modifier only keys. + return false; + } + // TODO: Current bindings expect the character to be lower case, but + // it looks like vim key notation uses upper case. + if (isUpperCase(lastPiece)) { + pieces[pieces.length - 1] = lastPiece.toLowerCase(); + } + return '<' + pieces.join('-') + '>'; + } + function getOnPasteFn(cm) { var vim = cm.state.vim; if (!vim.onPasteFn) { @@ -1168,15 +1166,10 @@ dom.importCssString(".normal-mode .ace_cursor{\ function defineOption(name, defaultValue, type) { if (defaultValue === undefined) { throw Error('defaultValue is required'); } if (!type) { type = 'string'; } - var opt = name; - if (typeof name == "string") - opt = { - type: type, - defaultValue: defaultValue - }; - else - name = opt.name; - options[name] = opt; + options[name] = { + type: type, + defaultValue: defaultValue + }; setOption(name, defaultValue); } @@ -1193,8 +1186,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ value = true; } } - option.value = value; - if (option.set) option.set(value, cm); + option.value = option.type == 'boolean' ? !!value : value; } function getOption(name) { @@ -1428,9 +1420,23 @@ dom.importCssString(".normal-mode .ace_cursor{\ exCommands[name]=func; exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; }, - // This is the outermost function called by CodeMirror, after keys have - // been mapped to their Vim equivalents. - handleKey: function(cm, key, origin) { + handleKey: function (cm, key, origin) { + var command = this.findKey(cm, key, origin); + if (typeof command === 'function') { + return command(); + } + }, + /** + * This is the outermost function called by CodeMirror, after keys have + * been mapped to their Vim equivalents. + * + * Finds a command based on the key (and cached keys if there is a + * multi-key sequence). Returns `undefined` if no key is matched, a noop + * function if a partial match is found (multi-key), and a function to + * execute the bound command if a a key is matched. The function always + * returns true. + */ + findKey: function(cm, key, origin) { var vim = maybeInitVimState(cm); function handleMacroRecording() { var macroModeState = vimGlobalState.macroModeState; @@ -1496,13 +1502,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input'); } clearInputState(cm); - var command = match.command; - if (command.type == 'keyToKey') { - doKeyToKey(command.toKeys); - } else { - commandDispatcher.processCommand(cm, vim, command); - } - return true; + return match.command; } function handleKeyNonInsertMode() { @@ -1520,31 +1520,44 @@ dom.importCssString(".normal-mode .ace_cursor{\ else if (match.type == 'partial') { return true; } vim.inputState.keyBuffer = ''; - var command = match.command; var keysMatcher = /^(\d*)(.*)$/.exec(keys); if (keysMatcher[1] && keysMatcher[1] != '0') { vim.inputState.pushRepeatDigit(keysMatcher[1]); } - if (command.type == 'keyToKey') { - doKeyToKey(command.toKeys); - } else { - commandDispatcher.processCommand(cm, vim, command); - } - return true; + return match.command; } - return cm.operation(function() { - cm.curOp.isVimOp = true; - try { - if (vim.insertMode) { return handleKeyInsertMode(); } - else { return handleKeyNonInsertMode(); } - } catch (e) { - // clear VIM state in case it's in a bad state. - cm.state.vim = undefined; - maybeInitVimState(cm); - throw e; - } - }); + var command; + if (vim.insertMode) { command = handleKeyInsertMode(); } + else { command = handleKeyNonInsertMode(); } + if (command === false) { + return undefined; + } else if (command === true) { + // TODO: Look into using CodeMirror's multi-key handling. + // Return no-op since we are caching the key. Counts as handled, but + // don't want act on it just yet. + return function() {}; + } else { + return function() { + return cm.operation(function() { + cm.curOp.isVimOp = true; + try { + if (command.type == 'keyToKey') { + doKeyToKey(command.toKeys); + } else { + commandDispatcher.processCommand(cm, vim, command); + } + } catch (e) { + // clear VIM state in case it's in a bad state. + cm.state.vim = undefined; + maybeInitVimState(cm); + console['log'](e); + throw e; + } + return true; + }); + }; + } }, handleEx: function(cm, input) { exCommandDispatcher.processCommand(cm, input); @@ -2105,7 +2118,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ newHead = copyCursor(origHead); } if (vim.visualMode) { - newHead = clipCursorToContent(cm, newHead, true); + newHead = clipCursorToContent(cm, newHead, vim.visualBlock); if (newAnchor) { newAnchor = clipCursorToContent(cm, newAnchor, true); } @@ -2409,20 +2422,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page'); }, moveByParagraph: function(cm, head, motionArgs) { - var line = head.line; - var repeat = motionArgs.repeat; - var inc = motionArgs.forward ? 1 : -1; - for (var i = 0; i < repeat; i++) { - if ((!motionArgs.forward && line === cm.firstLine() ) || - (motionArgs.forward && line == cm.lastLine())) { - break; - } - line += inc; - while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) { - line += inc; - } - } - return Pos(line, 0); + var dir = motionArgs.forward ? 1 : -1; + return findParagraph(cm, head, motionArgs.repeat, dir); }, moveByScroll: function(cm, head, motionArgs, vim) { var scrollbox = cm.getScrollInfo(); @@ -2522,7 +2523,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ return Pos(lineNum, findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum))); }, - textObjectManipulation: function(cm, head, motionArgs) { + textObjectManipulation: function(cm, head, motionArgs, vim) { // TODO: lots of possible exceptions that can be thrown here. Try da( // outside of a () block. @@ -2561,8 +2562,15 @@ dom.importCssString(".normal-mode .ace_cursor{\ tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, false /** bigWord */); } else if (character === 'p') { - tmp = expandParagraphUnderCursor(cm, inclusive, true /** forward */, - false /** bigWord */); + tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive); + motionArgs.linewise = true; + if (vim.visualMode) { + if (!vim.visualLine) { vim.visualLine = true; } + } else { + var operatorArgs = vim.inputState.operatorArgs; + if (operatorArgs) { operatorArgs.linewise = true; } + tmp.end.line--; + } } else { // No text object defined for this, don't move. return null; @@ -4070,6 +4078,54 @@ dom.importCssString(".normal-mode .ace_cursor{\ return idx; } + function findParagraph(cm, head, repeat, dir, inclusive) { + var line = head.line; + var min = cm.firstLine(); + var max = cm.lastLine(); + var start, end, i = line; + function isEmpty(i) { return !cm.getLine(i); } + function isBoundary(i, dir, any) { + if (any) { return isEmpty(i) != isEmpty(i + dir); } + return !isEmpty(i) && isEmpty(i + dir); + } + if (dir) { + while (min <= i && i <= max && repeat > 0) { + if (isBoundary(i, dir)) { repeat--; } + i += dir; + } + return new Pos(i, 0); + } + + var vim = cm.state.vim; + if (vim.visualLine && isBoundary(line, 1, true)) { + var anchor = vim.sel.anchor; + if (isBoundary(anchor.line, -1, true)) { + if (!inclusive || anchor.line != line) { + line += 1; + } + } + } + var startState = isEmpty(line); + for (i = line; i <= max && repeat; i++) { + if (isBoundary(i, 1, true)) { + if (!inclusive || isEmpty(i) != startState) { + repeat--; + } + } + } + end = new Pos(i, 0); + // select boundary before paragraph for the last one + if (i > max && !startState) { startState = true; } + else { inclusive = false; } + for (i = line; i > min; i--) { + if (!inclusive || isEmpty(i) == startState || i == line) { + if (isBoundary(i, -1, true)) { break; } + } + } + start = new Pos(i, 0); + return { start: start, end: end }; + } + // TODO: perhaps this finagling of start and end positions belonds // in codmirror/replaceRange? function selectCompanionObject(cm, head, symb, inclusive) { @@ -5276,7 +5332,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ CodeMirror.keyMap.vim = { attach: attachVimMap, - detach: detachVimMap + detach: detachVimMap, + call: cmKey }; function exitInsertMode(cm) { @@ -5349,20 +5406,16 @@ dom.importCssString(".normal-mode .ace_cursor{\ }, fallthrough: ['default'], attach: attachVimMap, - detach: detachVimMap - }; - - CodeMirror.keyMap['await-second'] = { - fallthrough: ['vim-insert'], - attach: attachVimMap, - detach: detachVimMap + detach: detachVimMap, + call: cmKey }; CodeMirror.keyMap['vim-replace'] = { 'Backspace': 'goCharLeft', fallthrough: ['vim-insert'], attach: attachVimMap, - detach: detachVimMap + detach: detachVimMap, + call: cmKey }; function executeMacroRegister(cm, vim, macroModeState, registerName) { @@ -5628,7 +5681,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ Vim = CodeMirror.Vim; - specialKey = {'return':'CR',backspace:'BS','delete':'Del',esc:'Esc', + var specialKey = {'return':'CR',backspace:'BS','delete':'Del',esc:'Esc', left:'Left',right:'Right',up:'Up',down:'Down',space: 'Space', home:'Home',end:'End',pageup:'PageUp',pagedown:'PageDown', enter: 'CR' }; @@ -5646,7 +5699,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ if (name.length > 1) { name = '<' + name + '>'; } return name; } - var handleKey = Vim.handleKey + var handleKey = Vim.handleKey.bind(Vim); Vim.handleKey = function(cm, key, origin) { return cm.operation(function() { return handleKey(cm, key, origin); @@ -5750,7 +5803,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ }); return {command: "null", passEvent: true}; } - return {command: coreCommands.stop}; } else if (!vim.insertMode) { if (useragent.isMac && this.handleMacRepeat(data, hashId, key)) { hashId = -1; @@ -5925,10 +5977,10 @@ dom.importCssString(".normal-mode .ace_cursor{\ { keys: 'zf', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, { keys: 'zd', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, - { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAbove" } }, - { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelow" } }, - { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAboveSkipCurrent" } }, - { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelowSkipCurrent" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAbove" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelow" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAboveSkipCurrent" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelowSkipCurrent" } }, { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreBefore" } }, { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreAfter" } }, { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextBefore" } }, @@ -5955,6 +6007,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ }, exports.handler.defaultKeymap = defaultKeymap; + exports.handler.actions = actions; + exports.Vim = Vim; Vim.map("Y", "yy"); }); diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js index 8c9eeb65..7b51f23b 100644 --- a/lib/ace/keyboard/vim_test.js +++ b/lib/ace/keyboard/vim_test.js @@ -592,6 +592,80 @@ testVim('{', function(cm, vim, helpers) { helpers.doKeys('6', '{'); helpers.assertCursorAt(0, 0); }, { value: 'a\n\nb\nc\n\nd' }); +testVim('paragraph motions', function(cm, vim, helpers) { + cm.setCursor(10, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(4, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(7, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(16, 0); + + cm.setCursor(9, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(14, 0); + + cm.setCursor(6, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(7, 0); + + // ip inside empty space + cm.setCursor(10, 0); + helpers.doKeys('v', 'i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(12, 0), cm.getCursor('head')); + helpers.doKeys('i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(13, 1), cm.getCursor('head')); + helpers.doKeys('2', 'i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + // should switch to visualLine mode + cm.setCursor(14, 0); + helpers.doKeys('', 'v', 'i', 'p'); + helpers.assertCursorAt(14, 0); + + cm.setCursor(14, 0); + helpers.doKeys('', 'V', 'i', 'p'); + eqPos(Pos(16, 1), cm.getCursor('head')); + + // ap inside empty space + cm.setCursor(10, 0); + helpers.doKeys('', 'v', 'a', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(13, 1), cm.getCursor('head')); + helpers.doKeys('a', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + cm.setCursor(13, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(13, 0), cm.getCursor('anchor')); + eqPos(Pos(14, 0), cm.getCursor('head')); + + cm.setCursor(16, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(14, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + cm.setCursor(0, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(0, 0), cm.getCursor('anchor')); + eqPos(Pos(4, 0), cm.getCursor('head')); + + cm.setCursor(0, 0); + helpers.doKeys('d', 'i', 'p'); + var register = helpers.getRegisterController().getRegister(); + eq('a\na\n', register.toString()); + is(register.linewise); + helpers.doKeys('3', 'j', 'p'); + helpers.doKeys('y', 'i', 'p'); + is(register.linewise); + eq('b\na\na\nc\n', register.toString()); +}, { value: 'a\na\n\n\n\nb\nc\n\n\n\n\n\n\nd\n\ne\nf' }); // Operator tests testVim('dl', function(cm, vim, helpers) { From c5edaa3608d0e3a540d104be15be499a79677737 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 13 Dec 2014 16:45:56 +0400 Subject: [PATCH 330/545] allow filtering tests in browser runner --- lib/ace/test/all_browser.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index 1ffbb01a..7ac5092e 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -72,6 +72,8 @@ document.body.appendChild(nav); if (location.search) testNames = location.search.substr(1).split(",") +var filter = location.hash.substr(1); + require(testNames, function() { var tests = testNames.map(function(x) { var module = require(x); @@ -81,6 +83,12 @@ require(testNames, function() { async.list(tests) .expand(function(test) { + if (filter) { + Object.keys(test).forEach(function(method) { + if (method.match(/^>?test/) && !method.match(filter)) + test[method] = undefined; + }); + } return AsyncTest.testcase(test) }, AsyncTest.TestGenerator) .run() From 8019a21475618b03127459e43b4825660208c3ac Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Sun, 14 Dec 2014 20:34:41 +0100 Subject: [PATCH 331/545] added abc mode --- demo/kitchen-sink/docs/abc.abc | 171 +++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/_test/tokens_abc.json | 2207 +++++++++++++++++++++++++++ lib/ace/mode/abc.js | 58 + lib/ace/mode/abc_highlight_rules.js | 114 ++ lib/ace/snippets/abc.js | 7 + lib/ace/snippets/abc.snippets | 15 + 7 files changed, 2573 insertions(+) create mode 100644 demo/kitchen-sink/docs/abc.abc create mode 100644 lib/ace/mode/_test/tokens_abc.json create mode 100644 lib/ace/mode/abc.js create mode 100644 lib/ace/mode/abc_highlight_rules.js create mode 100644 lib/ace/snippets/abc.js create mode 100644 lib/ace/snippets/abc.snippets diff --git a/demo/kitchen-sink/docs/abc.abc b/demo/kitchen-sink/docs/abc.abc new file mode 100644 index 00000000..d8ac326e --- /dev/null +++ b/demo/kitchen-sink/docs/abc.abc @@ -0,0 +1,171 @@ +%abc-2.1 +H:This file contains some example English tunes +% note that the comments (like this one) are to highlight usages +% and would not normally be included in such detail +O:England % the origin of all tunes is England + +X:1 % tune no 1 +T:Dusty Miller, The % title +T:Binny's Jig % an alternative title +C:Trad. % traditional +R:DH % double hornpipe +M:3/4 % meter +K:G % key +B>cd BAG|FA Ac BA|B>cd BAG|DG GB AG:| +Bdd gfg|aA Ac BA|Bdd gfa|gG GB AG:| +BG G/2G/2G BG|FA Ac BA|BG G/2G/2G BG|DG GB AG:| +W:Hey, the dusty miller, and his dusty coat; +W:He will win a shilling, or he spend a groat. +W:Dusty was the coat, dusty was the colour; +W:Dusty was the kiss, that I got frae the miller. + +X:2 +T:Old Sir Simon the King +C:Trad. +S:Offord MSS % from Offord manuscript +N:see also Playford % reference note +M:9/8 +R:SJ % slip jig +N:originally in C % transcription note +K:G +D|GFG GAG G2D|GFG GAG F2D|EFE EFE EFG|A2G F2E D2:| +D|GAG GAB d2D|GAG GAB c2D|[1 EFE EFE EFG|[A2G] F2E D2:|\ % no line-break in score +M:12/8 % change of meter +[2 E2E EFE E2E EFG|\ % no line-break in score +M:9/8 % change of meter +A2G F2E D2|] + +X:3 +T:William and Nancy +T:New Mown Hay +T:Legacy, The +C:Trad. +O:England; Gloucs; Bledington % place of origin +B:Sussex Tune Book % can be found in these books +B:Mally's Cotswold Morris vol.1 2 +D:Morris On % can be heard on this record +P:(AB)2(AC)2A % play the parts in this order +M:6/8 +K:G +[P:A] D|"G"G2G GBd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| +[P:B] d|"G"e2d B2d|"C"gfe "G"d2d| "G"e2d B2d|"C"gfe "D7"d2c| + "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| +% changes of meter, using inline fields +[T:Slows][M:4/4][L:1/4][P:C]"G"d2|"C"e2 "G"d2|B2 d2|"Em"gf "A7"e2|"D7"d2 "G"d2|\ + "C"e2 "G"d2|[M:3/8][L:1/8] "G"B2 d |[M:6/8] "C"gfe "D7"d2c| + "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:| + +X:4 +T:South Downs Jig +R:jig +S:Robert Harbron +M:6/8 +L:1/8 +K:G +|: d | dcA G3 | EFG AFE | DEF GAB | cde d2d | +dcA G3 | EFG AFE | DEF GAB | cAF G2 :| +B | Bcd e2c | d2B c2A | Bcd e2c | [M:9/8]d2B c2B A3 | +[M:6/8]DGF E3 | cBA FED | DEF GAB |1 cAF G2 :|2 cAF G3 |] + +X:5 +T:Atholl Brose +% in this example, which reproduces Highland Bagpipe gracing, +% the large number of grace notes mean that it is more convenient to be specific about +% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them +I:linebreak $ +K:D +{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| +{gcd}c<{e}A {gAGAG}A>e {ag}a>f {gef}e>d| +{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad| +{g}c/d/e {g}G>{d}B {gf}gG {dc}d>B:|$ +{g}ce {ag}a>e {gf}g>e| +{g}ce {ag}a2 {GdG}a>d| +{g}ce {ag}a>e {gf}g>f| +{gef}e>d {gf}g>d {gBd}B<{e}G {dc}d>B| +{g}ce {ag}a>e {gf}g>e| +{g}ce {ag}a2 {GdG}ad| +{g}c<{GdG}e {gf}ga {f}g>e {g}f>d| +{g}e/f/g {Gdc}d>c {gBd}B<{e}G {dc}d2|] + +X:6 +T:Untitled Reel +C:Trad. +K:D +eg|a2ab ageg|agbg agef|g2g2 fgag|f2d2 d2:|\ +ed|cecA B2ed|cAcA E2ed|cecA B2ed|c2A2 A2:| +K:G +AB|cdec BcdB|ABAF GFE2|cdec BcdB|c2A2 A2:| + +X:7 +T:Kitchen Girl +C:Trad. +K:D +[c4a4] [B4g4]|efed c2cd|e2f2 gaba|g2e2 e2fg| +a4 g4|efed cdef|g2d2 efed|c2A2 A4:| +K:G +ABcA BAGB|ABAG EDEG|A2AB c2d2|e3f edcB|ABcA BAGB| +ABAG EGAB|cBAc BAG2|A4 A4:| + +%abc-2.1 +%%pagewidth 21cm +%%pageheight 29.7cm +%%topspace 0.5cm +%%topmargin 1cm +%%botmargin 0cm +%%leftmargin 1cm +%%rightmargin 1cm +%%titlespace 0cm +%%titlefont Times-Bold 32 +%%subtitlefont Times-Bold 24 +%%composerfont Times 16 +%%vocalfont Times-Roman 14 +%%staffsep 60pt +%%sysstaffsep 20pt +%%musicspace 1cm +%%vocalspace 5pt +%%measurenb 0 +%%barsperstaff 5 +%%scale 0.7 +X: 1 +T: Canzonetta a tre voci +C: Claudio Monteverdi (1567-1643) +M: C +L: 1/4 +Q: "Andante mosso" 1/4 = 110 +%%score [1 2 3] +V: 1 clef=treble name="Soprano"sname="A" +V: 2 clef=treble name="Alto" sname="T" +V: 3 clef=bass middle=d name="Tenor" sname="B" +%%MIDI program 1 75 % recorder +%%MIDI program 2 75 +%%MIDI program 3 75 +K: Eb +% 1 - 4 +[V: 1] |:z4 |z4 |f2ec |_ddcc | +w: Son que-sti~i cre-spi cri-ni~e +w: Que-sti son gli~oc-chi che mi- +[V: 2] |:c2BG|AAGc|(F/G/A/B/)c=A|B2AA | +w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e +w: Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi- +[V: 3] |:z4 |f2ec|_ddcf |(B/c/_d/e/)ff| +w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il +w: Que-sti son~gli oc-chi che mi-ran - - - - do +% 5 - 9 +[V: 1] cAB2 |cAAA |c3B|G2!fermata!Gz ::e4| +w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, +w: ran-do fi-so, tut-to re-stai con-qui-so. +[V: 2] AAG2 |AFFF |A3F|=E2!fermata!Ez::c4| +w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh, +w: ran-do fi-so tut-to re-stai con-qui-so. +[V: 3] (ag/f/e2)|A_ddd|A3B|c2!fermata!cz ::A4| +w: vi - - - so ond' io ti-man-go~uc-ci-so. Deh, +w: fi - - - so tut-to re-stai con-qui-so. +% 10 - 15 +[V: 1] f_dec |B2c2|zAGF |\ +w: dim-me-lo ben mi-o, che que-sto\ +=EFG2 |1F2z2:|2F8|] % more notes +w: sol de-si-o_. % more lyrics +[V: 2] ABGA |G2AA|GF=EF |(GF3/2=E//D//E)|1F2z2:|2F8|] +w: dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_. +[V: 3] _dBc>d|e2AF|=EFc_d|c4 |1F2z2:|2F8|] +w: dim-me-lo ben mi-o, che que-sto sol de-si-o_. \ No newline at end of file diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 3245d8a7..cba800ac 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -43,6 +43,7 @@ Mode.prototype.supportsFile = function(filename) { // todo firstlinematch var supportedModes = { ABAP: ["abap"], + ABC: ["abc"], ActionScript:["as"], ADA: ["ada|adb"], Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], diff --git a/lib/ace/mode/_test/tokens_abc.json b/lib/ace/mode/_test/tokens_abc.json new file mode 100644 index 00000000..c65ae2a5 --- /dev/null +++ b/lib/ace/mode/_test/tokens_abc.json @@ -0,0 +1,2207 @@ +[[ + "start", + ["comment.line.percentage","%abc-2.1"] +],[ + "start", + ["information.keyword","H:"], + ["information.argument.string.unquoted","This file contains some example English tunes"] +],[ + "start", + ["comment.line.percentage","% note that the comments (like this one) are to highlight usages"] +],[ + "start", + ["comment.line.percentage","% and would not normally be included in such detail"] +],[ + "start", + ["information.keyword","O:"], + ["information.argument.string.unquoted","England "], + ["comment.line.percentage","% the origin of all tunes is England"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","1 "], + ["comment.line.percentage","% tune no 1"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Dusty Miller, The "], + ["comment.line.percentage","% title"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Binny's Jig "], + ["comment.line.percentage","% an alternative title"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad. "], + ["comment.line.percentage","% traditional"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","DH "], + ["comment.line.percentage","% double hornpipe"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","3/4 "], + ["comment.line.percentage","% meter"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G "], + ["comment.line.percentage","% key"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","a"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Hey, the dusty miller, and his dusty coat;"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","He will win a shilling, or he spend a groat."] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Dusty was the coat, dusty was the colour;"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Dusty was the kiss, that I got frae the miller."] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","2"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Old Sir Simon the King"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","S:"], + ["information.argument.string.unquoted","Offord MSS "], + ["comment.line.percentage","% from Offord manuscript"] +],[ + "start", + ["information.keyword","N:"], + ["information.argument.string.unquoted","see also Playford "], + ["comment.line.percentage","% reference note"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","9/8"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","SJ "], + ["comment.line.percentage","% slip jig"] +],[ + "start", + ["information.keyword","N:"], + ["information.argument.string.unquoted","originally in C "], + ["comment.line.percentage","% transcription note"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|[1"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["text","["], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text","] "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"], + ["text","\\ "], + ["comment.line.percentage","% no line-break in score"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","12/8 "], + ["comment.line.percentage","% change of meter"] +],[ + "start", + ["barline.keyword.operator","[2"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["text","\\ "], + ["comment.line.percentage","% no line-break in score"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","9/8 "], + ["comment.line.percentage","% change of meter"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","3"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","William and Nancy"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","New Mown Hay"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Legacy, The"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","O:"], + ["information.argument.string.unquoted","England; Gloucs; Bledington "], + ["comment.line.percentage","% place of origin"] +],[ + "start", + ["information.keyword","B:"], + ["information.argument.string.unquoted","Sussex Tune Book "], + ["comment.line.percentage","% can be found in these books"] +],[ + "start", + ["information.keyword","B:"], + ["information.argument.string.unquoted","Mally's Cotswold Morris vol.1 2"] +],[ + "start", + ["information.keyword","D:"], + ["information.argument.string.unquoted","Morris On "], + ["comment.line.percentage","% can be heard on this record"] +],[ + "start", + ["information.keyword","P:"], + ["information.argument.string.unquoted","(AB)2(AC)2A "], + ["comment.line.percentage","% play the parts in this order"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","6/8"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G "] +],[ + "start", + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","A]"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","B]"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["comment.line.percentage","% changes of meter, using inline fields"] +],[ + "start", + ["information.keyword.embedded","[T:"], + ["information.argument.string.unquoted","Slows]"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","4/4]"], + ["information.keyword.embedded","[L:"], + ["information.argument.string.unquoted","1/4]"], + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","C]"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"Em\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["string.quoted","\"A7\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["text","\\"] +],[ + "start", + ["text"," "], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","3/8]"], + ["information.keyword.embedded","[L:"], + ["information.argument.string.unquoted","1/8]"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","6/8]"], + ["text"," "], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","4"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","South Downs Jig"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","jig"] +],[ + "start", + ["information.keyword","S:"], + ["information.argument.string.unquoted","Robert Harbron"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","6/8"] +],[ + "start", + ["information.keyword","L:"], + ["information.argument.string.unquoted","1/8"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["barline.keyword.operator","|:"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","9/8]"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","6/8]"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","D"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator",":|2"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","5"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Atholl Brose"] +],[ + "start", + ["comment.line.percentage","% in this example, which reproduces Highland Bagpipe gracing,"] +],[ + "start", + ["comment.line.percentage","% the large number of grace notes mean that it is more convenient to be specific about"] +],[ + "start", + ["comment.line.percentage","% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them"] +],[ + "start", + ["information.keyword","I:"], + ["information.argument.string.unquoted","linebreak $"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","f"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric",">"], + ["text","{"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator",":|"], + ["text","$"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["text"," {"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","g"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","6"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Untitled Reel"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","b"], + ["text"," "], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","b"], + ["pitch.constant.numeric","g"], + ["text"," "], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"], + ["text","\\"] +],[ + "start", + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","7"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Kitchen Girl"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["text","["], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","4"], + ["text","] ["], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","4"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","4"], + ["text","]"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","b"], + ["pitch.constant.numeric","a"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","4"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["comment.line.percentage","%abc-2.1"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","pagewidth 21cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","pageheight 29.7cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","topspace 0.5cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","topmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","botmargin 0cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","leftmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","rightmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","titlespace 0cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","titlefont Times-Bold 32"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","subtitlefont Times-Bold 24"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","composerfont Times 16"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","vocalfont Times-Roman 14"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","staffsep 60pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","sysstaffsep 20pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","musicspace 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","vocalspace 5pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","measurenb 0"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","barsperstaff 5"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","scale 0.7"] +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted"," 1"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted"," Canzonetta a tre voci"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted"," Claudio Monteverdi (1567-1643)"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted"," C"] +],[ + "start", + ["information.keyword","L:"], + ["information.argument.string.unquoted"," 1/4"] +],[ + "start", + ["information.keyword","Q:"], + ["information.argument.string.unquoted"," \"Andante mosso\" 1/4 = 110"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","score [1 2 3]"] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 1 clef=treble name=\"Soprano\"sname=\"A\""] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 2 clef=treble name=\"Alto\" sname=\"T\""] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 3 clef=bass middle=d name=\"Tenor\" sname=\"B\""] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 1 75 % recorder"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 2 75"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 3 75"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted"," Eb"] +],[ + "start", + ["comment.line.percentage","% 1 - 4"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son gli~oc-chi che mi-"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","/"], + ["text",")"], + ["pitch.constant.numeric","c"], + ["accent.constant.language","="], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi-"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","/"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","/"], + ["text",")"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e que - - - - sto~il"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son~gli oc-chi che mi-ran - - - - do"] +],[ + "start", + ["comment.line.percentage","% 5 - 9"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","z"], + ["text"," "], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," ran-do fi-so, tut-to re-stai con-qui-so."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","F"], + ["barline.keyword.operator","|"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","z"], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," ran-do fi-so tut-to re-stai con-qui-so."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," ("], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text",")"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","z"], + ["text"," "], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," vi - - - so ond' io ti-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," fi - - - so tut-to re-stai con-qui-so."] +],[ + "start", + ["comment.line.percentage","% 10 - 15"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["pitch.constant.numeric","f"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","z"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","\\"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto"], + ["text","\\"] +],[ + "start", + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"], + ["text"," "], + ["comment.line.percentage","% more notes"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," sol de-si-o_. "], + ["comment.line.percentage","% more lyrics"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","3/2"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","//"], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","//"], + ["pitch.constant.numeric","E"], + ["text",")"], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," "], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["barline.keyword.operator","|"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","c"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto sol de-si-o_."] +]] \ No newline at end of file diff --git a/lib/ace/mode/abc.js b/lib/ace/mode/abc.js new file mode 100644 index 00000000..b6eb237a --- /dev/null +++ b/lib/ace/mode/abc.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js + */ + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextMode = require("./text").Mode; + var ABCHighlightRules = require("./abc_highlight_rules").ABCHighlightRules; +// TODO: pick appropriate fold mode + var FoldMode = require("./folding/cstyle").FoldMode; + + var Mode = function () { + this.HighlightRules = ABCHighlightRules; + this.foldingRules = new FoldMode(); + }; + oop.inherits(Mode, TextMode); + + (function () { + // this.lineCommentStart = ""%.*""; + // this.blockComment = {start: ""/*"", end: ""*/""}; + // Extra logic goes here. + this.$id = "ace/mode/abc" + }).call(Mode.prototype); + + exports.Mode = Mode; +}); \ No newline at end of file diff --git a/lib/ace/mode/abc_highlight_rules.js b/lib/ace/mode/abc_highlight_rules.js new file mode 100644 index 00000000..6ffe9c9b --- /dev/null +++ b/lib/ace/mode/abc_highlight_rules.js @@ -0,0 +1,114 @@ +/* This file was partially autogenerated from https://github.com/jimhawkridge/SublimeABC + + Modifications + + - more classes to express the abc semantic + - added syntax highlighting for Zupfnoter conventions (https://github.com/bwl21/zupfnoter) + - separate note pitch and note duration - even if it looks the same + + ***********************************************************************************************/ + + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var ABCHighlightRules = function () { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + start: [ + { + token: ['zupfnoter.information.comment.line.percentage', 'information.keyword', 'in formation.keyword.embedded'], + regex: '(%%%%)(hn\\.[a-z]*)(.*)', + comment: 'Instruction Comment' + }, + { + token: ['information.comment.line.percentage', 'information.keyword.embedded'], + regex: '(%%)(.*)', + comment: 'Instruction Comment' + }, + + { + token: 'comment.line.percentage', + regex: '%.*', + comment: 'Comments' + }, + + { + token: 'barline.keyword.operator', + regex: '[\\[:]*[|:][|\\]:]*(?:\\[?[0-9]+)?|\\[[0-9]+', + comment: 'Bar lines' + }, + { + token: ['information.keyword.embedded', 'information.argument.string.unquoted'], + regex: '(\\[[A-Za-z]:)([^\\]]*\\])', + comment: 'embedded Header lines' + }, + { + token: ['information.keyword', 'information.argument.string.unquoted'], + regex: '^([A-Za-z]:)([^%\\\\]*)', + comment: 'Header lines' + }, + { + token: ['text', 'entity.name.function', 'string.unquoted', 'text'], + regex: '(\\[)([A-Z]:)(.*?)(\\])', + comment: 'Inline fields' + }, + { + token: ['accent.constant.language', 'pitch.constant.numeric', 'duration.constant.numeric'], + regex: '([\\^=_]*)([A-Ga-gz][,\']*)([0-9]*/*[><0-9]*)', + comment: 'Notes' + }, + { + token: 'zupfnoter.jumptarget.string.quoted', + regex: '[\\"!]\\^\\:.*?[\\"!]', + comment: 'Zupfnoter jumptarget' + }, { + token: 'zupfnoter.goto.string.quoted', + regex: '[\\"!]\\^\\@.*?[\\"!]', + comment: 'Zupfnoter goto' + }, + { + token: 'zupfnoter.annotation.string.quoted', + regex: '[\\"!]\\^\\!.*?[\\"!]', + comment: 'Zupfnoter annoation' + }, + { + token: 'zupfnoter.annotationref.string.quoted', + regex: '[\\"!]\\^\\#.*?[\\"!]', + comment: 'Zupfnoter annotation reference' + }, + { + token: 'chordname.string.quoted', + regex: '[\\"!]\\^.*?[\\"!]', + comment: 'abc chord' + }, + { + token: 'string.quoted', + regex: '[\\"!].*?[\\"!]', + comment: 'abc annotation' + } + + ] + }; + + // this.embedRules(JsonHighlightRules, "json-") + + this.normalizeRules(); + }; + + ABCHighlightRules.metaData = { + fileTypes: ['abc'], + name: 'ABC', + scopeName: 'text.abcnotation' + }; + + + oop.inherits(ABCHighlightRules, TextHighlightRules); + + exports.ABCHighlightRules = ABCHighlightRules; +}); diff --git a/lib/ace/snippets/abc.js b/lib/ace/snippets/abc.js new file mode 100644 index 00000000..da0448ef --- /dev/null +++ b/lib/ace/snippets/abc.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./abc.snippets"); +exports.scope = "abc"; + +}); diff --git a/lib/ace/snippets/abc.snippets b/lib/ace/snippets/abc.snippets new file mode 100644 index 00000000..11e2d735 --- /dev/null +++ b/lib/ace/snippets/abc.snippets @@ -0,0 +1,15 @@ +snippet zupfnoter.goto + "^@${1:target}@${2:some_id},${3:some_id}" + +snippet zupfnoter.annotation + "^@!{1:text}@${2:some_id},${3:some_id}" + +snippet zupfnoter.annotationref + "^#${1:target}" + +snippet zupfnoter.target + "^:${1:target}" + + +snippet zupfnoter.print + %%%%hn.print {"startpos": 20, "t":"Sopran, Alt", "v":[1,2], "s":[[1,2]], "f":[1], "sf":[2], "j":[1]} From 7da354d5f33202ab0d7dd78263e5fa220f7f03b7 Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Sun, 14 Dec 2014 23:40:47 +0100 Subject: [PATCH 332/545] fixed Uncaught TypeError: undefined is not a functionapp_config.js:147 (anonymous function)app_config.js:146 setDefaultValuesmode_creator.js:6 --- lib/ace/lib/app_config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/lib/app_config.js b/lib/ace/lib/app_config.js index 84b9e70c..bc5518d7 100644 --- a/lib/ace/lib/app_config.js +++ b/lib/ace/lib/app_config.js @@ -141,11 +141,11 @@ var AppConfig = function() { opts[name].value = value; } }; - + this.setDefaultValues = function(path, optionHash) { Object.keys(optionHash).forEach(function(key) { this.setDefaultValue(path, key, optionHash[key]); - }); + }, this); }; this.warn = warn; From 95eed254393eeda6079a0386d87e0fe2a6807024 Mon Sep 17 00:00:00 2001 From: Bernhard Weichel Date: Sun, 14 Dec 2014 23:53:52 +0100 Subject: [PATCH 333/545] small fix in the snippets --- lib/ace/lib/app_config.js | 2 +- lib/ace/snippets/abc.snippets | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/lib/app_config.js b/lib/ace/lib/app_config.js index bc5518d7..ead26a98 100644 --- a/lib/ace/lib/app_config.js +++ b/lib/ace/lib/app_config.js @@ -141,7 +141,7 @@ var AppConfig = function() { opts[name].value = value; } }; - + this.setDefaultValues = function(path, optionHash) { Object.keys(optionHash).forEach(function(key) { this.setDefaultValue(path, key, optionHash[key]); diff --git a/lib/ace/snippets/abc.snippets b/lib/ace/snippets/abc.snippets index 11e2d735..65b0fd65 100644 --- a/lib/ace/snippets/abc.snippets +++ b/lib/ace/snippets/abc.snippets @@ -1,8 +1,8 @@ snippet zupfnoter.goto - "^@${1:target}@${2:some_id},${3:some_id}" + "^@${1:target}@${2:distance}" snippet zupfnoter.annotation - "^@!{1:text}@${2:some_id},${3:some_id}" + "^@!{1:text}@${2:x_offset},${3:y_offset}" snippet zupfnoter.annotationref "^#${1:target}" From dafa24d5e18bbacd9decb2f5c8a7796b3b137ce1 Mon Sep 17 00:00:00 2001 From: Ryan Mehta Date: Mon, 15 Dec 2014 12:33:49 -0800 Subject: [PATCH 334/545] change variable char to character --- lib/ace/mouse/mouse_handler.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index 6b331eee..596d8503 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -3,7 +3,7 @@ * * Copyright (c) 2010, Ajax.org B.V. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright @@ -14,7 +14,7 @@ * * Neither the name of Ajax.org B.V. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -46,15 +46,15 @@ var MouseHandler = function(editor) { new DefaultHandlers(this); new DefaultGutterHandler(this); new DragdropHandler(this); - + var focusEditor = function(e) { - // because we have to call event.preventDefault() any window on ie and iframes + // because we have to call event.preventDefault() any window on ie and iframes // on other browsers do not get focus, so we have to call window.focus() here if (!document.hasFocus || !document.hasFocus()) window.focus(); editor.focus(); }; - + var mouseTarget = editor.renderer.getMouseEventTarget(); event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click")); event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove")); @@ -85,12 +85,12 @@ var MouseHandler = function(editor) { editor.on("mousemove", function(e){ if (_self.state || _self.$dragDelay || !_self.$dragEnabled) return; - - var char = editor.renderer.screenToTextCoordinates(e.x, e.y); + + var character = editor.renderer.screenToTextCoordinates(e.x, e.y); var range = editor.session.selection.getRange(); var renderer = editor.renderer; - if (!range.isEmpty() && range.insideStart(char.row, char.column)) { + if (!range.isEmpty() && range.insideStart(character.row, character.column)) { renderer.setCursorStyle("default"); } else { renderer.setCursorStyle(""); From b5c9b7f3954e88647a25e92473ca12037c27e728 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 19 Dec 2014 18:45:25 +0400 Subject: [PATCH 335/545] fix typo in IE mouse handler --- lib/ace/mouse/mouse_handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index 596d8503..26985862 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -64,7 +64,7 @@ var MouseHandler = function(editor) { event.addMultiMouseDownListener(editor.renderer.scrollBarH.inner, [400, 300, 250], this, "onMouseEvent"); if (useragent.isIE) { event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor); - event.addListener(editor.renderer.scrollBarH.element, "mousemove", focusEditor); + event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor); } } event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel")); From ed5c38b7c87cece4de1acc17912aa3043dd0b11a Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 19 Dec 2014 18:50:15 +0400 Subject: [PATCH 336/545] update list of users --- index.html | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/index.html b/index.html index 73598f7b..a377c612 100644 --- a/index.html +++ b/index.html @@ -795,10 +795,10 @@ if (match) { Plunker
  • - - Application Craft -
  • + + Chrome Dev Editor +
  • @@ -838,7 +838,7 @@ if (match) { Inkling Habitat
  • - + Code Combat
  • "}; + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/xml_worker", "Worker"); + worker.attachToDocument(session.getDocument()); + + worker.on("error", function(e) { + session.setAnnotations(e.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + this.$id = "ace/mode/xml"; }).call(Mode.prototype); diff --git a/lib/ace/mode/xml/dom-parser.js b/lib/ace/mode/xml/dom-parser.js new file mode 100644 index 00000000..669cd985 --- /dev/null +++ b/lib/ace/mode/xml/dom-parser.js @@ -0,0 +1,262 @@ +define(function(require, exports, module) { +'use strict'; + +var XMLReader = require('./sax'), + DOMImplementation = require('./dom'); + +function DOMParser(options){ + this.options = options ||{locator:{}}; + +} +DOMParser.prototype.parseFromString = function(source,mimeType){ + var options = this.options; + var sax = new XMLReader(); + var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler + var errorHandler = options.errorHandler; + var locator = options.locator; + var defaultNSMap = options.xmlns||{}; + var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"} + if(locator){ + domBuilder.setDocumentLocator(locator) + } + + sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator); + sax.domBuilder = options.domBuilder || domBuilder; + if(/\/x?html?$/.test(mimeType)){ + entityMap.nbsp = '\xa0'; + entityMap.copy = '\xa9'; + defaultNSMap['']= 'http://www.w3.org/1999/xhtml'; + } + if(source){ + sax.parse(source,defaultNSMap,entityMap); + }else{ + sax.errorHandler.error("invalid document source"); + } + return domBuilder.document; +} +function buildErrorHandler(errorImpl,domBuilder,locator){ + if(!errorImpl){ + if(domBuilder instanceof DOMHandler){ + return domBuilder; + } + errorImpl = domBuilder ; + } + var errorHandler = {} + var isCallback = errorImpl instanceof Function; + locator = locator||{} + function build(key){ + var fn = errorImpl[key]; + if(!fn){ + if(isCallback){ + fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl; + }else{ + var i=arguments.length; + while(--i){ + if(fn = errorImpl[arguments[i]]){ + break; + } + } + } + } + errorHandler[key] = fn && function(msg){ + fn(msg+_locator(locator), msg, locator); + }||function(){}; + } + build('warning','warn'); + build('error','warn','warning'); + build('fatalError','warn','warning','error'); + return errorHandler; +} +/** + * +ContentHandler+ErrorHandler + * +LexicalHandler+EntityResolver2 + * -DeclHandler-DTDHandler + * + * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler + * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2 + * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html + */ +function DOMHandler() { + this.cdata = false; +} +function position(locator,node){ + node.lineNumber = locator.lineNumber; + node.columnNumber = locator.columnNumber; +} +/** + * @see org.xml.sax.ContentHandler#startDocument + * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html + */ +DOMHandler.prototype = { + startDocument : function() { + this.document = DOMImplementation.createDocument(null, null, null); + if (this.locator) { + this.document.documentURI = this.locator.systemId; + } + }, + startElement:function(namespaceURI, localName, qName, attrs) { + var doc = this.document; + var el = doc.createElementNS(namespaceURI, qName||localName); + var len = attrs.length; + appendElement(this, el); + this.currentElement = el; + + this.locator && position(this.locator,el) + for (var i = 0 ; i < len; i++) { + var namespaceURI = attrs.getURI(i); + var value = attrs.getValue(i); + var qName = attrs.getQName(i); + var attr = doc.createAttributeNS(namespaceURI, qName); + if( attr.getOffset){ + position(attr.getOffset(1),attr) + } + attr.value = attr.nodeValue = value; +// Fork : сохраняем тип кавычки (" или ') + if (attrs[i].quotSymbol){ attr.quotSymbol = attrs[i].quotSymbol; } +// endFork + el.setAttributeNode(attr) + } + }, + endElement:function(namespaceURI, localName, qName) { + var current = this.currentElement + var tagName = current.tagName; + this.currentElement = current.parentNode; + }, + startPrefixMapping:function(prefix, uri) { + }, + endPrefixMapping:function(prefix) { + }, + processingInstruction:function(target, data) { + var ins = this.document.createProcessingInstruction(target, data); + this.locator && position(this.locator,ins) + appendElement(this, ins); + }, + ignorableWhitespace:function(ch, start, length) { + }, + characters:function(chars, start, length) { + chars = _toString.apply(this,arguments) + //console.log(chars) + if(this.currentElement && chars){ + if (this.cdata) { + var charNode = this.document.createCDATASection(chars); + this.currentElement.appendChild(charNode); + } else { + var charNode = this.document.createTextNode(chars); + this.currentElement.appendChild(charNode); + } + this.locator && position(this.locator,charNode) + } + }, + skippedEntity:function(name) { + }, + endDocument:function() { + this.document.normalize(); + }, + setDocumentLocator:function (locator) { + if(this.locator = locator){// && !('lineNumber' in locator)){ + locator.lineNumber = 0; + } + }, + //LexicalHandler + comment:function(chars, start, length) { + chars = _toString.apply(this,arguments) + var comm = this.document.createComment(chars); + this.locator && position(this.locator,comm) + appendElement(this, comm); + }, + + startCDATA:function() { + //used in characters() methods + this.cdata = true; + }, + endCDATA:function() { + this.cdata = false; + }, + + startDTD:function(name, publicId, systemId) { + var impl = this.document.implementation; + if (impl && impl.createDocumentType) { + var dt = impl.createDocumentType(name, publicId, systemId); + this.locator && position(this.locator,dt) + appendElement(this, dt); + } + }, + /** + * @see org.xml.sax.ErrorHandler + * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html + */ + warning:function(error) { + console.warn(error,_locator(this.locator)); + }, + error:function(error) { + console.error(error,_locator(this.locator)); + }, + fatalError:function(error) { + console.error(error,_locator(this.locator)); + throw error; + } +} +function _locator(l){ + if(l){ + return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']' + } +} +function _toString(chars,start,length){ + if(typeof chars == 'string'){ + return chars.substr(start,length) + }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)") + if(chars.length >= start+length || start){ + return new java.lang.String(chars,start,length)+''; + } + return chars; + } +} + +/* + * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html + * used method of org.xml.sax.ext.LexicalHandler: + * #comment(chars, start, length) + * #startCDATA() + * #endCDATA() + * #startDTD(name, publicId, systemId) + * + * + * IGNORED method of org.xml.sax.ext.LexicalHandler: + * #endDTD() + * #startEntity(name) + * #endEntity(name) + * + * + * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html + * IGNORED method of org.xml.sax.ext.DeclHandler + * #attributeDecl(eName, aName, type, mode, value) + * #elementDecl(name, model) + * #externalEntityDecl(name, publicId, systemId) + * #internalEntityDecl(name, value) + * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html + * IGNORED method of org.xml.sax.EntityResolver2 + * #resolveEntity(String name,String publicId,String baseURI,String systemId) + * #resolveEntity(publicId, systemId) + * #getExternalSubset(name, baseURI) + * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html + * IGNORED method of org.xml.sax.DTDHandler + * #notationDecl(name, publicId, systemId) {}; + * #unparsedEntityDecl(name, publicId, systemId, notationName) {}; + */ +"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){ + DOMHandler.prototype[key] = function(){return null} +}) + +/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */ +function appendElement (hander,node) { + if (!hander.currentElement) { + hander.document.appendChild(node); + } else { + hander.currentElement.appendChild(node); + } +}//appendChild and setAttributeNS are preformance key + +return { + DOMParser: DOMParser + }; +}); \ No newline at end of file diff --git a/lib/ace/mode/xml/dom.js b/lib/ace/mode/xml/dom.js new file mode 100644 index 00000000..8845f35c --- /dev/null +++ b/lib/ace/mode/xml/dom.js @@ -0,0 +1,1204 @@ +define(function(require, exports, module) { + +/* + * DOM Level 2 + * Object DOMException + * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html + * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html + */ + +function copy(src,dest){ + for(var p in src){ + dest[p] = src[p]; + } +} +/** +^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));? +^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));? + */ +function _extends(Class,Super){ + var pt = Class.prototype; + if(Object.create){ + var ppt = Object.create(Super.prototype) + pt.__proto__ = ppt; + } + if(!(pt instanceof Super)){ + function t(){}; + t.prototype = Super.prototype; + t = new t(); + copy(pt,t); + Class.prototype = pt = t; + } + if(pt.constructor != Class){ + if(typeof Class != 'function'){ + console.error("unknow Class:"+Class) + } + pt.constructor = Class + } +} +var htmlns = 'http://www.w3.org/1999/xhtml' ; +// Node Types +var NodeType = {} +var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1; +var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2; +var TEXT_NODE = NodeType.TEXT_NODE = 3; +var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4; +var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5; +var ENTITY_NODE = NodeType.ENTITY_NODE = 6; +var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7; +var COMMENT_NODE = NodeType.COMMENT_NODE = 8; +var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9; +var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10; +var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11; +var NOTATION_NODE = NodeType.NOTATION_NODE = 12; + +// ExceptionCode +var ExceptionCode = {} +var ExceptionMessage = {}; +var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = ((ExceptionMessage[1]="Index size error"),1); +var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = ((ExceptionMessage[2]="DOMString size error"),2); +var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = ((ExceptionMessage[3]="Hierarchy request error"),3); +var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = ((ExceptionMessage[4]="Wrong document"),4); +var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = ((ExceptionMessage[5]="Invalid character"),5); +var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = ((ExceptionMessage[6]="No data allowed"),6); +var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7); +var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = ((ExceptionMessage[8]="Not found"),8); +var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = ((ExceptionMessage[9]="Not supported"),9); +var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = ((ExceptionMessage[10]="Attribute in use"),10); +//level2 +var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = ((ExceptionMessage[11]="Invalid state"),11); +var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = ((ExceptionMessage[12]="Syntax error"),12); +var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = ((ExceptionMessage[13]="Invalid modification"),13); +var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = ((ExceptionMessage[14]="Invalid namespace"),14); +var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = ((ExceptionMessage[15]="Invalid access"),15); + + +function DOMException(code, message) { + if(message instanceof Error){ + var error = message; + }else{ + error = this; + Error.call(this, ExceptionMessage[code]); + this.message = ExceptionMessage[code]; + if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException); + } + error.code = code; + if(message) this.message = this.message + ": " + message; + return error; +}; +DOMException.prototype = Error.prototype; +copy(ExceptionCode,DOMException) +/** + * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177 + * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live. + * The items in the NodeList are accessible via an integral index, starting from 0. + */ +function NodeList() { +}; +NodeList.prototype = { + /** + * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive. + * @standard level1 + */ + length:0, + /** + * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null. + * @standard level1 + * @param index unsigned long + * Index into the collection. + * @return Node + * The node at the indexth position in the NodeList, or null if that is not a valid index. + */ + item: function(index) { + return this[index] || null; + } +}; +function LiveNodeList(node,refresh){ + this._node = node; + this._refresh = refresh + _updateLiveList(this); +} +function _updateLiveList(list){ + var inc = list._node._inc || list._node.ownerDocument._inc; + if(list._inc != inc){ + var ls = list._refresh(list._node); + //console.log(ls.length) + __set__(list,'length',ls.length); + copy(ls,list); + list._inc = inc; + } +} +LiveNodeList.prototype.item = function(i){ + _updateLiveList(this); + return this[i]; +} + +_extends(LiveNodeList,NodeList); +/** + * + * Objects implementing the NamedNodeMap interface are used to represent collections of nodes that can be accessed by name. Note that NamedNodeMap does not inherit from NodeList; NamedNodeMaps are not maintained in any particular order. Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index, but this is simply to allow convenient enumeration of the contents of a NamedNodeMap, and does not imply that the DOM specifies an order to these Nodes. + * NamedNodeMap objects in the DOM are live. + * used for attributes or DocumentType entities + */ +function NamedNodeMap() { +}; + +function _findNodeIndex(list,node){ + var i = list.length; + while(i--){ + if(list[i] === node){return i} + } +} + +function _addNamedNode(el,list,newAttr,oldAttr){ + if(oldAttr){ + list[_findNodeIndex(list,oldAttr)] = newAttr; + }else{ + list[list.length++] = newAttr; + } + if(el){ + newAttr.ownerElement = el; + var doc = el.ownerDocument; + if(doc){ + oldAttr && _onRemoveAttribute(doc,el,oldAttr); + _onAddAttribute(doc,el,newAttr); + } + } +} +function _removeNamedNode(el,list,attr){ + var i = _findNodeIndex(list,attr); + if(i>=0){ + var lastIndex = list.length-1 + while(i0 || key == 'xmlns'){ +// return null; +// } + var i = this.length; + while(i--){ + var attr = this[i]; + if(attr.nodeName == key){ + return attr; + } + } + }, + setNamedItem: function(attr) { + var el = attr.ownerElement; + if(el && el!=this._ownerElement){ + throw new DOMException(INUSE_ATTRIBUTE_ERR); + } + var oldAttr = this.getNamedItem(attr.nodeName); + _addNamedNode(this._ownerElement,this,attr,oldAttr); + return oldAttr; + }, + /* returns Node */ + setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR + var el = attr.ownerElement, oldAttr; + if(el && el!=this._ownerElement){ + throw new DOMException(INUSE_ATTRIBUTE_ERR); + } + oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName); + _addNamedNode(this._ownerElement,this,attr,oldAttr); + return oldAttr; + }, + + /* returns Node */ + removeNamedItem: function(key) { + var attr = this.getNamedItem(key); + _removeNamedNode(this._ownerElement,this,attr); + return attr; + + + },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR + + //for level2 + removeNamedItemNS:function(namespaceURI,localName){ + var attr = this.getNamedItemNS(namespaceURI,localName); + _removeNamedNode(this._ownerElement,this,attr); + return attr; + }, + getNamedItemNS: function(namespaceURI, localName) { + var i = this.length; + while(i--){ + var node = this[i]; + if(node.localName == localName && node.namespaceURI == namespaceURI){ + return node; + } + } + return null; + } +}; +/** + * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 + */ +function DOMImplementation(/* Object */ features) { + this._features = {}; + if (features) { + for (var feature in features) { + this._features = features[feature]; + } + } +}; + +DOMImplementation.prototype = { + hasFeature: function(/* string */ feature, /* string */ version) { + var versions = this._features[feature.toLowerCase()]; + if (versions && (!version || version in versions)) { + return true; + } else { + return false; + } + }, + // Introduced in DOM Level 2: + createDocument:function(namespaceURI, qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR + var doc = new Document(); + doc.doctype = doctype; + if(doctype){ + doc.appendChild(doctype); + } + doc.implementation = this; + doc.childNodes = new NodeList(); + if(qualifiedName){ + var root = doc.createElementNS(namespaceURI,qualifiedName); + doc.appendChild(root); + } + return doc; + }, + // Introduced in DOM Level 2: + createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR + var node = new DocumentType(); + node.name = qualifiedName; + node.nodeName = qualifiedName; + node.publicId = publicId; + node.systemId = systemId; + // Introduced in DOM Level 2: + //readonly attribute DOMString internalSubset; + + //TODO:.. + // readonly attribute NamedNodeMap entities; + // readonly attribute NamedNodeMap notations; + return node; + } +}; + + +/** + * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247 + */ + +function Node() { +}; + +Node.prototype = { + firstChild : null, + lastChild : null, + previousSibling : null, + nextSibling : null, + attributes : null, + parentNode : null, + childNodes : null, + ownerDocument : null, + nodeValue : null, + namespaceURI : null, + prefix : null, + localName : null, + // Modified in DOM Level 2: + insertBefore:function(newChild, refChild){//raises + return _insertBefore(this,newChild,refChild); + }, + replaceChild:function(newChild, oldChild){//raises + this.insertBefore(newChild,oldChild); + if(oldChild){ + this.removeChild(oldChild); + } + }, + removeChild:function(oldChild){ + return _removeChild(this,oldChild); + }, + appendChild:function(newChild){ + return this.insertBefore(newChild,null); + }, + hasChildNodes:function(){ + return this.firstChild != null; + }, + cloneNode:function(deep){ + return cloneNode(this.ownerDocument||this,this,deep); + }, + // Modified in DOM Level 2: + normalize:function(){ + var child = this.firstChild; + while(child){ + var next = child.nextSibling; + if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){ + this.removeChild(next); + child.appendData(next.data); + }else{ + child.normalize(); + child = next; + } + } + }, + // Introduced in DOM Level 2: + isSupported:function(feature, version){ + return this.ownerDocument.implementation.hasFeature(feature,version); + }, + // Introduced in DOM Level 2: + hasAttributes:function(){ + return this.attributes.length>0; + }, + lookupPrefix:function(namespaceURI){ + var el = this; + while(el){ + var map = el._nsMap; + //console.dir(map) + if(map){ + for(var n in map){ + if(map[n] == namespaceURI){ + return n; + } + } + } + el = el.nodeType == 2?el.ownerDocument : el.parentNode; + } + return null; + }, + // Introduced in DOM Level 3: + lookupNamespaceURI:function(prefix){ + var el = this; + while(el){ + var map = el._nsMap; + //console.dir(map) + if(map){ + if(prefix in map){ + return map[prefix] ; + } + } + el = el.nodeType == 2?el.ownerDocument : el.parentNode; + } + return null; + }, + // Introduced in DOM Level 3: + isDefaultNamespace:function(namespaceURI){ + var prefix = this.lookupPrefix(namespaceURI); + return prefix == null; + } +}; + + +function _xmlEncoder(c){ + return c == '<' && '<' || + c == '>' && '>' || + c == '&' && '&' || + c == '"' && '"' || +// Fork : сохраняем тип кавычки (" или ') + c == '\'' && ''' || +// endFork + '&#'+c.charCodeAt()+';' +} + +// Fork : не реплейсим символьные коды +function replaceSpecialSymbols(string, symbolRegExp){ + var newString = string.replace(symbolRegExp,_xmlEncoder); + // нужно заменить & на & кроме случаев, когда & - начало символьного кода (напр., " или  ) + // заменяем в несколько этапов, сначала заменяем символьные коды на спец. конструкцию + newString = newString.replace(/&(\w+|#\d+);/g,'~HtmlCode::$1::endHtmlCode~'); + // после заменяем все &, которые не являются началом символьного кода + newString = newString.replace(/&/g,'&'); + // меняем спец. конструкции обратно на символьные коды + newString = newString.replace(/~HtmlCode::(\w+|#\d+)::endHtmlCode~/g,'&$1;'); + return newString; +} +// endFork + +copy(NodeType,Node); +copy(NodeType,Node.prototype); + +/** + * @param callback return true for continue,false for break + * @return boolean true: break visit; + */ +function _visitNode(node,callback){ + if(callback(node)){ + return true; + } + if(node = node.firstChild){ + do{ + if(_visitNode(node,callback)){return true} + }while(node=node.nextSibling) + } +} + + + +function Document(){ +} +function _onAddAttribute(doc,el,newAttr){ + doc && doc._inc++; + var ns = newAttr.namespaceURI ; + if(ns == 'http://www.w3.org/2000/xmlns/'){ + //update namespace + el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value + } +} +function _onRemoveAttribute(doc,el,newAttr,remove){ + doc && doc._inc++; + var ns = newAttr.namespaceURI ; + if(ns == 'http://www.w3.org/2000/xmlns/'){ + //update namespace + delete el._nsMap[newAttr.prefix?newAttr.localName:''] + } +} +function _onUpdateChild(doc,el,newChild){ + if(doc && doc._inc){ + doc._inc++; + //update childNodes + var cs = el.childNodes; + if(newChild){ + cs[cs.length++] = newChild; + }else{ + //console.log(1) + var child = el.firstChild; + var i = 0; + while(child){ + cs[i++] = child; + child =child.nextSibling; + } + cs.length = i; + } + } +} + +/** + * attributes; + * children; + * + * writeable properties: + * nodeValue,Attr:value,CharacterData:data + * prefix + */ +function _removeChild(parentNode,child){ + var previous = child.previousSibling; + var next = child.nextSibling; + if(previous){ + previous.nextSibling = next; + }else{ + parentNode.firstChild = next + } + if(next){ + next.previousSibling = previous; + }else{ + parentNode.lastChild = previous; + } + _onUpdateChild(parentNode.ownerDocument,parentNode); + return child; +} +/** + * preformance key(refChild == null) + */ +function _insertBefore(parentNode,newChild,nextChild){ + var cp = newChild.parentNode; + if(cp){ + cp.removeChild(newChild);//remove and update + } + if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){ + var newFirst = newChild.firstChild; + if (newFirst == null) { + return newChild; + } + var newLast = newChild.lastChild; + }else{ + newFirst = newLast = newChild; + } + var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild; + + newFirst.previousSibling = pre; + newLast.nextSibling = nextChild; + + + if(pre){ + pre.nextSibling = newFirst; + }else{ + parentNode.firstChild = newFirst; + } + if(nextChild == null){ + parentNode.lastChild = newLast; + }else{ + nextChild.previousSibling = newLast; + } + do{ + newFirst.parentNode = parentNode; + }while(newFirst !== newLast && (newFirst= newFirst.nextSibling)) + _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode); + //console.log(parentNode.lastChild.nextSibling == null) + if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) { + newChild.firstChild = newChild.lastChild = null; + } + return newChild; +} +function _appendSingleChild(parentNode,newChild){ + var cp = newChild.parentNode; + if(cp){ + var pre = parentNode.lastChild; + cp.removeChild(newChild);//remove and update + var pre = parentNode.lastChild; + } + var pre = parentNode.lastChild; + newChild.parentNode = parentNode; + newChild.previousSibling = pre; + newChild.nextSibling = null; + if(pre){ + pre.nextSibling = newChild; + }else{ + parentNode.firstChild = newChild; + } + parentNode.lastChild = newChild; + _onUpdateChild(parentNode.ownerDocument,parentNode,newChild); + return newChild; + //console.log("__aa",parentNode.lastChild.nextSibling == null) +} +Document.prototype = { + //implementation : null, + nodeName : '#document', + nodeType : DOCUMENT_NODE, + doctype : null, + documentElement : null, + _inc : 1, + + insertBefore : function(newChild, refChild){//raises + if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){ + var child = newChild.firstChild; + while(child){ + var next = child.nextSibling; + this.insertBefore(child,refChild); + child = next; + } + return newChild; + } + if(this.documentElement == null && newChild.nodeType == 1){ + this.documentElement = newChild; + } + + return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild; + }, + removeChild : function(oldChild){ + if(this.documentElement == oldChild){ + this.documentElement = null; + } + return _removeChild(this,oldChild); + }, + // Introduced in DOM Level 2: + importNode : function(importedNode,deep){ + return importNode(this,importedNode,deep); + }, + // Introduced in DOM Level 2: + getElementById : function(id){ + var rtv = null; + _visitNode(this.documentElement,function(node){ + if(node.nodeType == 1){ + if(node.getAttribute('id') == id){ + rtv = node; + return true; + } + } + }) + return rtv; + }, + + //document factory method: + createElement : function(tagName){ + var node = new Element(); + node.ownerDocument = this; + node.nodeName = tagName; + node.tagName = tagName; + node.childNodes = new NodeList(); + var attrs = node.attributes = new NamedNodeMap(); + attrs._ownerElement = node; + return node; + }, + createDocumentFragment : function(){ + var node = new DocumentFragment(); + node.ownerDocument = this; + node.childNodes = new NodeList(); + return node; + }, + createTextNode : function(data){ + var node = new Text(); + node.ownerDocument = this; + node.appendData(data) + return node; + }, + createComment : function(data){ + var node = new Comment(); + node.ownerDocument = this; + node.appendData(data) + return node; + }, + createCDATASection : function(data){ + var node = new CDATASection(); + node.ownerDocument = this; + node.appendData(data) + return node; + }, + createProcessingInstruction : function(target,data){ + var node = new ProcessingInstruction(); + node.ownerDocument = this; + node.tagName = node.target = target; + node.nodeValue= node.data = data; + return node; + }, + createAttribute : function(name){ + var node = new Attr(); + node.ownerDocument = this; + node.name = name; + node.nodeName = name; + node.localName = name; + node.specified = true; + return node; + }, + createEntityReference : function(name){ + var node = new EntityReference(); + node.ownerDocument = this; + node.nodeName = name; + return node; + }, + // Introduced in DOM Level 2: + createElementNS : function(namespaceURI,qualifiedName){ + var node = new Element(); + var pl = qualifiedName.split(':'); + var attrs = node.attributes = new NamedNodeMap(); + node.childNodes = new NodeList(); + node.ownerDocument = this; + node.nodeName = qualifiedName; + node.tagName = qualifiedName; + node.namespaceURI = namespaceURI; + if(pl.length == 2){ + node.prefix = pl[0]; + node.localName = pl[1]; + }else{ + //el.prefix = null; + node.localName = qualifiedName; + } + attrs._ownerElement = node; + return node; + }, + // Introduced in DOM Level 2: + createAttributeNS : function(namespaceURI,qualifiedName){ + var node = new Attr(); + var pl = qualifiedName.split(':'); + node.ownerDocument = this; + node.nodeName = qualifiedName; + node.name = qualifiedName; + node.namespaceURI = namespaceURI; + node.specified = true; + if(pl.length == 2){ + node.prefix = pl[0]; + node.localName = pl[1]; + }else{ + //el.prefix = null; + node.localName = qualifiedName; + } + return node; + } +}; +_extends(Document,Node); + + +function Element() { + this._nsMap = {}; +}; +Element.prototype = { + nodeType : ELEMENT_NODE, + hasAttribute : function(name){ + return this.getAttributeNode(name)!=null; + }, + getAttribute : function(name){ + var attr = this.getAttributeNode(name); + return attr && attr.value || ''; + }, + getAttributeNode : function(name){ + return this.attributes.getNamedItem(name); + }, + setAttribute : function(name, value){ + var attr = this.ownerDocument.createAttribute(name); + attr.value = attr.nodeValue = "" + value; + this.setAttributeNode(attr) + }, + removeAttribute : function(name){ + var attr = this.getAttributeNode(name) + attr && this.removeAttributeNode(attr); + }, + + //four real opeartion method + appendChild:function(newChild){ + if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){ + return this.insertBefore(newChild,null); + }else{ + return _appendSingleChild(this,newChild); + } + }, + setAttributeNode : function(newAttr){ + return this.attributes.setNamedItem(newAttr); + }, + setAttributeNodeNS : function(newAttr){ + return this.attributes.setNamedItemNS(newAttr); + }, + removeAttributeNode : function(oldAttr){ + return this.attributes.removeNamedItem(oldAttr.nodeName); + }, + //get real attribute name,and remove it by removeAttributeNode + removeAttributeNS : function(namespaceURI, localName){ + var old = this.getAttributeNodeNS(namespaceURI, localName); + old && this.removeAttributeNode(old); + }, + + hasAttributeNS : function(namespaceURI, localName){ + return this.getAttributeNodeNS(namespaceURI, localName)!=null; + }, + getAttributeNS : function(namespaceURI, localName){ + var attr = this.getAttributeNodeNS(namespaceURI, localName); + return attr && attr.value || ''; + }, + setAttributeNS : function(namespaceURI, qualifiedName, value){ + var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName); + attr.value = attr.nodeValue = value; + this.setAttributeNode(attr) + }, + getAttributeNodeNS : function(namespaceURI, localName){ + return this.attributes.getNamedItemNS(namespaceURI, localName); + }, + + getElementsByTagName : function(tagName){ + return new LiveNodeList(this,function(base){ + var ls = []; + _visitNode(base,function(node){ + if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){ + ls.push(node); + } + }); + return ls; + }); + }, + getElementsByTagNameNS : function(namespaceURI, localName){ + return new LiveNodeList(this,function(base){ + var ls = []; + _visitNode(base,function(node){ + if(node !== base && node.nodeType === ELEMENT_NODE && node.namespaceURI === namespaceURI && (localName === '*' || node.localName == localName)){ + ls.push(node); + } + }); + return ls; + }); + } +}; +Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName; +Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS; + + +_extends(Element,Node); +function Attr() { +}; +Attr.prototype.nodeType = ATTRIBUTE_NODE; +_extends(Attr,Node); + + +function CharacterData() { +}; +CharacterData.prototype = { + data : '', + substringData : function(offset, count) { + return this.data.substring(offset, offset+count); + }, + appendData: function(text) { + text = this.data+text; + this.nodeValue = this.data = text; + this.length = text.length; + }, + insertData: function(offset,text) { + this.replaceData(offset,0,text); + + }, + appendChild:function(newChild){ + //if(!(newChild instanceof CharacterData)){ + throw new Error(ExceptionMessage[3]) + //} + return Node.prototype.appendChild.apply(this,arguments) + }, + deleteData: function(offset, count) { + this.replaceData(offset,count,""); + }, + replaceData: function(offset, count, text) { + var start = this.data.substring(0,offset); + var end = this.data.substring(offset+count); + text = start + text + end; + this.nodeValue = this.data = text; + this.length = text.length; + } +} +_extends(CharacterData,Node); +function Text() { +}; +Text.prototype = { + nodeName : "#text", + nodeType : TEXT_NODE, + splitText : function(offset) { + var text = this.data; + var newText = text.substring(offset); + text = text.substring(0, offset); + this.data = this.nodeValue = text; + this.length = text.length; + var newNode = this.ownerDocument.createTextNode(newText); + if(this.parentNode){ + this.parentNode.insertBefore(newNode, this.nextSibling); + } + return newNode; + } +} +_extends(Text,CharacterData); +function Comment() { +}; +Comment.prototype = { + nodeName : "#comment", + nodeType : COMMENT_NODE +} +_extends(Comment,CharacterData); + +function CDATASection() { +}; +CDATASection.prototype = { + nodeName : "#cdata-section", + nodeType : CDATA_SECTION_NODE +} +_extends(CDATASection,CharacterData); + + +function DocumentType() { +}; +DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE; +_extends(DocumentType,Node); + +function Notation() { +}; +Notation.prototype.nodeType = NOTATION_NODE; +_extends(Notation,Node); + +function Entity() { +}; +Entity.prototype.nodeType = ENTITY_NODE; +_extends(Entity,Node); + +function EntityReference() { +}; +EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE; +_extends(EntityReference,Node); + +function DocumentFragment() { +}; +DocumentFragment.prototype.nodeName = "#document-fragment"; +DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE; +_extends(DocumentFragment,Node); + + +function ProcessingInstruction() { +} +ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE; +_extends(ProcessingInstruction,Node); +function XMLSerializer(){} +XMLSerializer.prototype.serializeToString = function(node){ + var buf = []; + serializeToString(node,buf); + return buf.join(''); +} +Node.prototype.toString =function(){ + return XMLSerializer.prototype.serializeToString(this); +} +function serializeToString(node,buf){ + switch(node.nodeType){ + case ELEMENT_NODE: + var attrs = node.attributes; + var len = attrs.length; + var child = node.firstChild; + var nodeName = node.tagName; +// Fork : считаем, что у нас HTML-документ + var isHTML = true;//htmlns === node.namespaceURI +// endFork + buf.push('<',nodeName); + for(var i=0;i'); + //if is cdata child node + if(isHTML && /^script$/i.test(nodeName)){ + if(child){ + buf.push(child.data); + } + }else{ + while(child){ + serializeToString(child,buf); + child = child.nextSibling; + } + } + buf.push(''); + }else{ + buf.push('/>'); + } + return; + case DOCUMENT_NODE: + case DOCUMENT_FRAGMENT_NODE: + var child = node.firstChild; + while(child){ + serializeToString(child,buf); + child = child.nextSibling; + } + return; + case ATTRIBUTE_NODE: +// Fork : сохраняем тип кавычки (" или ') + аттрибут config всегда должен сохранять значение в одинарных кавычках ( config='{"caption":"Кнопка"}' ) + if (node.name === 'config' || (node.quotSymbol === '\'')){ + return buf.push(' ', node.name, '=\'', replaceSpecialSymbols(node.value + '', /[<']/g), '\''); + } +// endFork +// Fork : не реплейсим символьные коды + return buf.push(' ',node.name,'="',replaceSpecialSymbols(node.value + '', /[<"]/g),'"'); +// endFork + case TEXT_NODE: +// Fork : не реплейсим символьные коды + return buf.push(replaceSpecialSymbols(node.data,/[<]/g)); +// endFork + case CDATA_SECTION_NODE: + return buf.push( ''); + case COMMENT_NODE: + return buf.push( ""); + case DOCUMENT_TYPE_NODE: + var pubid = node.publicId; + var sysid = node.systemId; + buf.push(''); + }else if(sysid && sysid!='.'){ + buf.push(' SYSTEM "',sysid,'">'); + }else{ + var sub = node.internalSubset; + if(sub){ + buf.push(" [",sub,"]"); + } + buf.push(">"); + } + return; + case PROCESSING_INSTRUCTION_NODE: + return buf.push( ""); + case ENTITY_REFERENCE_NODE: + return buf.push( '&',node.nodeName,';'); + //case ENTITY_NODE: + //case NOTATION_NODE: + default: + buf.push('??',node.nodeName); + } +} +function importNode(doc,node,deep){ + var node2; + switch (node.nodeType) { + case ELEMENT_NODE: + node2 = node.cloneNode(false); + node2.ownerDocument = doc; + //var attrs = node2.attributes; + //var len = attrs.length; + //for(var i=0;i" + value + "", 'text/html'); + } catch (e) { + console.log("Error while parsing innerHTML " + e); + } + if (doc) { + ownNode = this.ownerDocument.importNode(doc.documentElement, true); + + while (this.firstChild) { + this.removeChild(this.firstChild); + } + while (ownNode.firstChild) { + this.appendChild(ownNode.firstChild); + } + } + } + }); + Object.defineProperty(Element.prototype, 'outerHTML', { + get: function () { + return this.toString(); + } + }); +// endFork + Object.defineProperty(LiveNodeList.prototype,'length',{ + get:function(){ + _updateLiveList(this); + return this.$$length; + } + }); + Object.defineProperty(Node.prototype,'textContent',{ + get:function(){ + return getTextContent(this); + }, + set:function(data){ + switch(this.nodeType){ + case 1: + case 11: + while(this.firstChild){ + this.removeChild(this.firstChild); + } + if(data || String(data)){ + this.appendChild(this.ownerDocument.createTextNode(data)); + } + break; + default: + //TODO: + this.data = data; + this.value = value; + this.nodeValue = data; + } + } + }) + + function getTextContent(node){ + switch(node.nodeType){ + case 1: + case 11: + var buf = []; + node = node.firstChild; + while(node){ + if(node.nodeType!==7 && node.nodeType !==8){ + buf.push(getTextContent(node)); + } + node = node.nextSibling; + } + return buf.join(''); + default: + return node.nodeValue; + } + } + __set__ = function(object,key,value){ + //console.log(value) + object['$$'+key] = value + } + } +}catch(e){//ie8 +} + +return new DOMImplementation(); +}); \ No newline at end of file diff --git a/lib/ace/mode/xml/sax.js b/lib/ace/mode/xml/sax.js new file mode 100644 index 00000000..89e82d4a --- /dev/null +++ b/lib/ace/mode/xml/sax.js @@ -0,0 +1,608 @@ +define(function(require, exports, module) { +'use strict'; + +//[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] +//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] +//[5] Name ::= NameStartChar (NameChar)* +var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF +var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\u00B7\u0300-\u036F\\ux203F-\u2040]"); +var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$'); +//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/ +//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',') + +//S_TAG, S_ATTR, S_EQ, S_V +//S_ATTR_S, S_E, S_S, S_C +var S_TAG = 0;//tag name offerring +var S_ATTR = 1;//attr name offerring +var S_ATTR_S=2;//attr name end and space offer +var S_EQ = 3;//=space? +var S_V = 4;//attr value(no quot value only) +var S_E = 5;//attr value end and no space(quot end) +var S_S = 6;//(attr value end || tag end ) && (space offer) +var S_C = 7;//closed el + +function XMLReader(){ + +} + +XMLReader.prototype = { + parse:function(source,defaultNSMap,entityMap){ + var domBuilder = this.domBuilder; + domBuilder.startDocument(); + _copy(defaultNSMap ,defaultNSMap = {}) + parse(source,defaultNSMap,entityMap, + domBuilder,this.errorHandler); + domBuilder.endDocument(); + } +} +function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){ + function fixedFromCharCode(code) { + // String.prototype.fromCharCode does not supports + // > 2 bytes unicode chars directly + if (code > 0xffff) { + code -= 0x10000; + var surrogate1 = 0xd800 + (code >> 10) + , surrogate2 = 0xdc00 + (code & 0x3ff); + + return String.fromCharCode(surrogate1, surrogate2); + } else { + return String.fromCharCode(code); + } + } + function entityReplacer(a){ + var k = a.slice(1,-1); + if(k in entityMap){ + return entityMap[k]; + }else if(k.charAt(0) === '#'){ + return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x'))) + }else{ + errorHandler.error('entity not found:'+a); + return a; + } + } + function appendText(end){//has some bugs +// Fork : не реплейсим символьные коды + var xt = source.substring(start,end);//.replace(/&#?\w+;/g,entityReplacer); +// endFork + locator&&position(start); + domBuilder.characters(xt,0,end-start); + start = end + } + function position(start,m){ + while(start>=endPos && (m = linePattern.exec(source))){ + startPos = m.index; + endPos = startPos + m[0].length; + locator.lineNumber++; + //console.log('line++:',locator,startPos,endPos) + } + locator.columnNumber = start-startPos+1; + } + var startPos = 0; + var endPos = 0; + var linePattern = /.+(?:\r\n?|\n)|.*$/g + var locator = domBuilder.locator; + + var parseStack = [{currentNSMap:defaultNSMapCopy}] + var closeMap = {}; + var start = 0; + while(true){ + var i = source.indexOf('<',start); + if(i<0){ + if(!source.substr(start).match(/^\s*$/)){ + var doc = domBuilder.document; + var text = doc.createTextNode(source.substr(start)); + doc.appendChild(text); + domBuilder.currentElement = text; + } + return; + } + if(i>start){ + appendText(i); + } + switch(source.charAt(i+1)){ + case '/': + var end = source.indexOf('>',i+3); + var tagName = source.substring(i+2,end); + if (parseStack.length > 1) { + var config = parseStack.pop(); + } else { + errorHandler.fatalError("end tag name not found for: "+tagName); + break; + } + var localNSMap = config.localNSMap; + + if(config.tagName != tagName){ + errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName ); + } + domBuilder.endElement(config.uri,config.localName,tagName); + if(localNSMap){ + for(var prefix in localNSMap){ + domBuilder.endPrefixMapping(prefix) ; + } + } + end++; + break; + // end elment + case '?':// + locator&&position(i); + end = parseInstruction(source,i,domBuilder); + break; + case '!':// 0){ +// Fork : не реплейсим символьные коды + value = source.slice(start,p);//.replace(/&#?\w+;/g,entityReplacer); +// endFork +// Fork : сохраняем тип кавычки (" или ') + el.add(attrName,value,start-1, c); +// endFork + s = S_E; + }else{ + //fatalError: no end quot match + throw new Error('attribute value no end \''+c+'\' match'); + } + }else if(s == S_V){ +// Fork : не реплейсим символьные коды + value = source.slice(start,p);//.replace(/&#?\w+;/g,entityReplacer); +// endFork + //console.log(attrName,value,start,p) +// Fork : сохраняем тип кавычки (" или ') + el.add(attrName,value,start, c); +// endFork + //console.dir(el) + errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!'); + start = p+1; + s = S_E + }else{ + //fatalError: no equal before + throw new Error('attribute value must after "="'); + } + break; + case '/': + switch(s){ + case S_TAG: + el.setTagName(source.slice(start,p)); + case S_E: + case S_S: + case S_C: + s = S_C; + el.closed = true; + case S_V: + case S_ATTR: + case S_ATTR_S: + break; + //case S_EQ: + default: + throw new Error("attribute invalid close char('/')") + } + break; + case ''://end document + //throw new Error('unexpected end of input') + errorHandler.error('unexpected end of input'); + case '>': + switch(s){ + case S_TAG: + el.setTagName(source.slice(start,p)); + case S_E: + case S_S: + case S_C: + break;//normal + case S_V://Compatible state + case S_ATTR: + value = source.slice(start,p); + if(value.slice(-1) === '/'){ + el.closed = true; + value = value.slice(0,-1) + } + case S_ATTR_S: + if(s === S_ATTR_S){ + value = attrName; + } + if(s == S_V){ + errorHandler.warning('attribute "'+value+'" missed quot(")!!'); +// Fork : не реплейсим символьные коды + el.add(attrName,value/*.replace(/&#?\w+;/g,entityReplacer)*/,start) +// endFork + }else{ + errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!') + el.add(value,value,start) + } + break; + case S_EQ: + throw new Error('attribute value missed!!'); + } +// console.log(tagName,tagNamePattern,tagNamePattern.test(tagName)) + return p; + /*xml space '\x20' | #x9 | #xD | #xA; */ + case '\u0080': + c = ' '; + default: + if(c<= ' '){//space + switch(s){ + case S_TAG: + el.setTagName(source.slice(start,p));//tagName + s = S_S; + break; + case S_ATTR: + attrName = source.slice(start,p) + s = S_ATTR_S; + break; + case S_V: +// Fork : не реплейсим символьные коды + var value = source.slice(start,p);//.replace(/&#?\w+;/g,entityReplacer); +// endFork + errorHandler.warning('attribute "'+value+'" missed quot(")!!'); + el.add(attrName,value,start) + case S_E: + s = S_S; + break; + //case S_S: + //case S_EQ: + //case S_ATTR_S: + // void();break; + //case S_C: + //ignore warning + } + }else{//not space +//S_TAG, S_ATTR, S_EQ, S_V +//S_ATTR_S, S_E, S_S, S_C + switch(s){ + //case S_TAG:void();break; + //case S_ATTR:void();break; + //case S_V:void();break; + case S_ATTR_S: + errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead!!') + el.add(attrName,attrName,start); + start = p; + s = S_ATTR; + break; + case S_E: + errorHandler.warning('attribute space is required"'+attrName+'"!!') + case S_S: + s = S_ATTR; + start = p; + break; + case S_EQ: + s = S_V; + start = p; + break; + case S_C: + throw new Error("elements closed character '/' and '>' must be connected to"); + } + } + } + p++; + } +} +/** + * @return end of the elementStartPart(end of elementEndPart for selfClosed el) + */ +function appendElement(el,domBuilder,parseStack){ + var tagName = el.tagName; + var localNSMap = null; + var currentNSMap = parseStack[parseStack.length-1].currentNSMap; + var i = el.length; + while(i--){ + var a = el[i]; + var qName = a.qName; + var value = a.value; + var nsp = qName.indexOf(':'); + if(nsp>0){ + var prefix = a.prefix = qName.slice(0,nsp); + var localName = qName.slice(nsp+1); + var nsPrefix = prefix === 'xmlns' && localName + }else{ + localName = qName; + prefix = null + nsPrefix = qName === 'xmlns' && '' + } + //can not set prefix,because prefix !== '' + a.localName = localName ; + //prefix == null for no ns prefix attribute + if(nsPrefix !== false){//hack!! + if(localNSMap == null){ + localNSMap = {} + //console.log(currentNSMap,0) + _copy(currentNSMap,currentNSMap={}) + //console.log(currentNSMap,1) + } + currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value; + a.uri = 'http://www.w3.org/2000/xmlns/' + domBuilder.startPrefixMapping(nsPrefix, value) + } + } + var i = el.length; + while(i--){ + a = el[i]; + var prefix = a.prefix; + if(prefix){//no prefix attribute has no namespace + if(prefix === 'xml'){ + a.uri = 'http://www.w3.org/XML/1998/namespace'; + }if(prefix !== 'xmlns'){ + a.uri = currentNSMap[prefix] + + //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)} + } + } + } + var nsp = tagName.indexOf(':'); + if(nsp>0){ + prefix = el.prefix = tagName.slice(0,nsp); + localName = el.localName = tagName.slice(nsp+1); + }else{ + prefix = null;//important!! + localName = el.localName = tagName; + } + //no prefix element has default namespace + var ns = el.uri = currentNSMap[prefix || '']; + domBuilder.startElement(ns,localName,tagName,el); + //endPrefixMapping and startPrefixMapping have not any help for dom builder + //localNSMap = null + if(el.closed){ + domBuilder.endElement(ns,localName,tagName); + if(localNSMap){ + for(prefix in localNSMap){ + domBuilder.endPrefixMapping(prefix) + } + } + }else{ + el.currentNSMap = currentNSMap; + el.localNSMap = localNSMap; + parseStack.push(el); + } +} +function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){ + if(/^(?:script|textarea)$/i.test(tagName)){ + var elEndStart = source.indexOf('',elStartEnd); + var text = source.substring(elStartEnd+1,elEndStart); + if(/[&<]/.test(text)){ + if(/^script$/i.test(tagName)){ + //if(!/\]\]>/.test(text)){ + //lexHandler.startCDATA(); + domBuilder.characters(text,0,text.length); + //lexHandler.endCDATA(); + return elEndStart; + //} + }//}else{//text area +// Fork : не реплейсим символьные коды + // text = text.replace(/&#?\w+;/g,entityReplacer); +// endFork + domBuilder.characters(text,0,text.length); + return elEndStart; + //} + + } + } + return elStartEnd+1; +} +function fixSelfClosed(source,elStartEnd,tagName,closeMap){ + //if(tagName in closeMap){ + var pos = closeMap[tagName]; + if(pos == null){ + //console.log(tagName) + pos = closeMap[tagName] = source.lastIndexOf('') + } + return pos',start+4); + //append comment source.substring(4,end)//|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|/=|%=|\\+=|\\-=|&=|\\^=|,|;' }, @@ -106,11 +106,11 @@ var RustHighlightRules = function() { { token: 'meta.preprocessor.source.rust', regex: '\\b\\w\\(\\w\\)*!|#\\[[\\w=\\(\\)_]+\\]\\b' }, { token: 'constant.numeric.integer.source.rust', - regex: '\\b(?:[0-9][0-9_]*|[0-9][0-9_]*(?:u|u8|u16|u32|u64)|[0-9][0-9_]*(?:i|i8|i16|i32|i64))\\b' }, + regex: '\\b(?:[0-9][0-9_]*|[0-9][0-9_]*(?:u|us|u8|u16|u32|u64)|[0-9][0-9_]*(?:i|is|i8|i16|i32|i64))\\b' }, { token: 'constant.numeric.hex.source.rust', - regex: '\\b(?:0x[a-fA-F0-9_]+|0x[a-fA-F0-9_]+(?:u|u8|u16|u32|u64)|0x[a-fA-F0-9_]+(?:i|i8|i16|i32|i64))\\b' }, + regex: '\\b(?:0x[a-fA-F0-9_]+|0x[a-fA-F0-9_]+(?:u|us|u8|u16|u32|u64)|0x[a-fA-F0-9_]+(?:i|is|i8|i16|i32|i64))\\b' }, { token: 'constant.numeric.binary.source.rust', - regex: '\\b(?:0b[01_]+|0b[01_]+(?:u|u8|u16|u32|u64)|0b[01_]+(?:i|i8|i16|i32|i64))\\b' }, + regex: '\\b(?:0b[01_]+|0b[01_]+(?:u|us|u8|u16|u32|u64)|0b[01_]+(?:i|is|i8|i16|i32|i64))\\b' }, { token: 'constant.numeric.float.source.rust', regex: '[0-9][0-9_]*(?:f32|f64|f)|[0-9][0-9_]*[eE][+-]=[0-9_]+|[0-9][0-9_]*[eE][+-]=[0-9_]+(?:f32|f64|f)|[0-9][0-9_]*\\.[0-9_]+|[0-9][0-9_]*\\.[0-9_]+(?:f32|f64|f)|[0-9][0-9_]*\\.[0-9_]+%[eE][+-]=[0-9_]+|[0-9][0-9_]*\\.[0-9_]+%[eE][+-]=[0-9_]+(?:f32|f64|f)' }, { token: 'comment.line.documentation.source.rust', From 3fe1383cdc3cbf8af378ede0c05afb5446f15acf Mon Sep 17 00:00:00 2001 From: Kevin Ushey Date: Wed, 28 Jan 2015 10:53:42 -0800 Subject: [PATCH 389/545] [xml] ensure tag name starts with letter --- lib/ace/mode/xml_highlight_rules.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/ace/mode/xml_highlight_rules.js b/lib/ace/mode/xml_highlight_rules.js index 5bb1086b..91da0e70 100644 --- a/lib/ace/mode/xml_highlight_rules.js +++ b/lib/ace/mode/xml_highlight_rules.js @@ -35,6 +35,9 @@ var oop = require("../lib/oop"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var XmlHighlightRules = function(normalize) { + + var tagRegex = "[a-zA-Z][-_a-zA-Z0-9]*"; + this.$rules = { start : [ {token : "string.cdata.xml", regex : "<\\!\\[CDATA\\[", next : "cdata"}, @@ -44,7 +47,7 @@ var XmlHighlightRules = function(normalize) { }, { token : ["punctuation.instruction.xml", "keyword.instruction.xml"], - regex : "(<\\?)([-_a-zA-Z0-9]+)", next : "processing_instruction", + regex : "(<\\?)(" + tagRegex + ")", next : "processing_instruction", }, {token : "comment.xml", regex : "<\\!--", next : "comment"}, { @@ -60,7 +63,7 @@ var XmlHighlightRules = function(normalize) { xml_decl : [{ token : "entity.other.attribute-name.decl-attribute-name.xml", - regex : "(?:[-_a-zA-Z0-9]+:)?[-_a-zA-Z0-9]+" + regex : "(?:" + tagRegex + ":)?" + tagRegex + "" }, { token : "keyword.operator.decl-attribute-equals.xml", regex : "=" @@ -96,7 +99,7 @@ var XmlHighlightRules = function(normalize) { next: "pop" }, { token : ["punctuation.markup-decl.xml", "keyword.markup-decl.xml"], - regex : "(<\\!)([-_a-zA-Z0-9]+)", + regex : "(<\\!)(" + tagRegex + ")", push : [{ token : "text", regex : "\\s+" @@ -132,7 +135,7 @@ var XmlHighlightRules = function(normalize) { tag : [{ token : ["meta.tag.punctuation.tag-open.xml", "meta.tag.punctuation.end-tag-open.xml", "meta.tag.tag-name.xml"], - regex : "(?:(<)|(", next : "start"} @@ -166,7 +169,7 @@ var XmlHighlightRules = function(normalize) { attributes: [{ token : "entity.other.attribute-name.xml", - regex : "(?:[-_a-zA-Z0-9]+:)?[-_a-zA-Z0-9]+" + regex : "(?:" + tagRegex + ":)?" + tagRegex + "" }, { token : "keyword.operator.attribute-equals.xml", regex : "=" From c8404712484293e3241dbec1c8dbd801e92c325c Mon Sep 17 00:00:00 2001 From: Tyler Long Date: Thu, 29 Jan 2015 14:47:57 +0800 Subject: [PATCH 390/545] XAML is XML https://msdn.microsoft.com/en-us/library/cc295302.aspx --- lib/ace/ext/modelist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index db2d2f80..69aa8972 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -159,7 +159,7 @@ var supportedModes = { Velocity: ["vm"], Verilog: ["v|vh|sv|svh"], VHDL: ["vhd|vhdl"], - XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl"], + XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"], XQuery: ["xq"], YAML: ["yaml|yml"], // Add the missing mode "Django" to ext-modelist From 3e32d5bf7e1cf83585cfba7184d45aa1b607210b Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Jan 2015 18:38:51 +0400 Subject: [PATCH 391/545] workaround for vim cursor getting stuck on folded lines --- lib/ace/keyboard/vim.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index 7312821f..0641897f 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -2396,6 +2396,15 @@ dom.importCssString(".normal-mode .ace_cursor{\ (line > last && cur.line == last)) { return; } + // /ace patch + var fold = cm.ace.session.getFoldAt(line, endCh); + if (fold) { + if (motionArgs.forward) + line = fold.end.row + 1; + else + line = fold.start.row - 1; + } + // /ace patche if (motionArgs.toFirstChar){ endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); vim.lastHPos = endCh; From 42b43b1fbe22c2c584c6b71685e699fd67aae2c9 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 29 Jan 2015 19:41:40 +0400 Subject: [PATCH 392/545] fix highlighting of indented bash heredocs --- lib/ace/mode/sh_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/sh_highlight_rules.js b/lib/ace/mode/sh_highlight_rules.js index 9dd9aa33..9d32055a 100644 --- a/lib/ace/mode/sh_highlight_rules.js +++ b/lib/ace/mode/sh_highlight_rules.js @@ -104,7 +104,7 @@ var ShHighlightRules = function() { token : "keyword.operator" }, { stateName: "heredoc", - regex : "(<<)(\\s*)(['\"`]?)([\\w\\-]+)(['\"`]?)", + regex : "(<<-?)(\\s*)(['\"`]?)([\\w\\-]+)(['\"`]?)", onMatch : function(value, currentState, stack) { var next = value[2] == '-' ? "indentedHeredoc" : "heredoc"; var tokens = value.split(this.splitRegex); From 703a5394e3f29a7273070dfd7b5888fc54566432 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 3 Feb 2015 17:42:17 +0400 Subject: [PATCH 393/545] toggle fold commands must work for all selections --- lib/ace/commands/default_commands.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index d018e8bd..e941806b 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -97,24 +97,28 @@ exports.commands = [{ name: "fold", bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"), exec: function(editor) { editor.session.toggleFold(false); }, + multiSelectAction: "forEach", scrollIntoView: "center", readOnly: true }, { name: "unfold", bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"), exec: function(editor) { editor.session.toggleFold(true); }, + multiSelectAction: "forEach", scrollIntoView: "center", readOnly: true }, { name: "toggleFoldWidget", bindKey: bindKey("F2", "F2"), exec: function(editor) { editor.session.toggleFoldWidget(); }, + multiSelectAction: "forEach", scrollIntoView: "center", readOnly: true }, { name: "toggleParentFoldWidget", bindKey: bindKey("Alt-F2", "Alt-F2"), exec: function(editor) { editor.session.toggleFoldWidget(true); }, + multiSelectAction: "forEach", scrollIntoView: "center", readOnly: true }, { From d9e4b52ee12ce5972dadae36171eaed8bf9d0eb2 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 5 Feb 2015 15:57:24 +0400 Subject: [PATCH 394/545] fix alt-e at the last error --- lib/ace/ext/error_marker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/ext/error_marker.js b/lib/ace/ext/error_marker.js index 05d50498..5dbe3d2e 100644 --- a/lib/ace/ext/error_marker.js +++ b/lib/ace/ext/error_marker.js @@ -62,7 +62,7 @@ function findAnnotations(session, row, dir) { if (i < 0) i = -i - 1; - if (i >= annotations.length - 1) + if (i >= annotations.length) i = dir > 0 ? 0 : annotations.length - 1; else if (i === 0 && dir < 0) i = annotations.length - 1; From 388f0235b77a8951aec18f2ff08eade7dcb4985e Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 12 Feb 2015 19:45:43 +0400 Subject: [PATCH 395/545] fix #2348 packaged require breaks node-webkit --- build_support/mini_require.js | 87 +++++++++++++++-------------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/build_support/mini_require.js b/build_support/mini_require.js index 88937f35..1ecbb78b 100644 --- a/build_support/mini_require.js +++ b/build_support/mini_require.js @@ -38,69 +38,62 @@ var ACE_NAMESPACE = ""; -var global = (function() { - return this; -})(); +var global = (function() { return this; })(); +if (!global && typeof window != "undefined") global = window; // strict mode if (!ACE_NAMESPACE && typeof requirejs !== "undefined") return; -var _define = function(module, deps, payload) { - if (typeof module !== 'string') { - if (_define.original) - _define.original.apply(window, arguments); +var define = function(module, deps, payload) { + if (typeof module !== "string") { + if (define.original) + define.original.apply(this, arguments); else { - console.error('dropping module because define wasn\'t a string.'); + console.error("dropping module because define wasn\'t a string."); console.trace(); } return; } - if (arguments.length == 2) payload = deps; - - if (!_define.modules) { - _define.modules = {}; - _define.payloads = {}; + if (!define.modules[module]) { + define.payloads[module] = payload; + define.modules[module] = null; } - - _define.payloads[module] = payload; - _define.modules[module] = null; }; +define.modules = {}; +define.payloads = {}; + /** * Get at functionality define()ed using the function above */ var _require = function(parentId, module, callback) { - if (Object.prototype.toString.call(module) === "[object Array]") { + if (typeof module === "string") { + var payload = lookup(parentId, module); + if (payload != undefined) { + callback && callback(); + return payload; + } + } else if (Object.prototype.toString.call(module) === "[object Array]") { var params = []; for (var i = 0, l = module.length; i < l; ++i) { var dep = lookup(parentId, module[i]); - if (!dep && _require.original) - return _require.original.apply(window, arguments); + if (dep == undefined && require.original) + return; params.push(dep); } - if (callback) { - callback.apply(null, params); - } + return callback && callback.apply(null, params) || true; } - else if (typeof module === 'string') { - var payload = lookup(parentId, module); - if (!payload && _require.original) - return _require.original.apply(window, arguments); +}; - if (callback) { - callback(); - } - - return payload; - } - else { - if (_require.original) - return _require.original.apply(window, arguments); - } +var require = function(module, callback) { + var packagedModule = _require("", module, callback); + if (packagedModule == undefined && require.original) + return require.original.apply(this, arguments); + return packagedModule; }; var normalizeModule = function(parentId, moduleName) { @@ -119,7 +112,6 @@ var normalizeModule = function(parentId, moduleName) { moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); } } - return moduleName; }; @@ -128,12 +120,11 @@ var normalizeModule = function(parentId, moduleName) { * definition function if needed. */ var lookup = function(parentId, moduleName) { - moduleName = normalizeModule(parentId, moduleName); - var module = _define.modules[moduleName]; + var module = define.modules[moduleName]; if (!module) { - module = _define.payloads[moduleName]; + module = define.payloads[moduleName]; if (typeof module === 'function') { var exports = {}; var mod = { @@ -149,19 +140,15 @@ var lookup = function(parentId, moduleName) { var returnValue = module(req, exports, mod); exports = returnValue || mod.exports; - _define.modules[moduleName] = exports; - delete _define.payloads[moduleName]; + define.modules[moduleName] = exports; + delete define.payloads[moduleName]; } - module = _define.modules[moduleName] = exports || module; + module = define.modules[moduleName] = exports || module; } return module; }; function exportAce(ns) { - var require = function(module, callback) { - return _require("", module, callback); - }; - var root = global; if (ns) { if (!global[ns]) @@ -170,13 +157,13 @@ function exportAce(ns) { } if (!root.define || !root.define.packaged) { - _define.original = root.define; - root.define = _define; + define.original = root.define; + root.define = define; root.define.packaged = true; } if (!root.require || !root.require.packaged) { - _require.original = root.require; + require.original = root.require; root.require = require; root.require.packaged = true; } From 0b20e4dc1d0ae1c04b08f90bec878d8565c087d5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 12 Feb 2015 19:46:21 +0400 Subject: [PATCH 396/545] fix #2351 Minification fails on Windows --- Makefile.dryice.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index f6f4b42f..0ce7c657 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -307,6 +307,7 @@ function buildAceModuleInternal(opts, callback) { ignore: opts.ignore || [], withRequire: false, basepath: ACE_HOME, + transforms: [normalizeLineEndings], afterRead: [optimizeTextModules] }, write); } @@ -407,6 +408,10 @@ function getLoadedFileList(options, callback, result) { callback(Object.keys(deps)); } +function normalizeLineEndings(module) { + module.source = module.source.replace(/\r\n/g, "\n"); +} + function optimizeTextModules(sources) { var textModules = {}; return sources.filter(function(pkg) { @@ -452,10 +457,10 @@ function optimizeTextModules(sources) { if (/\.css$/.test(pkg.id)) { // remove unnecessary whitespace from css input = input.replace(/\n\s+/g, "\n"); - input = '"' + input.replace(/\r?\n/g, '\\\n') + '"'; + input = '"' + input.replace(/\n/g, '\\\n') + '"'; } else { // but don't break other files! - input = '"' + input.replace(/\r?\n/g, '\\n\\\n') + '"'; + input = '"' + input.replace(/\n/g, '\\n\\\n') + '"'; } textModules[pkg.id] = input; } From b0475ce3e4aa6dc0daa3913a0c439a17c59c4f35 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 16 Feb 2015 14:27:22 +0000 Subject: [PATCH 397/545] Added C++11 tokens to highlighting rules --- lib/ace/mode/c_cpp_highlight_rules.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/mode/c_cpp_highlight_rules.js b/lib/ace/mode/c_cpp_highlight_rules.js index b5a29799..9d2f33dc 100644 --- a/lib/ace/mode/c_cpp_highlight_rules.js +++ b/lib/ace/mode/c_cpp_highlight_rules.js @@ -18,13 +18,13 @@ var c_cppHighlightRules = function() { var storageType = ( "asm|__asm__|auto|bool|_Bool|char|_Complex|double|enum|float|" + "_Imaginary|int|long|short|signed|struct|typedef|union|unsigned|void|" + - "class|wchar_t|template" + "class|wchar_t|template|char16_t|char32_t" ); var storageModifiers = ( "const|extern|register|restrict|static|volatile|inline|private|" + "protected|public|friend|explicit|virtual|export|mutable|typename|" + - "constexpr|new|delete" + "constexpr|new|delete|alignas|alignof|decltype|noexcept|thread_local" ); var keywordOperators = ( @@ -33,7 +33,7 @@ var c_cppHighlightRules = function() { ); var builtinConstants = ( - "NULL|true|false|TRUE|FALSE" + "NULL|true|false|TRUE|FALSE|nullptr" ); var keywordMapper = this.$keywords = this.createKeywordMapper({ From 16b542aea4c0fa584d2af5633976158c3c58d335 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 18 Feb 2015 23:17:05 +0400 Subject: [PATCH 398/545] reduce crazy large negative top value on hidden textarea (fixes #2362) --- lib/ace/keyboard/textinput.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index faf73a4a..38fe0923 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -51,7 +51,7 @@ var TextInput = function(parentNode, host) { text.setAttribute("spellcheck", false); text.style.opacity = "0"; - if (useragent.isOldIE) text.style.top = "-100px"; + if (useragent.isOldIE) text.style.top = "-1000px"; parentNode.insertBefore(text, parentNode.firstChild); var PLACEHOLDER = "\x01\x01"; @@ -77,7 +77,7 @@ var TextInput = function(parentNode, host) { }); this.focus = function() { text.style.position = "fixed"; - text.style.top = "-10000000px"; + text.style.top = "-1000px"; text.focus(); setTimeout(function() { text.style.position = ""; From 4bc34f4eae5a45c00e7e5d94f25ebe7439aa7ce3 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 18 Feb 2015 23:26:22 +0400 Subject: [PATCH 399/545] fix #2341 do not use ace_editor id for the default style --- lib/ace/virtual_renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 484ebb5e..5696745c 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -46,7 +46,7 @@ var FontMetrics = require("./layer/font_metrics").FontMetrics; var EventEmitter = require("./lib/event_emitter").EventEmitter; var editorCss = require("./requirejs/text!./css/editor.css"); -dom.importCssString(editorCss, "ace_editor"); +dom.importCssString(editorCss, "ace_editor.css"); /** * The class that is responsible for drawing everything you see on the screen! From b3da9336eed368b5a23bb86b731caee1b43768cd Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Mon, 23 Feb 2015 07:01:43 -0500 Subject: [PATCH 400/545] add 'lean' mode for Lean Theorem Prover files --- lib/ace/ext/modelist.js | 2 +- lib/ace/mode/lean.js | 101 ++++++++++++ lib/ace/mode/lean_highlight_rules.js | 224 +++++++++++++++++++++++++++ lib/ace/snippets/lean.js | 7 + lib/ace/snippets/lean.snippets | 0 5 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 lib/ace/mode/lean.js create mode 100644 lib/ace/mode/lean_highlight_rules.js create mode 100644 lib/ace/snippets/lean.js create mode 100644 lib/ace/snippets/lean.snippets diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 69aa8972..fba3a245 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -99,6 +99,7 @@ var supportedModes = { JSX: ["jsx"], Julia: ["jl"], LaTeX: ["tex|latex|ltx|bib"], + Lean: ["lean|hlean"], LESS: ["less"], Liquid: ["liquid"], Lisp: ["lisp"], @@ -192,4 +193,3 @@ module.exports = { }; }); - diff --git a/lib/ace/mode/lean.js b/lib/ace/mode/lean.js new file mode 100644 index 00000000..e421f2b5 --- /dev/null +++ b/lib/ace/mode/lean.js @@ -0,0 +1,101 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var leanHighlightRules = require("./lean_highlight_rules").leanHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var Range = require("../range").Range; +// TODO(soonhok): figure out behavior and foldmode +// var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +// var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = leanHighlightRules; + + this.$outdent = new MatchingBraceOutdent(); + // this.$behaviour = new CstyleBehaviour(); + // this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "--"; + this.blockComment = {start: "/-", end: "-/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + if (match) { + indent += tab; + } + } else if (state == "doc-start") { + if (endState == "start") { + return ""; + } + var match = line.match(/^\s*(\/?)\*/); + if (match) { + if (match[1]) { + indent += " "; + } + indent += "- "; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.$id = "ace/mode/lean"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js new file mode 100644 index 00000000..d5f9a67c --- /dev/null +++ b/lib/ace/mode/lean_highlight_rules.js @@ -0,0 +1,224 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var leanHighlightRules = function() { + + var keywordControls = ( + ["import", "tactic_hint", "protected", "find_decl", + "private", "opaque", "definition", "renaming", "hiding", "exposing", + "parameter", "parameters", "begin", "proof", "qed", "conjecture", "premise", "premises", + "constant", "constants", "example", "attribute", "local", + "hypothesis", "lemma", "corollary", "variable", "variables", "print", + "theorem", "context", "open", "as", "export", "axiom", "inductive", + "with", "structure", "record", "universe", "universes", "alias", "help", "environment", + "options", "precedence", "postfix", "prefix", "calc_trans", + "calc_subst", "calc_refl", "infix", "infixl", "infixr", "notation", + "eval", "check", "exit", "end", "using", "namespace", + "section", "set_option", "omit", "classes", "instances", "coercions", "raw", + "add_rewrite", "extends", "calc", "have", "obtains", "show", "by", "in", "let", + "forall", "fun", "exists", "if", "then", "else", "assume", "match", + "take", "obtain", "from", "axioms", "fields"].join("|") + ); + + var storageType = ( + ["Prop", "Type", "Type'", "Type₊", "Type₁", "Type₂", "Type₃"].join("|") + ); + + var storageModifiers = ( + "\\[(" + + ["persistent", "notation", "parsing-only", "visible", "instance", "class", "prefix", "axioms", "fields", + "multiple-instances", "classes", "instances", "coercions", "options", "trust", + "coercion", "reducible", "irreducible", "raw"].join("|") + + ")\\]" + ); + + var keywordOperators = ( + [].join("|") + ); + + var builtinConstants = ( + "NULL|true|false|TRUE|FALSE" + ); + + var keywordMapper = this.$keywords = this.createKeywordMapper({ + "keyword.control" : keywordControls, + "storage.type" : storageType, + "keyword.operator" : keywordOperators, + "variable.language": "sorry", + "constant.language": builtinConstants + }, "identifier"); + + var identifierRe = "[A-Za-z_\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2100-\u214f][A-Za-z0-9_'\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2070-\u2079\u207f-\u2089\u2090-\u209c\u2100-\u214f]*"; + var operatorRe = new RegExp(["#", "@", "->", "∼", "↔", "/", "==", "=", ":=", "<->", + "/\\", "\\/", "∧", "∨", "≠", "<", ">", "≤", "≥", "¬", + "<=", ">=", "⁻¹", "⬝", "▸", "\\+", "\\*", "-", "/", + "λ", "→", "∃", "∀", ":="].join("|")); + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", // single line comment "--" + regex : "--.*$" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment "/-" + regex : "\\/-", + next : "comment" + }, { + token : "string", // single line + regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, { + token : "string", // multi line string start + regex : '["].*\\\\$', + next : "qqstring" + }, { + token : "string", // single line + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token : "string", // multi line string start + regex : "['].*\\\\$", + next : "qstring" + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" + }, { + token : "storage.modifier", + regex : storageModifiers + }, { + token : "keyword", // pre-compiler directives + regex : "#\\s*(?:include|import|pragma|line|define|undef|if|ifdef|else|elif|ifndef)\\b", + next : "directive" + }, { + token : "keyword", // special case pre-compiler directive + regex : "(?:#\\s*endif)\\b" + }, { + token : keywordMapper, + regex : identifierRe + }, { + token : "operator", + regex : operatorRe + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\;|\\." + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "text", + regex : "\\s+" + } + ], + "comment" : [ + { + token : "comment", // closing comment + regex : ".*?-\\/", + next : "start" + }, { + token : "comment", // comment spanning whole line + regex : ".+" + } + ], + "qqstring" : [ + { + token : "string", + regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', + next : "start" + }, { + token : "string", + regex : '.+' + } + ], + "qstring" : [ + { + token : "string", + regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'", + next : "start" + }, { + token : "string", + regex : '.+' + } + ], + "directive" : [ + { + token : "constant.other.multiline", + regex : /\\/ + }, + { + token : "constant.other.multiline", + regex : /.*\\/ + }, + { + token : "constant.other", + regex : "\\s*<.+?>", + next : "start" + }, + { + token : "constant.other", // single line + regex : '\\s*["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]', + next : "start" + }, + { + token : "constant.other", // single line + regex : "\\s*['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']", + next : "start" + }, + // "\" implies multiline, while "/" implies comment + { + token : "constant.other", + regex : /[^\\\/]+/, + next : "start" + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("start") ]); +}; + +oop.inherits(leanHighlightRules, TextHighlightRules); + +exports.leanHighlightRules = leanHighlightRules; +}); diff --git a/lib/ace/snippets/lean.js b/lib/ace/snippets/lean.js new file mode 100644 index 00000000..a3c01639 --- /dev/null +++ b/lib/ace/snippets/lean.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./lean.snippets"); +exports.scope = "lean"; + +}); diff --git a/lib/ace/snippets/lean.snippets b/lib/ace/snippets/lean.snippets new file mode 100644 index 00000000..e69de29b From 7572a9543e0f09a69f84029f3a2ac576dde1db53 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 24 Feb 2015 18:42:03 +0400 Subject: [PATCH 401/545] update syntax docs --- index.html | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/index.html b/index.html index 9e05ed68..e2440eb1 100644 --- a/index.html +++ b/index.html @@ -470,7 +470,6 @@ var fonts = lang.arrayToMap(
    this.$rules = {
         "start" : [ {
             token : "text",
    -        merge : true,
             regex : "<\\!\\[CDATA\\[",
             next : "cdata"
         },
    @@ -480,13 +479,7 @@ var fonts = lang.arrayToMap(
             regex : "\\]\\]>",
             next : "start"
         }, {
    -        token : "text",
    -        merge : true,
    -        regex : "\\s+"
    -    }, {
    -        token : "text",
    -        merge : true,
    -        regex : ".+"
    +        defaultToken : "text"
         } ]
     };

    In this extremly short sample, we're defining some highlighting rules for when Ace detectes a <![CDATA tag. When one is encountered, the tokenizer moves from start into the cdata state. It remains there, applying the text token to any string it encounters. Finally, when it hits a closing ]> symbol, it returns to the start state and continues to tokenize anything else.

    From 5ce334e930f8c2f97e45993ed7ac10baf43da2cb Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 24 Feb 2015 18:49:59 +0400 Subject: [PATCH 402/545] update CONTRIBUTING.md --- CONTRIBUTING.md | 15 ++++----------- doc/Contributor_License_Agreement-v2.pdf | Bin 89761 -> 0 bytes ...porate_Contributor_License_Agreement-v2.pdf | Bin 376398 -> 0 bytes 3 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 doc/Contributor_License_Agreement-v2.pdf delete mode 100644 doc/Corporate_Contributor_License_Agreement-v2.pdf diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c44edcb0..062af59c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,16 +7,9 @@ Feel free to fork and improve/enhance Ace any way you want. If you feel that the There are two versions of the agreement: -1. [The Individual CLA](https://github.com/ajaxorg/ace/raw/master/doc/Contributor_License_Agreement-v2.pdf): use this version if you're working on an ajax.org in your spare time, or can clearly claim ownership of copyright in what you'll be submitting. -2. [The Corporate CLA](https://github.com/ajaxorg/ace/raw/master/doc/Corporate_Contributor_License_Agreement-v2.pdf): have your corporate lawyer review and submit this if your company is going to be contributing to ajax.org projects +1. [The Individual CLA](https://docs.google.com/a/c9.io/forms/d/1MfmfrxqD_PNlNsuK0lC2KSelRLxGLGfh_wEcG0ijVvo/viewform): use this version if you're working on the Cloud9 SDK or open source projects in your spare time, or can clearly claim ownership of copyright in what you'll be submitting. +2. [The Corporate CLA](https://docs.google.com/a/c9.io/forms/d/1vFejn4111GdnCNuQ6BfnJDaxdsUEMD4KCo1ayovAfu0/viewform): have your corporate lawyer review and submit this if your company is going to be contributing to the Cloud9 SDK and/or open source projects. -If you want to contribute to an ajax.org project please print the CLA and fill it out and sign it. Then either send it by snail mail or fax to us or send it back scanned (or as a photo) by email. +If you want to contribute to the Cloud9 SDK and/or open source projects please go to the online form, fill it out and submit it. -Email: ace+cla@c9.io - -Fax: +31 (0) 206388953 - -Address: Ajax.org B.V. - Keizersgracht 241 - 1016 EA, Amsterdam - the Netherlands \ No newline at end of file +Happy coding, Cloud9 diff --git a/doc/Contributor_License_Agreement-v2.pdf b/doc/Contributor_License_Agreement-v2.pdf deleted file mode 100644 index 1c4baa870a07e67cffbbc63ac897c57a0d1ca44b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 89761 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

    M;`=Vk&NS|}T3~YZ}xH5?<?dH?gt0B?qUk6# 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


    1wW7;3||sc1?0IL%t=DIFzp@>c@>ItW*nzoru6P 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 WIsu2*UmGv%=43&lq!g7GL;8Q((E}&| diff --git a/doc/Corporate_Contributor_License_Agreement-v2.pdf b/doc/Corporate_Contributor_License_Agreement-v2.pdf deleted file mode 100644 index dbeaf37cc5dea9f57f673a748c97486ec62fd870..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376398 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%0AY3il;Q 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 + + + + + + +

      + +
      + + + \ No newline at end of file diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 16805ce2..57924056 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -326,13 +326,14 @@ exports.addCommandKeyListener = function(el, callback) { }); if (!pressedKeys) { - pressedKeys = Object.create(null); - addListener(window, "focus", function(e) { - pressedKeys = Object.create(null); - }); + resetPressedKeys(); + addListener(window, "focus", resetPressedKeys); } } }; +function resetPressedKeys(e) { + pressedKeys = Object.create(null); +} if (window.postMessage && !useragent.isOldIE) { var postMessageId = 1; From 3ce8d76c8943ad424e1821819e48fffd60768ac5 Mon Sep 17 00:00:00 2001 From: Phill Campbell Date: Mon, 27 Apr 2015 18:49:12 +0100 Subject: [PATCH 514/545] Expose ClipboardEvent in editor paste event --- lib/ace/editor.js | 4 ++-- lib/ace/keyboard/textinput.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index f00f74f6..19d4b84e 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -920,12 +920,12 @@ var Editor = function(renderer, session) { * * **/ - this.onPaste = function(text) { + this.onPaste = function(text, event) { // todo this should change when paste becomes a command if (this.$readOnly) return; - var e = {text: text}; + var e = {text: text, event: event}; this._signal("paste", e); text = e.text; if (!this.inMultiSelectMode || this.inVirtualSelectionMode) { diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 0bd57eed..4a2bb72c 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -306,7 +306,7 @@ var TextInput = function(parentNode, host) { var data = handleClipboardData(e); if (typeof data == "string") { if (data) - host.onPaste(data); + host.onPaste(data, e); if (useragent.isIE) setTimeout(resetSelection); event.preventDefault(e); From d080fe51d4433c9217bc40acbbc5876843254e7a Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 28 Apr 2015 19:01:24 +0400 Subject: [PATCH 515/545] fix #2468 error in strict mode --- lib/ace/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/config.js b/lib/ace/config.js index 34bf50fd..fe9312fd 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -39,7 +39,7 @@ var AppConfig = require("./lib/app_config").AppConfig; module.exports = exports = new AppConfig(); var global = (function() { - return this; + return this || typeof window != "undefined" && window; })(); var options = { From e72f1d833751756fdb237a35ff0a9549487bf0bf Mon Sep 17 00:00:00 2001 From: Alex Gilding Date: Tue, 28 Apr 2015 20:24:13 +0100 Subject: [PATCH 516/545] Add indentation for Scheme Just copied over the Clojure indentation rules to Scheme and changed the keywords to suit the language, so that Scheme programs can be automatically indented too --- lib/ace/mode/scheme.js | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/lib/ace/mode/scheme.js b/lib/ace/mode/scheme.js index aa462a10..2360b3da 100644 --- a/lib/ace/mode/scheme.js +++ b/lib/ace/mode/scheme.js @@ -39,15 +39,92 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var SchemeHighlightRules = require("./scheme_highlight_rules").SchemeHighlightRules; +var MatchingParensOutdent = require("./matching_parens_outdent").MatchingParensOutdent; var Mode = function() { this.HighlightRules = SchemeHighlightRules; + this.$outdent = new MatchingParensOutdent(); }; oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = ";"; + this.minorIndentFunctions = ["define", "lambda", "define-macro", "define-syntax", "syntax-rules", "define-record-type", "define-structure"]; + + this.$toIndent = function(str) { + return str.split('').map(function(ch) { + if (/\s/.exec(ch)) { + return ch; + } else { + return ' '; + } + }).join(''); + }; + + this.$calculateIndent = function(line, tab) { + var baseIndent = this.$getIndent(line); + var delta = 0; + var isParen, ch; + // Walk back from end of line, find matching braces + for (var i = line.length - 1; i >= 0; i--) { + ch = line[i]; + if (ch === '(') { + delta--; + isParen = true; + } else if (ch === '(' || ch === '[' || ch === '{') { + delta--; + isParen = false; + } else if (ch === ')' || ch === ']' || ch === '}') { + delta++; + } + if (delta < 0) { + break; + } + } + if (delta < 0 && isParen) { + // Were more brackets opened than closed and was a ( left open? + i += 1; + var iBefore = i; + var fn = ''; + while (true) { + ch = line[i]; + if (ch === ' ' || ch === '\t') { + if(this.minorIndentFunctions.indexOf(fn) !== -1) { + return this.$toIndent(line.substring(0, iBefore - 1) + tab); + } else { + return this.$toIndent(line.substring(0, i + 1)); + } + } else if (ch === undefined) { + return this.$toIndent(line.substring(0, iBefore - 1) + tab); + } + fn += line[i]; + i++; + } + } else if(delta < 0 && !isParen) { + // Were more brackets openend than closed and was it not a (? + return this.$toIndent(line.substring(0, i+1)); + } else if(delta > 0) { + // Mere more brackets closed than opened? Outdent. + baseIndent = baseIndent.substring(0, baseIndent.length - tab.length); + return baseIndent; + } else { + // Were they nicely matched? Just indent like line before. + return baseIndent; + } + }; + + this.getNextLineIndent = function(state, line, tab) { + return this.$calculateIndent(line, tab); + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; this.$id = "ace/mode/scheme"; }).call(Mode.prototype); From a61d304cbb348432fa3c71099ffa3809ccabd3ee Mon Sep 17 00:00:00 2001 From: Brian Jordan Date: Thu, 30 Apr 2015 17:14:16 -0700 Subject: [PATCH 517/545] Remove unused variable `EditSession` --- lib/ace/autocomplete/popup.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ace/autocomplete/popup.js b/lib/ace/autocomplete/popup.js index a151c746..ead0c47c 100644 --- a/lib/ace/autocomplete/popup.js +++ b/lib/ace/autocomplete/popup.js @@ -31,7 +31,6 @@ define(function(require, exports, module) { "use strict"; -var EditSession = require("../edit_session").EditSession; var Renderer = require("../virtual_renderer").VirtualRenderer; var Editor = require("../editor").Editor; var Range = require("../range").Range; From cd8099b0ad952c916f512b2309d82920da388103 Mon Sep 17 00:00:00 2001 From: Brian Jordan Date: Thu, 30 Apr 2015 17:38:19 -0700 Subject: [PATCH 518/545] Remove unused parameter `mutateData` & add ;s --- lib/ace/autocomplete.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 7e5674ae..d3b41b65 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -142,7 +142,7 @@ var Autocomplete = function() { // we have to check if activeElement is a child of popup because // on IE preventDefault doesn't stop scrollbar from being focussed var el = document.activeElement; - var text = this.editor.textInput.getElement() + var text = this.editor.textInput.getElement(); if (el != text && ( !this.popup || el.parentNode != this.popup.container ) && el != this.tooltipNode && e.relatedTarget != this.tooltipNode && e.relatedTarget != text @@ -349,7 +349,7 @@ var Autocomplete = function() { doc = selected; if (typeof doc == "string") - doc = {docText: doc} + doc = {docText: doc}; if (!doc || !(doc.docHTML || doc.docText)) return this.hideDocTooltip(); this.showDocTooltip(doc); @@ -416,7 +416,7 @@ Autocomplete.startCommand = { bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" }; -var FilteredList = function(array, filterText, mutateData) { +var FilteredList = function(array, filterText) { this.all = array; this.filtered = array; this.filterText = filterText || ""; From ad22b71cfe9293dda3fe1c689299d08580f29441 Mon Sep 17 00:00:00 2001 From: Brian Jordan Date: Fri, 1 May 2015 10:56:08 -0700 Subject: [PATCH 519/545] Update comment, add missing semicolon [ci skip] --- lib/ace/edit_session.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 3e941375..7296dc34 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -151,7 +151,7 @@ var EditSession = function(text, mode) { this.$foldData = []; this.$foldData.toString = function() { return this.join("\n"); - } + }; this.on("changeFold", this.onChangeFold.bind(this)); this.$onChange = this.onChange.bind(this); @@ -679,10 +679,10 @@ var EditSession = function(text, mode) { }; /** - * Returns an array containing the IDs of all the markers, either front or back. + * Returns an object containing the all of the markers, either front or back. * @param {Boolean} inFront If `true`, indicates you only want front markers; `false` indicates only back markers * - * @returns {Array} + * @returns {Object} **/ this.getMarkers = function(inFront) { return inFront ? this.$frontMarkers : this.$backMarkers; From 9323a2616b07d97d2288d1aecd55791b8866b9d9 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Mon, 4 May 2015 22:54:09 -0600 Subject: [PATCH 520/545] Added support for nim programming language. --- lib/ace/ext/modelist.js | 1 + lib/ace/ext/themelist.js | 1 + lib/ace/mode/nim.js | 113 ++++++++++ lib/ace/mode/nim_highlight_rules.js | 238 +++++++++++++++++++++ lib/ace/snippets/mask.js | 7 + lib/ace/snippets/mask.snippets | 0 lib/ace/snippets/nim.js | 7 + lib/ace/snippets/nim.snippets | 130 +++++++++++ lib/ace/theme/the_night_after_tomorrow.css | 139 ++++++++++++ lib/ace/theme/the_night_after_tomorrow.js | 39 ++++ 10 files changed, 675 insertions(+) create mode 100644 lib/ace/mode/nim.js create mode 100644 lib/ace/mode/nim_highlight_rules.js create mode 100644 lib/ace/snippets/mask.js create mode 100644 lib/ace/snippets/mask.snippets create mode 100644 lib/ace/snippets/nim.js create mode 100644 lib/ace/snippets/nim.snippets create mode 100644 lib/ace/theme/the_night_after_tomorrow.css create mode 100644 lib/ace/theme/the_night_after_tomorrow.js diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 7a5a1e9c..5ab899a5 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -117,6 +117,7 @@ var supportedModes = { MUSHCode: ["mc|mush"], MySQL: ["mysql"], Nix: ["nix"], + Nim: ["nim"], ObjectiveC: ["m|mm"], OCaml: ["ml|mli"], Pascal: ["pas|p"], diff --git a/lib/ace/ext/themelist.js b/lib/ace/ext/themelist.js index 2350a2e2..0df76b02 100644 --- a/lib/ace/ext/themelist.js +++ b/lib/ace/ext/themelist.js @@ -73,6 +73,7 @@ var themeData = [ ["Solarized Dark" ,"solarized_dark" , "dark"], ["Terminal" ,"terminal" , "dark"], ["Tomorrow Night" ,"tomorrow_night" , "dark"], + ["The Night After Tomorrow" ,"the_night_after_tomorrow" , "dark"], ["Tomorrow Night Blue" ,"tomorrow_night_blue" , "dark"], ["Tomorrow Night Bright","tomorrow_night_bright" , "dark"], ["Tomorrow Night 80s" ,"tomorrow_night_eighties" , "dark"], diff --git a/lib/ace/mode/nim.js b/lib/ace/mode/nim.js new file mode 100644 index 00000000..cbf48ef2 --- /dev/null +++ b/lib/ace/mode/nim.js @@ -0,0 +1,113 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var NimHighlightRules = require("./nim_highlight_rules").NimHighlightRules; +var NimFoldMode = require("./folding/pythonic").FoldMode; +var Range = require("../range").Range; + +var Mode = function() { + this.HighlightRules = NimHighlightRules; + this.foldingRules = new NimFoldMode("\\:|="); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "#"; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[\:=]\s*$/); + if (match) { + indent += tab; + } + } + + return indent; + }; + + var outdents = { + "discard": 1, + "return": 1, + "raise": 1, + "break": 1, + "continue": 1 + }; + + this.checkOutdent = function(state, line, input) { + if (input !== "\r\n" && input !== "\r" && input !== "\n") + return false; + + var tokens = this.getTokenizer().getLineTokens(line.trim(), state).tokens; + + if (!tokens) + return false; + + // ignore trailing comments + do { + var last = tokens.pop(); + } while (last && (last.type == "comment" || (last.type == "text" && last.value.match(/^\s+$/)))); + + if (!last) + return false; + + return (last.type == "keyword" && outdents[last.value]); + }; + + this.autoOutdent = function(state, doc, row) { + // outdenting in python is slightly different because it always applies + // to the next line and only of a new line is inserted + + row += 1; + var indent = this.$getIndent(doc.getLine(row)); + var tab = doc.getTabString(); + if (indent.slice(-tab.length) == tab) + doc.remove(new Range(row, indent.length-tab.length, row, indent.length)); + }; + + this.$id = "ace/mode/nim"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/nim_highlight_rules.js b/lib/ace/mode/nim_highlight_rules.js new file mode 100644 index 00000000..e762a636 --- /dev/null +++ b/lib/ace/mode/nim_highlight_rules.js @@ -0,0 +1,238 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ +/* + * TODO: nim delimiters + */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var num_suffix = "(\'[Ff]32|\'[Ff]64|\'[IiUu]8|\'[IiUu]16|\'[IiUu]32|\'[IiUu]64)"; + +var NimHighlightRules = function() { + + var keywords = ( + "addr|and|as|asm|atomic|bind|block|break|case|cast|const|continue|" + + "converter|defer|discard|distinct|div|do|elif|else|end|enum|except|" + + "export|finally|for|from|func|generic|if|import|in|include|interface|" + + "is|isnot|iterator|let|macro|method|mixin|mod|nil|not|notin|object|of|" + + "or|out|proc|ptr|raise|ref|return|shl|shr|static|template|try|tuple|" + + "type|using|var|when|while|with|without|xor|yield" + ); + + var builtinConstants = ( + "true|false|nil|NotImplemented|Ellipsis" + ); + + var storageType = ( + "string|seq|array|expr|stmt|typed|untyped|any|auto|bool|cdouble|cfloat|"+ + "cchar|clongdouble|clong|clonglong|cshort|csize|cstring|cstringarray|"+ + "culong|culonglong|cushort|guarded|natural|openarray|ordinal|pointer|"+ + "range|set|shared|static|typedesc|varargs|void" + ); + + var builtinFunctions = ( + "defined|declared|declaredInScope|echo|$" + ); + + //var futureReserved = ""; + var keywordMapper = this.createKeywordMapper({ + "invalid.deprecated": "debugger", + "support.function": builtinFunctions, + //"invalid.illegal": futureReserved, + "constant.language": builtinConstants, + "storage.type" : storageType, + "keyword": keywords + }, "identifier"); + + var strPre = "(?:r|R)?"; + + var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))"; + var octInteger = "(?:0[o]?[0-7]+)"; + var hexInteger = "(?:0[xX][\\dA-Fa-f]+)"; + var binInteger = "(?:0[bB][01]+)"; + var integer = "(?:" + decimalInteger + "|" + octInteger + "|" + hexInteger + "|" + binInteger + ")"; + + var exponent = "(?:[eE][+-]?\\d+)"; + var fraction = "(?:\\.\\d+)"; + var intPart = "(?:\\d+)"; + var pointFloat = "(?:(?:" + intPart + "?" + fraction + ")|(?:" + intPart + "\\.))"; + var exponentFloat = "(?:(?:" + pointFloat + "|" + intPart + ")" + exponent + ")"; + var floatNumber = "(?:" + exponentFloat + "|" + pointFloat + ")"; + + var stringEscape = "\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})"; + + this.$rules = { + "start" : [ { + token : "comment", + regex : "#.*$" + }, { + token : "keyword", + regex : "(proc|method|temdplate|macro|macromethod|converter|func|iterator) ", + next : "qproc_name" + }, { + token : "storage.type", + regex : "(c|cu|u)?int(8|16|32|64)?", + }, { + token : "storage.type", + regex : "(c|cu|u|cs)?char", + }, { + token : "storage.type", + regex : "float(32|64)?", + }, { + token : "docstring", + regex : "##.*$" + }, { + token : "string", // multi line """ string start + regex : strPre + '"{3}', + next : "qqstring3" + }, { + token : "string", // " string + regex : strPre + '"(?=.)', + next : "qqstring" + }, { + token : "string", // multi line ''' string start + regex : strPre + "'{3}", + next : "qstring3" + }, { + token : "backtick", // ` string + regex : strPre + "`(?=.)", + next : "qxstring" + }, { + token : "string", // ' string + regex : strPre + "'(?=.)", + next : "qstring" + }, { + token : "constant.numeric", // imaginary + regex : "(?:" + floatNumber + "|\\d+)[jJ]\\b" + }, { + token : "constant.numeric", // float + regex : floatNumber + }, { + token : "constant.numeric", // long integer + regex : integer + "[lL]\\b" + }, { + token : "constant.numeric", // integer + regex : integer + "\\b" + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|=" + }, { + token : "paren.lparen", + regex : "[\\[\\(\\{]" + }, { + token : "paren.rparen", + regex : "[\\]\\)\\}]" + }, { + token : "text", + regex : "\\s+" + } ], + "qqstring3" : [ { + token : "constant.language.escape", + regex : stringEscape + }, { + token : "string", // multi line """ string end + regex : '"{3}', + next : "start" + }, { + defaultToken : "string" + } ], + "qstring3" : [ { + token : "constant.language.escape", + regex : stringEscape + }, { + token : "string", // multi line ''' string end + regex : "'{3}", + next : "start" + }, { + defaultToken : "string" + } ], + "qqstring" : [{ + token : "constant.language.escape", + regex : stringEscape + }, { + token : "string", + regex : "\\\\$", + next : "qqstring" + }, { + token : "string", + regex : '"|$', + next : "start" + }, { + defaultToken: "string" + }], + "qstring" : [{ + token : "constant.language.escape", + regex : stringEscape + }, { + token : "string", + regex : "\\\\$", + next : "qstring" + }, { + token : "string", + regex : "'|$", + next : "start" + }, { + defaultToken: "string" + }], + "qxstring" : [{ + token : "constant.language.escape", + regex : stringEscape + }, { + token : "backtick", + regex : "\\\\$", + next : "qxstring" + }, { + token : "backtick", + regex : "`|$", + next : "start" + }, { + defaultToken: "backtick" + }], + "qproc_name":[{ + token : "proc_name", + regex : "\\w+", + },{ + token : "start_bracket", + regex : "(\\(|=|$)", + next : "start" + }], + }; +}; + +oop.inherits(NimHighlightRules, TextHighlightRules); + +exports.NimHighlightRules = NimHighlightRules; +}); diff --git a/lib/ace/snippets/mask.js b/lib/ace/snippets/mask.js new file mode 100644 index 00000000..7fbca678 --- /dev/null +++ b/lib/ace/snippets/mask.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./mask.snippets"); +exports.scope = "mask"; + +}); diff --git a/lib/ace/snippets/mask.snippets b/lib/ace/snippets/mask.snippets new file mode 100644 index 00000000..e69de29b diff --git a/lib/ace/snippets/nim.js b/lib/ace/snippets/nim.js new file mode 100644 index 00000000..6e6d02bb --- /dev/null +++ b/lib/ace/snippets/nim.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./nim.snippets"); +exports.scope = "nim"; + +}); diff --git a/lib/ace/snippets/nim.snippets b/lib/ace/snippets/nim.snippets new file mode 100644 index 00000000..a8a20a00 --- /dev/null +++ b/lib/ace/snippets/nim.snippets @@ -0,0 +1,130 @@ +snippet #! + #!/usr/bin/env nim +snippet imp + import ${1:module} +snippet from + from ${1:package} import ${2:module} +# Module Docstring +snippet docs + ## File: ${1:FILENAME:file_name} + ## Author: ${2:author} + ## Description: ${3} +snippet wh + while ${1:condition}: + ${2:# TODO: write code...} +# dowh - does the same as do...while in other languages +snippet dowh + while true: + ${1:# TODO: write code...} + if ${2:condition}: + break +snippet with + with ${1:expr} as ${2:var}: + ${3:# TODO: write code...} +# New Function +snippet proc + proc ${1:fname}(${2:`indent('.') ? 'self' : ''`}): ${3: return type} = + ##${4:docstring for $1} + ${5:# TODO: write code...} +snippet deff + def ${1:fname}(${2:`indent('.') ? 'self' : ''`}): + ${3:# TODO: write code...} +# New Method +snippet defs + def ${1:mname}(self, ${2:arg}): + ${3:# TODO: write code...} +# New Property +snippet property + def ${1:foo}(): + doc = "${2:The $1 property.}" + def fget(self): + ${3:return self._$1} + def fset(self, value): + ${4:self._$1 = value} +# Ifs +snippet if + if ${1:condition}: + ${2:# TODO: write code...} +snippet el + else: + ${1:# TODO: write code...} +snippet ei + elif ${1:condition}: + ${2:# TODO: write code...} +# For +snippet for + for ${1:item} in ${2:items}: + ${3:# TODO: write code...} +# Encodes +snippet cutf8 + # -*- coding: utf-8 -*- +snippet clatin1 + # -*- coding: latin-1 -*- +snippet cascii + # -*- coding: ascii -*- +# Lambda +snippet ld + ${1:var} = lambda ${2:vars} : ${3:action} +snippet . + self. +snippet try Try/Except + try: + ${1:# TODO: write code...} + except ${2:Exception}, ${3:e}: + ${4:raise $3} +snippet try Try/Except/Else + try: + ${1:# TODO: write code...} + except ${2:Exception}, ${3:e}: + ${4:raise $3} + else: + ${5:# TODO: write code...} +snippet try Try/Except/Finally + try: + ${1:# TODO: write code...} + except ${2:Exception}, ${3:e}: + ${4:raise $3} + finally: + ${5:# TODO: write code...} +snippet try Try/Except/Else/Finally + try: + ${1:# TODO: write code...} + except ${2:Exception}, ${3:e}: + ${4:raise $3} + else: + ${5:# TODO: write code...} + finally: + ${6:# TODO: write code...} +# if __name__ == '__main__': +snippet ifmain + if isMainModule: + ${1:main()} +snippet " + ## ${1:doc} +# test function/method +snippet test + def test_${1:description}(${2:self}): + ${3:# TODO: write code...} +# test case +snippet testcase + class ${1:ExampleCase}(unittest.TestCase): + + def test_${2:description}(self): + ${3:# TODO: write code...} +#getopt +snippet getopt + try: + # Short option syntax: "hv:" + # Long option syntax: "help" or "verbose=" + opts, args = getopt.getopt(sys.argv[1:], "${1:short_options}", [${2:long_options}]) + + except getopt.GetoptError, err: + # Print debug info + print str(err) + ${3:error_action} + + for option, argument in opts: + if option in ("-h", "--help"): + ${4} + elif option in ("-v", "--verbose"): + verbose = argument diff --git a/lib/ace/theme/the_night_after_tomorrow.css b/lib/ace/theme/the_night_after_tomorrow.css new file mode 100644 index 00000000..48d2602c --- /dev/null +++ b/lib/ace/theme/the_night_after_tomorrow.css @@ -0,0 +1,139 @@ +.ace-tomorrow-night .ace_gutter { + background: #25282c; + color: #C5C8C6 +} + +.ace-tomorrow-night .ace_print-margin { + width: 1px; + background: #25282c +} + +.ace-tomorrow-night { + background-color: #1D1F21; + color: #C5C8C6 +} + +.ace-tomorrow-night .ace_cursor { + color: #FFFFFF +} + +.ace-tomorrow-night .ace_marker-layer .ace_selection { + background: #373B41 +} + +.ace-tomorrow-night.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px #1D1F21; + border-radius: 2px +} + +.ace-tomorrow-night .ace_marker-layer .ace_step { + background: rgb(102, 82, 0) +} + +.ace-tomorrow-night .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid #4B4E55 +} + +.ace-tomorrow-night .ace_marker-layer .ace_active-line { + background: #282A2E +} + +.ace-tomorrow-night .ace_gutter-active-line { + background-color: #282A2E +} + +.ace-tomorrow-night .ace_marker-layer .ace_selected-word { + border: 1px solid #373B41 +} + +.ace-tomorrow-night .ace_invisible { + color: #4B4E55 +} + +.ace-tomorrow-night .ace_keyword, +.ace-tomorrow-night .ace_meta, +.ace-tomorrow-night .ace_support.ace_type { + color: #C4A400 +} + +.ace-tomorrow-night .ace_storage, +.ace-tomorrow-night .ace_storage.ace_type { + color: #327FD7 +} + +.ace-tomorrow-night .ace_keyword.ace_operator { + color: #8ABEB7 +} + +.ace-tomorrow-night .ace_constant.ace_language{ + color: #934B9F +} + +.ace-tomorrow-night .ace_constant.ace_character, +.ace-tomorrow-night .ace_constant.ace_numeric, +.ace-tomorrow-night .ace_keyword.ace_other.ace_unit, +.ace-tomorrow-night .ace_support.ace_constant, +.ace-tomorrow-night .ace_variable.ace_parameter { + color: #37BC9B +} + +.ace-tomorrow-night .ace_constant.ace_other { + color: #CED1CF +} + +.ace-tomorrow-night .ace_invalid { + color: #CED2CF; + background-color: #DF5F5F +} + +.ace-tomorrow-night .ace_invalid.ace_deprecated { + color: #CED2CF; + background-color: #B798BF +} + +.ace-tomorrow-night .ace_fold { + background-color: #62A5D6; + border-color: #C5C8C6 +} + +.ace-tomorrow-night .ace_entity.ace_name.ace_function, +.ace-tomorrow-night .ace_support.ace_function, +.ace-tomorrow-night .ace_variable { + color: #62A5D6 +} + +.ace-tomorrow-night .ace_support.ace_class, +.ace-tomorrow-night .ace_support.ace_type { + color: #F0C674 +} + +.ace-tomorrow-night .ace_heading, +.ace-tomorrow-night .ace_markup.ace_heading, +.ace-tomorrow-night .ace_string { + color: #CD0000 +} + +.ace-tomorrow-night .ace_proc_name { + color: #04939A +} + +.ace-tomorrow-night .ace_backtick { + color: #1DAA49 +} + +.ace-tomorrow-night .ace_entity.ace_name.ace_tag, +.ace-tomorrow-night .ace_entity.ace_other.ace_attribute-name, +.ace-tomorrow-night .ace_meta.ace_tag, +.ace-tomorrow-night .ace_string.ace_regexp, +.ace-tomorrow-night .ace_variable { + color: #FFFFFF +} + +.ace-tomorrow-night .ace_comment { + color: #3465A4 +} + +.ace-tomorrow-night .ace_indent-guide { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y +} diff --git a/lib/ace/theme/the_night_after_tomorrow.js b/lib/ace/theme/the_night_after_tomorrow.js new file mode 100644 index 00000000..3108e2a9 --- /dev/null +++ b/lib/ace/theme/the_night_after_tomorrow.js @@ -0,0 +1,39 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-tomorrow-night"; +exports.cssText = require("../requirejs/text!./the_night_after_tomorrow.css"); + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); From ef4537a09981f142b11a79b47c6e242e04bd2a80 Mon Sep 17 00:00:00 2001 From: Brian Jordan Date: Tue, 5 May 2015 09:07:46 -0700 Subject: [PATCH 521/545] Update edit_session.js Fix extra `the` --- lib/ace/edit_session.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 7296dc34..f9b43a76 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -679,7 +679,7 @@ var EditSession = function(text, mode) { }; /** - * Returns an object containing the all of the markers, either front or back. + * Returns an object containing all of the markers, either front or back. * @param {Boolean} inFront If `true`, indicates you only want front markers; `false` indicates only back markers * * @returns {Object} From 0abd9ec30e4bc6225cb01b62e34cc5ba1fd23b1f Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 11 Oct 2014 02:38:06 +0400 Subject: [PATCH 522/545] rounded corners for selections --- lib/ace/css/editor.css | 27 ++++++++++++ lib/ace/layer/marker.js | 51 ++++++++++++----------- lib/ace/theme/clouds.css | 1 - lib/ace/theme/clouds_midnight.css | 1 - lib/ace/theme/cobalt.css | 1 - lib/ace/theme/dawn.css | 1 - lib/ace/theme/idle_fingers.css | 1 - lib/ace/theme/katzenmilch.css | 1 - lib/ace/theme/kr_theme.css | 1 - lib/ace/theme/merbivore.css | 1 - lib/ace/theme/merbivore_soft.css | 1 - lib/ace/theme/mono_industrial.css | 1 - lib/ace/theme/monokai.css | 1 - lib/ace/theme/pastel_on_dark.css | 1 - lib/ace/theme/solarized_dark.css | 1 - lib/ace/theme/solarized_light.css | 1 - lib/ace/theme/terminal.css | 1 - lib/ace/theme/textmate.css | 1 - lib/ace/theme/tomorrow.css | 1 - lib/ace/theme/tomorrow_night.css | 1 - lib/ace/theme/tomorrow_night_blue.css | 1 - lib/ace/theme/tomorrow_night_bright.css | 1 - lib/ace/theme/tomorrow_night_eighties.css | 1 - lib/ace/theme/twilight.css | 1 - lib/ace/theme/vibrant_ink.css | 1 - lib/ace/theme/xcode.css | 1 - 26 files changed, 54 insertions(+), 48 deletions(-) diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css index cef995c8..87eb67b3 100644 --- a/lib/ace/css/editor.css +++ b/lib/ace/css/editor.css @@ -422,3 +422,30 @@ position: absolute; z-index: 8; } + +/* +styles = [] +for (var i = 1; i < 16; i++) { + styles.push(".ace_br" + i + "{" + ( + ["top-left", "top-right", "bottom-right", "bottom-left"] + ).map(function(x, j) { + return i & (1< next, row == end), + layerConfig, row == end ? 0 : 1, extraStyle); } }; @@ -136,7 +137,7 @@ var Marker = function(parentEl) { extraStyle = extraStyle || ""; stringBuilder.push( - "
      Date: Wed, 20 May 2015 19:48:01 +0400 Subject: [PATCH 529/545] update changelog --- ChangeLog.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index e9c41e4c..3077d171 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,5 +1,16 @@ +Version 1.2.0-pre + +* New Features + - Indented soft wrap (danyaPostfactum) + +* API Changes + - unified delta types `{start, end, action, lines}` (Alden Daniels https://github.com/ajaxorg/ace/pull/1745) + - "change" event listeners on session and editor get delta objects directly + 2015.04.03 Version 1.1.9 + - Small Enhancements and Bugfixes + 2014.11.08 Version 1.1.8 * API Changes From fe96eef206b15b88f6bd8d6364b3980ede970472 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 10 Mar 2015 20:14:36 +0400 Subject: [PATCH 530/545] fix require for paths ending with .js in the worker --- lib/ace/worker/worker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/worker/worker.js b/lib/ace/worker/worker.js index 928000dd..7a047584 100644 --- a/lib/ace/worker/worker.js +++ b/lib/ace/worker/worker.js @@ -69,7 +69,8 @@ window.require = function(parentId, id) { if (!window.require.tlns) return console.log("unable to load " + id); chunks[0] = window.require.tlns[chunks[0]] || chunks[0]; - var path = chunks.join("/") + ".js"; + var path = chunks.join("/"); + if (path.slice(-3) != ".js") path += ".js"; window.require.id = id; importScripts(path); From af5c7a9c3b44da1a64517bd8d5e4a07df32d20ba Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 22 May 2015 02:34:30 +0400 Subject: [PATCH 531/545] improve require support in worker --- lib/ace/worker/worker.js | 83 +++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/lib/ace/worker/worker.js b/lib/ace/worker/worker.js index 7a047584..28fc0fe2 100644 --- a/lib/ace/worker/worker.js +++ b/lib/ace/worker/worker.js @@ -1,8 +1,9 @@ "no use strict"; ;(function(window) { -if (typeof window.window != "undefined" && window.document) { +if (typeof window.window != "undefined" && window.document) + return; +if (window.require && window.define) return; -} window.console = function() { var msgs = Array.prototype.slice.call(arguments, 0); @@ -19,6 +20,7 @@ window.ace = window; window.onerror = function(message, file, line, col, err) { postMessage({type: "error", data: { message: message, + data: err.data, file: file, line: line, col: col, @@ -37,7 +39,7 @@ window.normalizeModule = function(parentId, moduleName) { var base = parentId.split("/").slice(0, -1).join("/"); moduleName = (base ? base + "/" : "") + moduleName; - while(moduleName.indexOf(".") !== -1 && previous != moduleName) { + while (moduleName.indexOf(".") !== -1 && previous != moduleName) { var previous = moduleName; moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); } @@ -46,7 +48,7 @@ window.normalizeModule = function(parentId, moduleName) { return moduleName; }; -window.require = function(parentId, id) { +window.require = function require(parentId, id) { if (!id) { id = parentId; parentId = null; @@ -64,18 +66,36 @@ window.require = function(parentId, id) { } return module.exports; } - - var chunks = id.split("/"); + if (!window.require.tlns) return console.log("unable to load " + id); - chunks[0] = window.require.tlns[chunks[0]] || chunks[0]; - var path = chunks.join("/"); + + var path = resolveModuleId(id, window.require.tlns); if (path.slice(-3) != ".js") path += ".js"; window.require.id = id; + window.require.modules[id] = {}; // prevent infinite loop on broken modules importScripts(path); return window.require(parentId, id); }; +function resolveModuleId(id, paths) { + var testPath = id, tail = ""; + while (testPath) { + var alias = paths[testPath]; + if (typeof alias == "string") { + return alias + tail; + } else if (alias) { + return alias.location.replace(/\/*$/, "/") + (tail || alias.main || alias.name); + } else if (alias === false) { + return ""; + } + var i = testPath.lastIndexOf("/"); + if (i === -1) break; + tail = testPath.substr(i) + tail; + testPath = testPath.slice(0, i); + } + return id; +} window.require.modules = {}; window.require.tlns = {}; @@ -101,9 +121,9 @@ window.define = function(id, deps, factory) { } if (!deps.length) - // If there is no dependencies, we inject 'require', 'exports' and - // 'module' as dependencies, to provide CommonJS compatibility. - deps = ['require', 'exports', 'module']; + // If there is no dependencies, we inject "require", "exports" and + // "module" as dependencies, to provide CommonJS compatibility. + deps = ["require", "exports", "module"]; var req = function(childId) { return window.require(id, childId); @@ -114,16 +134,16 @@ window.define = function(id, deps, factory) { factory: function() { var module = this; var returnExports = factory.apply(this, deps.map(function(dep) { - switch(dep) { - // Because 'require', 'exports' and 'module' aren't actual - // dependencies, we must handle them seperately. - case 'require': return req; - case 'exports': return module.exports; - case 'module': return module; - // But for all other dependencies, we can just go ahead and - // require them. - default: return req(dep); - } + switch (dep) { + // Because "require", "exports" and "module" aren't actual + // dependencies, we must handle them seperately. + case "require": return req; + case "exports": return module.exports; + case "module": return module; + // But for all other dependencies, we can just go ahead and + // require them. + default: return req(dep); + } })); if (returnExports) module.exports = returnExports; @@ -132,9 +152,10 @@ window.define = function(id, deps, factory) { }; }; window.define.amd = {}; - +require.tlns = {}; window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { - require.tlns = topLevelNamespaces; + for (var i in topLevelNamespaces) + require.tlns[i] = topLevelNamespaces[i]; }; window.initSender = function initSender() { @@ -174,21 +195,23 @@ var sender = window.sender = null; window.onmessage = function(e) { var msg = e.data; - if (msg.command) { + if (msg.event && sender) { + sender._signal(msg.event, msg.data); + } + else if (msg.command) { if (main[msg.command]) main[msg.command].apply(main, msg.args); + else if (window[msg.command]) + window[msg.command].apply(window, msg.args); else throw new Error("Unknown command:" + msg.command); } - else if (msg.init) { - initBaseUrls(msg.tlns); + else if (msg.init) { + window.initBaseUrls(msg.tlns); require("ace/lib/es5-shim"); - sender = window.sender = initSender(); + sender = window.sender = window.initSender(); var clazz = require(msg.module)[msg.classname]; main = window.main = new clazz(sender); - } - else if (msg.event && sender) { - sender._signal(msg.event, msg.data); } }; })(this); \ No newline at end of file From a799a4086f1e9e9912c110e9c329b4101a4047af Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 25 Apr 2015 03:02:08 +0400 Subject: [PATCH 532/545] fix quote pairing for "\n" --- lib/ace/mode/behaviour/behaviour_test.js | 10 ++++++++++ lib/ace/mode/behaviour/cstyle.js | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/ace/mode/behaviour/behaviour_test.js b/lib/ace/mode/behaviour/behaviour_test.js index 9dc27bf8..245edf99 100644 --- a/lib/ace/mode/behaviour/behaviour_test.js +++ b/lib/ace/mode/behaviour/behaviour_test.js @@ -144,6 +144,16 @@ module.exports = { exec("selectleft", 1); exec("insertstring", 1, '"'); assert.equal(editor.getValue(), '("foo")'); + + editor.setValue("", 1); + exec("selectleft", 1); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '""'); + exec("insertstring", 1, '\\'); + exec("insertstring", 1, 'n'); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '"\\n"'); + }, "test: xml": function() { editor = new Editor(new MockRenderer()); diff --git a/lib/ace/mode/behaviour/cstyle.js b/lib/ace/mode/behaviour/cstyle.js index a1dce91e..dd1b0d14 100644 --- a/lib/ace/mode/behaviour/cstyle.js +++ b/lib/ace/mode/behaviour/cstyle.js @@ -269,8 +269,8 @@ var CstyleBehaviour = function() { if (leftChar == "\\" && token && /escape/.test(token.type)) return null; - var stringBefore = token && /string/.test(token.type); - var stringAfter = !rightToken || /string/.test(rightToken.type); + var stringBefore = token && /string|escape/.test(token.type); + var stringAfter = !rightToken || /string|escape/.test(rightToken.type); var pair; if (rightChar == quote) { From 2e2d9bcdc9fa97b7b30e51dd0b864911c33e115c Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 26 Apr 2015 21:27:25 +0400 Subject: [PATCH 533/545] add more php extensions --- lib/ace/ext/modelist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 7a5a1e9c..6bc79c8b 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -122,7 +122,7 @@ var supportedModes = { Pascal: ["pas|p"], Perl: ["pl|pm"], pgSQL: ["pgsql"], - PHP: ["php|phtml"], + PHP: ["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], Prolog: ["plg|prolog"], From 5705a7c2c1090605877b8fdf7e9a7a9ee782d257 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 30 Apr 2015 03:55:19 +0400 Subject: [PATCH 534/545] fix toggle comments in handlebars mode --- lib/ace/mode/handlebars.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/ace/mode/handlebars.js b/lib/ace/mode/handlebars.js index 3f2e7179..164ad43f 100644 --- a/lib/ace/mode/handlebars.js +++ b/lib/ace/mode/handlebars.js @@ -13,7 +13,6 @@ var Mode = function() { HtmlMode.call(this); this.HighlightRules = HandlebarsHighlightRules; this.$behaviour = new HtmlBehaviour(); - this.foldingRules = new HtmlFoldMode(); }; @@ -21,7 +20,7 @@ var Mode = function() { oop.inherits(Mode, HtmlMode); (function() { - this.blockComment = {start: "{!--", end: "--}"}; + this.blockComment = {start: "{{!--", end: "--}}"}; this.$id = "ace/mode/handlebars"; }).call(Mode.prototype); From dc7643db8df6611de25b5ce37468ee233fee5ff2 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 22 May 2015 21:57:13 +0400 Subject: [PATCH 535/545] better invisible tabs (fixes #2109) --- lib/ace/layer/text.js | 7 +++---- lib/ace/layer/text_test.js | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index a105768d..01afb9f3 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -52,7 +52,7 @@ var Text = function(parentEl) { this.EOL_CHAR_LF = "\xAC"; this.EOL_CHAR_CRLF = "\xa4"; this.EOL_CHAR = this.EOL_CHAR_LF; - this.TAB_CHAR = "\u2192"; //"\u21E5"; + this.TAB_CHAR = "\u2014"; //"\u21E5"; this.SPACE_CHAR = "\xB7"; this.$padding = 0; @@ -128,8 +128,7 @@ var Text = function(parentEl) { for (var i = 1; i < tabSize + 1; i++) { if (this.showInvisibles) { tabStr.push("" - + this.TAB_CHAR - + lang.stringRepeat(" ", i - 1) + + lang.stringRepeat(this.TAB_CHAR, i) + ""); } else { tabStr.push(lang.stringRepeat(" ", i)); @@ -145,7 +144,7 @@ var Text = function(parentEl) { spaceClass = " ace_invisible_space"; tabClass = " ace_invisible_tab"; var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); - var tabContent = this.TAB_CHAR + lang.stringRepeat(" ", this.tabSize - 1); + var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize); } else{ var spaceContent = lang.stringRepeat(" ", this.tabSize); var tabContent = spaceContent; diff --git a/lib/ace/layer/text_test.js b/lib/ace/layer/text_test.js index e3403ca4..3946ec66 100644 --- a/lib/ace/layer/text_test.js +++ b/lib/ace/layer/text_test.js @@ -91,7 +91,7 @@ module.exports = { var EOL = "" + textLayer.EOL_CHAR + ""; var SPACE = function(i) {return Array(i+1).join(" ")} var DOT = function(i) {return Array(i+1).join(textLayer.SPACE_CHAR)} - var TAB = function(i) {return textLayer.TAB_CHAR + SPACE(i-1)} + var TAB = function(i) {return Array(i+1).join(textLayer.TAB_CHAR)} function testRender(results) { for (var i = results.length; i--; ) { var stringBuilder = []; From 386c508042e80aeab4fb388816babee9f74466ce Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 22 May 2015 22:14:15 +0400 Subject: [PATCH 536/545] convert paste into command --- lib/ace/commands/default_commands.js | 12 ++++++++++++ lib/ace/editor.js | 13 +++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index f1e267c1..de14df85 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -423,6 +423,12 @@ exports.commands = [{ exec: function() {}, passEvent: true, readOnly: true +}, { + name: "copy", + exec: function(editor) { + // placeholder for replay macro + }, + readOnly: true }, // commands disabled in readOnly mode @@ -439,6 +445,12 @@ exports.commands = [{ }, scrollIntoView: "cursor", multiSelectAction: "forEach" +}, { + name: "paste", + exec: function(editor, args) { + editor.$handlePaste(args); + }, + scrollIntoView: "cursor" }, { name: "removeline", bindKey: bindKey("Ctrl-D", "Command-D"), diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 22b43dd2..5da8a961 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -916,13 +916,15 @@ var Editor = function(renderer, session) { * **/ this.onPaste = function(text, event) { - // todo this should change when paste becomes a command - if (this.$readOnly) - return; - var e = {text: text, event: event}; + this.commands.exec("paste", this, e); + }; + + this.$handlePaste = function(e) { + if (typeof e == "string") + e = {text: e}; this._signal("paste", e); - text = e.text; + var text = e.text; if (!this.inMultiSelectMode || this.inVirtualSelectionMode) { this.insert(text); } else { @@ -940,7 +942,6 @@ var Editor = function(renderer, session) { this.session.insert(range.start, lines[i]); } } - this.renderer.scrollCursorIntoView(); }; this.execCommand = function(command, args) { From 2a089863e24472836116a32973852af4a66d7f1e Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 18 May 2015 16:24:10 +0400 Subject: [PATCH 537/545] fix highlighting of line-height:1.5 in less mode --- lib/ace/mode/less_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/less_highlight_rules.js b/lib/ace/mode/less_highlight_rules.js index d39bdeae..a0162765 100644 --- a/lib/ace/mode/less_highlight_rules.js +++ b/lib/ace/mode/less_highlight_rules.js @@ -231,7 +231,7 @@ var LessHighlightRules = function() { regex: "\\.[a-z0-9-_]+" }, { token: "variable.language", - regex: ":[a-z0-9-_]+" + regex: ":[a-z_][a-z0-9-_]*" }, { token: "constant", regex: "[a-z0-9-_]+" From 9f57989043842d906e88e6744da952ac55101260 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 27 May 2015 19:56:28 +0400 Subject: [PATCH 538/545] fix highlighting of tables in Gherkin mode --- lib/ace/mode/_test/tokens_gherkin.json | 40 ++++++++-------- lib/ace/mode/gherkin_highlight_rules.js | 62 +++++++++++++------------ 2 files changed, 53 insertions(+), 49 deletions(-) diff --git a/lib/ace/mode/_test/tokens_gherkin.json b/lib/ace/mode/_test/tokens_gherkin.json index d16ffc6c..173d9798 100644 --- a/lib/ace/mode/_test/tokens_gherkin.json +++ b/lib/ace/mode/_test/tokens_gherkin.json @@ -56,34 +56,34 @@ ],[ "start", ["text"," "], - ["comment","| "], - ["string","start "], - ["comment","| "], - ["string","eat "], - ["comment","| "], - ["string","left "], + ["comment","|"], + ["string"," start "], + ["comment","|"], + ["string"," eat "], + ["comment","|"], + ["string"," left "], ["comment","|"] ],[ "start", ["text"," "], - ["comment","| "], - ["string"," 12 "], - ["comment","| "], - ["string"," 5 "], - ["comment","| "], - ["string"," 7 "], + ["comment","|"], + ["string"," 12 "], + ["comment","|"], + ["string"," 5 "], + ["comment","|"], + ["string"," 7 "], ["comment","|"] ],[ "start", ["text"," "], - ["comment","| "], - ["string"," 20 "], - ["comment","| "], - ["string"," 5 "], - ["comment","| "], - ["string"," 15 "], - ["comment","| "], - ["string"," "] + ["comment","|"], + ["string"," 20 "], + ["comment","|"], + ["string"," 5 "], + ["comment","|"], + ["string"," 15 "], + ["comment","|"], + ["string"," "] ],[ "start" ],[ diff --git a/lib/ace/mode/gherkin_highlight_rules.js b/lib/ace/mode/gherkin_highlight_rules.js index d54db204..04ce877c 100644 --- a/lib/ace/mode/gherkin_highlight_rules.js +++ b/lib/ace/mode/gherkin_highlight_rules.js @@ -36,18 +36,18 @@ var stringEscape = "\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f] var GherkinHighlightRules = function() { - // need to include constant ints + // need to include constant ints this.$rules = { - start : [{ + start : [{ token: 'constant.numeric', regex: "(?:(?:[1-9]\\d*)|(?:0))" - }, { - token : "comment", - regex : "#.*$" - }, { - token : "keyword", - regex : "Feature:|Background:|Scenario:|Scenario\ Outline:|Examples:|Given|When|Then|And|But|\\*", - }, { + }, { + token : "comment", + regex : "#.*$" + }, { + token : "keyword", + regex : "Feature:|Background:|Scenario:|Scenario\ Outline:|Examples:|Given|When|Then|And|But|\\*", + }, { token : "string", // multi line """ string start regex : '"{3}', next : "qqstring3" @@ -56,22 +56,22 @@ var GherkinHighlightRules = function() { regex : '"', next : "qqstring" }, { - token : "comment", - regex : "@[A-Za-z0-9]+", - next : "start" + token : "comment", + regex : "@[A-Za-z0-9]+", + next : "start" }, { - token : "comment", - regex : "<.+>" + token : "comment", + regex : "<.+>" }, { - token : "comment", - regex : "\\| ", - next : "table-item" + token : "comment", + regex : "\\|(?=.)", + next : "table-item" }, { - token : "comment", - regex : "\\|$", - next : "start" + token : "comment", + regex : "\\|$", + next : "start" }], - "qqstring3" : [ { + "qqstring3" : [ { token : "constant.language.escape", regex : stringEscape }, { @@ -81,7 +81,7 @@ var GherkinHighlightRules = function() { }, { defaultToken : "string" }], - "qqstring" : [{ + "qqstring" : [{ token : "constant.language.escape", regex : stringEscape }, { @@ -96,15 +96,19 @@ var GherkinHighlightRules = function() { defaultToken: "string" }], "table-item" : [{ + token : "comment", + regex : /$/, + next : "start" + }, { + token : "comment", + regex : /\|/ + }, { token : "string", - regex : "[A-Za-z0-9 ]*", - next : "start" - }], + regex : /\\./ + }, { + defaultToken : "string" + }] }; - - - //new TextHighlightRules().getRules(); - } oop.inherits(GherkinHighlightRules, TextHighlightRules); From 8c1d0ab7cffb7d7efc2b49e5ec15ab9da92c18f1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 28 May 2015 13:56:33 +0400 Subject: [PATCH 539/545] fix autocomplete blur handler --- lib/ace/autocomplete.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index d3b41b65..331c2001 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -143,9 +143,10 @@ var Autocomplete = function() { // on IE preventDefault doesn't stop scrollbar from being focussed var el = document.activeElement; var text = this.editor.textInput.getElement(); - if (el != text && ( !this.popup || el.parentNode != this.popup.container ) - && el != this.tooltipNode && e.relatedTarget != this.tooltipNode - && e.relatedTarget != text + var fromTooltip = e.relatedTarget && e.relatedTarget == this.tooltipNode; + var container = this.popup && this.popup.container; + if (el != text && el.parentNode != container && !fromTooltip + && el != this.tooltipNode && e.relatedTarget != text ) { this.detach(); } From abdc4c7510e413ce072ba59c11d93b4ec4c0f26e Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Fri, 29 May 2015 09:55:02 -0600 Subject: [PATCH 540/545] Fix invalid syntax in autoresize.html The options literal had a duplicate key. --- demo/autoresize.html | 1 - 1 file changed, 1 deletion(-) diff --git a/demo/autoresize.html b/demo/autoresize.html index ef4cbe04..b0464ecd 100644 --- a/demo/autoresize.html +++ b/demo/autoresize.html @@ -49,7 +49,6 @@ require(["ace/ace"], function(ace) { var editor = ace.edit("editor3"); editor.setOptions({ - maxLines: 100, autoScrollEditorIntoView: true, maxLines: 8 }); From 446e3e1bf9fa5346100324b1e870329493bda1ef Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 31 May 2015 16:48:35 +0400 Subject: [PATCH 541/545] fix #2522 Popup position is off when gutter isn't shown --- demo/kitchen-sink/dev_util.js | 2 +- lib/ace/autocomplete.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/kitchen-sink/dev_util.js b/demo/kitchen-sink/dev_util.js index 8dab857c..f466285d 100644 --- a/demo/kitchen-sink/dev_util.js +++ b/demo/kitchen-sink/dev_util.js @@ -39,7 +39,7 @@ function warn() { s.shift(); // remove the getter s = s.join("\n"); // allow easy access to ace in console, but not in ace code - if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}/.test(s)) { + if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}|\(:\d+:\d+\)/.test(s)) { console.error("trying to access to global variable"); } } diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index d3b41b65..caef17ca 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -100,7 +100,7 @@ var Autocomplete = function() { var rect = editor.container.getBoundingClientRect(); pos.top += rect.top - renderer.layerConfig.offset; pos.left += rect.left - editor.renderer.scrollLeft; - pos.left += renderer.$gutterLayer.gutterWidth; + pos.left += renderer.gutterWidth; this.popup.show(pos, lineHeight); } else if (keepPopupPosition && !prefix) { From 1514d5f374b1b295894f5f911cb8e0ebbda0febe Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 31 May 2015 17:06:32 +0400 Subject: [PATCH 542/545] fix #2483 Exception on ctrl-alt-shift-click when $enableJumpToDef is true --- lib/ace/mouse/multi_select_handler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/mouse/multi_select_handler.js b/lib/ace/mouse/multi_select_handler.js index 45704b39..649043fa 100644 --- a/lib/ace/mouse/multi_select_handler.js +++ b/lib/ace/mouse/multi_select_handler.js @@ -83,7 +83,7 @@ function onMouseDown(e) { var selectionMode; if (editor.$mouseHandler.$enableJumpToDef) { if (ctrl && alt || accel && alt) - selectionMode = "add"; + selectionMode = shift ? "block" : "add"; else if (alt && editor.$blockSelectEnabled) selectionMode = "block"; } else { @@ -117,7 +117,7 @@ function onMouseDown(e) { if (shift) { oldRange = null; - range = selection.ranges[0]; + range = selection.ranges[0] || range; editor.removeSelectionMarker(range); } editor.once("mouseup", function() { From 2249d06337d561508eebcf00966a011cbef061f1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 31 May 2015 17:41:34 +0400 Subject: [PATCH 543/545] fix #2484 Hard-coded characterWidth in static_highlight.js and remove dependence on mockdom --- demo/static-highlighter/server.js | 17 +++++++++++------ lib/ace/ext/static_highlight.js | 10 +++++----- lib/ace/lib/dom.js | 8 +++++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/demo/static-highlighter/server.js b/demo/static-highlighter/server.js index 0878fec2..ea8361d4 100644 --- a/demo/static-highlighter/server.js +++ b/demo/static-highlighter/server.js @@ -2,15 +2,13 @@ * Simple node.js server, which generates the synax highlighted version of itself * using the Ace modes and themes on the server and serving a static web page. */ -// $' + // include ace search path and modules require("amd-loader"); -// load jsdom, which is required by Ace -require("../../lib/ace/test/mockdom"); - var http = require("http"); var fs = require("fs"); +var resolve = require("path").resolve; // load the highlighter and the desired mode and theme var highlighter = require("../../lib/ace/ext/static_highlight"); @@ -20,15 +18,22 @@ var theme = require("../../lib/ace/theme/twilight"); var port = process.env.PORT || 2222; http.createServer(function(req, res) { + var url = req.url; + var path = /[^#?\x00]*/.exec(url)[0]; + var root = resolve(__dirname + "/../../").replace(/\\/g, "/"); + path = resolve(root + "/" + path).replace(/\\/g, "/"); + if (path.indexOf(root + "/") != 0) + path = __filename; res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); - fs.readFile(__dirname + "/../../build/src/ace.js", "utf8", function(err, data) { + fs.readFile(path, "utf8", function(err, data) { + if (err) data = err.message; var highlighted = highlighter.render(data, new JavaScriptMode(), theme); res.end( '\n' + '\n' + - highlighted.html + + highlighted.html + '' ); }); diff --git a/lib/ace/ext/static_highlight.js b/lib/ace/ext/static_highlight.js index b2287f15..2acb3ac5 100644 --- a/lib/ace/ext/static_highlight.js +++ b/lib/ace/ext/static_highlight.js @@ -37,6 +37,10 @@ var baseStyles = require("../requirejs/text!./static.css"); var config = require("../config"); var dom = require("../lib/dom"); +var SimpleTextLayer = function() { + this.config = {}; +}; +SimpleTextLayer.prototype = TextLayer.prototype; var highlight = function(el, opts, callback) { var m = el.className.match(/lang-(\w+)/); @@ -149,12 +153,8 @@ highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) { session.setUseWorker(false); session.setMode(mode); - var textLayer = new TextLayer(document.createElement("div")); + var textLayer = new SimpleTextLayer(); textLayer.setSession(session); - textLayer.config = { - characterWidth: 10, - lineHeight: 20 - }; session.setValue(input); diff --git a/lib/ace/lib/dom.js b/lib/ace/lib/dom.js index ef2f7caa..2cbfe23e 100644 --- a/lib/ace/lib/dom.js +++ b/lib/ace/lib/dom.js @@ -91,6 +91,11 @@ exports.toggleCssClass = function(el, name) { return add; }; +if (typeof document == "undefined") { + exports.importCssString = function() {}; + return; +} + /* * Add or remove a CSS class from the list of classes on the given node * depending on the value of include @@ -173,9 +178,6 @@ exports.getInnerHeight = function(element) { }; -if (typeof document == "undefined") - return; - if (window.pageYOffset !== undefined) { exports.getPageScrollTop = function() { return window.pageYOffset; From 3f31ca57ed5b31443e0874dd40e15f2990d552b2 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 1 Jun 2015 01:06:39 +0400 Subject: [PATCH 544/545] fix typo --- static.js | 3 ++- tool/mode_creator.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/static.js b/static.js index a711715e..3b75c2b6 100755 --- a/static.js +++ b/static.js @@ -21,7 +21,7 @@ http.createServer(function(req, res) { if (req.method == "PUT") { if (!allowSave) return error(res, 404, "Saving not allowed pass --allow-save to enable"); - save(req, res, filename); + return save(req, res, filename); } fs.exists(filename, function(exists) { @@ -86,6 +86,7 @@ function save(req, res, filePath) { } res.statusCode = 200; res.end("OK"); + console.log("saved ", filePath); }); } diff --git a/tool/mode_creator.js b/tool/mode_creator.js index 7a2aea59..44aa67d0 100644 --- a/tool/mode_creator.js +++ b/tool/mode_creator.js @@ -126,8 +126,8 @@ function handleSaveResult(err, editor) { return log( "Write access to this file is disabled.\n"+ "To enable saving your changes to disk, clone the Ace repository\n"+ - "and run the included web server with the --allow-write option\n"+ - "`node static.js --allow-write` or `static.py --puttable=*`" + "and run the included web server with the --allow-save option\n"+ + "`node static.js --allow-save` or `static.py --puttable=*`" ); } editor.session.getUndoManager().markClean(); From 6cec0b28b2d8f7a41b8e16242bbb170ae5fab87d Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 1 Jun 2015 13:50:32 +0400 Subject: [PATCH 545/545] improve tmlanguage importer --- tool/lib.js | 105 +++++++++++++++++++++++++++++++++++++++++++-- tool/tmlanguage.js | 4 +- 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/tool/lib.js b/tool/lib.js index 8809595c..3d57b6e0 100644 --- a/tool/lib.js +++ b/tool/lib.js @@ -14,8 +14,16 @@ exports.parsePlist = function(xmlOrJSON, callback) { }); } else { try { - xmlOrJSON = xmlOrJSON.replace(/^\s*\/\/.*/gm, ""); - json = JSON.parse(xmlOrJSON) + xmlOrJSON = xmlOrJSON.replace( + /("(?:\\.|[^"])*")|(?:,\s*)+([\]\}])|(\w+)\s*:|([\]\}]\s*[\[\{])|(\/\/.*|\/\*(?:[^\*]|\*(?=[^\/]))*?\*\/)/g, + function(_, str, extraComma, noQuote, missingComma, comment) { + if (comment) + return ""; + if (missingComma) + return missingComma[0] + "," + missingComma.slice(1); + return str || extraComma || '"' + noQuote + '":'; + }); + json = JSON.parse(xmlOrJSON); } catch(e) { json = cson.parse(xmlOrJSON); } @@ -24,10 +32,101 @@ exports.parsePlist = function(xmlOrJSON, callback) { return json; }; + exports.formatJSON = function(object, initialIndent) { - return util.inspect(object, false, 40).replace(/^/gm, initialIndent||""); + return JSON.stringify(object, null, 4).replace(/^/gm, initialIndent||""); }; +exports.formatJS = function(object, initialIndent) { + return formatJS(object, 4, initialIndent); +}; + +function formatJS(object, indent, initialIndent) { + if (typeof indent == "number") + indent = Array(indent + 1).join(" "); + + function $format(buffer, totalIndent, state, o) { + if (typeof o != "object" || !o) { + if (typeof o == "string") + buffer.push(JSON.stringify(o)); + else + buffer.push("" + o); + } + else if (Array.isArray(o)) { + buffer.push("[") + + var len = totalIndent.length + var oneLine = true; + for (var i = 0; i < o.length; i++) { + if (typeof o[i] == "string") { + len += o[i].length + 2 + } else if (!o[i]) { + len += (o[i] + "").length + } else { + oneLine = false; + break; + } + len += 2; + if (len > 60) { + oneLine = false; + break; + } + } + + for (var i = 0; i < o.length; i++) { + if (o[i] && typeof o[i] == "object") { + $format(buffer, totalIndent, state, o[i]); + if (i < o.length - 1) + buffer.push(", "); + } else { + if (oneLine) + i && buffer.push(" "); + else + buffer.push("\n", totalIndent + indent) + $format(buffer, totalIndent + indent, state, o[i]); + if (i < o.length - 1) + buffer.push(","); + } + + } + if (!oneLine && buffer[buffer.length - 1] != "}") + buffer.push("\n" + totalIndent) + buffer.push("]") + } + else { + var keys = Object.keys(o); + buffer.push("{", "\n"); + for (var i = 0; i < keys.length; i++) { + buffer.push(totalIndent + indent); + if (/^\w+$/.test(keys[i])) + buffer.push(keys[i]); + else + buffer.push(JSON.stringify(keys[i])); + buffer.push(": ") + + if (keys[i] == "regex" && typeof o[keys[i]] == "string") { + try { + var re = new RegExp(o[keys[i]]); + buffer.push("/" + re.source.replace(/\\.|\//g, function(f) { + return f.length == 1 ? "\\" + f : f; + }) + "/"); + } catch(e) { + $format(buffer, totalIndent + indent, state, o[keys[i]]); + } + } else { + $format(buffer, totalIndent + indent, state, o[keys[i]]); + } + + if (i < keys.length - 1) + buffer.push(",", "\n"); + } + buffer.push("\n", totalIndent, "}"); + } + } + var buffer = []; + $format(buffer, initialIndent || "", {}, object); + return buffer.join(""); +} exports.fillTemplate = function(template, replacements) { return template.replace(/%(.+?)%/g, function(str, m) { diff --git a/tool/tmlanguage.js b/tool/tmlanguage.js index 0e458330..b5d8b851 100644 --- a/tool/tmlanguage.js +++ b/tool/tmlanguage.js @@ -662,10 +662,10 @@ function convertTmLanguage(name, langStr) { var languageHighlightRules = lib.fillTemplate(modeHighlightTemplate, { language: languageNameSanitized, - languageTokens: lib.formatJSON(patterns, " ").trim(), + languageTokens: lib.formatJS(patterns, " ").trim(), uuid: language.uuid, name: name, - metaData: lib.formatJSON(language, " ").trim() + metaData: lib.formatJS(language, "").trim() }); if (devMode) {

      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%0AY z3il;QJ^iJnXsk@>e+jk!D1;TH-g&FD-~Wiz$^xhY(_FkL^(J5%O_gQPq|)j&C$3DG zzh=5VX>7!9Uu`D4+R+xp1TV~|>aQa;gFS`+ERq(u=`7%{S4_5B(A|MoKh7S`o#kWm36LSZBo*V*!rs^n}QyiL=+t z_@tCg$0f&W5P*mgRV=6t{tkFVO^E>(|AW-(yoeZb$q8_F-htHEboFxJr@ggX964gC z>iC29!?AzT1kYR<9Jz~Lz-={@LO5kG16Yf}ureMdkVZ?XWkurw(}f{KOsSjJ%8~CA zqW0alXv5z>w#-|dnN!(yritYYIbOh~ps%Z!!`$t4cKfP=hM&eI1-$ktrxBN(Pc}2^m=H4zY&0)Nz zsPhiXB6on#cQgqw0;rW@Sqfw+V{eqbgba|_fYD$uO|p*SbO6Z`wur!^f)sJ^12n)5 z;(Z7*RN5Rz4nPSF8(18Wm*bymUaAKIhCpgEQjr>ZC@*Lz!Hb_%Fd~G95XhDQO`33q z#2s_Lsh>EG*h<+cg&d{GG}Xf5Q7dRb*5peK-l(46G{+$VRkjcZ1e6s42gp}u4GsLs zgXc!_97$CvyyHksF(qRqli}Veu7i9xV{By71bv!M*j@~%Mu#Sk(dUlVWsfoDVV4CG zu_@SB!<&w5b=O;6^aaj3_P5%+B9hrRG+CSE@!|*L=dOK7yUlyXit!PNV&ii}GK*Z! zQMoP#8(#?&)8$~q;;GMcH)N5li@`d^z`SuG5u774nJQ-!u1{#E^>3+Kms~05#HGH*MEa72hBj$C50JJegaem<= z&!=N1KBN16#PXQ;KS|5Xt2%z7{={*y+qZ+uv#)Tth%lyRWl<~%DGle#kQ$4!X)i7T z3dMloR_JG)!fnnSLTXVH{qWS#ZAWG0*6*3GZ+LQ5?gZ`D5aV9Y@Vy-0;T!?S3SFYC zuwAM5EH53Ep6O!D9AnI(QSsB5$Xx1(4FybG`_End%|+{fp-=ot~`0I)FdKS7HB`7`Yh6MGi32C>7ZkxnYu(|2N^Bi^LKD*_2lra|D*pjDepj4 zRTZ6%<_*ELc}FQRL>C^`PohCmd0((Xf;GX)SWBMH+AHRRfNPdGdhIQpz0Ftb1+_ij zn;HMD@K3y6Ug@!5higQt(jfcWB!!Yr6wP46(ae;t$M*ajicd@SHkaSKFq>oF*dy=p z%4h7beq`aw_}vv1mE0NI+J*h)wQCsDHFWj?(`mK#-!9w9LHB{-d)R*E6p=MLBAWq# zb7Z#c3&UweZp1OiCb zkp{B6=|ddCiO(B99)MmgFKLpU%!TX-hx0ehSItzWU=>fn%ylXMo>_4vNFl7qPYBT@rG_f61cy3F0~ZOR;D%5*YjGPUTT z&Gm`0_(ocMqH^(%(OaC2ESXt2*~2ShAIE4<4BhDY?9%U;w*2H3GN0yW+S1YmX^o{kHQ z$`nVh=&i2WJonJu9)F9U^lao0X6oMAp2{uHXHK1Mt!=PlZi8hv$~2`xl~#85aLs}^ z`jYl5+@Lx&duJt52Zrww;{8_W_ta+I22vvh`UQ~qPtmExutF%302A7DW1l$os^DDP z4`;;&&;DRS?0#hpz3K_ zuEu@7n$12l-u|U&%Z#^Dag+ZNH*wLLAk&VKkvlOO7jPd%&5ER`TsJ*fpXMx_XhklX zY`2IU&#+vMy7gGFpW7}*zOsJG+>hSfl6>maDY_3G5bEjR14N42LvPEYa6?p9|Dc7A z1W)?qCgGxjm1{r=qTO=sS}Qw^FLLG9s?5Vvo{RN;;oXrhtZ`kmhxREOByG}FpDCTQ zA$O!v*n891s5{@N4F9MM->7Uj;AJQuvB>IaEXU~1bzagW?VfQ9*8Re~p6zMptLmB> znme(?M4P^BKYH12-hb%9u(ji(cKB-3f$349nM{RoEU;@>2EF*EO-N$5`jeOt)8=?b zrA`b>9R16Pr{dP{DLYeGUViFuN&T5a*SartbJaSFAj;GV91stiw3NeqYLn^Y7sB^FUu=wAYb~j zW3p`$5T_6pCKs>_`m zzBeRdmw$AMt2t$)F@3awtsEAgaGPJa#U~;UyKX0ajs;u>-_$f z@XV^5dE1W#z4&_2YpcdbY-bZO=0JCc=en87J)$h$kvSfkEEipdlOY}Ftj_|}JR=GM zG-X~3Y=K(#-Q+t(rMt#v`7BzgU%UC}sbipYb6XGBE{IdG;V6Rfa$jY2Rb6X)>6ykY zwzEHZ?airwjGOY(XF-cBo)IOUkv4WkafYXdHq}F$EZ&+74??2yC<58xTy!}&DT0Rm z&SK5f*^uh2&rrV2Q;L)4AD$Bwo*5LDiW?i1j>#EAkrAQkqi1b!`@{VIo~8Z$yr`9l zyYovbjvqaB=IGhx8YaCJO^f5q6(O(4ad9%UEZxvZUDjxy`a%LojUXL1<)Wl8;SM4- z3Y47m2Bx_Pb5D8AcV3P4eDyuw=zU|D$2R4lP&yn+(pB60HT>ii_=JB)N4K{2Utx0l^u{uXs zy*1@N;Us0DDrrBXjj1C|$xg;(5~M|O35ai4UO=P`D=enRU9@Sz3)Y3cwdT;FL-aU0 z`0aJ%A-`gnC6;3xks7duGfKDTSH&UVr30)v$)~;XXk~Twspe_VXnp^>%;lxk(-I1( z8doiyLO6PabfXP9_ZV3fvN`KSV;19QTzCe|^wE`Jtmtk$I6BIPy3HZ;lT3RbocI22 z%h8&1wLM*2cP47*Y`49j!~XOKdnZM%=Kuk+7!@UEIeZO;ewrL?Md0L3n~>umP)1-Z z#OeA>0(k#ED*WT!`|``n3$iQAvwG@|UaC2XLe1%C$_=XG=o?XdG4s#Sf?_J;-|9im zBV9oUT7`rj2?46e9pFJ?574H?FjaZ}`EscMK~f|OZ6NOe0v!JwfLyW&z{+5hsOhVo zFGXsylY_Yu0-un+ z%xM|yx*rt3#XLSk7nigB+KWE2eW16>q|47X)1*vmfH5Nb+QRy8C*a>;!9$j>A zL=KxhUBi<(e`(^Z71N$K8WXK=W*ockc~j8K?~aeyDW-*EOYaHAj<*zO14BW11*tPe z8#0hW;HF1})lXCG9fklY4vZ-q6_t5c`0kLHoqvk`U|(VR@#?0twOm8bXiyN}-G>p@ zwYDx6t?g&)+Rk0FZ_7FT$nWM&{Y%2cMf;Fr3QT8_i@P=h5eGVmwerXe@5n5EB0Fa6 zxr7(ztP_xpEE?w9$-n?3LqX~+Orbm@^8^Nk=LJOM`h{ishoz5=%nZ_``G)Utp0&yC zx!1otQ~%NK)KB HG4ICvCgrn^?+Zy=X{O1VuqCBcItg_Dc|HN|0c$5isu(_nrc7FV&}~7c)0|X}xcvI;U4gHc z`-N@#o$kZ5lB1RN7cVq6h;87kpHfg|bR>Jh^{zqTD3mDItvp}o)S^QvT>64hBqSC# z`V$t*9Aw$ocD1{a+pG>%HGi6MeA4eDgZ}!u(_h~8kJ`J23g4BMIserX#1kIRna>>1+`C|+f&bm_eV&6S`2X{$x8G6`zJJSn}b9qN)hrRT| zm5t>WR#dc1owp)z(Iy{l3QJ2YSNX?QI4#T=J##n5v@*g`fH=>Ev8&cXrqa3UtYXSY zmrEy7M!9M1<_Hek>Hd4&pJUc-FF2NAEoiDfQGX=g-ce)kxkP_tpvjmG#|S~R6QNW8 zJ0dj@gUm-EMYJMRB~lDP2lY>45=Vt3iA1~!al{KL>W4rmHU5CsB@+=X<@$-HAhneF zDh&fX{3;(Aj-Ro_fMnG_Nmlw*4>=C4Qm;YFCM}rQiGvtYK|Vtr68JP*q8fNwh)yRc;q*D7!s(oK>&VefUvM^gui)W*+EkjQ3IIgqbcNC=VaKPF@Clv-}|1l@YC8h!i;InAggqPm<;{x-x{V991ExHdk1^;b{=iF^U zOOLo3%bXS^W069#QlCZm;DlBVR?1{aS#kVHAU}C)caMAR^(844meZZ(M;m%OxsbQ> zGSkF%=Gny6)kuV{_G`7(7wa24c4k@rd&VNSr;V<2KlRq^8xxUoPgsU$Y=wXPfzb=n zkZ(dCiAeQ{Oh+^!0PixFf8A6*Qi8RTqs(`RHyjvYu#DuW7Pgz|GZ_GQMW%a1PV}PoA;dD=Z0XbHPSnPEo|Z^bJIgn!9c6D<5cA z?F6aotEw)yc5oz}FyIzWIm|>12m}g?5G=-ME*yWQz%fcGoEPCjQ|x2+4?`tF&bQl- zU$s9Lwc2ap8V}t*hB1%?VWL_U#|*79p~0L+4h?`m6($1;Ib(DwuDVqA;Cs&5;r*wC zrwyxiBxmI1X6{c*e}8A5^DlLQp=r$Vj?~!hU6jNoL4ZTFA5mYT@iPqJb@O!fcST>n?z4vF7$w>I%Vj4Ah+t#@k*{bNs# zUR30yD-iuo$KY0sIRQ;E%GCnm1tWDOI45n9D^?j%IsOsplR^`}GjCPsI%`gwJ+s}u zrPls<_$L3CKYqZN7J#h?!z5)+iRFF|CY>S~b&GnTMg&G{ZKHKXBsfAZlJ$%`G9o+= z12)g747d3^*=XQDf3w%q@&6aT{Qb|iSxOI{Jawj_wz~adLm$`CvR_YOCXGdDFG}e} z8@>&G4xjTw#Z)CQBG=K6IF*l-w-Oh46R1jH8G%5c0g#gGCNeV#xI<-pi@&MRpr#K3 zGM13wrIHFUDtR~cs6JH+u6oGvOOg7_V602YekqAQyDEWM2 zjxvONsfF6wT1Hm4fq=I}n`30S#3VC0k~?+5@Ci!fp6kI#C7iPGz@Gut>X`CP{Rkq2 zk^%s%iLz$|uog(opqC43g~09QI0Wt}yjE$qFW7m&f6iJ@O)4lkOov+Sqt9Rk4W$0s z{8XO>J0?9B7yJI|B3s6};}uC+1=IhYF#7p*cg@`MpNn!mBhvh|>ByO3CQdYFt-Tkl z`QryEdye&F7S+^Mi$e;#udw-qGqSH;>b)!^0XGphGcDd%({z4S%Kq_xo$vHl^8`bp z>!R&JOUl1CH|^`Q)5R9E2qDS@Qb(miHhPL9QV)|PC!OV9y>+C)0us4t(%d7H-6K=E zdV|H*|5#`lqc0o3{3w=qUVnQ#@Ja3e%!*yHGc!BCw4|iu`0?X4H8u2l`p6KKDCD|W zv*tglMyxEl>H(=o%-t67>Ia&YJ3#7& zN`cg@-zqJH_8@Ykz4RkBIbwySG$3HC@w&Psky_rlhEa2SkNrfmJ#N>jaiQzHOnbys ziO>hdFih3=85$`7EihU*Ou<=$(AY!-!#>WZWo18bR^s%(y=C}dXHI6ynFBc|j+X8( zI{w7mPds1Q?HXA+BEmK@e1}Ybn3W~kk0!%!QPR(r?%#E!;l%mco=defc&>7$OpH1x zl!DaEV=!@x!YFT zby*!BRoQ>D@^IjsZR0hmF0+&P6-^v;W>O2JzV5_2f*kyyzk}2x^riRc%X!~5H`Bvh z;ikK{uRY}65`auVY zeY~Z-m7eo5JTC74{CyHUc>S5p^Qeek+TORtLoG@mX3V+6`1BH1~86A8%}n&9f#6E zDmjub6iS_1l5r!EYKUafZ6h_%EF^G0QVTguNROD7yLwIBPk0%rWw~U3JaTnF*cME= zoV2;abYryHPK)+pfyRv4UC*ued3EjMGnQ;i$vIqJc;@)Q!&MD`irYLTblbf%cXB}< zcPF_l+{1Dejflu}jY?xyVf0gPc>X%_mkZyGU%NN2 z{LINS)z}_0Fk^ToVS0!bJ{+WOz1)w~?qNGYYRvM`{9r+bPDtl3S~ht8clW;J$Z?LcIBE8} zuqv&C+rzCgDw@+pCe8Zzql{yPN6)rjthZln=g2$om=g6*(u%PN%Y5w|n+lRr1z+7m z`igmiIFVH_z0=-aE3RirIn?~Ec}ws5?fkLP+XCOny=(4{Z!F4k3NQ0BpLB{U9<8;q zMxgLBQ#Ljl?I@jflr|sdq{+wDj<)R`o*fvr|31ww?-$)Dv^F)_R*r?9R5qp5{g(;PTdEhempOXqfGP?Pkgfy5`4i#H1E8n{l+s&G@RsNq zeq^%a0T6j0L#16Wus3kR7D4F1#+x)r1bS^RXn#rei-Y?1Hmww6}bHMBD6+IfWqQm%9E7A2uTomYC>JDI~j-`#$^ zt@{(}p(kF_PI^B2?%x_b=WM+9wZyTD4v(b91NPX{|ME_UbS9R(yL29{QS~+Y=LL1FS zv>jRz!z3)3JB2Q~sjU5hIV%Ffw~h`=g17xJJq)B~fN{4rWpvaY|Ak3DPcEOaWJhZL z@xup7+MCZ-R-HOr*Sb2t#rw&3{TC#o`i<77-J{vBly|u8Qy?|R*uK2t)%W*g9z0W5 zS7WE;baQdE7~(129_<69M!oLhI5^oUZdx^WB#^N&ydxuSBjNm|;!%riqa#a4DYz+`F5A$Qk&n`1vjJE|fz%8{JtFda z*?O>W>*T0J-+3FR$D}#Gwt@TE-NTaEL`lD+UX(;YWUF+9h~vH^#n=_U5-7UK7>?J| zTgS{v^q#doXvPO_zYP!g-Tc`r_iQOVm4EO!3N;c5g@~36TU6P5M_6>n6H&>d_t6ap zg9E}HVG%zCL`tilLzvQczff22IH`^aLMqs#V%e7>g`A;f4qR1QNe$vv`c)65xILtX z7#PC0vfdr3y;VO%l9U8!N4DQsJ2DP+LDAHF)w0}bzPAyd@=|cv3nfF73h~6@q3%>t zhnXWdh8R*L5)uM)8cs|S6X1N#y|LYW+_iA^OiM>mi~Sez8$v=q$L3^ARK{pc&hVX6 zR3#G~x7h!{)>x{@9 zcKSf!nDE_b`j5<8^V8XHC*_?waH8f?XJ=b?OW(Clv0jaE#V|{euoSboxAQ{Vr8D&n zJMzksPqjQTYuUZO(fG{YGHTJ@d$qQ2=!$Xo=xolKEYHY&0pUA@QC3vi@aaLD_KQsS zjYx9~Pscx6pEuHw!#yU>k=sYS^sdvN4L-k_^C#^)rguJ1&pmkJP*v@zy3Te6k6nxg zRhXs{9ea~wRSqAiC%m*2q;@h`MrpG~YliEX0dPd>#;R(Nnt`goU-A}%9-PDMH%KjL z5;XEsR8Asb`Ns7V+;Mifx%KMVZu|e5)=v&yAE4dOTB>Vg)|jXqM@Nkh=0<6A?ltF* zirmZIpYcz|y}hNNu>4eY)#>ie3zs@BayDscv;DiXSBK2n5i6W)`)w1nCOe~@RmMh854=KxkY3-&ECurf3EYl+%t2%w=R`EabKIA$bGDQJ4%x~Qu_~%K)1*= zSmYL&L6vbp4UPm!2kSNG7uSq`?c)b#zVTb#il?-1Zp}ZEd+5~Zsu~c431QkZEJ9}D z|5r-RTdfzBHu~TI;2VGo$YCjp5w^sXqie_P=(#+OAzz&zYMFY43`O?$PkrMbK(qQM zvmE$=KXtBN(xw()^-zS{Kx#On&I+ofR?}2NhUtMwW(-vLlWbSZ;^-j`zfu>ny$vYT zFtht-q9Lm(IArh)-F_fjR@Og<)Yt%FiV0G)TCE%+#O$A9DU^S{Wk*%t#M$qSHzqrU z?FV^BMX_aOxXv@C$a&FT=jT88R>bOWJr}vZ^msv8*~P}%_LjzmihE!a9jll^sF(Ovqo|IikZvPby-v5U3^gl^~1 ziQyMk+&>bT>Jy%fPK}B^%4i*>&mI-A%Vpjtp3lXHJRSPP)3ev@$}B8BT6wCv;Y>Xc z$f?gXOR9S~ty;jxm#tGX`(4svAOGSK7UIQFK|_5F*EvU~-!prg-;DR7R%~aT8l=9` z&M0DVq-G{ff*0~hESO7}Mg!$4ZLuXBXe(>Adp~0i(eA)DSeS}MWUG$qmNibL-_(uN zWV2CgRQR58Ge7>`jOB^x2g)msG&a<n7_6 z5NFtplT62iXG}Dt2mCdD+3u3O!>4O5Gyu~*9j(fERhEcCh&p3-!>#riZzuWvLGSkL+fFmqWB$Q$WcNfB-mNL(JtE3FGD?)49!fnb zi!bRe5%}S4&ZtQ1sK|V$$UNuJeJ$jFSl!_(m#j`M*X9sH+B ziwUCZ>B!S#Ji=3h!uL)I-Q@RF%o8ugtw=3hos@1VKXm8>XZtoF=T#QbsvSkB8vgI& zQTrVOW`wOH@JU1f2zc;I4-uqHCcfi{nsnszuPGXMiWWHlsUge}#T@;TY~XLe6frbQ zf>qD$AvId<0EUpPn&z$YgeC;H<>*2(-?1!?{=w?vR&%`V_>_?$liDgAX}i%cTh~8} z)QDAq)Ley(T8+pRatV{~m3b%Ptry15`@}6`Kjzwv{d-%I^;-&E{x8~V!7lE|7#(p7>5quYLcDPOpU>xj)@1ul_gz))Lqy{3A?P%D%$*KeSnodHe;g} zWV(c9v&9cLCY+VlY#hg7;YLPEC#lTAQN89vVt#0aDvAuZ8lP2F+){Ze-{xi1pZVl<&LXp`%%qd>uUR(A2JG;}4)}O9# zLf~BPCIf~A;=1*#-PbtArsra3bNAIgEjC*!D*RBN{Q|@|Y(}+mR-H`>tMcM9+${i7z4d2+;;PU_2dk^qBuH)`|(L2FT zQC)6v;w0Z2r+hAXlRR;p;y6y?$d*+pkrGMti(63G)G5iLdKV?JH?e}~y%GSy3ibw) zAUe@|$9})r1FWtH5&~%!`HS~CT%No4Vo#s{%$%7y(WypC3yjI2d-<7nObK>(IPQ5` zJfX2?4B_XB=1?|)+6 z-jG=mpP5~}yWrfJ;|=w7(t%EKBX63R$u#_3F6b?`yNZ@_S7cV9Gk2b-JQ;-!iXnke zo0nNSPt5#{%YeDgf+rOo1F5Mz-*R{6qo|u%RWoyKNKNmJme$R8UR5Vh0j7|uFpV-Z zqk)enpgHV{v+CQqQCC&&)&5wujyt8B-Fw+enh(|Nx(1|XJ|St6ircL&L2Hrop|)(-M?8v_-jrMf)tGZ{Zz(tQK4&O%H4}I|H!uCAEG{qJKA`l zydIAm!RY=ry{E-sJOoTSBrvDY-M*$aBBV6cRX4RaZ_g|I?*GiWclL9)M{V$5km|Ou z$YoIpL=U<&)sZ%xSgFyV#(1mb9}87X@{LLKiphY5VApS=BYo=J)ptI)^v93JZb~YQ zk4q>m%sWt!L%dTCloY~jTnsmtjDoRt%)EMH-ucCNka};k$kf+{)SjVRE|ICnLTb=N z%^#ploRP7-Y8?`=MvozgQ(C9bS)Oy>;w|phtuvn8=WEFWsV6zUKx%{j=ljMO>5Hia zOlOdM7o>T_q~7;j>eQcEe*0NcZdOs{sgtd3jqQEy9fOz%>aDH4`;ONB@Zlx*&iMdv z*A^CfF1RXYGS@3QKQJo&J25-{#{TKf6V0U+&8T{MJ6dEjNL(Rgma1iPlaQKz!&6Ik zrw2NQFq}sh--t0A*xlMZaOgx!$aAaj`$hC!PrN=Y?9*wB6IfrqF}r|Z?^x0b9HRtv3{yKU^)}ig0g$0GXE}TBxT3gO8Ka>`tZEC;2<}$UpxS*dn`zTt< zT~Svku)26+W)xB@;grU*g1I}dSw5Ptz3v$bQtzje$B)#=ysA;aigT6BYMU8e4w{?b zGR_QtLO+;q=56K+&4=U3@K?OYL~7ONV{jnKc9BMzr5hy=)6(&jc+J0|qqr!JnEhC?aa7)plZ3#OMAKZPRyo?~gDEI*D{*I>Fi*@@e zTOWLR{nT0SPq8MTXH#$Bg|c_HKo|q=qf6w8S8R^^q7wI*eAM!HMQ!`mytkj-v3E~Z zM}1pQe^7m5|L7(_Il3b&5 zHEfCTf_e6UzfDAm%OW+cQ#DlfX2VronCZJD)%)pGkA>+-D_Gt5&RXsJuh0M8lW%QG zIGCMUbaYo?_0jz;Rp&a|o7%B_6EwSuYYe2OU5MO6ef@Z8VNrJXtQXm*_KMB+j=jua zUA8lM=pUW#I)CGBPrZXhS;>LJYM**6+i!ia%{X*Hy0x`gSR=i)Z>VK}Gi}g9V8G0d zc|dGxKy0$NW5=YR<$wA>?9R*s$Mzj+uDsCN-h|`b#ZFYhGKtE{>cW?YI0ziu)mJrM zS248erz}H};N=5`BX}$Hz+ftSwvIL)ojuuj{-XXb^Iw_vAJz$vJU1ocv&r`O02>FX zmrQWOHQp#PDr*MQm{USd^zv+#n4xQTsa9 zYV@nj`9pCS08k%QJyq4q-uVI7wIMZ>M-n6gi4%>Vh!XfB_cr(FWxcv(eaRj3KAI5v zIi{h$3*>m6Df+3DK#yId)8Z;Q7a2S&_c?a7Jcw#hD|mEe#mTup20g zx~~H*W=+Syd#R=O%zEuk>vlu{{!qP5!L<2W_1yXH6`SX}pxFP}{m8JB96Rog`0VE| zZHg=Ik@arXa#ccPn z#NW2GR0~Sg=BE+gNyNR&$<$^IRVDc-{7Foj7PQJ^@y^LFuHmLIGS#bF$<45Yd9(&>DAT^wj@aXI>z#8?7 zH&gEblAweQDeu)Cn-0#L_kn-Z4xc6YzR|n=Y{ejTpd;IWX}|)Q&I3eLQi7XbOePEi z4sMfTQzpkI-2H4y;3G?)e0g0{o76TC;HgwkOr9Id ztX~EVIKw$|#7iw*kc*{6OIvFxwxZ+iSs?A^A{XV{aqr#8DqBzrh=H48D>il;oc zdqVUuQcsLZngH7zlQ)9Y#ePu*lA`nAlo$w=6z`<&=0iru_v!swWVU9@30z$49u`O7 z-}|DrPkiXrdmnyr&RaXz7nT*CtT}zYy0x)ku%ofB_2Ta-QiBf2rLCPHA)Nw5 zXK1+mTD|d4K?6|gl%6HLgX75s^+9S~yzw3!(XQqw1Nh!S;qAuqpP&82ix zpr#bF+Rj5`A~kgYreQpsp_zv8lIvBUG2TNds?%-)QXAC};}x;t6&T<@*`8wxfFpS| z`u`ifW?IO4Hf?dxaJOd>QNbA~o%7(7b5dVHB@n0s|2^Wv)RO$tBSi(-^_6G3IwfK} zI4O&Iplh%bM>xHts^>3*-k3h;BMu|rZvn?kUhe$S%tL>)$eh3zO5M-_MkRb>N!&N) zz4>0o>3wI}1ZTIg%@C-u<0XoOSSb$-34%0q>%AZ~kGh)J2J9c`IM>*ic=Y_AKfciO z-yPboUiS>zI`!#&)0dvmB62ChEY3M&)=&UCDwE{t$ncCx@mUl<_4$+l$LH>kz2p0z zOaC@x#q-OHvI{D!jyJWOs_w0*9&D;dLx^^mm@;(o@Ycf^6T<1MF_2o0DRPpj6;gY~ zC>;o$Ij-a%oq4q~HT~I5-x7qgpEj}M(9ts}alTG>=!LEN_Z=(maD46^mFOCs2~vB6 z=L!l$Wh2Kakxeiqy5GpV+fgq7$cBKffnxjsMRhK29vjD>ztw z^kiR4GebwA&>GHH)?4cJ&h88K1Aja375_OO`o*MrM`tih=IE#)V~m`~&dh_DD+R$xnKEuV%?~iOTmtWR6J> zj7~zP7Nm|&X99S{>^5X-L23?aH(*+j8gzztG87%d_Yu4nb;p#KPiWD*Ty5E$yy+Xd z6*J4b=YKT){>Asdxc;5w(xS61M=P2tYZ?YIUKs4}X<<^|3?g}51_4UT#jBvVpaY=b z3oOv|gra#HZ-)2aZi2FNx$2?1gOXfk<#_{n=a1K`Vx!+<_8t|u(K59`dpJIz z52PLu?l1!H>mAe^bp54-qwGcicR+~0O^Zr{oyHBs)tUwvIm5AYei*788DvcIILWr- z&N*-VaQ+L)rDyjYKXLfrp61#MZLNm-MKK0_oqcW1?cIHq-MZzYI=(3Mn-@R*g~JBMU0#7q-Bhc& zs|?EXsf*%gI5xWf=A{`Azx?->kKTzpy6;5C@gsE|)t!BHt$K5t-ibp2d%8MoC~2hI zM^A*yJo!qb#@b71zfGj3i@e93{Gu|h5~;=70Ho%iQNwotD>6I=0QreASP=ODc(`LysUYg(?lu0QQ6*6vPaCZES}N3NUkPuE-PoMLacjyLhd*ap2 zA4}@w7xuYY+1SmPIQ!#Yzm=MGs(H_$6SWoRQGHGd6P1Om(vH@?y5|0q^}WSa?TglD`2SPTg!^CohJ70z2Og0bL>YBoxJR?+ zdc|b1B^2n0pX7)qnt^XrmV3-D_vm7;s9oMs`M!>PKSwTO5#Y$0U?*h++EhmF0rqSe zCPyy6)GXNn&mGXhlW@D99I|f4oOkh_{z>H9AEq6SFF8|s?qYRgXG?1*DlB$h3|9X# z^Y-ic2ujOE-JrB6B%%DyaB!tOz=ZYG*957lJWWtSC>0(9sZGcuL;cl=@V6$YnHe6A zfz%3}DU0`zN32#Ia=nHanC6ANb~I9}CU93nLk1m!S+2nIh^deH@P=m066vvV&L7o# z*P#72kQxKmUI-C_gCS@#Z-?3kbX-DyWO;vP*e1Ac&6e*TTMWHr?fXVw9;_8qdDz*X z9Y$(0lPsU#{m_zyD|cp=o;q>Sli4p3 zje$QzrL114keb)3%&2=d+G%v)T5P7ah&bNcriHEei+S&Sns(;+xehi2h%DNx6S&$y zYJ&!%z=Y1zUK(pOU&3^BcC^(tG@qzy+K_jA`>DP^3;w|67fYu^?C=Rs09Hm7I;=gQ zhExnL!sJW>Y>D0vy*=qyF9iHc#D6XRY|)215(bL}=?PW~y9U#p2Ac~8ljrtG5-~5}Gb_QBD z_&5>~pWP!e1s$RafDB^_WqU>E0@DV36v^F@4{-Z9vV5(nfC2}h`Uh|Hc;J=0ABtMA zVtc`%vePFk355+K(9+jW*AZ}2=4@XVR%Pv-dUjbi0aPc3uJ8=oel_za3$tfDk%2at zgn*!p-uee?AHiuq2&>gkqk+T)-5J#)}?@jjOYyFF1XM5hHh z5)GtIW*V#BhAE<-fnYc#_$9xntN=$wKvWuFO@@yo#YgcQeyN3}u<`A0OPUh4Y0{&w z-~Gt*{}A!&n{fq2r)u|~C@-(RNXTBgq`R|694xMCHs7dD9PfJ}uw2kv#L_V^&cp@C zEP0>=AiG448*h;}=6BQwbfa!#v_iq0YKt>cnCNC^=##OL8W^Q3cp-PS7hrCD|L*Nm zKui&;6jfpFszjQp%H;`pXIWn1rrC<$y(VAz2D2=B?8YNCY%tPLH?#o4XV5+!t5Y_9F{vhB~CrKzC*i1Xclvh-B;>WDE9r@f%Ft$$U%(3$q zODeiQ+g*3}BQJX2|1#7mz@7}{ADyU=YA;_=TUFr+VcYM0?1S$=`rE&GV8P0yeT4^4 z9XoNnqT)2RfxUelz3eGL78H{JO*1%$t0Hbf#SP7X;qA+tgi5Nhy9BB4eDwL7gVcuM z(_l*)wIZmZ6ia`j2hzPMi0>>-_cOpFh;Z!=4IQYf%Mgjfgxy_3?M@D>IjUw&n1V6LnRU zuzE0g$kc}4xH938IdlUr0XsD_)P1BV`nRVa3vih**jls_O{=-8se5nDzz^rWeD`C^ z?ugjzZNZxHfMzY!q6*z&^VtZ%SOT#+(2)!l!y3`yM#`o04HizgCcmgOl|XhrB8-Fb z?#AfwV_@1dGV!*U#OXnwy8krnoA+B6eYzug_u+#lPFGeE^RLbD&NHfP@D?N0{XO_! zaN4*O(g6)7E{x77fZ(p&k-k<)ZJNU=ydGV7^+bUnc>s?3s}VBc#>~(qV=C)aDdL1gn%)iys;f67t=!9()kqggKXSC{$ZMrSBa6+!bAQky+|r6Evlapsi9 zTS?g|mQ$yoK9D0rlS$}JP6p85PCoRVx$n+gknO#2zZRC~7E_F=6V)~9{&@b=@r8TSckexavA(jluA>t>J^0v>3K}EKA(c(t11G8)pIo-i z=kfRXLx2x@ONLh|5WIY$j?6$urh86p)^8{yZUO&%3GS+kDjgBTzLBLf?t|`|H7$H zeh_Glr$wU^6{AW#S8eC6MI`ymUOVaUqJQ!D>;Ls&%$9AL`*s(eKUGpyvA?~myi;$% zXAFxgP)1rWJ&tG%(2aD(IQ|zReFdbJz;b*&qWuP`@zQcfl8VaWIMHz?U&mGMQxCyu zfuDm71FaGth5e!~9hT?q9Y?-x{lwR?$zySvW=)wCQ{)$(O>lLbgD{CF&V~omBRalx)7jrvt@f)(k4Y^;T$(9Y|G@}P2URn=!cI-?8qx9C@#HlzMcT3q8~B( zP}IT{hABe74pN_P(dU1hIQh{Rwb?7iKYyryO5IUzNcmV;P>-(aM6hG`k^;c3y`L-ZB-#Euxd=P+o4Z7o$5)w@sEJ^aja zzkjv_JoY{z{#;}CXwiGM*nRXW{p{~Znqc2K!JgpnfZ@zy|JpSsM~js^rX3zJj76%K zq+}9#&**fwm`vB0EPkV5t{EfeeQ1xboD{s;_x@*R{yoXH-oPPo~rYeV4CNuE!Tq7EHJc)Lvq*+M1W-m8EhWZ&kgCnT)O#NmbGs4xA`yL zr`e1Amh5*8j>Gd5nvXLGlorh@>zWux{`Pc#dnO?)AO&s+!ciGMvFQO($$nv5W>i@o z7UOD1Dx}6YD%l4*Zx9@4j$lv}F&QM(!VkP$aj7*@6O*W zo?-bM)t{d|#m6o#s5qY@g1JX!W2j8&JfZo4_LKliyvMwafe*a>_YeOzA@$_;t$7DZ zN=u7#+v-ma^i}oi7YTr^kecmPp}x}B19}e%)vJJN{!oybKNn#Bl1x2})B}U;To9v7 zklMQ49bV#UklII(`t#eKe9y^Ci$K28OU6Zsbe4nx5sFMb2$a+dnbune*((;VgHb)- zqK7ZvH6`RzH~SXNx|4{elcMun=O*|@dg&ykYl^S6C-G!5aNb#uLCCEy7tG=f2 z!E zZU6I#4}Kc)a(d~xlNah+I%TWE5U2@rXT(C0xpLz!iV~fV%t+~8qocVSgDz9Xu-xi_ zWf|)4tiQ+)&et@im6reY?B^%{=9N1ZWN0DD?n_Fwh5P8+QAnL>a7O~uU@?dcQY)}F zFdCRn<)brFv&JXd5@v+0|3<{8GkzUA_ub74-d`1;m2>jMk%scqy%#GuWmfOz*e@A+ zsz;K^`FnCHwB-&lf{G$4jzMFg!wRWEF^DC9#dQlCDinJ}-~p*s^~R__7-68FsI0+O z{zO&Ye2JN%U0;dRbOoSEaW@F5X$}_^R?w#IJh=p^;hInmP+_z3mo)0;3=pN?XryLk zLH9bagl0RgTVi>&_YBk$SL&30clfHw)@}Z_L>~dE3~zh3r#;`@UhLx7t3{P)v2ygD zdrYFABc3RrQ^V8z!?HMlPm4%*C-6~B!pxX$QyyIQonJcECFbqkQ&Le?+0usH2|=WL zhoF6m5V5L-9MMqmfNO1UJ6+fI{fF#-JpbK$96JNWuX&ed+l5RWV2dZZV%;*svgN+eHI8j36Hj%NHMBQ1*Y&p5ijp7w zp+FA*n5B|aE*?;b_ zg_Nt_n6>CXA9wVy2b>$z`jNG(mvC@$H3;PlBe^);29ZH=7X);}QU zI~X=X2F9tfr5g-_Jns3VD$L!G>=-&ZF`1Ttl}h_Ph?0F!0(jp3@beQag4FO8<4-Ui z+T4xP=DZuTeEaUwBNr{mKcs(tV&Lw1 zAHyejJCfL>W(u)=?`KPM#XKphkh_dpOfiWO^mL>J*y8xHzjY@YE7+CcJv1p|`yF%M z`|bmdcXwp1i%-fcEQodfi*eP{mY!A087o}Oq+_ONBSIPw^DRxa(Od$}76C&MK=8zX#Xg-WcN(aHRl zg$9p$Z^XuL&3=nmWRERdv$pWS#*Fm+M-J9joI{bJ6JKcL$ZnYi#u~e!{c|0AUeR`l zyrQutE?f!h01LiCp>b;g+PMdWZW>@sm6Z1NN|on1^*524#wvb;x2ZQcXL#EfNUhM5 z7m`uMU6X`()#Xxu7z_$k{E}j;ZtYl@rPGJ1|J5WJdldN1HS`$E%CH226!hrrb$VA5 zMBtRJ-~VCJlt^GP5%?4OhEQo^54zCBzR$&8szsq*%hwj9xyC~G;-*FuZ(jUG*s}P{qCB}lJ+k#RWeNOW$AOaf9DDmrf<^#SVRW6PXKjKs)oB+j)5tp8@o zwlzoEj@7o+RA1<6sv2l-fT|(Ia=+3AhekEv8Q906p0JB+;&X2MS=hv1zw&2`5?mg7 zpThyQka&#iTw`|=9mT_zLmabdK^vw%_~y4BdG-H>zW>&aeK{pZ_V3?6&hw_PRFf+` zr}8Qp%mzZ`D5UNg7(wb6L2CMH{4mWgy&Y-V+)V~j#|gAC{#Xld}@jvi2V+t*Nf>By1NN2&4Vn;Y`T#gnM7_ z5X#|}=8l&?To=8rXv(i%B)I5p*0>qS>6Uc2$SlB1A+>@n1F18G--BU@Dh8=>uk(zK zcaMp4kHrixexmL3A3eQk<*xJ9)lE8)MLQcYUBk?jSU^TsTxooM*XKsF&~l5Pf`GAf zs*wb#MchW`4^mSH)+tG@?#8aRx`P)Q7OcpliX~XFkLhm7MCU~<^+re zsjrH8;~bFN=Y0Gp?B*<4@%+a0+*9YW_Y|Eza|{m-wD96oLG_G*ph~y^un+PFq*lXn z6YdZzE(-bsQs0E$9$myuMrtGlS@JA0qFc4Im#QaK=(tQyw8lY2MWA*h`P)(qq~7Ij zFLAf+b#)YKvDw;!6!#c-_4tXADH9{IC)oD5IreF>CE5bqIpe2AuD$QES7ScTOy6_r zL|J)bTaWlkq3&g`*eFrmDca1S*sN+DOh4W@{b!N41+Vw9QN%&bvDasDiH9WtY7fn! zN`lnUkotU(#hp+OunkcqAT?BFvUNL&%#_IO6CQc(<*f4sXX}riJkj1z+22-AD+z!y z#)T408Cn3@$o_2Ql-GA`*<11b*-Jfs66*FJOaAJ$-F}uN?a6KUh50Tdjz`ArQOOe? zd~@b6pZ@XOmlrQjEI3+q@@ysNO|zAwY(&k`9HZRvf5oy?$>_GP1yWNXfYOlh2dmn8 z@@odaAGKzh2-ImJ)-icRtcy30T4ZWZQO;z$M2XcC;oy`^jWQ%4HchjndOcIB%}bu{ zNDlnf(&$f;(sv&#C^%Slyu72KcQ^t!NT5*4zz7MoVm#^Nq{?o6_mS$jvx5P@TsUps zM}c9Vb8Z*z(jGCz2=Z)OAlJillGw-?sRNwD2vXzp9UJemAl@}5DZsw%n<2}s%hOL? zXzXuk(%b5B=)<#x)iI2Z;~%rD`K3Z?vCV@GVy>!|a;J@=07oqYjti6vfmTyNx}g7b zo1Rjw|I3^Cs3X|xmmPm4QyXdoSZ-L6Yd~uHigPXhIP8-bQp#2qaLj1?;p3-T8(`^M zbs`tRIE<*}jnNPW>S~&MD}QTZ+#h6WH4Lgl$V0NewlX#1swq<=UteG9dbQKhES;{q z(K0n_9Wo$ZQo;`Ru;+NDO^@8L=eGHu`dbs+?PAOAWl#0BB@-IL!q{_&H~-1nQOwZDy+6tc-Hbf*>+?-h}vJ+^wn;~xh8=fZ!pzx(o< zlszZPPoJ&0STA}Zv}DY7aGya`*BIrF|0_kCjW$3U$A#1k;`kF?dbKjO;Du0Vv3IKK z)n887H{*%7r^h5ys0$_yGIWIm#mWu)+!Ce8_Yo-m-|0c}r24XatR-4-9z zLer*1#OXpVJs3u%@&ddC`^VNhoS$pIWsV0F+T@^~eT<@M##f@sM8) z_VW2er@sF5;6J>UKRGg<__vycL6-$W=d)^9r0$MXEoyk-jDJ2bYSSFszhPZt-+p{m zan*sdtw#=@9&GOrm?kcZK(+kGPz+->))L0-ypdgWecsKgICN07|29gdr#bOPl=1#5r zIHK2<3;iT1L)t(k*4u0%=b_DjZ{k8nzy zA#$;~eN#qBYFYO;AANDgGB_I0+( zVW~`YL~`{`-otg3v*7YSS3PIE>+6Bk;FeHp{u^xU>aW!Ge_Qg|w7JU}2!I&ZC&f@1 zoL(x}LE{Gwk6!=EXUZ7zS?I?1y z7kFE9{4801mK@Fs@ro>B-okcz2uI3%7L3+nVL@@SPQKl;>CfiBxibCW;S*T3tO zaYGyI5XZh7dI8KZU?eieGBMzIL{#M=ux$JQ6$1{;So94@kfP%Qx@Gg>Z`d~bg~kyA zR143bZ)umYa+8gPlMa8YSlsa=wfv!Fb70u2A3wcid12k&Qyqs6o*iuK>1}K@f-v;q zCf6xkzJbuxj&y@N=z8_OT9SW2YLhgX8T#b+0;$<;zh0B!+TKG)sXwIaZnR7-%SslR zkb|bK-eZmZySw!JLOz~o*~-?Q<|u&P3bD1N8!5xvnjsQ&WGY7hxI2>Fq69hxD{Z?q zRNwYJgj{g3Ci%|)Y|2ARAAfzv&OPNP&s4P3Rufvvu!Vu9LUGaTvBL$0H}Vi1Wo$Jd zhOGoEgM0V$6~m9uQWQwPWtd~2>aRFP&w4uva5LChKzmp{cQe( zf3^Inb={07KPK?0$Gy5+2PB~4$ch--c>!!=9` zza~gc%nM?12!37c*Y~yS-wS&44*NFOhy-9777M!tZ~@_t(E&IZmkE)mJ`k}1Zb1`6 z&=v&IY`NYXIU1He!ItXx@SBgkow9M)@jWNb9xppx(@@1xF8JBu)rRgD1WEIa1guGUzLs6y zkzlvX79hzbDiw?t@1z)1Mi~Ji8^0a&;cvH>96aAx&l#I->{0g_hkSm;{JG}AHU1E& z8%AmwXhUJZoxIbxbU6NE9D4_952E|7*7c$u{XgE!oF2NtGX$hAfOl0ZSLwu9FRasR zKx*NjBDVQix7-)8@~wjA{Z;z0)6E=;+tt$6KR`%I4wnU~**7=1+&>`o@G#w^{{RRs z3Ij3}QjBfOgszVZi>BX4i!w~es5X^1W$OQ3NDXWOmk^*qy{cP(Cw2eQyz09nH~2=x zV}+~P3q>BW=i)wt&y+aBTGM6ZR>_?_0Wwrx%w+gVo+B@{^y%5B8h;S<+Zm6( zJ~@0lX6IUHGKW!WvL&6ZIkJ)2-R#sP$uBbAH!^`(8D{m|ZRrFkrovd%_*fDr&tLV> zM|oi%?8rM-exbUKgC>XB|0}N~#ZM|`Nrd8_4!xze>d4;O$_mKhro0n>_tXnMKYsk4 z2cMn%bNlz_z4A|?FTS*9dsa!w@gsXWYL4Mp4C&&})e5?DIoJ4&Q17cmYByW@_!Bl= zSE>ER7#U;{8#D0Yx9KPU$nxoAdz`CXVu=Ws0lDQ$t%R)ZeCsO8;I}HbwqOk^t z!C((P+lwGJVXGc{Gd|;FJ>FXFAhoy;j7YoJIDlXIXTwNsY)OlRNc~% z>?WaA&}($PbVy&4cJBL&w%%@!_YO}YRFN3w$*PovphllnBWuTz&Cra0KDgS`U5TUa zNW90f?a}3X*OoLVl~i1)>t!>mqX+v-z*;Qa)WROF?g&?*s{FORn;7>8?Y9~ulVm9x zcqPzRSkJd))Nf!C6v4czu{Mh{Gh>(g2c#wpHPpYdsrzKF{=m?e`rHq``Pef*ej+M$-!bAR zSJyPOwRXwL&?d~FM#NrpO$B_c3F0$rO`~ok=#PSFMWZm%z9TmIj;G%L-mDkm4px?)uI%9W078#Q zNtd~l6l?|r;1?1i5861;p|>~m0s+4xkeVF)k8B1zBQ=bQfHiERY!0(;eq=!3QmwPmGimlm68hVc!a0=& zgPqS3W<>za!Z-~xMOTN^ObNW*wcs67tve<>{MJM7WGz^g6TiO#2)%>VCYYHW0!Wom?Le5=3QA2<7x$)7L~H$(f4&bd#v zx;`l`zvrn}riQQdiQFcH3#1m97D)v8nlhD~&;QK}MGU2!KZAB42xlZ<`ss zV&X3xcmLDFuddjL8|>-RCoeX4a-4AYpkWF_B(NbNJ`fr(2D9@^?qbq9G>CiD{xenI z`^9X(p9X&`avkPLT6lsXQx7AxRK_MUzL}`Z7ceaXnt=`>+wZh){?@#A=e@aY_nCTZ zy*e8?l@H=Bm%>n$r_a^2=dPX%-}xktKw>9D{H3PO!3zyt2|0V8dvkf(o})SYkMBNq z=IHqg7wT)9+8fcw4hjkV5+}e5foW$3;7jkn$`8^#MjDOO!>ms4pz_k1`Opgi5!+-> z|7vCGCpS!;{Z919JBkh*s;j7gMRE4h8q_-o?X3_*8Y;#HguT$u_37(RwBHl-{-lU4 z9@bf9HQJcg=bCPV64TlHJk63+I__%$yWv zG6|&+cOPp!EFaHhGNS|_R)B%jL`0cl+i_RO@`v9^$UM{3z%iwbRUkEC>PHXSrPF5g zFUI?X2B^h>rpd?|U@cQt2A&;63?u1&lwd=^G;^J5AKak^bL!14Nvx4 zRD!45Fj&(l!Dy8ve^oLy+A2b|y9M*+9n)=FX3YQKyTPwnR%aH~_MUI;udZ)3Ivibx zfHn50)baQ0Vqqdvs~{fEa^h%-5@_JUp~Ixlx4fm!vyN6!=P`n}PX?i6n%1-C zOUw)nyb1f%qq`A0sY1|Zf}2N8d~Fdia$9#}*Gq zq86Dfgv(Ya*4HGMb0k@zZwY|7kUPwDt^B~yTOtriIE6(2u(dNEfBi3?c=R<|;7X zd~F$_*26_yx=(%6kedBsC!`+e>BbaTKRKk&TAn>&&PSMe`!7Plg7#ZMu%T};gxL{E zHq+Rx5H*M($OuxqMyB}ATYbl@rGNbEu#dLH@7Y&ed-l*^dkxGg#$+JDc#`x^UpsaM z$1XHIwD_Y5KVLXKc%ye%q86N_q)P*x6Wko}u2Jz?bb_k`wTwb)l*7y}1F5+?@?C6c z9${Oigs=IVg=?1=oj-B0qouxPkOR%-7_{Nb9M&t%pOGJq|9_C0k!3Ib3#6vuG>hYG z42}^h%1(e@-L2zxxT{(J*=s42pZp|X?#dZaNv=WLIP}VYF=uJPmY~fLv04^|fz;9i zHh7h*(0+S@)Rr8N;1q95@}z~FakhSP$Or$hbmQXf#RqB!8ZjnQ+;;E45Jx2w>2v^x zz2B!xp~HBP8fZ{ReZBN!zk4^C(~k_xM4{MaVNO+E-M_X-%_15Dsj0j|YU+=0&By;; zNX>K^)N9)G9jE)h6ZVnY+)uq1uwh4#iVXCGZq|Ia$YNJPYF2%wD^W)r$hJaY-6Qke zBMV%uJV#-et3{`IMD3Uq_StO@JoCu&E5o0DBRM1IOxf|qi{(9?EdvMwB9<` z*jq$aB|rKuF&q1vTADYf<$jibY|4My?zC;35S=O*E!uB{f^@|#7$hhc;o8u{s~t~} zTA*C`3bq=lSny6FNOM3^^qQQ#Wi@q;a*Dd5t4wc`z?yUZlH~*E04Wk`grN_*Rm4Z? z3?_HAbk)~%Hr0xycUNb7{}7(GM85^Igsxs9m|ybJ-{GTzX@eMkO^|w!{Yn%vskQoj z!5>Tr-;5~gxgcMQFve?m$YheBmJw}pB(dCc$ph0Q;jhH}0MR=?a8d4*u+{fI^31H~ z-b>6cWb$;kRO|iCtsV94eQiYhCjJU{jx+Bb;^0d{oB~~!CVXy;GqU?@+lE%;oSXh% z&&-&&e&&K)moS2X$g~krdKjkTwU`9J+RGN_WlJy=GSsugNMv$72nKH1F~PBY%Dnd@ zHWuceZ>g)P?Wn83$j}^LGjsi@w_)Bn1aBzbPa<6#GfJimD`;@2yQ{yUUCxd_-lLcF z>JNRCHtER^edetr?9T-J;6iu81$oEr(jv1Aum+}wk=nrMtAlBJj3Jv4k>wpK3J~vw zSuQa&WF?C^h|E(VU^2|xgppUd2PRUa?8 zE2K8{W9I1Jss@`CfR5o7O7%doOX}?WQEf5v8`}Fdl&NV2W8qxkOY%UoYNJAG?q(0% zk|A)0kDH+V1~!k?=wYi%rp*1=Z(*8-1#D!Zdu+BxWSXZX%Ohf!tEI@;=ED>`QFFv= zq8QI{v*fv1@?9-N`$VA5(W3E|+A`I$;@-zzd|^}Jo2!#Diw>T+P*KxV)6?BH)XP32 zW-x|JM_-3dVuy_LcReS;PCjr-1471Z>7`|)Q2W`F1z5l5jC0L@0g$yDHg z!?LkKBDq=9_$c4XNAB_ik`|eUT`?}YSgKE-x8k1{t&ZP!_Sm_~=5}0dM670%oxA#y zvF2MYU>8YQ3Co7O&!G_QdIxc#?-o zY+{HF_OMJXhWtYRmFQvH>1mB8 zK#GK}wGw)+$i<2;0|!0lx;j!k35W8;2Y>h6rX9!X#aaIR*{-%rPd8wmTsNd1Va52L zxd%+s)rP%RKU56UEhZt{;Jzl^u`xe1?%>SO4>`}BL+zUN z^+F>2OOC5G%PlfPI^k*(L?F+SSQ=O)}}q-Lbs zd-VO)`d`}Cc+X$!vM5L61W7_lT9eUt`G&Lg3?f6pKxABL5{142<+dyjOP)tWzI+8z z%jrDHnr+i$>+1g#x%`8?s@0jNQV&$`tLrT5=&NgOZ*6UEZ*L{FwY88}iTvoqfzs8z z`h@|#tYzqU>(HK7{a0@#`abc2Ys5~0Y4nr$;aZbDtcilfqS?zA%0nKE<_Ch*X&%;i zl4eQKESYZjcSmGSwZwh?8Ti4X8qJ}at%&vCo{x4-AJ_yuA*N`Y&@{OSx z=*8j{HUn#RWrr+ZDY^=29bPXlu3b4y2e6Q``Sl6sn3$g4ztbn0wvYj5jr9n=rE>X}XYBkRt1 z&RXRjoWQX%YM!{+5=kz0cupdL;JCzA4zq=N!qgEHV7E);E)N(~R)K5)C2N)hmyiv& z&3$)yag`j$eEM{=p_Wl2$`n%9S5Bny&HzRi{Wr7Bm{GtqdMG1gnK9G)<(#`lU0;@Z z?3?qJ-4(UkEo3DgaGv-Q76Gx8qcjJjEwf}v(7&r_^5lEGo<_t-r^PmG@ zA%>>L#n9ivrmBgjDuC#rP;7La%_ra*7awT_{KnS@sTl&ZC+S*u=l^IiJ+9=+Vi zpX=1mcIjt3^fEGEzMt&U_jc;}O?pwCo>|_#{YP>Cy;sYaq)|65EDjt8uYDG#1W9M_U3If>*&i@`Pmg9&lvXMp}$pC zS9MUOQzhyTgefe(1mo04zEW)j;}F12X_WVlA~lj=JrN+cpSnGG9kwWPX2FuZE-zq37VjUvePT$Qe@MDV zSe_OsJ9k=Ck`{$*o20Sf7?$lFn&%!~AS5nYVt{K)61DlC{nfL{_rI3+#9Mh!yqo{j z+I@3BFAdsQ8noeH$ohl98%sksl!k0N#GNO>>kiCcf8dh)y!E9aThGm1dpK(2o_X&j z&HFU>pI%MnqzNqoCmO@K+ln7bf|n(Z0}6?iA<8|72}#Um_?YP$ndB3(l_Y^N#eHm_ zW-DY zy?O=hH!5Bf49L{ZNR6A+$4Pmw=AXSiVjTx|!xU-H9%XuHAzOSbn@J1@8xUgWK#I(E zfp-$^ceYnVl6S;T4}z#$QLAFXwVNQKo}t_RJZ8gxFWWZzow&#~1#?#J4cmTh-ugpx z*BzXzgW3rQ7QXiASv zcekXHM3*b*hQVYWfqF<%tH@%_Qs@z$>lc>f6TTDC8|w=Kp?E)??;pJKKVIHZaJ+U; z$w3aSMt)KA$D}a7`^XNzfdQtQjWaJsklKLhp^mP`TJ{>)WZAH%>fe_o_ym2TS+=;o zv{$BmbP*2Jm{1A|b38|cC@Z9mk=a^guF>#JT1}tR;R3tkpAyy-&6Xg#g(yxE-={^F zYPS8FWtUq-3WutEFLq_fy3E9rH5DyAE%mK^AT@Crey^lzMi6vR=HDjti~$y41nXMS zjq5-9S2K;AX&2OnI{!W*HGSxe)KJSSbv~_Q-SMr7)I4Dr`9#twN64yX+f2zkUAY|<7G*} zZ&av|HCK@x0}eoebg;(TvfU?QyGuAnBkj^c^V}96)`F6zTejc##2cR$l%L}G&8B8C z3}f4G2!qvO$8JMj=BRAFqerjo(@*v32>2&E^}`MAr#pI2cj-r321=WT4!7w?+x5~` zy|hKT?r5`qtXV(Rte*x9&c0 zpuXZfURvx-vjsp$$yUG+F|n}4HpIL>y{=#X`>>bpeCqXpuuWPRoZeoMsjX;V**)3H zK*$RPsbz0^7^x%kz-ywWdq=22#McioZ8vb^8JT=v)OK9pzd7$+hJNC#4`+mZJ~?z_ zVCV*w@V1^D@j3U2VH+=-riZM$cmA9AJo)OktgCOgZFZZ#g`IIP4$KP8agMrkV6$fNPEQKAl6u3uZ`-BTp(*#uC+5+V6RIi}*w>|#m`UB0YlS_`5vwPmw zN8BDR=8l+38Y|A&q8%O_MH0UBK|LD2o8MfLkv>*0BO^IwH;7hQqQJpa@2S&&6#m|n zr#|quZqpWEW68!7aqsEg94$0O3r+Bk&Yln}hLkem!jP~i!0Sv`iyQ#Ts$qe^KCx;H z7MEEeiI0qwJKq|~RiNDXb6cv{Vu|pNm8R%D9HpA|AbSL^wtO-2pZnoALY6H}Ik2ay z>&U6vj#~CAdJVCf38I=YJmFO{ox4CikyhU73v?I{QY%>!qy`ot(Oh3cq*hY%Wxq#SvX$rIWs#b(xP{ZltoF4cH5eoTfrWgt(2Yeywo?w+71P*G zEOYn*^3v5;->yHK**w(}ug(5^!eVeOSqo0^U$V<9DpRDM@D#6bWRP@M3nnG9oMlB@ zSoPV!HwmP60mK1ogLQ`*_=KhUho%IEBn5^f_=hF`);y>v3Za3CThW$FwY$GY!#yx&?2) zb3xj_znWfjw7H?YM(=LwZm%J{QuC06kAP#5-N1p~fo8qBRiF9D(n;YT-xl%7?ctwJ z5B+pn*otYPtEPpn#yELO=-Mfv>&;~F8*8VBtOg^Dw0d&Lh8ZCn?wGgyyR(*loLE@P zfiE5PdQUS%iGiUYK~*8|0)1CaslMamM4=7qv=sL6^ecb{0aRd){+wd+$Jd1Zn< zNn?i*p%rQ@MEk4nLcr&3o$%OOi$2wHO=l*|*93`=3q z8G0sw%%89XK+`88Zk&l}hW+`3u&w@KOr#`cqjy-QcW5rjD@>9{I1>isf_X5U1#n+7 zI2ogtsGiJoHHAPl0+*q^hvoAK*?OB}=ij`P{p)u#Gs>DyUu?#pLil+Z4lK~yj8G&J zs*7G49%30~1Fwd0T)K}3DlvAKP4X?C``7}oe!H3_R_Fky#-q9rpRAk){a;_&$)Pax zh8D^`6n=09pG=%Un=DU&m}RSEXDvKYvm~<SLF6$bUhdH;$370O2&qx)6)RGBF@|eH*&d7~_687=i z+0`3zFC0ACb+N8j@8;0zX4N4*eVj%w^OHn-N16{$DId*;(lxi@GSQX{C}uk9UKT8f zyaCK1*6~Y_UBUD%1Z$<$q1&hf+c5wc^+(>kY~^`qR-O#?SN+Z3a+!IRp*NV@W4uR| zqClUYU7Pk>l{NZ~!qen8$fyoC%NkuP-ar$mGne@`=e+swx@XL;V=SmALoh}?Rn6%- zu8|%SuLZcO~=S?6lb*LF8nwluO^-qSQhSVo1^7>RZFHR$JBbg$VTXi+jD1H5Kfs}jKDP`HOHwS z*a|4H-bjqI+<4e4v8gf1D`?jzKJ<#eb*BMCVD$J?x;B4%z^u0xeY~!;wCG~_q3(`) zY}$FRFt1d*=c3*VXbb}1=XCwQmn8&*ZZV)4bpCR>Y@tBm7n4W9^!1%TqVN%(%_6)U z%z$ju80kwe%`l0Bm|@S1Tel%sjzG4-j*7WBA#*wGRrai5^W1{Bf?@>P{ix{NvBviL zu0Br0HcS{g#g{>%j7lK;FNT=zf^rBx4NI5OeTmSr0-rS9I0r79K zXB@2V(Ra7%Pp;m5XT&;KUoZBX;D~~mnYbmYR;mzjv)Z4f#5Ofc^RZO{E>&1Ppky!gdw|$ z#AtW|H}!zjdPg?_Vf3`at&^WzsRboSFbd?0uoUsfM4KIyV1P0d?@I|9Xdo9Pf~{c^ zzSWmYf^I7DdxJ_qD8`cn5S@#-+{-D^={E*h{!%4Xouw7w*ux}a3QMC5bwT3P`Rk)U zOg&jv%Q={}wP)IU#axx%V6qPBn8mbrHt45XbdM+A)$H4WX;*84vy#w>q&t&$r#$tK z#925GVQ}iBZ$G~wyYzHfOZBOtwn~anA~0hjbXX#&O1W2e3B(&QpGS}yXpk4m^LAZ4 zoBQep^nx~h;)6?l!?#H2tuJ6`eEIp?{b#+i;A3R!-F4+hdOGTrOwATGv{&zKK+2=U z>H$6ZO!r-nz3d;p_3DZ+$L9fNl4tw%XXB6D{=^%8PkuHr8n1A}91i`NbMe;GR3xiV)$C^zhBlKeqVd=18?*d)`Wnl zG?3a5#`#;(o54^G?|FgIww=T35n;d<;??pP>3&1NhRelp7loZ(*QJ*=4nFzXR=+1c1EXqx@=XYMIg1odyp6Z zpzzd5K^y-u{GH7GXOEpdUtV#xv9+aF4hIqF9Mao*;fxyk*?M+={4LG4T|9bFp^L?u zNyfi2lc|MgdD?UR!xJYy^5!DKf*(27P(I`U@vEe~0g^_hLWZe4unM+Ha5=0UofHQjp_& z8d1Mf?w*T7;h$vQIr|+H&f|Z-!QkD{`GX8-ps+aqnrxl{%?i=LW%ZTZnQ6>V1HPTQ zh)$r>TmZXpR7^?k5s7S|`&v_xuWt+A@YlhwY}tFVw5qAHv5m9ehC140G-V4#Wa>+i z+TfE%(+agHo$tfHF(wD$bi|Iri1*ddJ&4od_S0Q|8Ts*q$KIJ787DFMLzCnTGHmG) zhZS1_Qp--Xu^Ej-O#Q`~9VUc3PM4zY0DOHSlD%iW=l$TzcSn5o!&lRZnlf?Tr`n?* z`i5==sln(GJ2V7pLup1=7#4T3mqA_xZHz-unCA+)h-SYdZt~M96C>A830Zzu$Vd0T z9v^@3LUju#koL8;6YmJcQD1)-(+BOID7~4qB<7N8I}b;9&P{s)u{G%}=r9HxfDTHy zBLjSpha0*1a@-|7L*>B;po*Fsur`)VCunDgsQex|RK3dRfZ?GqyW-X&HPrxlVJB!2 zyoU+amjJZ$M{_fRM%}bQF}sTllYuEgmFQvTijB^zVH(zcvkVOS!2ctQg8yOByRb}V z?JzJ+{d%pg7uV|FdGv*e;ahxS#e)Wm6j`Sc=~`H-S9Cu4(Mf2soH|6LG9$4QYNjvX z+X=^!o7fOUM<=GXw){9q4O<|RyX>vwuhxdu z8lwBICjHOnzxhqedQ_(4d^0~2wg(yQ2F@P?sRfir1m`bs8Q?Y)K}y>r446tz`x>IL zm*JK@Uq>bu)Z!2knqc5{vU^1G#NhRJKeXu0q}{vDH6c9q^r9#vh7TGNI!Smw#f&jD zatQ}0m^6Y)>Z!ULCY^jO-(7MyR;xZ(R(_$XtuNzP&Dwo+-+AH{zuzpoXHhE0*om45 zC4eOjV-h1izi?vo?FdrK=8@6W2BSjrfpUIe6U|bfC1J)BZwLOTU{J0myp_+`z!=jgh9zMbm4y#bRBwI zGyB&lIm+AgN?l)fqI<^UuVNuAFdd$zSuzwr1KA4NSh=GTJT{g>;@C1e2@#fkG4{Vy z5*jk1do-1hUzHJNKxxj6SIOHhQ`Si7YF~16J%<5W;kC3bER_aw-r}8e--%qmi|A+j z&%&_v^fq7sgK;yPvB*db)s3C|TXgp)mZANYgAv0pKyp@%jsvyBQhjWhAoYZY--ud~ zUU2wSLsc2p0nD6XQ3A;0d@j=EY53Sv462S&R9IrhS>b~GfkNuRPORCHsnhE8J7zEQ z4_W8V>80Y8GhUd68XHLcp=0@ulEa6pFPsFa**KMgdLXu1+UzriQ zj?+aAS7p4Fzm%>}XzC50KjNCCwpx^~+mx)0NhN0R01%4ebgys`LS=r+o{N!&_tuS3 zmdH7RP~bH-4;(3iYm$HPhHuPy)w(hz{Y>-OmZ3Icwjn7>031f-3yU&_#y}$VpOOD! zR26=!J5c5Pk-_aJ`fgXJ>@OgQVi1r}*1M)m|9=*44G7+F*9*I~*;|QWKJl3nSO^B! z4O>t{=RqhVKwDqv4@;c#$kGRp1A!JEGM__9Cxwf)6yC2u5`{`jdS zQ~v46Y4)F8Xf{lTJY|?vM6;i7iJB)C^wDj98L+UTa#6Sn+IH18K zs+VL;q&6YX)FC^+=Vs;+sFmyq{deXfE~&Zt$Pf4#fZ|+j1E^)Ha(#V}T5%v$*p#U+ z+amQ4q-JPnl&Zhk3e~6^cQ=umq8SBh%QZ$l)mL9aYUcicfCBK$4j0RXpo@|nz~YGD zTJo8ABS&<7)|!%;k!vJSC-lmafilg_o1fk!d3DPPgRMJ zhW<^61__EGKOQm0HWt3vx{R4pj6ak=m%kNlo)qL<#7MaY-B583FIQFSPpo5!=ghY> z&}bu#z00xT|30^Ab6HQqfy%ntz5xhISC8HUQa7{?HB>aU>}}CKXTRcR-{v2g>l2nw zH6VtD4*9F^^0V+%&eS%L`YrpatlYz8?1_u{w}I3$bHF>sqW@ZvTGS&Vo|rllK>~Rv z%Eq3qfq@HsI<32X&N4!Nd0BQEVv(pr$C?!!l_E}RCb*%+WK(Z^DX zu3zleO9%Csyf1xD`pM(9WX`t)b( z4%8m1*Q=X27gZm^*a7=MImku+1B@;~YI<*&8p`kk$AZX`jG-LPt0%_8&h8FON#N}^ z9H{%JC2N21Y=Zk^pG=I(!u~<5$RcwHY(fYZ&#)cLXE+}kC`ihB31`LO5TT6p2>p#> zA&r=*?vXn^LbrL&-!$p*5AXcB<&lMNu1(*QSbXfg%_%>9GKw=sU4Ci}4BIT-W!tSe zIN$@Zn)ADN61c#a`N|}Ic*!%Pq);{v@HbzOu02QCb~40U$bxhDt7p=d#GlKrmNP^; zJG=GvdcEVKIxUn=pmU&0GM)GUOtW1eyvnV=AiRiXko_wWTT^Hvqi8ZZ&s$q>cBrX| zk~&rO#^5y6FZtOes&5n8%nV%t`dq0Wcn@&Hx2hA!j94;Xx6S~m)mHVD>frpG=F=#C zk8Eo;!OUE@I*ob}l~m7^>YLu+Qa$5by-V_6LTVPnfY1swmS~*}qz19uB~CSm@N`P} z&@=sdT8Dmn_$Lz`TP3KYJ;wug4@(Bpw7Vl$BK#wPDk}HoI~!Gy0w|&3^P;S3Gkrq8 zNZ8pzDh)f^TtcQmI>f|9VwH?9MWpa2#vhtReDQJ$5~rJyBD})z>k&t-%T`sO8Jz$M zaBCKgqJhGPSQ01Nw)j5s>dS@oZzUZ*QP$pB(X8VH(+QF`H0zD!%`JOdb)VTUc-gm1 zjKnYu2V2OLVDxyBh+s%w_H>Zi?~!+GtMW1rb13Hdp4K`jlQFc0P~4B}4JTzg6Yx<} z;qnh4YmDu%pUW@=2<0~nko10{a3AAvibKt}&3P>_eEroTHAGl@YU_kY-vgQ$Z0LCGeKT;02aeDGA@EgYTUUSeMmo!z_bjRN~RK6Ig5u_Ft#c-Si ztcg*U4onl++&g@W_qyw zQ!P;oh(aSWbvjn!B*U~o7#MY4Fb0M25-tyY^0!YX zypdf~+NjsH^mH`W>)ojG;7f(QR5G=;0w8ck>apvuK+ROz^9FUPHMLU#E^?bqgK_}Pm*Lb3y_1-=ovK9cgiA_}}B3Oy}_?v`TC+maKMtSRG6 z{Fp!C5BYOm!mD^8iI=+v5pE@yD5k_4_lVr>Y2V`(S)zsJyW0xJTX`4~JI6U~oo?Uw zqn8qY^YV_u(#E#R_QA6AdT-;9-gt5FA~N-X7G3+FNPqi=!0;@;-~w+ef0Z%*?Z=ihJwy8h%RnSW$oJ=wYqi)D`fM0q0>t3+OX#Ar&JwPy0eufMu|*RF$yYO2cz zx?5SotO8&KYhJ9&%5>cpe-5AV>GlMV;2qvqc>m}UdE#Nq@vs#$aBdO1-6D$c$9E6Q zVSFdpc3qeG!&zNSLN80cCl>e|%u38UJ12HY@PV3m zMc7qj-U2Fvg`2-Mf$$^5;$w1p*|NN>IbK%6t?zQT?Q#QZ!&6oCb#2zicSLRVd-RQ| zk1YGZCk3&|xXB0fo-{K#vrPp%_UT)@)fgvw`|9+>vE zbCgL2NAO_4Mk#)g=@Tr(3{0jUu!?tgq)TWW3Cc>O-`$#RuZOkB zji(w1Dry@VYO98NJNpdxGdib>rmODY96i}mk@-CS>qItG#P9c2q>#;q*rDDA*9`y*Ksz-`NA(6D*h9_jj+X`=|R5mD=y91YMRYgD0#>P7b_w*X4;_!pX{Z{+p~Te ztZNhkje+@=8kRZEkHvNv*h+znenTxlD?C=`RjJ=|I6a$tsn3pcILQu8lIcE(dgEdj zkv^RCx44OU2t(AUW1uV>{x0R%BD+ z|Lj@`@d{qV>xcwVbwz6_9%LiyYa!`lE`8fNv5!s48`ddraxw-uWxr)5>ka2L48}0u zvAq7y&a>lopIvNq>Ui|cilXL6_X^dGWslVLWgS&m(3@4K9gJL*4WhH7-i^gl-1Mb%@+TE z@=!fTT@n^?5`1`E-`kU{Ihw@E|syKg-y`<`;+kd~o*eg8}h( zlZrZvt2;0)@VFJj;3$Hw0dUp;gYt%-mNF@5^2dNVdeh`&Zw9Hc(Hzt!&>p9SF`uqy zG^stVr!BQTI_BrY!**j6d+gDNvE{_qY!Y9$mZJ?qys)VTT10{RTE$|Edm?ZP5i<3* zg}jd?2q$U@UfX(hh|SeWoJ)hY_`beo=cG^U?N5p?C8XZUzgP9}!K2!8b#oQ0g`%3K zi1bpupMu`_*l)DG7z6$og}~8fBkbc|`{C4Uwm1s_rAEg82b#wZF~dslsKMq)IvPa} zv5>ToqDA7{<|+Nm5=U?pL$+TW_4S@DA#oSdE9AG!i))&z>#PUq$TrSzaOI>4<9Hp5=(nw6 z`&va)y}{@`azZo+$NGSvqI>Dmx8AbmBNC#5NVL#JvF|#F(d!|5F5#RYY@fJO@Y*hH z&?JA;M%sJ+5psYnA0LqR-F8-c$BErx(OEYu+lx!p)fjGUs_1MiuWl)*Q|oQ_7-e>N z$j<2gJ79i5^YeR8@0iC9wh>~SaFXo}6Z_xJrJIgTCu(Jjdd9Y};oFYAYjp#Aaf9>z&m*YWXKAqc^#NaoYk%c& zFiMe@mtS69O3oH%bXt3J0}!V~tqzh`Off&#Z~J9zkujVjdT!(|diXXbS+?P$A#}ko z6N(*T1${W;cQ`_vn(>P2kD!lrY#*DbJ~r3ivc-0?pet{12)*SH^*ZM|*%)*8l{f9N zK`vGpVzC*&j}8BA?1gI`$GCj5J6{(O+ftK=8DJgvu1z$i6{c-J{LP;DnC$x7W!M~E z-HtDkuw4P!>jRCf3y2^$6xIuo8XpE?X*5%g5G-0N5o5RQ zAM$_J?>Qd*#{JlNX}&7sZbeyjdu_G4vyoVgEp@OEZa1j+N{dE*=KjXNLf+kdWsH;f zjbAV0Q|rMnZ#W6qQuR$6(hAhnGb1`Xj()v2-u75*TyE*Tx(?)y;xkd4XbbI+$Z7B0mAHov?9DASFx8*b zWnW<*GD`Ys0`yk%A&r535sH^ZsBXR61$NNJRO_Ttx#M)(Rnn$c1| zku(_4gbB(ap3tiY!{|`6Gt^)VJkvPYm{|{gV&(8G)*x~S0ng!~zjooyE6Od)20IH+ zW&SKD>=POQ{9v4c1#4Oj5E~oeUtzFEJh){`0c=p?jpgSh9?B|}7}E~eF*m?AG4&ap zp{{CCXVs{;c%PrLb^mzV>mztc*bm_y8xb0He``T++_!B-ece)Db4u**fgQr*`a5BE z`*L5)t8eZ&)8FF40E=@2%rAiYTU_i%=rT4&z;`8>W$P{Bd=2w!HQ>RZlQMf?z3?3Nib(JpS*u0wl- zx6%qL%jz1N9+RUpyO5fUemA272Be1i>ivZXXmNI{1Hd#zYBkQtu6U$QsZ)C=+?}vB ze6;1|!CW$mi;^W=y?`jB(qG{px;tXbw_)?YcQfD=Whm7JwUOhjgq*RHrwn zv7;tFO9w^|wdD`7i63MY|DwpBeU8nw-f&d*^~xIPmHvhukUHuu>+7gLZ|(g371f_e zQt>Q*?`L(oza{7tA*+-9tWLeQ^Jst0rGEC;-sDF1cNM*EFL>QiG{`IY9ozW+HnAFn z+b-&BLrT1_4JrUj2?Okf?^<6Qzx}we^|9mP!t6q9snl6tSxvr3A~Vcn1vtvI3zZlT zij1~O2AG)gVg|iwt88k=l6}&fMiso%raqcp^Ip)62|w>2yX*I%mSn@gfeuO7!5#;2 zU^5?x6ar^t9?$TW@Q!UPh+!30lZ?^;D-rs<6CGkE>^eU19~@Jwuv3aVXA?5`imZDN zDjTttdm~m#U~H$pv#tVT?=ax;aU%CZ%IGaVL%usO;FmL_9Rw)f!FG~2IfB=@B3R={ z8Y4x+EMiBP#}2bV(}-m_Nk9V`WJ%^PhMFmcn#tb!HEM*NP|H<1-t20+Zus@tAmRd8mfTI*}xl-(!C zapH*KZI^@tZ3o#V46+sW#vKR)8wUdJig?E+>b0#W`s_IM+LoZcKZN)DHt_8)z50IX z(eDcnxP8CydizVCK41Ct`O^RGEx~<159uW#FkZoncpZ^|XoQITov;1h`9AEmZ}+_R z&ED6xo$kkpeh2GLcU}ccz2TgOL2tMJ?zmwbGA2LVDsslwK>rJ(!g~+v%S&q29rzl# zp}eECT#eHhCTt5BX>ko92iZVA5KeDtC`UYmD;;1X9%>$?z5UScqkLgr@!j%Te0YOy zH7OKmNV1}=4c#c{=f8y16sDoHo~U67V6B(DM*W`Gg-JV)55+nnoEwfkSZqbe^|J(X z;$3UOAgctp@PptVzUz|q4?)X+bh^M-FG$Y?JV8d()oUi&KiwXZ_^d>hjDn}AnWe|-CV<@NSg zq#pMB!mU3;s6{0H??YbyKJ1NcN8d6#*9Ygfnn&Oxqk)`QY=!-lY~u%Y6Rld{nJxYP z9MPK`QD58GQM=Ag-x}t9F)i^{T}4GpWpVkFmZm42m}VkP4`m88LTQ5-|MQTVv`q4A zbrU8+$TwL9HIK8J)$jXXn`Cx!#ID~*bK|hd32ZGK*$HzR6&QBWP@9;c*0IDuvL!3P z`*J1yxbZlbvp**RybZLG4YX0fh5Uz@UDvXY9JYeQ|Yd zOC#2`B1H`JkyF|Ji!mjtFg0PCKGB@FrQhK~D?(vH+XJ;V!IXxF%YaoEV6hJoo~mC& zLX|%vp;1vaOImFlEd0n0n>yu++ZQp$ zK4(4uBS;OoL9oche?)3p3N*7YV4hpnv=rDp{;5L2TkMPQP=gTl1X87m!iD6i@TuoT zE<)m>NR76KEe^Xr0HGZ)=A*63M`Q-`YMFZ2XZE^Ik>eb&Z!m_G)84fe53z-=?iCHS zjT^;{9%*%XtmVZaKOGwOL)hSddyM|VecTsLqdu`7^NA%(xE=W~>ye+>j{2Ab8uO7| zFI~KX7inx`KkkYUx1&C@8@0u4$mgE#{M)<#w|hofoSneE0cOBbFPTTMp*Eu7mZD)e zY1a(OCq~!eu+8xs88`2ilsqhHYpZ#zZYu4pC{f!UzdnAe$8fVtz+6DmpCSTM9LXR% z<$&E$Gi}a(=5szev#7APt)dm1puu!vHnPINBhGeacJ2PNNR99yg89S}W4=g5N9D1) z?y>q-lbTsj_Om^e+?MFvi$71?>I45p2mp{~|3+Q{q|J+-2)5h4x zj~9t3%^01x()l(dGx>SUse4X@h{GZf7y=u#CGh**5g02p70@|@gLbv z*}@z4p<~|*v4?j^>>|BScEplE?(c}yxH00 z#M0KPrWW#HH9oI?(uTZ4SRe@J&tA}$nn;aXC}+(+re-$>erQyn8x*W&LU@Z_nh)Uz zI$&TK>XZTmPykvNen!Q1IhuMHKS61Of$sR2rr9IXzkEw0N3Lmyn)1f7p~)Nk;2BwF z*@k2Q4KHE=G1H$|&)ATvh|T|icRlS39VAFH>X7L5NjXoh>tSZ4`ViVox? z593HN7uHJ}Ya2Vm=IV@{CnkO!I{8b#DW5v)f9|aNk=5)EcNu=V+vwAsi~rR{MxXA+ z6T{DT8h*Cj@ZY}}efDdwTm)lY#OrKq@ZjOh|JyPBpB6}N_7DDA-v*8O!hiA)2XW#C zSn4J72sVNv8fT*z#YujHlZ0W+8TP+@>~%O+m0DO_a<{Ri76L0%H*JvKbsq|nsfMQT>7nwria*9r5ST`%;xLZwW+fm=G33nRA^Mt zY~7llS@MlNCp+3(JD=REZrgiJ=@oO!z~4*a?O@$ltY$ zoal_6wV+4LFS#9U8$Z)7YU9m@|C~dH{N>xcAD{_B?|Wy)t~JKpII1uYGe2> zo5i14E&IsIykLtS*XAJ;Nf%@E_!t4pqT9)qcdZRoSl?FD(tcK$KI=29v0MDL zIkA&Ha$eichp~#84m6xmwxZEC#KkSFhyjj*zRvtUuJLcX#P)NJ9pDr_*fDB|L)0+) z=zi8W`a37~aZGvLK6!wh3>%<*7#w>>S#Yns0^bp;TXD!sJ;uT7FoeYzfvg(rr3cCr z3X>uWT#RzlNn1b?E`XHgMU^K4Kt0mIaH_5m!*lgEFc%@A@TmqyR8X+Ae~qYUY^=&f z7+eU9S9(lX_cAZN4+d^2Z(xb0`z$~73HYIGBN$i(Z+P)V2~jcPSJs1s{>IU7aH3f> zC|u-)6+5!??1lW&3qQewIsha^alkg~QN(N>UnGrZpW_wwEqD+uBBu#~D@YhFn>rQv zvmCNdXaS)_z!y6JFX13m5*^s z9nO(-BOM>(nUtUkMsNgZ@08%j6Z|yJHcHR@?1G)g7W^3UDergl(5uH|vd+b)UlnIE zltDd_qRdE9#&tp|k&?tniL%#}NL~@A;q~q~Y0R0|rFrM#GtY_&PDmbD9F`dV9IExD z{~Vi3V5ysDFi8kJGyH>LXkD5kVv100Gtw-6oSky8Yvw=)(KzcfGq$?#jg;m+th!g% z+5&?MCk@uC&q%Xp{o+2>;`b4D2?TdIQi?v%QP0SVRpSh%bEN~Vg%iB8-nNpWvpL!9 zy!Q72zwV8UNPC!5r@r5)u5EdQX+d&Q$|D@bM9Qh#qGjp`y?LpNA6bI3#q@N;BXz}N zb(y^}=AugooK+Blo|dA3()d>=mlhu|;0FZo?eJ{6yPNtk_I zmh)=rk2s0cJz;L7@aA>F%^L~%(fs@v{!O^?lKYqAZ(ooU2VX6ixy4)iyYTs(Yg#tf z$Jzp><418~LC6l1BjU$HRGu!RX7Cz$1VX*ztm^9^ndl_MPO9^_28CVA6eQov%PVZD z!|E*T#DyXSbz;5%HZq8sRkX;MGG=yneo8ww83dA;w!)Nq>XoM}|C&MpTX*S4#KhTi?^Z@6mflg6_90>ub z$GRk7(cM_z?ANR$?|R;R*C`2SxajOU@^!$ui?WQenyQw@D(u4sEy{E!2q#@)A=3er z$OE>L|3P#l0KpWh%;5nBL3090aZ$BNl_7QUq)Ul2;DwOT{CF3U^ibo73d)mS=vGs7 zz`GRk5IK!dQ{^IZdf_La1Ky%BQx4(2+6%l*f>0LND+`ivUSb z!BS}>EhgEnL5%0J$3CR5P^5;X3jOey%s??8?UJ(tfIsT{YV~J(;&g4#kGHyl0ko;E z@(~s{COb&R+KERwfP^C*1tXpKpwSNevG#)T9ML4MYzkLC*-k!zE5tbGNV}Nv+(u*BF@YnW?7*MqCK=)&9_ApL z;>@46`}n`TFUDk--Yu5P4wx5uictlUJzBbAx4q1l4 zN7=?quqQOm9@R#GiZs%ZRHxDQ!m->0$O_UP&xL6unBXWI=cJfmCzx)2VeXDYhTnSz zTv9|UbCS}tb8_-tRsBKDDY%u7kA?H{3sG${3o1Za1!cMU#Razub8p>8rMf7&xy9|2 z&Nn`=IrUsb<7|Z^ZG>ZO_>=4srrGhQaAPLe-Wbnea)bwN@78YS0wYsr{oIU!4m|^HJqTMxjJjO>CC@&CEm$=BB1%|v@ z8tW=C^onh6tz0c*lH11M1AtiojVp{55qoZdp6Qhg2uPV)WY z3ot>oF$D;?FWFIqrj9W1^uTMH0`xpsWv>?{%Laf4uV@AXKN!)~%qg2G&74v{SOq6E z06Z8>VC@IZI9WfN7V7~6e=kyl0ZpD^pCIqZ5wb(=G5Fah&q{zkp&r{AQmeYE%N(UlzT8FNy2|3(s^aqM8hnOXSc{d|9c5L`sCrERj*&W8h3XoYOJO&%vhO@>t|@D;D(Yx$xLe!4b5F$NuYIT6Mgsar z+o^!p6C9*doFr2m?D8@)RCinjH7b2qY5;}DRHcmYK(&n z2nF2KcZxQ2x&F<`)L=zr)Pv5XibwYvA62%r)wSU0QKHhHOW0Ey)Y$d}g!znadfd|S zxVE+9VSW3(X7$}C)JDHW=q1f{`%FQ8B_%IowGxlqVkHDj4s? zpJpGY%ORx2C4~;fKFlp~m}fG&V_KfF>Gm zQmfVfa6NA9cyQ8NDSyOpY zV?`0F8BU0JSkwBTwzaqhAK%r~R+To@SJl+jW))ThT~q07anap%a;kL{%6F`td=ghO zjVqdN7q7#OoyLusYKLMKpjeR|hQy=_ITA6Bb%-Hk&!6HX(BeeSwLa$?|8QSq;>|ln z>ZTeTnuc9;C{hCy(M3hy0Bg+PV!#&be!VGJ0y&Dl8@x2!~7fR zl87D1VS{PeM^CrA3YumgjaI-Ey%f($p%dweP!muk#yY`Zi=E?geZKWE>+?x5x9jfL zccMjO**V$87j_E~5(Cp+r_Xd!o&ejFz%#=qg>s^Dp?J~Tg7O5UQkC)|4GCRJe?my= zp?Z=;`GO0P10B!-r?0#`eoYOGwD1<70Z8}UxL*PXfQ%l$;uf4BDr6JUB65}!HdD{d zHG-iv!3F$lOEdt0BY|x9A1?y6la7#Tea%uQ3q-M4~A)jjE z{2H8D{G=JcUG!M(5t*~t{=B|p>{MqlG_8(D;v{aIwzFumvkV6F1XuBRo)BwnKoeYr zlbxknPKnx%$vXDQS`JCmoMcm6B~#o4I=mY*txoHI>*H}T@w_N4IX$EFetvaPK2Es6 zvL+bi=p%rzsuSbxYJ7*@-io7_AfH}d2#o!!A3tgZKwx07fgv)d*7>9ZUw~rObW2lH zb9+&XnqSyCZ>yia<;kh8H^vd3#mLB1C&e^J1-PB+ES>BkoaCA?fybY~!>`gw&Z@~y z$y1$FKx!QiK86!VBaEAJlFcQGLhxloIR|G1KO}7EsAS zHOWyq#ZeBV#ssC7i$KdIVVX04stYJ#vI~+%{0by7!9_LENe(}lndBs$f9dMsZg`H{~cZh-m!E?VueXm`8r&XO> zr+)BQo!_CpkX5(qm}rgTX+zHMump4+qO@T}I0=A>fYI@Uqur%r+{BQEj#Gl3 zJxHkKNVvtg_h|35@c|jb97$dl@Zu(X8M@BwV2rXrB$Vgn+$=9GBcpAdj{!G0eQd!t z|CyG@k%|saf&m#AIY?+S^DZNbgh?)9$a%agsZNtzAb;^R=Y(mF{HYG{S}r1Oo@~6m zXpH$4z1^n`wuRarjlZ6B>+XZ1hRR~>zwxT-580d?ON%?nUQC!5fYl1Zqy~Dm*d`8& zzrDS+qV=)lVe6uwz4f;rnzH-+G$-j~C)HFZnU<4yx`S}KV*&^kESd@OIKf51P*;v1 z#&H-xaEt|NV`OG3Ct7>g>F*Cne)joIntHRYs`5!4kQ(TNRh?u48mI>k0TwbRjN@_W zY#=lz78G`3QJ4IF?Pu;M=2#q_<1NM_>M>sF5Fn{hy(7qcvbzjc#6&m67>o%xCrmUy ztM$_!t?ca|01MDCk4MkSHQfvQ{5rSEj}KdIRD=k zGkyx4;~YKCCUUBqa*S&-z7(6}lQjl4+(oSA%%AQQ1A+(bf+=^1k<_$lPNY%b38@dR zQZ$pf9`RFuJ+R*8wEJaca#3T>-QxCE%#YW?T*3Bi>L*xji9H`MX^svrOjpLXVUQXu zL59r7EYzeWxP$Tq27za&#Fwi_=vAsV;Xz2Kcc^YCZB3p0Tt8GaG%Bl{U!;4f-qvIT zPw*C!corg|{9kk-Fn(e=fgcP2rV$k`nhQ3k^!B+dAu!D*!T?_o2^;5gJ#3<^=Wj=9 zaDwvHF1gWWTXh?{H;x+0FqQXT{yGH>bMO=7DB@gWf0pdm4e`lqQ z*dS!wqAuZr2Vrng$+N+p>!JKmq=qp^8Y4EWK%IZwgdtWaguDhd79r2G{B4e_5IPfG zDs6Wa)X{WTiI%H;3Qs=8O+3k6ILTcA7k;SX>8>d{E~(lMDZp!O7loF)T+2hG?-o6C z=fO3W`_8By#HHNIyLGdnvZ%STkQ@)ee4K*RksKNqsdGd%pq{+UqI;(DATZ*f%M(iHk@}!w;L{o;X%O9zK2#K7zbH5HRYNCg5s+(-8t74k7k{B4yDs7%( zDo;Gc4S5m3oywEqS1soh{G{a^r{^u1>?t4brquFEo$f4{Z*%TFha(ZP+`C03=#&Ak zi|X3)n$+*v?Vr8lpuSzKj0n(h?0*hg&QD=>1nw7}x9sr`wMyv}_UczN62DCdjG45jvPZGV$zOjN-d5Fb{*pHI1u-#`x#Tq{RTe=8SXw{;vBKkGtSU0Ue6&$*Hwsg!5hkVnj0bb zr@Bifc!)t$c|si*p}vz?*GUQ?OyXgDUNy!$ZJbZ?7{_=WyU3+3*Qb5%ZG9ktFV9g* z6nAdrS69|xvbCaJ4N-jNcGQ@2Y@zej*&gB<9!g{udKg%y?Ftfrw0OcPJn1Ai`6QkK zgc_yoq0n)YYJ)2mp`N=`-vc8vf^j=9%-nH!`HtX233<}o2PI{t*b$xVzwrv|4^jB2 zJ4C(XAE--J!OX+1sMr^*{mI>S_4a+&Xa5{Beb*^e0Bu+0be>Y%S)$`8oZ%wWbrtCV zhJY`mX&^5OR31{kgv3*vW-XXhn>gJ_Gv310L|28@@0KRn>wYmWk>ksmE5C?T(6C@i2&M8_DM%Vs5ZSMFo}ja z!8u{Nmjc$~RGWy=--l^`?YY?|-pP}8vK9!Ir$ z0XWujmudldT~yPY6SZ9vwcQg*F5J2@1~V6Fm~Ad8g`m zD(2f?GqF14eO4&XzEfFSS6*3BTGv|AuJ*euoBo-@eD0Omu97+KNX`yW)GCS9)QU;L60ZWb(841%V)UD2x{{r7zCc>CczxyO#8_Bj*$x; zA{N5#Mq>A(mrRw3``}pb>SW~XX@I||cMfg(3i|AWvI}3o( zlU?OZ4Uy@3NOgE35F`vaKpG4w(f`7r4XHCQT3ki5-K8LHPR!)(r{?_<_OZjksEmi{ z_eyH2E1#h9;INWcSbuOvG^ReW)`+P*6sghB348+xu#b6rXHmQQLVB6*=MEFU@t zGD;cR12Q3EVN68a!eT@dfEeK?V^;2oAk+#y56L1gp)v28;qHCk_+R?b^H_97aaK`X zRdYvE8yR^c4Ic$Wz?u{q8a?F%tW%vv{&!pcfInzmbg7^}p$T82Az5V(4}#$pc%WBV z6nL%&^@lzOKtQF_R5VpC>!(R0PI^&h*zkA=O%COc{)Hy=yeLuR3y{Gg1ztylG-l+N z-XcXdewGc^gWZY%8Ng_o1OdE1_SSnO&E}N#AUu$Zjj)FYJg`}&KhYjyk7)nmEyMLw zq^7ZfLkI_QK=yHg6Uep)d+aUCB$XbX;}rlap3{qlq`x9g&0F{phDoHWc6GnhWgg%y zyn@&e26YM22HZpJG?JING#)B3riNjljqI4z+0lY}UecjHB)qxI;=n@3%Rp-APpW@_ zAn55pO)(^bR@b5AMo@3MXQ~#DfVB=UMb9G{h&G*$krTxs?bn6P_bmi6gWqVg-as99~NH$sY%bM6XTh;s@p{O zoAkc0)8n4ia*dtgES{tgD2PX5b1h~rg|zS zd8#IRB~SNK&3BDmVtZ=WzQ~yL`xVWdC6zU$HBI-bnj+*`dLR5^V0Oa5DQ=O6WG+vl z#}n&$sI)zk&`p@^ku=3UX_~tV_()VePpt1Mn&m2(UyW@6WvZUn?YdeLcb(Er+97K$a${u^IT(}b@lC|FlIj6DQ2!q4E=SkOWbT1{z7jR zY=)^03FxAd(RjdzN0OdjI@BhEDTrUB3sb>0ex^&TE-w}%A=5m>I_``Fc=G8y)ik%1 z$?j=bygkYZ@G3Fz5iW7QVDL+z$&YTQqm$E9vu>p(mlhT_w&1I8b+KA~P+7dv@wbJ} zk-9E%(_BQPzwDU^xe-KzPIe=aL)yex!oUmcB|<8=#BAWfdJ#e_U|!cI0^cATeD7%< zayCBmel9kgsVT?KaOzH+Mb&lI(krMxfM}x6N%s(y2LunJ&4IeOU)!6QetA(e;JA1PV^>dz!+fsR+w6c^bn z57}J%$Yq?<<_F_$q(6L6iBEwDC^I{SGSh7&b#$_E;4H?tV9XNZ6ZTJHv-bNxR}Up+Hb-91&+ zQ{C0SLS$JXNG1j5&2xCvJ?J7or9~*`kG0>O&b9S%TW|Hf@BUZ)IRwt9F6A`*`R;yR zIlj(_Ih17_;s$Oh$lB!T#zq6hap6ZB0KS={}3r#catzHg0yGaf$}2-(u|Q^^}WKu|#XMez+CmG(M2 zbqJY)!+`bzW^ahKDXSo7P8A$(IwlPDsP4Bkl5)U?IAP7seJFL6dN%OJ_{>`#GDizmM%g?CF^Y=-o zUKRed>-d)IcI6%T<&9m5#~x$(ug4oX>}yBu-x-|p$**;tXLdqYg`rMPFSJ36an!at z4u2njzL;!fRdyL3LCfd3$LJMCA*Q4NswXPO!02CRXCJk9iS+hS zZ_A%U7Am|w(QG-Q#-l3F@zs~e%?|CIVfE|SdS{;s>a{n8^*(fREMgQAy6xXsXOb-S zPBD2`Zly!32t^nfXXM&?>H2zg8FNP&`3_lttAZWfq0lLGR7Lcjlj_F^@@u zKK(l<2?a^|B>&-ZeCf2Va$Pxk=^5!V43Y$?m0ah~i!rVm7;N)^romcbwo6nu@mM|t zO(1mo0Kmt2xHJ)*=BcBiGP##Rs?W0A9$So+A3lHafj4%dcJNEF{8paLUIg8+L;mB; z+$@%VPDXN2Za`_-VUFC3ZAmnj&U?#y+!i9QbZ;|_bFtaFPm$UM2rg*KY=tE-iojsH z2U>|bN(0F{C(7*UiMjj80v=i+eMZyt!?XN_52R{ zw5w`=7~9Cmcn!19)WvL$i{zh-Nf6Q>2G@dA-SwJj8>PRn(f}_C%r}a2PcmZmpxs5T zoWR!{Vdk&hk`uBi*F-F@i4?CWbT0k5Z?Z`XZy z4+L>0&`cN${_U0G1~*9xN8rS>SkrE4$%KjQ`j}%hg63Zr^2o~Rp2MHF`rM5 zEdr5-vcngJa*4EhEr?nXOPEmyOsa^`fRyLMl~4axrgo@VyGj;qeNGDtSf6A>w@~Kv1xj-fbLfa ziWk1@K0yH!JfLKw=JRLBS=c{EYCNLT>l2I5c)bbp$1~{YC~lOlj_J|u>GQg_T9KLX zL6$6?k!dF6l-a@2Qe|I|3AGntbYWkS;a!oDgjRs+ekqcFCNJZd;BgJmPY5VA$ytaN zQy=Me+j1uoihx%#byYJR^O+|KY#^AYRgX0ikCcVM&hJlM(Yx{(Kvh}q1xf}IPQ z)N8{2U=L)248l^MiIAW{n7tpZ>O%0--w+A155RIJz^H(&1-mlssBFs3x95zO|IVp( z3B}Q$;c%39Xki~Sm=-|c zte1cQ(r6#L7Xc@aSn z7o_{1I(H>UQB=PkSLt92jCt-7{+LG zMN8CyMw2k<)BX`<9tTx`paddj!hi*SfRre~jDCS2oD%CzG9S}STufK7B7CPNyZ=6$ zD!R}%MLWcdB**-$I7d*qPoow&M=19%lP=@Zz+IW&UJkd_y{+Dimz?tzddkWsg3TiN z^BWl`iSg3xolN8|*t52XE2rWW-zgOJo=?@8FX5>F5t#u_)d&t!EQtSK;A|(BJP3;Z z81gwvw^I8)&o438OS;tv2$b3b6%^stZUvL2OcN3!>bTZNA>Ngu#na< zY@oYxav?re>OZ1N3#r)iMWzV?W=zmn;V1kdDB|ERX3IK;iAi@OR;`IEslMi|bGM_^ zE3m5$Hc}4U>g^{lCRXnz17xl&TmxOlLwV$#ArKv;3I7f9R+46?3w|v!jbe2d`QNp z@2|VwcQuLBW7Pm$U>mN!czaOJ#37hwnjswI78-&SU$a$oeAT%&X@hB$!e-^*s1f?;t3O2D0_o{?B0 zb;BcyLbm%~`JD=Gf|!p&4}kE{Lre@s-HUrB{hbY`-M8Osq)=2XPY?~e3!3wfpkpFN zjtxw(5Z;)JP8%NzI&SZd;YJh1rOPWr_XtuB1s@Gnb7ec?4F@AjQkw2kxOQ&T+a+qC z6R^D^kKV~as*hgGF+&d~@0Exef#gUOm^MSUjX>=Wk`NnsHvn7{9MI$F^uY!PLmaL> zZ}#7n<|-3|t!92baAga(?$-(sgt2-ScMeC=tz#(p-dfQ9HKZ)ZkP=+Vsc)Otor zYe&i9eScCBf-&J|4^WOO+(i1j_#il+WQgtvMyI3KV#SPe1wIeq@K-9!7{Bo~<;G9#DdgJR;2u1Ac5_K<+#vqp7bTGL;U& zQh|Tc8vI=5hgeA#N>um3)e|2onanV9-*CcvwpwxZl&!{HaAIQ%0n*;T?xB;bcrDW79*U`suY2`#UD7iYVU4JndBWGFd=E9w0lcxwN!hAS;+?Md)mdGCyZOEYqgc&Ce zX@cJsEe3vU#tcg{uZpEux~9)cehx`S56kps5V>)uu@20az{6E*gyp7xp4LRmj{v-N zGXFXFI4Z8=_Q?A5;QI7bX?~?+YV_{*BI~aq6JX*fl2};Zy>3fOhN@x`fGjX>&zb=3 zICmAn@&!k2zD8{s%X(sPjl7hbUOt~i{2EAOU9E*)kChD&vM>N*M;8rasG?E^Rdf&n zh^PriDRX*942Rwg*7{3Y$b$`QJN!)QH6b~lXeF>o)Z4`sIJbmmyWmT!9;3t{a{KL( zZ#^EPZcXuE^n?B`eFD}Vgu0Y|oBbbzL0o=!fsCg(Rmaz2XBhP}4Pih@A`j+DxTE}N zupe=7Iy#gf;#xCIzBdcbwfJHKp@t;EahAe}Y}`Y;ki(#dF!a?p9+eWj7j)5a+r*5X zU3mIoyrD`6l}xw3(RF1$QP1tscB!&m`+s}}qdrvAh}do@z`ltEhJ^jr`hlP?UW>bh z!8FdI7@0x+lDlJte(apjwrbLwvl=&z6&OZN{d*@d#*{suCGXeq%0d&H{lcB-BR&y{XUx>;dA@P?j#mLtAg z>#O+muzw4Q_fg|C72Ic)b?`b`iep^JK?pMDzNa0-dsz|pYA6VMXR|IO`W8-0yzZ~O z?pRH&^*uJGb@QyOj`cm8qXO{>hJwVbm@->4$x)w4P%VoJ@H72DgxHkr9P}VKuZb&r zfrtV*4@H89{eta={+o=7Fe{|Aww@N;q>a6>aZ?gANXU%v%GJ=)tgf-ThVL7l3|ail z_x!$cd6SbJ>8We#nh#|q4b9QNv&bqH{Texd+065K{PKIOy8W2Rv^@X(Mk^DzQNhA~ z9V0YpD+2%_X&^xeTICL!b}MT{RNBCQ6PRCroky74L!pgXB1Fm5HzcRyfO7+t>>jSw(7>zAU>03zLBn_U!<{vrSjWVkm8-yRJ&q! z8Y^B~PMlcb4Vy&5RN%M7MciWf~&f!6bXK`4TUsmC?Lq|?a|!{FNkRw zK%{{$h&8UP{e_EHRL#lA`SvM-_{k(+@~DK{M5|H1K-^0wwu(<*4L3svrDaw1Zi9)< zB29pfG-Pq6Jf~FT`$YFN)+i|_XK_-PL2OroQ z>`C{7Megl)v-u;Hf!0`-tktROm7vsKH7%;=6&aC?Rug$e3;^AhVz0jVGvZi#m<@a8pf~_ z?(OMpF`kiUk_ePs-(%F?gKP!!1c&|vgc2Q?Kt%^FJA640Bs>9eplsD_f) zLMGIWL=`c$9yr7iCLM-P1!!cmeo^&4cmu9U0LrkDSNy+cRrQ7Vnfp^=Y^^3U!8S+V zXTL+sIS4v1(99eiV5lJq&6J!~i@w0f^SwiU+~;5bm^1)v^!B%Pu-A ze4OpBu3kGyFZD-1nUYqgYP>fK!ea~Q--?7KAvj{jf22h)mdm(j*FH<0zN0nk{Vof$ zDuvn2@)ukxD>~nK-KXwq-M8?ya(WoiSqvFha$&_``1|vGo@D|S3?;xuthh~4Xuw6{ z`Im(57KDf(h>&fKjHFwPq`%fU9_3zopNCt4Q;nUd8?OOOGG*GgXe>@pnOHm?+ciG> z&fH($oO}AAL)CXNLU0g7YtF*=Mjz|)ASaiM=g$q42UNZ2fO zT5M?8I@)eNr1F9uoE1_fwElr%GRrSGA6T7thPND5BU-^cKolx)>PhuN4Z14v<-#7< z(iwx%sRCcAQh+B6w+($9>pn0}6U`JzjriEp_(b=p*Vj+ZA6ENatTjk!VfZ*W6EQh* z$xxU`G&bJ?jQ65ce0Jf{T0uHt#oa_gqYYioEQ>}0v}51;Vg#rcBWszL=rwend{<}J{D z|K8vF`gN#Agbz*`c%N#P1%y-`xXN@<-2buB1i3;BDJ7g(?}7oC?pIRZgVrfp*9}i= z?j{03tTLtZ)pi$PRYN7;uH3ekhTFoou*EaezBI3CE&MEqEs$TJmjSejLBE!O5U`}R@Z%bYDQ!I+ zVDjUN4vDBklPUv;uHVJJgWTPe(&o@)ALA?pt)?=e5k)O`fD z@WBS=Q0cwP2Ju^~yn-RMFfc;tztf(#w}t2$G4S9d5TeK>3^Rz?GK~=AzsBkIizKJ^ z*_;CK$yN>4;ZLy#Kt&2#(@){UFv?RO33GZJb2>6>1#Su8MBw8fY#332O+qSh(!IY* zd!Dw%LWB$!SqFFisqj#HGQ!N|b0S`liOH%I0e8e@z`?c}_7FXQ?X<$bmL7|_lz3LQOFvjf%&D=&S+CZubLCXSc z2O%XJ6kHjEEO@i)=IL)D7j9C$;yTH`zj1c(u^;vfOTcEB$;x)b+6X&Q@3=6f)%@8V zeoL;8^?mTH&^kfjA!dJvQZqE#o{Rc39^ar5Hip+l4g!A=lP&sdF^AIrYtO!Ymhz21c8 zdf_JcmtmTUB$%x62~N96)anUA&zyjpt{?~u>=FdmkhAn8T|6UHzdj17*N%W$;XkHp z8EQxQvCD$9me7==^jQ{)6>a!Y!0Qdb5H(6eUAm3(?WzM9dV+BE zcpmv0tP@=8jHK6L{H<#YXpk(6MZ*};ja@Ipmxu4%?AMcSUmwP*Z&nt!TyW&%e7j|W zb)YxmkTbpd$4m6vnxF^dYnioGmG${(Hy}w<`Mdc%Cz%J7!%Ii^l0pM5%LX~2o0$?i z1i--mx#ZGh{yO@oykI-YMZri;&K=@d+4a(dA|wGGo|2-4NOWG0jZAw)C^kX zPbA4Za_Ti813#(ySM)0-q0tsR0qpfZj$o|UgSeiAWjCiz<|;QtHSnU&TgWtVAMzaY zb>7T@RIiR5NrHGGdx4g?1fNcaOsImzn+@Srf80Do)tOZ6#>qS4q{PD z?37M^PFH7xJIH_v1Q4{$pubKXziX{bJsK=MkjL!H9GoS2El9jF43#OhEqdgH68zru z8o69VveX{(>O{Ae=N0vJmDT?+$lCK!PWdP{9@|`0(4~ZaH)z?nxbr=?%H=3!f)1Vs zCes8l9aQT4@fEeW8%LCmI57<>3naD+-=|{Iic->v@b>^akDjn-r`LsaeNGZKWmFQJ z^(8liNl`B#Im&J72L$9yha&cQ@6Db2Ow%?)Y25sBzdcs3{I*4RASBjH2-%XayUF|K zC}S(a)sew@iCvnWt3dS~=l(Si7mV;kxdI`>9xBZd8p#m`Ma1zEu+=194JQ-Uq?F1I z86^NE?;)TO9@#|C8bNteH~IW*Zu=CyVbXYwvBEb8qG=~D{#AW(7ipA)JB~Eap9j$P z>!86nLtv?qC)fVV7^Mzq6U?Ppg}hc$(e@@eGMtH0mg{zZ;pN1hg~PF*$_GiT`@?2f zAxAW-^a0uDm??t1944(~s~)<5E{ct`E{PFBvm87|n1ujhByihh>}3% zejP^jZErt*g!p=dNVaL(nfAKz>|=y>13Ww$yerd{>5=j)rO{}DPn=<3b9 z99oj;4)g#X?h4~=ZyIMI#t4Pp0A(#Cu$}o3zY|Rm zSbJx`64h|EMPJi9Y+4k`xaB#H<^mJ7SQRRYfh>)HjcFC97Qx4>nA6MI1{D;i_|HH8 zO8PGKOGH2%FM~42Li!K!qs;iH zW>M%S(shv8V@&VPk74<{#^V(t@qx?`UtfzGOh!Q7O|0?w6Eu{E)_ofV`Vs{SM)Ui% zvg_Z9CsKds0kc5gK4Jct@7jJ|8QM0+_CGxRXBLK!))z3Pw;)J_b1NF{v9)Nhl6;u5 zup|!48w=%08;o1)quSQ5tLL(kOAwzX^$Zv(B>jN+QN+AonTYBDR%+#I-=@UYX=01w zd#Z(A&VN9A%(89XGAmxv>>lCl9#HDu_m=X%K*gdyi-&!YH*20EHg|nYvu8{_)L(|^ zpX7V*lecfrw}>5qA-p5fWP#dBQFEko9;S7Xa;6cX5h{bQ z@xhq;(UN2b&}jEwkGi-r2UvDCQaib14f=W5>`RaPbMZJX4)EG?Ja~mmB)j}7^Dcyx zuuzS)%~f=b(XcSoE3errY!QY(g4}%*6&|pAUJi5SO1kGNeF~O6C2Afcf(g(d_WKJs z5qUKNI+uC8f&ipYXqF+d7Mg;@q1|$yhZAk)9BJV1_yZD)2|Vqm2v>(I%c=&lXytkK zLFuYVR3AkRaSeXpk74CjtoRUBY;hUH7{K-h%OsP4{hJu-s?@J6oIgSBsoeS`B5!H! zP_q5YwLjcBJoH7#gi-*n!$v8&<-E$Q1*X2lV2ro_REU?x7|gPdlfUoVZbIJ2ScGj_ zw=}dD0udO;t(NM`$pqeYK1P2~I)NertZ{9)sssk3O1hP-eQK)jyCLTCr4m|BNpvsC z2&ZNfcLugjNOZ2Jb`EIPFBr7`;hPV(xApE{NJo*_g%KCl@o4D@iQNWKL@%BFED1|} z2IKyP?i21LWW_SOWYz5)Imn4evbA=AMt6^m-81)^=vbwJ5HQl;@7$cc%kUBs?+Y`- z$FY6-muYbV^BXNNc2V66c5Zw*KlL)G1tQfW4uf})6v?8HAXFz9Gg|{k60(6YB^jt_ zxC2&2|MtDRp5S)+MK9?czb7kAMR99(^G{bgL44s4r0`%66EHKapgPK)k&|ExS_rof zG`uog$hl|4b5}tSW+Uhs1o{?^ zi?bi$@vp#H%$;2}z=ShW|dNU#z#8WDOcT_r8kZ(Zc?{=9XiH(+lO2+Q&H@!fI3dAHLDxps+r+tPs0cymWbV<=q1LW%dxYQI+e1u1V1Ez7sVSgL%zu)Nmg+Rs%YU z%^Yqs-N?FrzlFAvZ|1p1>cl(U*rJZGN`%7c|b!ze7y46nGbAM6h zz+n=5=mbY7jUZ0H+WAx2@|BcUBgc@7J+(T0HE|NORwD&o6MH9sUQef~>W%_GtM17bx|C5%O8YT&VFkN#u($ozYt zG`O5es`aH|GN~!h+g-+C99f>Is+>+t0mZw2xn-ZV_{>#+vu6FO)yDk9sSmzbs(LQMIDjtc+`q#tky_0-lY11D2^^oUVblee{Bno$TG9 z^w<RjYpW*L`8- zEatwsHya4nzf(IPchv35S|GDYeCyAX!|*V}wRZja*Wuq1a@@2w=3D(^`^=m9D>8zQ z$8TmB=X?5D&|i;_l$q;ZhtZCR&rl!KIU6jfB@iijIj%L^6MF2tgVg4tfQ{u(U9-MH z@J#aV7ygYhdC8Yg&|CdkOJ3CP*8@373rux{##mIBzJ=mlikhvc+&a5!&~ub)?VjiD zmqG7;&tK*rr3l?mQ?;p=St&QCMHsF8Eoaf`_o?5P1S8Tk6`rf1&<-^*OTd)EbFy;B z(ArY1!W5_7T5=L}ol*$2c=jHj@pP>f0f*tM32LhFM7i?#ZirS;sqsNarC*DXbnDOWj zh!K+TspY3p)HoYGZ(p-_Q`fwm7E>2ww~eWGF`AuochF2xC}y;J_Rk9#)dM56S{Q$4 zk0TP1TW$U|4V~j>v>J_npxv)@etm7%CdePGu--Jk+KJOHMi0a2H|hs0UBAZPZvnn? z3m^1lmXKuXtWtb}R@UkDCw@Tt=-H0jUs`i?-iJkIYDA~fLT>9}Y3)zRq~)}6V{^MH zx98pEF8Y^J^ap0rW%T=IG?Ex?x5wKVs{EWsavl<2w|s)mv?(fLl~KSi4Cf{m)baRI zwK}4xUw*qS%xyNrcJseHyt$L}wj1p)R8rJ>c#j_`5P1Eow7mZET#o6PS#v#^8#H!) zA{FSQIE*NoZ2JV4ZJ*i9HLmJ zu9so2@pPXt-@)fk%1%|&P*zpf)l^$qJUD&4tH9%CK2pkbbznQ!(o~exY`M)&Gfx?z z)8g@7D=DAp!u^ZbR^tt;5OVM!hQpfU2unJ^-Amzf_u;B?RPAZCbbfvH%6%%jJ=Aej zqW;KE=^kt+0M|QQ_4xwnt*$*sCqc{%PYNGZe>vRuuz6V9C1AUKw#Lx?HagBx%GLidB|j;slyp@f zE38rimpmSC!aEogrUv0@FO&f>^Sh`J*{3hi*FrgXfyvhyw0a`O!`=Dcl@fo z$##5+@fG(n6Xv#x*r>FPUHAk6F$vQpQJEE<4W2)UGnf%rcASD0-dtZU;TOVV!`Mh) zFM#C}K+cP;uPKf9yN8->YSYsZsx8X zO(Dx2edW45h<`wtzLB(g+H0aU_uxDPdyO^C;&=N{m0nJ-Y7`48W=nRB*4^q-Ml>D6 zbGgqDrw!;XZgkJewK~Xgy0L(GE3lMyqsPtm?yhQC z+nD&80`11jq-(%8TF#|n4W&uV(E2(5EkkXU*SP>*yz`aRFCCdNZBX8gRC`mHsj! z0!tt>nU$T!&%#7z=kBywQ|QPOJNdEImrn4>X+83+vh&65wn1Rt_3V0~{Z6p?a@)h; z^O>8g@u}blo9pE{F+Qc;ddYj!7pbg_1HcS!ymf3T7-VB5ei_Pl2Nu2p=-JGuRv<54|qR>%z%$wm@K}dD}kbh7WBz3y$+1(IhJ;+hmrF-#b ztJZrr&v-F>L!^yj-nZjDEG;Ndc?Mm7l28JvG94Mp;_S7IenDF_0>VV9~v_ z(cxAJB;=u5lXhRx?fS6qDdwu>siwf0%<@zdD}8OGQNFmyjJ(vO2yf=dGC1!uLWM;6 z$K*&`dAYeg%@sWB$r8Ph$p>%ka^j}lB#OeX&5+?| zt4jzeqoef_4=Z6=p)EQ>N#HX}m|K?2WAfx-vYKm9J!nzfZq}P32DZ+UKe7^s6kZ%Iqs@?1khjTW7pI<0SYVPE^;4 z_R3Ch0uW(_gHNzkcPP%foTe7$CVaP&U8g*UO!KWPoY4VGDFBY7rDc-*iaF=<_QLvN zUAoaqxy))gqB`}eIldHd(1+~+A_WQe?9#@P^2Vl?bf5m%Y}yy1`%OTYv%tsM==zTD z>tx3zQ-RPmFT=O73UT7o*CSKGuEd(pi=S!(5B{JqevY3!G%J`1uX&WSw zBwg(n=wPXAmJteug%;C>Hp1##m#E`0@a^@gb=$6N_!Td0{Ifi_I=!$vzj$b4F4 zUHbhML7~U}_uU#h<3H+^_al6e83hb&t~WLFy=qBn6AR-94=l}W&EY9}dUZIe*I$g3 z1?Iy*BcWDTxSfj24mE8=Jty$wK9-0Ahp$ue0JNe3tyKw_moq z={9;cZ(m#Azd!EXCFBXD7o9Rh{G)omdw^?a-p zOS8^?5|c2t+S`7)iSap3v_=aegY^bvQ(AyF5xYNRNt|PAS=i@|w^v~}L~E1+(QkL< zPf6}o{MOc?5T_%)g!JL*cq=1vhXD}idK8S6$9qdVSEf2c$BV!g;k9^M3Z400Tz!Xl zL-NKmSj?(#{g|5ZY-{`6r1_&u!$GzZ5`rZ`S`{r~WZ_M`Y+cz{#&$4$4z_zi37VXU z3jvW)wU!HWhNvv5;at4bUf{Dviy7)|;NXiY-*AAKF#;bj zOyveMV5AA`5lIs|EQ^i#I#1&8uQ(j(Fj~s!k9mQRN}aP^y)_v#dGS#P!+bkL|X~r$mNU;!tq0 zNxJMV)y>{{a|1lOm)oIFHN!D6Z!Ia|NQ&5nkLf>9ICx4>V($*Tbks-h&9lBxYvq^lKwJ` zosf=NhgS^5eD2AD>-QHN7ceWGYg;oB8yIXk9RT-t865(?L)Fp;&Q>_?W;z zRr3I!%S#C0hyVNu^qYqW{kZ~0Hzvy%<2z4=U$&u3T$ovm%TO?_v^E0S++dkq-~fZB z-kAXiYJ210bUk9$U!*9{DXOb$D{J}u*g8WcPa#7`JKwpnO_q^Hgf~8F_`7 zgGaJb1-S`_x2C2)O~&P?V^rzomK4m)&J7K)PEOOuXi2E($W+|f&R??fnufk=x34l7 z6B*PrXO*jRSIj8@6>A9=ny4+8`w9*OH@50zN%-4`m`8bDA^-udg~0!+lTgBw$mwo* zDCnFe3{o<&YvOxIi>OSmfy;mT_7@Lso3phv_1WS#ib7s>PH=-2c#eT^WD}FS<#eGA zxb>c3vx2k|=+HzbcSXxv>)&u72cC#=>lwOG38YStNS+Yx+2)5|Hz+`A2rR;W`-|bI zyrv61OrB8b%rv9e^vkS7((P(AAI8R!360zxZT=$Me1ynxQy;j;P!6vyzbtF&SjZcB zR1(8dL3Yu05R?8!7#3w9|MNyqVMW5S9K9@b8^FXABzI3#WyniktE@gJ$c7qsvVKqV zcekI-m=5+5uV6Ty&#f3I5%P>GUn**SIwSl{zy&<<*jG{+TZMl)JLI|7)mG-}W_MQW z;^j=Yl*BBH|MvMoiMRC>(KY>7Tv76NX4Yb4Rd&m|te&D*Mi0Gjs9jo1$pz5#-7|U( zxofz$AySUK{fTWM5B|GTN+Iy&hAVR6GqxMKc$Z;Bx4ZB|+!Lg{+KJAIdu2rBoOWlqw-p7@HieV$$qInwjBJ z_VGrE3cNWT?5psd*FpF_gGiEfH_@ASW*#b2=%uQ>p4_E$Y9+zbKPs9|Z{?c{6IPbZ zfdD@vzV(I%U{BC;=G9K}LSXbw>tQ zetA^(l*bAYs)FrWuicBTVsXPuFOXUlW>Vqhx_Hmh-b4jTV)rG6l!_UCdy zY7Q9cSWBe%GrT)b4y$`$4#~FhP#uKCIYP!7#NIr!xpYr^Lo17QpC=soRyyTa8nvrG z<84o>D^iN9h-Y}yIT_`bvK9Z(RVwwDF-Yt%-_p1#%dOL&ppx^C;Z9^g{gj<6=NnS0 z?{Lf!XQA3!zI$6l&HllGxPyc60!2i_sff%9FVOSk#)Wx0**J9d`Tz`2<;b?u>Ep^h zU2vb8J)0?QSyVwg_@dA+N9-{H^B2OQ*#^-l7sZuqNB{y2Kjt68btJp%z93o{)pMLd zy}JJXn2Vh$;40^QT@kTO^1oE{{Sw#v%{69h3&ZE63G6Wpn;x*GV)XST{Ln@nHA;-m z-*S$PSQvW%wbr-u=wBGyJI$W#=6H4iJG&Gq9Hkb}R`!5gfS86pX$kyW05kDNQ+zEY zRo8jl+r3++2Q{OO2@^6cQtA6GF2gs8x=B_R=M$&a3_F}R%siQx8U?M%aQ9aUSWxc| z$dN1UwMpMJXE^4uol2!HDlLVXt46C7Sh|G%ab_ZB0E}Vwer_w3ijdS;T4a`F%4uLFT?tK`?fs6Hw^u(}6bbUw6a)H4EV6 zCS(fC^&%BKWQ<;T=5? zy&h%d|7Z06)0jUZU>-Cu1L_Jqu*NU}!Z9Dg4P*YlCXzVeD~9?KFh|{7FP<9sYSz*z zmO1gbBnODl_n4_?X=P1FGqvVJO3GPu>>0NHpC*+O`|rVh8m=16SXqUNUtUabON8weLypaECd@(pac}wmoQC6v-ym0s21k^$kBgB z!s6!~fhmNxO5H4RNhN1C{$V)#rRk*LY5yD?by?k3-g0DG_}3``g;iKpkeIttIO z*Bpn?ilcT+7hniDuC5FZy0y<9#r>E5<`vZFMeAxEBMB-ME!FSpa+YzVwS`PArqihd z-q;wPQ;mhD``JrhCE3sa3d3%V7?9gShYW7UfKIY|mgzAH=TEQ<4bM1ObyT5C4uSEo zHhPICx2~0SZ4aezB#Y9y1@V7%$N;ge3$ZRUmm40T0Q@&3-JJ;=swXUqut*tIXOHg7PE3RUqi_HFai#@`)*Oo4%k)8u8Mr_y-mx1!Jm&L}o8cgoTbCD|rg(u;~6v$bc5nf!S4%%EX`t z=>=8Y^c8a%ePo_JI4a0fH%pNvosEHHimM$@vFz3Izxw{eUl0i7?3T6%meb^$N|SM5 z=pocCy=_?NP$*l!=*>PAg%w{qCyydS^#62Za}7!`Uby?FmeZHo2`^obtLRm$r1tgH z#clHd^-eLEFT0I;%nA7PsPzBj0}dom&_tBVT&Nq_F%&}Y|43ni*+B##LTjnqNSdC) z0msMRWxD)7H-&|IrxyoJt=74Cs>Q}W+<@@zRm`En!48rZpfA@hJTFe;hrS8ITC-PS zOzljZU7Sn}ZU0lUH?o3ZW+P-I{7-?4gPo22|7tn@Tg%H!$RKNKXYOJ_$jtdur%cEo zZfWCU>hyE9F?2B%H8r+3F(u^ZhxspA58!GITl-B>#INoiBN*t_5Sz}Yt99*h8SV87 zLLwNX-xgY`^GPKSA>?$zA6_|YSnt#BPlxiN6l>=`>Cc{KPup`MUJ|yp*`+OaEihE^ zuyZAneQVPIHId`e2b!+@0Rn~pkFc+difdcCO|TH$-95OwL(oPWch}$$+}+*XY200d zyESeh!9BtKBj=uT?)~w`cz@_-!QQ);?3y*JYOR`9kbm`f-9Dt_73yc%P*4f?7n_`I@8xG?ax?>1040+IPQ>O(2?|b)6q;Ew7h5 z&^r1|!h#g3SQBZmD4v%q%lqyY*cr6zU--i=ou4mWQ@1mYsXe-dEBG1O4i-M13-+K8 z(I&8086V_FK3*B7I@5WZfx(ldR#w+u7d$u_##jaN+_!1|o%!UIdkRk{_S(SzA~5Yc zqYAk-;hPyzXwaFIAEnmUEOLeGDCxZoV_*>?JKW+= zNxw{(WTFy>LpUTE4d@*JVIR@R<8ptP=AFKKau(CU8_H*aYb~iK?RBKRRne#pQgG-s zw4@Rl6BPA?5P@ z8-s}7bi=iw!<}%co-wrk1$HwjDRT&MwjoO3c}|~=#*FUxzUevqW>$7spb#u}I^H7U zVlYlUd`HlaOml;__dW@snO%i-zxRBxVv+iSEJ7(Kk&>n86xLQ?4y73#OPU#ro2}wO zW&*%t7}I&6&c#~wZ@CYk-?1#iePjrZC=;3kd07Q20{85XzkH-w)R){7U9%D8qQMcy z667!ecO78sEiGgq2)u>{O!ltLc`l}^nf=bqc@M>XL#6JcK1VE`Cl)ZC+RNhbBf1f# z5f=cFDI}5e4$|KY_St*1SHKS?;I)+=k$T7ce*7E5C6YsR6N@s_KnzyaP(qjwW8RMw zDZs|I75+*pU#r-?ZZsclsE^}Gj2XPI7nE<_P}qldeu;BPrgf&t&U=4h7JD|Vu@y*XqTa!yNj+LF5z3~SbV|=W!A{hvm&+AUS{=>oYRPq{AS}J z@Gj>SLmBIA9VST(UBk1l#+bEZ7HrpbT=)`>VrlnmiGStqH_Ha6%P%T&VKJ0o(Ag&Q z2^s$`=@EYK-CeH_zw_=M*Qz@n+fkVJz3sH~Ve5#ns*QMl`_Sii(n3-VYGXw-2&@=@ zuhnA89qkdvKYvW2FJ8J8gM}M}`u)nnsA!;0Q8X)4yhxUj@(7g)fJ?s!NZb zVn=w#$5Qi;MJ1^UCrI_uvxtnbLPWA3DJ5L8ltW~cZjUWVi=Fh1d<)1%Sy0Q(5zQwG z6;A^`PgXcs>a%DrRYCW+k5&d>F-s&8BF2+6^82EF&iNkfLP5zs7$L(t>mIq!&)TT# zsNukL#|E3Cr{n);;>ORFtpnToyZH0gw=RYv6Cp*7BemO z+t|Z{f<^C`q=Klg{Lt-)QdvLcE<+j%qj2L@)R0V_Y%Fk$KJfDB@JgcD99Y$NahASq z>OIAZ-sIQWPGJ=u#Ihfxjom)lGdK>Xaq+7tui*D+jORxmLsVuq&{Y=eyq$YOo~ocC zu|9yY-;cl1CbdSOfg`%uf@sI^{Vq2^^j3eCwlMPWmrROd<+pwrNQcnp=N;IA2kF5q zNaugx>C5m=50-=T#2+@r!+)>^M6a?k=5@I@%hS?hu_1+C0rq=ZrDIaR~li{u` z=khTwMc(-lCp2o7=Ey}j!Kr(A+PG86cgKK7f~=1#L6!V$ornMv!bPkgyc^bc4N<+- z!DaRCeqh;cgqB1vE__x9do#u!f>Yv#d=h@6j}z~8cxm!!D3VGU?(HB41y-2uzD^`- zVf3ND&N^^NJjvh~!6}8+5s1{mz*~g7uM}cn)9^eZ+vsi+cZWP_Orl0rCTW|s9W{{c)DcY9M3CPhQ@zkWKJ+B%c4 z{RcahO`Ysq9N+d+kg)Rnr$x-p*7@xp-WvWu?i;+ynVMJ{irTrsX*0hyaI&zHaPhF} z{z2G(5c|)Sf1dvbn-v}HjDe=kB-(FZ#U)6XR7~BRNtmQ<-kvS`_ovw3pVB0{Burv< zU+f%#_J+o$B!4a!b7CR+OAt6g!8b&IljW~w2^K~c5*C*K2qeME$V~Dk#(%({?ayD> z|N7<6B^nAwR;I@Pxk}oGjfCxw(8_=A_FsYjYWqjvzl{mDzi?BN5rk3Uw&LpfXoNxVk8#70HyFUg9oU^0L+c5u6zgYfQG;aeb zYU%8xXzD0tXJcfu^O;=Y7I?uj^aa7+Bk4@mH zQdm}>9}DbmmLf%tAdNm!u-ZH zSgWZ#0;Ri)7Yf0nz~3S~1ciZ=R}^8uAg{wpR3(T8T4_eHl*|Kjb}URnzEMWR-U5qb zHtn;l3e_x`^fl147D5IO_v zPBU-@7N-7AT;ifN>ufsE%J))Gl;;sr$Vc>TbBx+rtRn$GnsLj!AwI^gF6DxvvtK%!=NZh>eV zeGqDOI)bK3L-!b90@l#kOqw74hv-;Q0P0#noL(=^VphVvEw`92t6#565-6T)6)lfi za)u?+wmH2)Ox#$s@OSjT_x8nt>h)%J7>7o0(VBTX$W0YBaOP8$(#NhL+H#ak*o%*! z0w17$HX=RG)6%r6V9=7OqooH(?W<79OFwP2?R2hEIRJ!$X_WJsG~rNGjHM}UPR5m(j$lNC;lr-($8MM zeo+e}E5*!!15@!*5Khr(tV=Q`kW1RaK7+?aSS$Mo&b_EZ|?R)jt4Ew!FcIQOWo2Es@%tWJbAQM7F zTgYCDKB5H=QMyXYKT4rICzxk9pP+^K371MUyIi~JdG<5IQoS`(kvb3cE-&RSFV)@( z!Pe4DJ#}qZ2AH3a02d(zl&RIS%IU{1%f=jtd-BeYE2|=~}VKCy=q_PFC@y z?S4=J?1q=sqt8;78o~L7W3CK@pBUAj7R+Un5xEVS>c}wwK3ULPB!I6hGmDBoOSJDi zyib+@%^fiNMK!a8w8=kDH0*``BeA*oyAp#oxT$rO>_y8fUQB1@)iwAJUy^0=7w7f# zmWK>|tCQj;I8|i|*Iz^?r*Ds9w#o&QG@6CFzvzpu_!o^mk8*e>TDej$oy%aIcdo#$ zI5gnav$eU{i7s{D5k(ds3wu5K-z^5JWFS+8ArCGQht~+=>AUl{@08Na9?~3~1i##t zlficog)O+h6=N1T+JW-gpjtvM4^#e-%7y`JX1}kvX@%Nufmqs- zJB?y9SFwe<+tyWdV{>3gV3eUFLCck@jgbNYXe=wjIFpSA9FBZaK z5*AnPVjq;3wp^W~kBU;e>Le;YH#ITS1ihPN8;7U%>H8Ycu38!p9%^ z+^(n5=l*^+uEV!tUn#H70ViweP-ifK+BAe}($8wrfuhTH$?GlTAahAa?A3Q2=-Rgw z>?g4`Tg2*~B<&u);`jcw_5GyK)S^z)pZDE2>ASDWsJhD-Dx{T#01sD1lF~37Fsr`N zJj+l^E*7gg`7eoGx%?e}FP^u`6L1q`qLvx*WL6{>jOfS-ADYCbW>=b7+JuI&h+-K8 z(bRot@_!pBBVw#U#z%i3*FutLCW^4)L)ma(E0 zLc!Zq7^x7nPl!CqiynXKS;}8sL|yS&la9O!ZmyK{f~$X-F>wQ54YJ$eUldUYeup7% z_}i{5H!#ogQ#ixH3nl-)o5kjKSOR$+M<_ZT5*6oZIQDrIXaiTXL#Q2^z?-{0`{PaD z>SN(5u4(4Cvp^QWD)KNVL3mYzBGM4YNx0os`ixDs6f~4g!i~+xDn7JT;l;&|Rf`S` ze8%{$5?m({<$O3mC-&-_(z}d8mgLZHk+G6kD+8(Ro8>ZPI9|&n49ByL#`Z1DQve)$ zxyQ;^mDo`8l)v@#%Mq->7*oT(h9y&5mYOfGs55*0)x_ykVJ(j&hYccV&AHIbQ@nq( z^+t@VWBZp2^AyboqcwwfTi6@*T;=In-*VA$Mv)~WktLT1qpKSz_%X;gvDZ5Jsxj-? za^T!>PZ0dyXWaxE6OXxkVKXrYTvn$^9EW9e&ANQ}iJxzD9*cP%Sdsz%;_RHi zU-cVDsiDlYR=cDRhmm{Yu&y1}{HW)FZhCzBFWcY+0Gqd^22w{ZS0$v?b*T9v@pYrl z`p~m_H@khl>E2^9haJA69s>t~5v0(?G0(ye%?sERhEoZ{Ynmd;)-bm$ zvuCU^my9vzyV%-2)t!eoM`F5IYWcZNr7UVAuD5U|x zXFofYm|i9cEoMlLy&a-Gp;ibLK)FrtzYc_h1~|0_*)<0Jk}|)FbBKN&YVpsmGG43t z$(J_iC8@)Q@KdO`ktm!-(Br;a>|kT$@&0p@T$h+KVu?U;TJHyf?fFd940BXZUNoT} z|4}sWV|sfc-@!^QFH2;Rs-0gRwQ>P`df}XAZFnHd(5(;HFJb3Q$_)KK-bhX}rq$HZjej`*Id*&|@){?@HNLaOsFX?OiS# z?)N=f7iujHyV}SfZ6tu381gr0yIrOyrvh6#aOKWpOuZ0q?9kHM2f?7{ph{fed8{2T z2GA8p&@A8m#sPY%K7%!5VN!zyime^N6_xO`Hl%}3ZJ!el&ktIc8(^`PhVm1#LvK5C zH1Y4r^)E$rO92@kawc#bggJ7MSuhta{p4&q-pC;A19eoJ5ye!jVrw^$x5EUciewl_ zA9Z6YSURZdJa1~yE-JZPbd;g&#H7IU&IOw6KiIqO>SzI&O;NwTfbSZ{$QK=j}1W@(H#I={HZ z5^ZJ*npCWYe#SGqS6l8%uiZQnh*u3I8~2Hz74&%iHO)0Ayol-Dp5x!=zsZ@bER&w` zyiJU5=)-AcgW?0BlLgB40o|egJ*l0dP{IRImC@eyibS~A1}a#p6o)0}1Zwx|w7jV5 z&fN7EZbsMJMKH$)8K<*9x<2Wy{nR2c09@1v$Gb3l06Sd2kOR%Oy}KC74XumZB-sJ; zax-69qQ-d(j3hNcE^aHE2NC@a9Fl1Gy(eMs>LSWRzrU3jlV4NhVmGY&U28ktI8%CZItBmhr$*p){@IuBmWR85(tu? zrBH=+!ZUf~acBo0`3?#g%8r+@v+9NF@7$CL%{bmK*hZFbVa>NPG~=>G3)5)E8dxot zxehdG4Yt@t+HAm~yHf1xYka#MUN{Y}lQg-Wu1;b1^%V zcZKM08F&3YmgM+}Sag|m%{(-$nUcolHu$Qa>$ki_>MI7&KYZkCNb>wu;#%MA0gB|1 z1rBxXSDh|Z`iZ@0@^lYRowb`*q>F1#?#$0zCy^i_6uDtdVnn7po{|A_P+o0agAD!I z5xzK+pG=i`_6-JYxf&!1l|&wn|Es@3IQ8T|z1D@wDX<(`)nd4&ge3Pbs$JrsiFMPc zeYJYXIVcxk;n40MYmr#&^FlPQZQ8!p{-H%`AfZTcYz-3|h}$yc@+IPQ8AC1|kN%@4 z_mvt>dKHu4ru%k&)9Y!K-Y;tcTQ8@%*TiRA;xlJA-_TPj_vs^o#CYlz!KofQm#>r4 z{uT0f&-SctRboZSul-$I5w{WxT9VF#dQ_D)$w zn4u8EZy4eaMr;TDj5B6ht7I*L5KP|Yl?SS9+%ICz z<0Z?@lXVOvl8O{3+k6GbX@&&sU5xGC-YUn<2UJnTtN5x-$1+o2d%)L>vqD*IwT`*- zAGGDYTXzSrJ-={fU9FlDyDh$kRBd7My;hJ93Vz2!Lgj_hGY=5M-;y==W~^EBeCRkW zRkIcRbtoTt?%Q2IdOX!E+qNb;mUm(oZn=yx-x?l*sBLuAG6WV)v-I|KCjZ^QfQM`A z|F)ect(jrA3XDcHk5EOdXa8tqou6|K>k;;ut){q0fU)WrM`c816`Q%qk6@uTS|Z#$ zZs#8c@`kotsLZTQy&OrY!O>rPj#L8r*+`WU{l!#$ytjPL%e>=v@%yd0B*V7L5%rH< z;t`L@GMfj)9BkLb)7zopD$^_L8c3UsP1=c$nPbGm zSOtCrFLb8q@a~xA2;P;Z*;lm zd^`1D$3}0^J5!TB&vaJgc1<~fD(+ayOj744tRW>=ODV0>8K2jr4JFk8={9J*#@;EC zgJwhrcCQc+i!=O}R@zF3$ErS6uJY{{ZwktaxBur7kDpcn&yX*Nwwu|7W*$w z&V)MSoZ?_I;{e5Du6nCQkfz9lN%Z9%=8~4~#PZKnoZqcfE#0LR`sIPLxT~C69P=Pt zi;_LWi=T8Jo%QO8)B}I3ItU1WE6kvx4PK}ndVHPkm5k=xT-`u66iL!XgCum~cmSKU4b#kfp>>N$%tl%3coan{$OG@~UXn^`WW z&wG8kuN}{FWRXwF=ZTlTa=0Rn6rrt#pr+xCysM_pQ_9!_ObXHe#n5|E-I`!=(lg?b z)`xoeAb{3y^H0SKjr8bTR2%x`62On52jP2;I4g%=n5ogq(*FK&&)!KTP^n~qDJ8ZAEE_Ozs%)}rQ42_1E6TT836#sB5s1QPJYL9s4wbmtqLr!i8(8z;n}}uH@*y+V~?3RpXU0z zbKhY*X`#}RGrvj%I@dnHq`{m>B6fOA6!C;u7jshQ zyB=1nXo6HWjh!H|B3QOXuk8~w3EV#wFvMK@Hi+M^z4W=!HtfqL3T4T?c|bis`8W3g z)FKD5R-C}*MP5n$PN2r@%;v_bOrwn1vjkt?dVz3AFgdij)pq{H9|rdq5x|7VgcJ4*?rPVICt7 zBQUTMb~aI!YaWGe*{{zWwsqF0Odm>iiju?mU?>vu-xsK%Luk z6&Hk>V|OW+svgB-ARGk9z;m@e5Ve^f=+PDYdh=5*!cLZ{cNDv|#l1@gzqD+I{J?*N|5 zHvu_Fe;dZkP!n*V*+PUOvGk0iRk#8o2p}>t^7T=;oYd+KJP&?#s?a1jss?vu)}8_w zSm`iC+h|g#f5f{aMVETavXab`98DJ2#1Htufd|=o$d+Q8Wf=WoT-4AKAtj{uY634>ac!PYLv1Np ziKB5r(8$^V2J2dbc>cxPu19khA?aY&tme|L3Ws(7Dq62{W zq0skyoRhs}oKC2{nI$}5m}OG98ypege#{wEAk1M{A3 zQeYZv)sDwja@VW4w{1(wgO*l%7y(PrB3S9;tx*+R&(mlm_C3&dMOWY4iIkg?uc1<8 zeXdxg{F>R7+`R!u_L47sH7P0`1d^{(J6!YJhO*`Uo^67eRrjgL%f;kp4;fy(Qxx7B zj+U`>t6-;@3&q6V=S;{m!rw98X}W6^XNtFCr4q7`0J*msSw>bV$?BK(ZnS?}$-Ss~ zD))4}9Hv%XI{8VBh}O4{5;Z+<8(3y%+FkNFu;A_-vR}K1Pikx$yHI|$LPVN1f4v4_ z41Mg@8vv6W&)QIBNEk(d(%pdH$|*_xVD@=$Ly zS1A5fHy&R(jqCD@c4Dz3Nz(i#d~$0}J*MRoU-KIEiPQD=_8~nGRAQxaE+0FxJvCJc zC6llDi{#^XH?P0pYq<8v^R6|>pENPG zu502#&c(FolT=B6AR4M_SMPnf>g%%zh z_x6tOh4h#tP=yyOY}qx@s@s$rc0J-3cAe?Af*|#_TYi^UWVC+>-J!)awffQ;FFaqF zngzNnWP*^5{4Y6jL-N-*v>Fq+NSPaL#I-mJ#cxU(f3T*+_X2*s7bm`g zdq26*e1jleq}6I{*q(q2i2kD3UA%Ul$D;$04~XWGhRz36EyhpzxTIzgxOCM`vN)?7 zlrJ=0E%@Iq=}zc7)fsFAlgWx=xNF;Iys>7EeMW-okJ6Z`k$ewp9gmG^Wmz`gPPRl} z@)ZL?q$RmgEO$cxT0u`fP%n^xu1#vo7S{p8n&Xz=bk^D(6lfs%Uoz=hX>!g`Kww5l zSz}R`_9D1y#r5XtHdLqkWptk|^ZWF)&eM+gMX8V`ZSFJ1)#;&Zg%8r*US7Y*QZM+a ze&}p7CP(kh^jyONK;5NFOs7BG_C!9({QYbQuYd1HI&^Mh>4(y>x?eUo!0fT#F%`wP>k;V}PAn`oUt&d~5 zy&A9Yo+d-Fzwq82-WcoK3K->k)txT?Sa?ja;s1Tu+&`@2MU0i=Z1mm+v*ZEmEy4Ek zT|5yfWMgX9F&G2spWs3-ov1-005Rj`MeDj{i6NP|2FvD3di^Kn*JVh6uHMorX)^4w zxl&1qtUin3tFK);j=pk6NG4uTF;!wY%tNt8Mnz?bKu!Czt>(|uvAqu*4AQanXZ%tv zipoT00`yj``s;4gJ!GZj&BktJ`lN@rCxbc%?E9^3jjlmpm>2}%c^J)~X?FiAP&W=( zKO12V*xXy1LQaz_pmi}`6~RxCt7l06Ek676bJMCF0~Yf&%z4m;9v70QUVEZCt?gl4 zz|Sb&YxG;Yp{kx1sU%RksEv`;STanu9{F&u&BR>Q8R4Re%hf(d^DcOCi8Cy-cBavk z42ugZi3>xmB?-*6(A450>-k~l*)cijVRd$G?iE4AL|C>~h12|K>k;SP^s&qJzUm#Rm_MP?+6kF~@Knss*V~j==u%_t``hfpF=P z)*)=yk(+crG5@s^-&W9N9vtA=*nleSVU2D?x9xXIoH7|U$KS8X{TniE!T zMGTQH$j62)_@@^ZSfaG|f^LX^E;tf$EMZe{yFa`rG*~iLvNLy@HMG zWMn?{FvW4Ss?{u6E?6;Oe92zVOSVE(MvMot(12A`s0>5DDL^@Bu&eE#vizPZ%>-YuVMmT)T0^+_M4LC?*OC0l)N zSg-BpJHqdYs;ODOP`>OL^$c z+B~rrM{))IE zxK!PY(-j&YE!c+h36LSXueV00D`a$phJ+ltSsfMH6e*9T1i-HI$^>I9DSrEG1#$XA zQ7V}dmdKQke2$tm7;Hg=T|h?e2(ofh%1RafQ=lU=VZU40c)akk(x7VS}& zlTqg%9YPfw8QeBv@k1(xwMpp${s&8mS(d!-{{MtRP$BX#;nO`L)d#Tm*#tYZp6`p{ z#&(j3b)bG{p!sg^(+6SP2>Aj-avTByQ9i(hkOzB|K; z70+BoyUpCKD`+k!YJx&fq}vhSRABEHkIdJLD(@R@_2&`!n!?JF0Y!g}>T#P$a3Szt zY_NqA=4UdtdJ@E;b6oxeTrQmypMf2@hG^zpEVHf7}!IW?LmPO1&WT*gZRYul?WHF z@pre+jOB6Oi>TFMbMFWJhaz7zof}P!`LW|43QSm4J!!_7ie9C)brqg|G)3Y902MKD z22#9_SakU&h}GCC*65OK_pdt5Vw>&28I! zdC*#js9og2w!+r8(IL>OU%%Y8s=-Jt8;*_4^x%6?6%Y{T5myOJ0yXsvfdhD_(=!A< z5;^`SF#hI_dpBVkF0U(8`2pyA^n8#givZ4|5)$lAT=(T|3e`FzWdhuPPXX4R@2v0 zC|<@{yqM&Ow7?%xN1nOs$ceYf-g+JT+nX5B|0BkC^|TCL1%Gd5|1hohTXsWWVtx8o ziq>zA_q2*v*~Sx``*D!AOSZdeEZGm3H$d`O1vZY>1Qw3=~U=U3h!5=(P0rX1bqE{@AJ}%^tuB7uat-Q zNu!~Un2zBx41vSk%zbY~IuS_Gx8KSk_?VtkD1`kD9TH^ks@>D&pZS3`S01fDMALWK zqtgtI?6P0%OJKYUNWPhwSz%^NL@7?QpxpS8T*IMdEY&kGntQ&6Zd6C+tOMh=AXsC?rEzRmm22+eSnxL>90j4Qus*Y?u zrtb1`TgvZV@LwkK!T{xy32JiQLw8FODK!Ih@wa-pD;5X;HWhyHjRU1W<9amC9#qX7 z=E>Zm&WTBNXN4=QDTqM(z}))1|NB#Hz-PLEOTjLUi-qEX z>8X9MA368l!n56R^>=fdjpfY|wwf&=QV8M&i=UXe;100>^RkpuK6{(Z%; z$qYUM8SeXUT)yLu- z8PgDQi-*ES~z&bLy}NHE5XP~gOt8Gj zxXBuP+kMNT_vN#}sLoQ9sR%SN%pU0zO&Jb*7k!!0=zYZCX7Tx>de^!BNB8NTooBxv zlp>#H1K?8c<}1|h_9~rab$`a6U?kq>b+%R6De{74Lv0PSIH*4NA(%k``?-+6{qa#| z{p+KA2QkgU;o%nDpn>n*)8yEutVBIq<%+0#=0U7g`sXF2d$tg|#!B77DGvU^oL{ZU zv^s%Wd$~Tujkg0J>@o;|(KQlQE6jirqJ!dEen?NrGTvCN*A^D*DP(kF&^Ac!V^LLeDnpZ=V=2EednjKHECMuN^x7 ziYaUE?yBh_zVs&5oXBTb7t<)Tf->E%B)PhAHWo^kzW9h-Pt0rr=Pa$;Stn5pcN+Dc zfiQ7FILy;(@CF`P&_TXL;{1F4XP@26Ct9J_^{@%xBWE&N*>oel52nJ7^z3pCWzY7i(P9VBKiEIr@d$Q4S3PU}*h28o*n1GBszat2lwhfV@o`l=k0E z4yZQ9Q_;{Ij=XdX$bW;|Te==Q1PS6#H>)x57iA{&B@!xFDRM}l@gDjZSUy(pqT-1V z(6x}wdR+zK5Bd;tK(mhuKrA;}r?gKIHYef9LgTziOb6u-n0RWW;MwZJ9L&%T^!4by zrQcF8Hw+#b4XNkcrnCv^psGC07O&pFs5(ulGr(an-PF`}7W9x`QYD<&2&fuPgBoft z|4j>?CVMA%FIS>w2{t%tlHVrg6%+h~3Tm z=n%f1yLX#9O{>!*RQfyGxW8cMGU@NA`^%=ls8qtz=xwLBeY;<@dfSIzZ6=<2wOMmk zb&`MxLe$C@sYse_;xFs+L)w?O4VQ_8Jqq>-rO1-69byO$8R$>v;K)RB;!B-i5$tWTY({arlT=; zy>|}ZAC$W~TQq;f6pjHkjPcrRJ(hoo-_7xBKM zp_}fqx4 z^6?9P{WoozN%EbzAHLURevL?f?5}pHp>~uGk(18O(2WO zb0>*~NNqc%Y8hxMVnr%%a}OAKd?K0Le}^Z zE^j03+7^M-TGCK>pplO=HS@6h?WCkPi|smWc*6A`wbHrl9_fkMN;qH}s`|qeQZA z5=QoFt4WS}pH5A{{bq393FT&isa_j#N2&LoGrEa4@0Ak3R?NM$Q&KvF!@#O|k!0aG zIJl)O6L;6-sgD9F!_3IUN{cr?jsHI>|8Km#R~F@+(o>1NKmv&6%+25RBmF4W*atmL zgQLl6QUw-{xB4svK=^fNJvLUHT~=leGWe;5q&t$mYJI@2H18FK4%o4)Y+rV5#;)_s z`zW)EKhL>c_6(t>{*&JBd>7sRgDN9JnTB(>MZEfy==2xGs^D}<_7WMUn@?HiK=!o` zi)Mutg00_eg1eVp5vd;7^iG~vb-LfIQZ?4XhFxhrjwp&`LBPXg-VKy%#zM9NlC^18 z4t8q{KdhN$SohI}?b3hM63InyFraHyaL0SCqbCrgz8duG39u=!jPhrlV<$X9e1Y6D zbXF4})r-Y@f~O!}8S=)A;~IbId%E0pf;=*Z=90Ut$vso&thF5C_Yr3M5G};M7~y#uNc{Feeer+a+D?r3LnJ-6&mr0_i2*TlqC(eX zH3@Bc0bf5t&qKIx{rvTNeyIMt0}@T*lHOyS`I`@T~oz}AZBcc*57;hE~Yrwt_uFXYNnFd67&MfC_K&DsTWOn2-+POoFy z#?F}A5I%jk5{cE2^iWwn+eAu612EjR6sF+}QzoJAvSJ|?54j_31SqcV{SSGK@(Tt` znhA;sU5iftP-40E>`4XT1`4rwnKANYDqZ9qjFFs$SA3>gBJAjK@wJiAZE}V_y73&`*wF~-&t|4LzW?8R8h4j~U9Q!B0&U=YlZyrG1yTBO-jew<=?`aDaGgqi{a#C+6woe@| zf6sh+Ijp_anVX44u)!O9VRuDM^9WH`aNeR-JW{cfnV;{J?FF-S!HFyeL`^>^IP$%ix70?%Ivev?r3G_~q-guP#cftbvQ zSugNjoM4hSKQZ0sy&m5Jyukm>f|#Ks2EpgqZw2i1xaSM)LrRP5M^1mu0oC8ULKo-b zdo;#SHb}TYbO!mnNIY~8u}sD#)KX6u{q})r0SDt?g*}2;uPc)23;LX$tPkmDO6(gA zZuQzk-wySH<3OS`C)j{n+FJh0FrN9un8BRWbiR2u;zw?=#OtCAKCki8c1(baf4eTM zuNwkf=6*)Q%zD&7z04zJ|%?7`+=mxQ+cOV;%j76qP%6fFs#Y(IZL*4!Lq;}=iNBAUJ!2?X3u zWbS>+_@VhO{X~_0u)!juv^X6*;*%&@1HYq&m1r0nnIH2~DMoaPW%Yd=?%4qqo?IzMVMvHFbOeAN+Qz&So1wIjmDH*RY{1jN3J7HeyI9p~scG0JQ3 z-$eQ42du`_n-Y3^507aBy0G=MvBn@$uilFOv9P(=SR-fOzd4TTe}SXgP?W1KKLQJZ zEwYwjQ=m>pE6w}yUCgOb*>z&Z8&o;_3DKG>w_C^Mg3`w%<65?p1(HQg+w_KYHk2vn z>72cIz6EmM1oLgEgAJlVAj4FrqQtE8?bG2|o7Da%hwoENlHg5u|4~m* zb+BopgW$F?dFFal(fMb&WL9?CtQLCqugiE$#jgiVDgaQrGS|znCDpgOPxYU=@70?j zbr-mEGH7c>nace$GDxqG&DmKeydbhYn!J}qGuIk6;7U3)W#$dqp&4S zN4lJE*&c4jyEoTLWHLWq4ja#onN{=aE$U&zfWw1O zEiOD+=McGBE?f7S!mio~8{N2FD7(mfMU09)1KfyAwBoYF`orNGt}pSRkXN7?i=J8c z(j}h)^^+GTJ$FBvH!rErpG2xBPKdj&5)=CVR!9TX_QbT(1T49vW93(w60Z~+pHJU& z4*W<+2^xY@+MbCnG0OP}m3!0Bgo0*{%RFcvuW2fU-s`URncUNr#_IHzj%<$jjMqHk!bw7a#+f%l^0sypi&Aqw8}C2L!uA3YL)4;ZB%F4u{t z?7O*UIgAsmr@riW-p9l}@r>k{k3!}CmVVFi>cr?2V|Pli_QZ1*tmtpgk!@P4W=FBJMTdk>1PC46oUz9bOuHOZ1Z!#Qts z(2FhUD4BEyWS%Fq^?rKxe)L?cP7P79hzymk2%td_2lW=wd|NlAP0CJDft3KyePbbt zo+BB+ZnP5?m0rqYIZ%B&G4|wi?x!fJG+sS5k_%B{#y2wLJ|rZE9KrXzEeM2glCdwn zh=+y3U)p&P5+zIhNIc#JAk5VN*xOr&Bf3oS`oxYThnwT6#n8>s*<$2eX>z8@!Sv12Sg3eSbua2W#?(-jh5Q+eb@j+D2FedJu5d(&KtET=idoadPF!I2xAZ6kJ_yL>0Bs=294 zU}_mrgRq48HZcOrbn_=|4CGU#)L|V->VQSc28i>Ws?UAX$J^X{(;;`9Pt_Rrg2`^# z3%t{3xu#BXdoTZj)pC=30>-yI>|m2gQ+KaHqCITo^MyS$hLT%J=Lkf z)MLFLP4K!m-R03d=PXPSGsh)=?D1Q3&ZZuS6-QR8%Lhq)$Kc>VA5pQ1Mpc;pMXjXE zYD0{*H*JXt^lhN)ZOionS>v(eL8D6>6t4r@qb+0U`-9gEQR%}MHsRf)@1;~2la3}3 zAjToy2buvo@jIAWIHG4>{l;EYlovbnj+BYu5)VU z?9&y#b?mZQ7nOxj6`?+bug7SgCj5vny>SIej%P1H!J8ie23 zeOU&c@E!e)wGT`mxWLq`o}_sY>L@7G)UOF=F?ARO`4rNm_r)zV3b|HWD zTt)A==e_L=Gj;BK$BgMeB|~P~-kW_sXR>$JB-dQa^FPU@=x@g!&v7fCxGQk(LEn#@ z6K2@o9OG8>-*$!LUCO68mCkf1n(kOM!KHY-Yr!P9$CF*tr@H2jw|fjPbd1`b>6A6& zmzyi>6SkjED(KN-rC^7_tHOja2IVKlVvNXeD8$8okQaRc{-6!zMNj<<)Xa&~%W2VYf)O$Kadz8Z`YpQ=4zdcQ^tZfnP=7`HxTd%AhR3rpGi#aH}vp2OpjJ zTYLVpm!3hzfNBGR${yN35PFpP}-#CQMICp!BYu;#RE+0(2_*mFl`{=Fq*AjEYHLZjF15#RF zQH};H33cAn6&UWTL?tI|J-vfB67GC%efoogKJVGz#(1bHe&T<4RQ;Dj;XkOsIqx0U zjIrK1?|SA;bQVo=D4gtAGTFI!oNL}Vm-IJ(j-7NOa^cCS|Nho)>DgQV+;weXQ1NT$ zQYVatsV6%Zy>lvS%CWnjo{pHZ=EOhO{5>o zf6zuB?g+y>Z11e8V5V##5A5d1Ad{!xkKZgZa5FJAWmFVN;7TD;69Wq1vXn+!Qur7k zTLNK2kH&KmXc~7!+B8M{1Dq(3xk-XErtO)`<224Z9gd75{EC#p*U+`;ZJ!Z#wU7i4 zI077jmm+{K1)nAATUOTz@$f+jHfPl^Q4LX1LxyS3tOk@VM^~fXK-Vv}Bt&Fp^As%J zFnXhVmkIWvWTB!kD#VOlkqz7%y0P$WKl51&-@Wl;M<#KtkOKYMQ5&EphrWjD1-3kM z{fUe!hjcouJ@J)8$n-Op6 zT}F}r$xfm%NAHifx^eLQ-Tm(23$~w~w%_-yGs$mz75>9B?;oC`H$4iW;J@WsIo_#q zrd`nt`@%OJiYEBizw1@{mi^-?4i9IYjhlVIXUQJh?+={Xar}5;MWIyDKRDcr$Al&j z>n}!#2PZrQ&@?r13uaX)YiinGufb$zGJ@`U?I3OY=@pi|IV=u+f2d&@laS-}lNbg2 zbWu*&e9+s09#+AiVtR*-&w}RX)o;QRHmc9UyGjerR9wogl=Waq77DBBC+c2;P%j%z zd0{ISY+8&r5mI4xXXAnKt1yw?XbZ{u5fB=aWr-t10jS`?0&_I00J4M_28lspFbp%% zlVL$*dN>#o8C}lh=@8=r00^s3u*2Y@Ib?e;3`bi49-kxd*Fylc99qvzBf!4!L4oy9 z;eaifenh*ObUKYzuTkmMAU;$()GufhqSouRsKjVJM(NcgSP5AV(bB3zsBBr4D>$lY z5aQ5W8DbxCo_y~}inakzr7#~JqzTI^Di&BJsiMb}9VIa+4N8nJqD<|0eVR?;BqPd9Qoq{L`iAU6;ynuGQmRi^n-U zoN_i|;x7An+m6rqdb@jg#)YiDIY&d^Id^|@V9i)(OEZr$PI1V6`(W~nUDpn}MI~p} z9PvhlEzk3wE;aWA;v1XP{`HXX=uh|rg@oRX;qwF2~ zj5#i8vrmOi-fA;{!@-oI^0)_gYnp00ds;jDI)FQ7F9+O^Crtgsa)O2vbYZ_WOKZlMeux1Om4$q$U$)XiHNNHN#MKnEVoQ&#Y(P`-C!c0Pxroo>06wv0O zsxZV@HvDJb%P7l=6zOM3Q5AqgTL(pe;GXPr6K;dMss)cW_>&m>pKkm_CAPkQPRxR?4Ijg-Y4hKO7Ku zf5JDrrtk8aeKu*5{o{8X^C$Y$zU^N5-?n-Ga4i5=f~mpU@3>TsajhEXkURF5go%fJ z-}!dSkH>!gVbjjo)Vxdg>!!;gN6*?A@)Dj_Z4 zO48DGCni~+pY51B-X--d_xpeM$au{|^tx;1+m5x3xklUQoxNQ&Sr?o$m!THlBXJ zmh@=p%QH+@AsfZ}qgELtTGERZzO;0tm_&<~qFzUd60T5EqLm0f5A^-Ty^tk{06%-7 z{(z90n_w|O$B;^=RVy@liOSHgBt1%6Oo@(2wFaz}rculFutX{QiE@A_looz0h=%5j z64Al-C?bl)UUh1k0I(tKU$oVu#W*)e40JJsDDvZWU=&lR6ElRFg6_DbkQqC8?K^CW)mY z9ws$1QlTKwYRi?RQbDSbf`YWjXg!ZQTaQsVl&o=o+*rs1tv}E@piGU7v3@{f4UA8l zaw1fIQ)eh@PAXt+L8pe2MO}-HRsvACMyDLsYO1A%?`^Nl{w02jt@=J6!I@;5xQ{_dXjrnBf>=hAUb#pBPVjXQR2($2G=?K={2 z`({jZ<+-BDF1LR8WmGxW|jZP>f+*4Ax@VPQj#AQi|TwY-J0OvR2 zMx()UW4$WUrX*tFtwzxxm2v{72z(=rQbY5w4q|y>5wm$nAbk}pz5QQEhU{HC7q=D@cEQ&UbnXdJo?%#aqWdi-}&D9+V9qv0e8O$xNo6+<9GLK zmw2m-8LPZ+Lv~%uUF{OPFZgzTFa4rBhgGQag_{aGGK_n)(~p`|!PKaH!3E5YjY=39 zQ^}yqfZerPIgE1jnaLFzs^ilj}V(dqg1Li;vvJoY%b6JIewa5 z=6L(uF%J0_$~3zNi;iAcYkzsWLr}7)y1Ko$Zy2^cRM(Um=olqBmYc|>3g{P%XtDnR+a2>MzMN9Mj%9b$g~y!9QK^|Bv0B z@oxElJCuTnS;icR`G41(UbN@b)zn*$vmX?s-z&{8&8w5ovGzqb_y5@CzU?ToF!P8u z&N1_~lQGkN3OW-Mmi0Kdv9!LftjjN4G;59ROlyxfw!6-9Ntx)8_P@@gjrFd5_gukb zhqCEzm1EC5o^AJN-ihcjKb~E=$H_11L3T-9X=RPLuD++EQ!y-sg%-u8I19Z10?>M$ z3J-<$+4c?&;i*9*I~o{g?RRr~(8I5sl zeD9UAG2rfxZqb;7y<(Wu4ahtD`&Duv3P8>GSx*HY6@n(KizX{Bhrz zgP!4ge3Q2O-P;h5vC1#=EARAGL3!T?WPav)`(NiDZMu+!Nm)l#-hZ7>afr^wa_Y?k z1{rMwq0br(19a0r(W$AKS`b>&(Uuk;xL&5{@4$6vW?&Y2F(Gkvs-3}iH~S=Q@}+`> zW7hkotT~^$%J2Ta{O{9G*#C~{tAF@;z@twC(pLsPhJ0}`XNB*B@2=*56`b*jPwLvx zf>q~}cY9ph^^5bKUz{RR(}&QjttB13us4`;iW@&8f7ru%g$WBCbkC-Tlh~kZyl@*C zo5f_|Gw03Mjy(VG>_2lC9J16#=3(T%VAw>>W$9*4(0l>TpcLlAU)e!ScDv^j`IW1l z{|T3yx95L-{){;?+j%~M`OFI=Jb&`}Gv*ZjpdCC#)CKtNX(u46S*=PbSE1(*t>T!X z;V;ibEw@Wu;*vi7Y{~++wCQ%qv)%4ac6&I%J>5c?;`(rgP0|O>_h+6-nRWKo2d)`2 zjz@fWI@~^~w4mG2JgAY#67^e`{(Gpe+q7tSp7m4I8Lmr2wBc3>j9RxjO$;!Zf?A(KB`MI=f3&_5ru@ zE9=@j2PFf{k6ovPrQJkWLfc?isUMb8byBOQU9_wPA{`zW7?w12_h*ZH>_SpExkruL zcPZI}4A!|f%3B@<7kOg<9#)@IM;rvv@&W!}k2tF0C_m*zKD zi%VOy3wQg^bj^9gIe%14J;pKff1ivVf876cP)L4uPH%OCvO`f`rSJ_E&0Y1=q;;qN zYxOU0?7uwAzxZ#b9>B})jbnHIaWHwF&BLjCufO)iPb+ph2gGKIDqBh`>RX!Hd)qsu z{Spn9t41k>SBExEumhI{I?W57hF-1#agw`L?a}1}U)Y2#w@+N^d=HO)v3u4myZdw8 zGB6O#!j}ipCc8bF?ebur^S$|)D8@GBJ-eh8Hj#FTMLC`7iniYF-Y%`IkEr3O28#-s zbx(|}f86(iMj-CgFi1kvDkputchPR|4^BobIFr24A#Lipv}ukxGu=c}ob$2t$#j>z z@%9-Q`(}B0XF1>b);YoNZndag+k&ZE(Z$f)MLqOnXp_))n}RLSG;N6D05YmgU}|*q zOB8A}#f#)bWFT8EWz9Kub;-F{Chwn%Uu2s+&+g7_`}@-!9!+z3ghxh8;g&VtEoZEI z?ilxc$eT_%V?9LwuumK7lJ&Oz!+)N=JGo>^6mjeW!Q?LB=G zxr+9R3mePx$Z%Bo{|`oHwXwNQW|V3^{10YibhmmYhd5-{v-8h~D3|%9xs0Q`C0;|* zU7o*it#%pR_N=FptlGw0d0=3oCaJK#io{d$d{5E-;8 zHT4v#Rg)co=`)T*PPa)Lb1v(RGimQSWxsyv_IRhvckR;OwS8=%jIm9hXqN$b^OuKj z+dKwKzI*calw*-!IL5|T4Au|o`-c@nechCN;ebRH2MpbUX%0gB98o1gu!FZvuY^;L zRxck`3=g8V1RaQFwCh|fCzt`FXIQUP>4yfXeLL|722shhN>$^aVf8Q9=bcQP zYMVXIF6SMGJPT#2?fr#Ef;ZS+vIbMo{NOr-=kmX)?=X>3mWEVH@ zZ1UTi&yQR0ws?=%v5WCHOUlc{<%7MAvi7F_j)AH!vS63rEa!~3obumtv^4XyjE-6V z`{(#^$Af>l7+#Ps>Z_^KcgvK+q^e$XF)GV9Hh1opGt&>8AA2HtwomR<*UT9X52hcF zU2-CF))u#qce(h6Kgup{tgLM4YVDK{N>#%Oom@w08azSY8bJWJ+Gy&>Y4q4)1lOU9 zDOOjrrXLHRa_06po3wY%KE`mc*MClfn*XkCmW3}5i#FCS1Fzgzr<^xVrB1d_pKF^s z@7T4NTIIdU_NJb`VM(7s-Y58hqnDJvHh=Vn*Q!sVl;}xyzhRr*rOB&LE&nBQ_VMW1 zwht$s%lPLn8E>4+f7_+}b^GGK+2p@rU-Xt;j^*W@WOIMkv8Xj3w?ahS)q?~+9s@m{ zv~)_W3j;SWI#n*ZeF6OMXKEEb7fpv$i(aimAzAwq>L&jb`R>uEX=hWW+N99%?41ec z?vFi}{+3-XWUNijc$+MQW6tHiZJYm=ZNXc%MgO!dddI$Gl6%d&_66hY^2fug;q2oX z4ms10MZUNB#1GboF2<%b4JzQ&(b6{n>o;;sKS{yr^d!V7;p`v%$bMh?7S_g45`Seg zbDz1YH=p@^x%$nk%r`Q}#2MVweE7m0R#?fAs^Y>zjARPJAuOE(#`G061uAf5pB1lEBTi$9iEIAzmEpMDt z;s4lCcjdR-%KrP8G&mlQwa*!qjCT>eZJ+y3$D+5~D*owGHpWRb!}h_VQ;`ly#RYA$ zu0eTMXS+d-c7ot-PE}E3M<=QyXwwj5r39lRwa?>(9_vzp4r&Pr%4)UtN=_^r7E4JN zY=&J!Qdq%N!kB8joG=uqhTsy@G(=XNxiRa+&55?i{3w`iitWP%M=r0mySl?RkTLb} zAaopz7#c!O@QlF?L!fCw0#Yk>d&S;(Ebda%lYbr&}mqNcjiCA)RbKGaw!HVk@_x~s8#;i ze&-24o_=kW?cCFe3*EBE+hx7>^W%RwmA&Rv`M>PS-t?$_%b~#X@=nB@GpBBSt;h7jK09v|WbIFv&2PT^H zCz|pejJG`;Yni4=nf}_!?>s&C&2^hHOAnWws;X=0Z0_u7YQYjvZ8Wm!C~v{c;nMvt zi#M2fm!QzcHiq6_mbALMx;m8S(jZS;TU&d3J5f42JBiFEJUu-qp}k~1n9eCWs@nJGEKRoDxY z2g$aTYH4X{Ap%tZ|M>(a3}C*Ri|QFbC)vrL2zUHR5-9`Kx0=XT<&pgbh`f45G(rxk zZncMQus$5Qi8HmvC6v2Imjo<1jIDBjA!mGS-h}v^@wen+^DvzXTwG2fp3$X2@ud$f zwmllT`7cYh>?*B1TYsstva++4gTMO3iZhQ`D;E=e5~-y^EpP!Hwj1m2F8X{`m%X^n z{+6}&zoOPXHvi+F6(3*L&`@M`t||`q`gjH=sT3EjW6*s;2c~or2V2Vf11b2EO)#?e^s<$A1;Q>48_@ z`?Yz~N67~&&bJ>r-+JmoTT?r`li)8VaPal=#Y+thm)aOn}qW6JaoG0y~Mn!PiwxbSr`0b!sM6Z zzdtknsnF$beYPjB^w_cEryFXkuXMEac2Hg+S79t_9gRh)5g0A3`>wXP@e|2nLR`!8 z^!nV#!`4pI>|m9A;?jfO(ZzuYhsG^E>}N#&myD0M+*11qj>(#^q|h(6DCG5{9IZwQ zA>liIzHHwg3@di#AE|0+s;jN)A<9 zTlmiOzbAa(yd9N)T-09X4aP4i^N%YHTEhPHTPQD`YeIA`I}X09`CPZzmUFD8sk5W< z+{vpwY+mmbM;Kf;;S(ZNZg>d)*d|?IboRvfJa!IF!02L0+CwqB{AaBk z|3ciW2_NpW79FfSfAGvX?qI`KzoV=3GPdh-Y$toS@GCQ4q8R^Pj}+!=Qv$*yG)quG z_+Pwuv8k!4v9a-j@-z?f5Qm2!i7!!uZ-Etw-9Vd!FjeN?DK4m#%alnLk2+Kk!-ao* zfG|1g;7!?wLk0;FQ^F-|ppLz{MsF7sbu>Xzu45=#{@h|Fr|VRp;-&0mg<8-UY~OM%B9|x z3!DzhS(dAcYJL>GC1lPT)%|LV0KgU@JEp(apyY$R z%I`<6`?ewJTk)CSkJR@dr3-K2_W#eb3DF=6S^!9Xs@7105>{FNK zy_-1pSFhgpg89*xV}CPi$+~T}qT(|rj-IQjsqX4#0iWG7;@}Xry&P(>Kl0MskC}H( zjmsP#YaJ%>L}SKsLRjX5Ge6V6pICP2XifduOP!4j8lb+bv;A@h7RC1CRjmmd^L&5$ z%6-opr~fsK_4rTrX4?)NJ6n0~%<+TWj7;e0t!&>BHNv;ZT(N+P6SEe|S(H7jS%}JF zqT{69{xjpJ-!|=>WJsR8yexRxVXv4n1b$F_d9b;F*%jd6R@zT?urXzFg4M^AJN}KM z9xEEcqvE>)Wqh!~BwU9|%?24$Vgn!twn3BDE^O5!A?Yr21em zBq16gzUkwL6cVqACXY#K}J5mDH8~Ufy9S~p_9Gouh6d!2~^@qlT2m4WIb5EGQNzgVs}GB1Acx2 z?!OeQVFhuB3HM|=ywzmYdHT4%7u?Um;f&u{o2vA1p(xTl!o7ft|=GjYZP^IS|?XgGgEPG791q-D| z-z>U6Cgln3`e)zWv9avj!Iqx$-F=OmA;(T_5cgDMmEQ_fzeoLWy?atj zHdEFCiz|GU_QSA&{c#hcbD7f^X5%3m69|(G`|e+yJ}x#FyZ3;l2ib(qk+2gNe)d0+ zD_`H9bKu;CX66_<-2IBMJEsAEwMc!v<5A*^ombB^b(hz6Y_J?(n_uf6)9 zH(`avs(Rq!QlBLUz2hqwq71*hL=JrYluvZQV+ol*G<>omqqL&Brn>%oLt~AwyuA8_ z38m;27|{t633|zJAEF{qPWITJUb^*h?dB;lxf9@5pbMuZ?RzYoZYYU4$Vs2GfijujoJXAaiQV*Bve|0>G(GrZ1!+-)vq=17^ka?uI zMn3b%@WI|PzT;aWIBy_>&n1w3DLxLL1ver!i9@hNs~g|Y27cAo*Ygvo1TvC>n#hg$ z5(iY0TCHQLB~NaA%K{FO;Eh?RAyAI?Du)D)l;2nvH|7g(WgrEV@ns6KD*1_Isba90 z>b@y?Ns;jV039Kvr+-+!>jw)zd^7!2$tC-_PGMsvW(g3gt#x+HpRV;> z>gcX)znXKlRkLQ#pSAC9D>##ud-!nK$+P7L+p5orO*DNS4Cr75Yu)Tit!TAB^wL`o z>ysv$(?en`w}jLouO@%<<&Ci`_LUqycDnA&h2ADqs*7UI8tc0bdq-P+Rc&31{oM^I zPt7wXDGE`=iK9o39jrWa*xuXByhL|9tD5~=lK=)Ryg_QEny|NLi9wuQ$Db?&unG4) zTf=|H?j9ey4Ff_ybAhL+&_BM+FWMGlwoFg31sgKCf-@kdgjLRQrhZ3*38a}RElLd} z0@21sgVf2>W73#t9UZYh_^rbpG1jr>466RI1uI{DbNf!~@#^O8md?J;URsH0%wH)| zlX!cFDD0&UF`o-78m`!FXIgA^S6+I3>*KGzF?H5QkHw}if$Xl&^GrD8_xj0z=u)*) z^miFE#s8wq;8!?M8fY%}jV_TZ}{qgFWHsyA3wxV4x zBlAw2kV3!cpGJl@2veQXr6o&vi-!mheEOD~d|ZD8vZ7mc5$yzvCn2GkAokmk5goU{d8g zQW_D>GxY4YBRWgJ#0#0MOoTT-fd#fRc(JJIN^Wl8+<(j(Iuy`GkiMBJ-6bl6u5X zhzutX@>E6*AVyW^DLIH4%vHp?H8J^)?Bmye}+|$ z#%~RdP4x=jc5CBv6sY zMMR@hPcT_0m~+O)SV_%uae;Td4gWMl=JyP#Kb-y9)`HIMndfW=&bKnn+uerTp~+&H zgjnglghtGstadxrs@E=aToUIqyl*|NO*=b&-sN@UZ!f3 ze!e{A&75iupt#V6@yC_!*7mk8`;k`rk3&D48v6PDODs?e0mF1tOsNmeUGd!Vtv>Zm_DwM6a^o{=@%{!T3A688o-@&uG%@`1A0_ND z??01Q$4MRb_KO&ywcA_H+j|i`6bD^c{?1i@DRdq+soIA~GL~S)gNM?P+Sz8>&#n|$ykg&{V&{}xo_*0R? z45E<3!s`0`HTyBU{o7%md^0-rK3ats(FwE_F18>rhE`$qi?ezywt1tSnK_EBV2a*0 z(MY(>H(oRkJp4%@KM{dw1X2WSmMD&QywyFy>Y0!i5SKMEIvESD@6TVmKBuAl?3MG4 zR~gcOZ zaEq((T5>cnjyW6~L&TuCqTu*q9R6UFg-#(IeFp@DOTIA&ykpCK6AFA{v!*Pw1x9TD z{*ts8*A#@U&bC$dR9(D=FzC3%OcBt0mF<)?67f(I%1B%GWx5ZQOEqC6-pl?qPA9m^ z?gPx2?5%VPyM05A{kzL8K@mxhyjdD(%=OggF!kY~%ZB+vO^(hR7o9^N!2{2EkB`op zV9sJDhxsum$3D>CB=8#So?^^=)VMp~nV4_BV0_|Fue|x$wlrJOvD4>j>+9M(JFp^? z@>UVcDmvfs>X2Nx&9`hJ5*=vgXjlm0n?C&@aUJrc+#cesCL-fV;NY!>5AXm7pb~4K zkf9bvVV$t}l8+ibv`0-rZTuuYAUnrDRqz6FfG3$aIr2Gg`6p?jgbqQ!V}g!;iPS13 zH>G?)>Bx&Q1278fB--L}Ow-XX>%}nyzx+`BR#t(GBmHWEYPABjFkh0VQcI1%IGuc=5_jM)jXP!M!+11(2nIuC0J=Si2G9mGSuniM6yCGGg*l^xcOv(4neCzq; z8=p75zukK5NL}}t7W;u_`|JCve;SiMB|ObzQI?+x!=VEK(bhmi+PJt3m#E#rOLHeK z&Yl>x<9`d}|)C-PG!EU^}!QR)5T^x(()jfSRz4q#cjtlh{FJ7o^ZK|a! zbYAX2(n(5trVT;PG z-Lyy{JC&o}`g%}En>xChE;ctb)?RFGY;6&%OGqub-;JuE_aZ(V-~6cv6jDL`Zv!Bz z?Dmh#+8$c8{sBYASWOm6v7CFMB?!j=FAj{hxh)ZGfPvpMy=}Sn;ZFkj zi3mia!HCsupdp5Dt?o-uRC9b6XN`+Vf6$Qf@SODvR~Ba+xpK1hN;_jZ&YZ@CK+J;o zKT_IU|LczYPkCVjPH3{2c8JknS0DT6Yc6(Y9;p7=thkUr>mP{P%ES?K^-hNTv9Y$` zm>h;!{xKA=Knz+i-!cKySrf(VF}oLY7~jGo@7M!gaizYox!&fK;Kdf#(4CV_ng6}a z@-yT1*LNSUsP1d0J%iL7?|GHo1kCg+8_1!B60;LZS%6R{J(N?o`K#kfZwu!O(Z~7Y z$YuNgt~lTxnd+k#E7WYF_ts@%P7o9;`tpsA?mQ0t+9*_PWe{EfOas>F*OSb-(=@yM zpIyo+c5fu+tlYda*OGJQX@5s5;7%n1VLWPTAe2P`P7BVzaQw3_# z@KbQ$5}0Pp05^u_n3|(nHBdOAY(A3mLHNVNKLJ&D6jJE z&Uz5SQUYIUzlN%HuGjweH+SD3wk|}!Gax3L2{C^RcTL5?#=;;|et?iRI06fK2Sn!w znytzdnI+hqi<5o=`AJ5jQ!{}^IN$olTD(xH;;e|Q5R+wcRN8k9Y2TZ-{x=I&q#kTM zSaqScsUEvAF6$Byz_h3*9I)7=}#JTt>=0_N6}zKT{q^J=T=s zACuu_ObLq4oE(!mEpq1%jXUCZ9m9D0!X+$sxqS#DH*P6H%wBE9EEY-HgXrbpnGRv! zd!+-*Gi2P2NX@a~AT`s-Vn{G-`l%G}g}VnJbr*TSVHK&BJ#Ea;_i~DJFH)i#sYPd( zJ%|>fI_gC>7&SymrK=aU+-^VKYyaDO$qz?v!C>BBo5k>n%RXp7qP0X9Dow)b6Ki#2 zi#JAAChKIKa3RKgnwdwuaCrDrh7*Bk9`RNtOoBz*v--qYJmYb>K5@CQ_koz~2N!Mo zap;B()}}+}`&v7%^|Xtv0m??h{$4^626VlDy8AGA0v8pezMd9WJ)^P0((-f71@%`$ z{;)9k#kcM=rGSH6yaN0MM(6sQExu-}w>cl@XR@Nqf_>vnnK(Rj5LkrioforJae2Px z)N#xnMD7D38IVkU?c-;b?%GyVbH3Hy*51>@kPnEFC__zLA2?7u&>$y0gkKnkVj$Gf z)^Ulzx?cOy7Q10vMeu^no|<%a8 zDMR8ZbJjiZ^3rGH)}|e-Ovt5fWLCpfnSWD{8cp@wn1cEf9t6IeR3|mi0UhnO`F3ZK8kmM2Sw@QBNb_*~ zLm)K;ROJjU1F(~@sOCbZWHB_~B-7v?kBl#=a!iD98G*>MAdZyF^ksYo365+B_Xk62 znU_o%q;_ocUr{S(W{i%+Ed#*ij+56Oo4dO@_nXw?xu zz^Ok;kN6c+D+T3!W34z65n>@S<-1F*4=woYdvo4jyfHiXaOJ7W^T-{=j#n`|;nb_{ ztDGAQOuv&`_n2;TKzQPmH?gP93wgcFJt~c*;Xq9)rfz-)i>J|wvL6_iA7n_I8n*dc z3qO8&dE#do$B#DKE1K-N7wtcd*)cV8>v&`GEg?1F_*lf}?7;d{%=(QL&AX4a#U~a$ zy(IDeSs&i7W6xJXaQp$UmZL z`lw;&w3r;`ewpR)5i`0>cL*i3dmI7(4{&}6|f9ijQ zMPKM*A}xhQ7n)i*SU|rnmyiOdu4kAsljLuqi|j(o4=WbdjZxV z=6KZn}jK*bgm}%&wc6+R5gawJ)ppEst@G6tSH(~jc5lo=La_Q)+3pxq4aDOZKETg7jRG=8f*8q9 zYGE*>mPC>u9^$B&NTTLZb7>nk3mEhOlrPn{H>FWFnvv6nNSc;w%Zf-oqQzh^KqJeUglh{We2{Y%NwE3L;sq#ywpE3ImDD3 zV950`S$tv(ebKMYc@y>fAJK06*6a`d62Ez!rEXBbu}rY+p~i}>Ateq-;l?CP+M1wYfTePsTMXqnk&8d$rToaj}~rfY;SWB`T`YQiZ) z2nU!Glf6omfp127m^oE;+ZU|d_t?T!_v?2B>Qb;9^o%L;h$+S*QOtFiF( z&i6!auuOVB;Za@Um={-K^hlFq#0%N(=0Z1P5oeb%fKeEd!{`n-)+G8D5#SZJm%hxL zoAZ2)xy<=9D>8P`_6H+3e=l@JLSla5xr^tUJH*+!R2)a*iRzP8Bdbk$i;#X3YpRt& z)Q<9+Uu!=6!}6quHJh1lX9t#-CeuAaET-e&q!qO0Ah(D4 zrz4s;`c>?Z9u+JGOBPCaR7k=jLmahE*`B{B#vr~sg4FO0%mS(;<&Z5)HyHhcg%5_* zDv=aIYSW}3fsePEon(j%xoH+q$Rl~Ba!>tShRZnMDbGz4A&{6Dz|$D;FgTGy0}r1N zBEOOxkhu&%YMRp^wQ+}n=~kQ}b6K2r^2CC-r)akM>(YF*wm?%!prJ6(i1}`&Z!{L* z+1}u_vC!X8=x@wpD9)StUSE@#&GR-FdYKD(D=r_skBKrF&Cis}hd4fAWIom)-oA|C zSwCH3bu;Y`Ht&4c`1wOKVs}+sIC`d~@jQE=x-PfWa%w0dkxK+V$v*R)xgQ12TpJXf zJ;r1k8CNvU^=c9&Thr{JrA+tXI*1Y#tThHw(Ji&q{ z#~uh}76lLmx?lA7>(t6s!~!=JU=(?Fw&)M?ahasVB``X;{5W zu2X-3)Cg3$POZ#-_vfgre2T2UctpJG4kA^*^awgxq%Nty`iqEO$Q7PV{J>=1rg7xA})#Jnrup!^yP~>YYVZ;8ISmE&SCvA+Mh(I*=*j$g8TrZ(! zQe}KX3lyIK8LoP!ZEaJGNslc2=#4$a`G?M3Y3b;#IgfmCRO^N*+`cI8m-+guO9G>) zAGBK3Tge$a6V26K_N2p&e=vP=?~h)&KXm=L@ErmAbOv?IEx4PCT}>tK6f?GzzC$CV zHHrpl5(T6y(Tp)RLye`d{bLgBGYuINwMi3az5mqfiCfF6PhaY5$993U+F^Mk2>TKK`vEZc!2MJ0t*Rp&5rxYT`_GXjNegYtYCBmYIeOOdN) z#-CIfEd=qa3SQ|44u+Wh=2sp^IWIq#K!4*~jVV7=fm;n9;E{=wCd5d3BqD%xj{4e7 z2Oetaq(=oo(KwZ72!w(RnGpmyT9kpF{0Z5TClU>1%mI`S{pVmvtwI~r%8cNlB*u{m zgg_W%44sRN=E!R4=dFH7vg)G-svlB7N(v3~6DAXADonWyhSV~e%*By!1M1?A{Yme> zEbL|zk2X)9|Grz;PXDC`$7oCajE4er#esSdFwHAE)iXN7)12$8FD4KLmcz>Y07ql4 zkI}|do~Nk*Wr6)Tc=!{&kEviHh-k(fKE&Y()aL~2#G6wr++uRwUoRNFIL$q7*TmRu zkA{A*Y-j1gv%PiITr=Hc@8Tq9w)NRhT)46#`AF~|4flm^^w;bgt<7*>R^j#b3Fm~e zd$c*A0OmSD`Yga25$9&gcQWTYM;CaBgUU0fa7y{2E#EWl`C(l0{EW6Ae^?e|NcJ(L zKnau&(;+iM!uJ0By|Q1tSN!w$tkWYlOw(?e9KCx&LM8@s?u$#@6ApSUIqVZx;cF-e z)MSs<=5fC>40O|#1SK3E#|EXy;|Mp#qJmWqMadmRUPg6epsop z@m7>^uFXn1bm{wxKK!O}`*_nnY@%GE^PFP~#>5o3MbknA!8Ds7orM;~#E581l)}Ki zwn8ssG3Vioi7v$p-6)Ns}g5{d(isnd)*zZtb|S?bZUrfc==6r>i}+M^&f)u7ZDi`U8ycShcQ_{BLe zwSD%oZu|2e=X^VUA64U_*(=7(F}87wF+?vEio8MaR*bp_YgGDvr1mftdFu;;by?%* zZJ791^M5@vcY8|4p^CzzWqB7HD%;rJa9JD=D2P#>+hy=q`<;Yon2x?$a!Vn=} ziquj*^OY*|6UDj#6aSDgigmOAdjE!>^h*@m$ZE0-lL`z?kG2vC}&?=NnNepuoNQ zJl~}U#zbWW=raLp(nO(ljwyDED*>$C7$j)ZIbkeh(T?#86CYoi_weflV;G0TX8Ya> zQd5M9`m6`cIg_IHKCvu!qG8uK!!FOL9iHY?m*|`k(bkdCg(!orhC+`hbVlpcgoCcy zQg`EFPkotZRL)p!+7#XH$@4xA{)_QP^A@L_zLpHKtZ1YumpXEewYf!G{t>C6 zKbH_nA%=NIMt8+H^fkp5gVY4_6A_3;<8h4ztg~orfqF}@rZ7lT>Z3p4W;!r3res8P zo{N6h_^9=Nej_paM9b;pb?xUHx#|lYM1^LF8tR`zi@4$Z>WI_|K2lWzsl`1STu;eT z0^122JFLg+e>p?@_}@(vUU_fq!p*_D6sEXAXPOFN?GaNBYSUQ+N-AJYvxGBrld)Qw zO`fmb%Ca@4@xbwE4ZZ;6V+wymdA|P1eN7J(FI2f8y`wzVrEx)UJDYu{6;q3LH^&E z_$`G1b2JZTwSZ9x5TLUJP$}f40Kf6AigfvtD)1HLyvYl7j7Jsq#FtY2#*}4ndm@DE1+VBtd`HKmXf?0hTB%UflX8X`GA zSo(mnq?3%qWTkS)K}hd@5zTl^%hmRf!&Dda7y zjCAfSQmfS`H4eBWLa;))Vn5kp|B-&}Sbd`V^75}oA99L5?W#NKt1Su8Aw5v2_q#=> zdzkWkbS3@->McH+3`|g%I-|?GM5beq?4`Fbo5%XByEcnaItyXgtN7{I!IbM}7V^PY zkNn9AM(fmNdm8hcV)OoUiRBwhbMMk@8~0YG|J;=izxK{1>qYCKOHG%$db-+m!BU%Jeqo5P6tRkgdxO7Kx;beK!UKT8gJR-8DLURCLbB z7~AOBVw5`%BjwEpN&@vo!1NexMR4rFF|Tdqw$LfBz7z1fc|UkXyEXq%YU!c!6Q^ow z8@kxq%2H#ma^u1fIyGp{YS9&8QFhfzvb*V_>APoNj#Fn1&KuBx^3_XBQ)mB1xyRo34CXZZb^szXWCC63Hx-aaj#p% zURQITQ%pY2Ioe9qdzx}+64XV2E|1$Q*lX{u&k^t)Q#dj-b!%r_nOgEbfA6V*+&qqVyZ zHlTibJiC0lc2{uJelcEMa$s~6BakwV9KpJbI-+PkhHRX-k+&#jfYwTLqEWe+i=3i` zbHVi8oHaIb$HP&d&-v8C{`wLj4K>%vU!-SH*G>p*GMOS6+&rf`dp)=)IvXgOC z4`cv3gOyjplPo5sBQliZk?_Q?Jd#>McoZo6VqKUIWy-|4=>ve0`;F|POA-zs$^!B& z9?~Z@H623aLm)9FhQdH1;Fn{7FJ;Jp2ois(Us<};DIVs2qz1k@ zuMDFpkeX>U;FygbC<_9+Bhy%e=1;EN!j6=m7>xsq$ZAktB6W~9o2w5cQh#Hy^=pfB zz8;(I9-lH!v+bb;pUhiTlyR*0C>ApuFs6V74HNUH+BW;84%r=+< zzNknICDaAZM{jl0WYQ%3;tO50=@XZfdM-?!Xy%}g3}ux+3#$fxbvNd+af!-uWdhvX z4`E|9`2m_D<|{zzd!kG3jm>v5W%%in?hjk@^1FL84z?7OSJ%|{pA$$ArG+!h#xood zH=suk{ih>X|07a^lHFXiijn`Bx|Xu@-OKhLzW`aGePe=YP*5!W}KA-UE+P%3&Wu?_8%ljHn**oj(+*H%o&18aXIYYDV|F2&G z3z`9lDFyybWv>*xDpIH*#V34-kS7Hi)o_ZS0;P;BgspN37fGpjB-1BTDf5RWNz(A8 zxvTlAo}rOiq8cD z=gX`e!*5L{=fr~>SH5O&))Do$O zOSw`;*nS&2_05r5P$+sa#6mu2(J-($(_t^WYX7l$+d~nXL&6ii!*>TK6fwEsWU#uJ zY@CWIxNXSxGGr-l!Fkr8-8DI4iYCtD7L^>JO?IF0dC=U%;5mr_^AgAEQ~k`@F8Xwk znwI9N%Y)(68qLX1o9nN!Fc$LA7mhI&k1!XxB$PTceA4cluGz}vq-$)A>(h^(JTJN! zeMfdo2$r5Z_eO&jBN^m1jKYaWR-e$RL2BTVc{dih`s&*4w%Wc|-{0l-i@D#{aX$7o z|ELrUw45SyTp8dQY%FJZ7$tvTk>C=|m3d~`t%t!z17;jJ##D$K&6GH&dTNr#&0hEP zyJ;H_wkIEMKG}4ouC0g52GB2<4!PRH?XhCEhD*)3iB+?uV*1>*L5sGHi?Mh_7mhL& zIkC`S5HnymI#}%(=xwm#7+*~^UsfL5&C$ z0mP&%d_wwUchd)I0UaKGmDJ)V3rT>QG=GvN1jrDTJV^tY%ISAFKz5F)-N=DqhCmp^ zlPNipJ`Wz5FM;xLB;!UuaU^+P1yWOMYC$0N!e#p>2RkOsS$&^rzn?bQ&5-BHmKk%I zlOC9}flc0M&BA4iUaZTp9LF(llkc4M{_{Tfp1py!R06%D(uv>- z?(2}%LM$kFmn{(-A?#wZj568oFI-t#g*Epf- z8j$LOW`2SU^2JGd9EH-C_?1~f<#ST7fIc`psJFlnhcS9;v%R$JNX1#bG`Umai#P^+ z+)M9IeoFg)3*%RA+)-X$e)dR3TU}*WW8LMp7EZ|)7>%?Cu33Me{R;ObNIm_frD&{7 z>3<2e|0skNq~3X}v)})S)XD;=0@GZ)DD@^_8cmgD(4^ApH7Bl2n7?MaK51;kZeMLC zyV}tf#RM2l z5mhXx4gL;zL`{hS7XO3P>b!^;a>)sBcHV*1*mU)B;HSN{TO2uJsp|NH_QSD%(ge?3 z863HbUchZNltMUVFaubN!LTwOCXhx;sbxju0n>#cL`H#AwB-hCkIB@e4`4yHDm$U%d@X=xQH;OW@S+<2`LTd%a9t2vS}|a0Sd){;a2Epox*L- z9YShR6aDbi&}~O$<<{?+uWxvARqh1s))3=f&+xq*-{Bkq#|mAdtgv0F_be|Rm7eKh z%p7CPp;7VEn8;k}hz$iyT>H;m{mn(|f1ywON#v$+e|vLM)TThwo{uRaF(8j^+))w0TD< zF+>+0)=#2AQh8snLV`8H%2-RD&e|*HgMe$6IC||ZoxROh>;<(w-+uDWw<+W=V(=~MV0n=%<_TMhs$wBvl;d|JA`(U1ZtERQvTAZ<;kT@Yih^hQ-W(RU`y5 zN*w4wt5DTgN0IC3M?@o^iHRHr8e}WFDWx!+=cYf&Kz^l*o2#51G%~#D-rsJ6Pt@>q+s9(vE12m|)D?AWLEs4Q%(}zz8=c_x8 z)au}nij#B}*Y)_mwvvOm{UcHXLibJ3WxCAW?rq8(W6E?gW-_(tq0RM)viL??e4=vk zkI`G4jVzg2IN8H1Vjst7PYm7Y`Rvl~n6~`(-E99C-wIiUt1lP9X{8ylM2 zI>o#msx<<)ySw8O;C7_4y0o_K^WwVu{u<}^$K{je?g|XEdPNp{0S%g5vT)O9C@zyr z2bh%h&{%OOaYB#N=ep{%kw3TMvY}ZaJDUNFLN*x*ZUkU<9-fX1jLH;8ujs9=+C2Br z-5!67pY&|x4`%A#*`CTR&u31ZZLMvvV{U_GH_9}nL6uf^_i)XEIQo+IE8L(uHG5|z zQU`|b65{<<==aoS-Ud=51^NY$_)pQP#jrvsk^mFhbYq`5_Nw4q+Ye{O2G9OrLhOET z4Yp({%vayLAj4Z<;u)1sjld-zO{S+-)QGb&W28BIl+og%DWK|UTCT=@zM9QGGv5BC zY0HeaQgM_25;t+tnjq7Tk&!zw8W(UMMa_z&s9ZNaSfA!BoM=TZnryd-9M7;^j=J?& zu%Fv5M!vFs%G{6M-I9Fj)G4|T9T4j2-~&X8+Cy*4qi{o1R{x-djs#Eo3LFp*o3xa}eB@vMK5s^As-B4KrET!sRQ3`G z7)js&P=FO#3W-5?yhNn04j~4kM~)f54kCcm{7G3<0e&M%Dv+rj+W&BndH?|uq$G?= zc7aDwD_NnwRRYwI0Unisc=$=y1;Y=ChU%N#m1+?$_%F*VX&_(vvSYGprnl!IDLBtt zelAI(x~Y0e!vF#Xa7O*}t3zs4WJ$>8y{-6+^XyNV@%9SOn5xU29KJUsVwZn(imN$g zq%nQ8fvp@CpKzOBxWy+T54&zBeU7ua* z(q}=7ES?c1o{=_oMRA6whc?win=Ia%3=cx0@+bn?;aqe%I4OdL{mx>|)Y*{gtj|!s z%~Oh#=O3OE6rLFrmWmr2m5#|7Ly-}o>7!?DaQnmj|DL7&{k*7^iM#VlDvlpLb>`^V z<{Bow6-|rd%oQQ8$Z>Hpvn<`vNL|)wpZY=qNR1#JHszwEFyRg&H42oR^aiH62y;() z&39gn^?da`-{^f~n8!Bdpin!9=6PZC6;VKg@r%gviOk@XX?Qr=n0~i8>mC#Ps!BW! zB_Q>vsO?^%>pY%~{p*sQ(VrG9*Gv@KL-wifw8LdfjkFh#OSiLpnKH(%~p(<%V zqm8K}P03EiWD=xBaS4cTSYAM+4J$0B$6d5(!3)-fzP0Aip+odII{58%jwj$W!ci9*fkXUYw#;^-Sud@=LS(Sl+s-M9ti=e z$Q|H8Vh_-!#V}QQ{`qpL06|hD3vD3p00JEU9DrQ12*Ao2TVKWEaf2J)K&CHNh1{eh3BqS&T< zLuYjf%bFHj>Y*xDGrP&8x@s#SNQIbn4N!${a{~V`SI$ev$b49&uCB(-`$51*0r`S7Om}P>)Os; zvTw^d{mAd;P5n#4#6|m%V+u@Xk&C-F0}%&0h_&*_4DZM+ej+<&?74&&=d2TujVv1G z+sVKHBSS&zEKH$1Bl83Xh35rCB9XNOtWv7>0MU{i2*gOqPUsu7X8m?%(enuHhU9tV<{$V1>;fdID%{6D2?Ilh2 zDK94Yg(snfLG~~ymq^Vd$v9<~Rza!QrPZVC(h|ay1|g>_m6K1di&ua~{KTKoz?)dg zWW8ueR0KsqEF+)UIQCB3u}Lo{jMZ%$qus;4xv@)2@0p*9xtB*|fm@j1l22q7{1=b} z$Qpp@oDs~#GV`Ff(vV!jcZP(0HsLw5?&G~%(hqJ(Iq=PABF4Y`<~ZFBXUxoEi$;gD zEK=YdVe^c%z|KGcm-~fn`kn5>w34Hh z^%pNRHi&KDte;X)WppHa!S${|;V6_S*R4EX=+vS^DO~!3Q6wZ5Hu@75%N%6c*LJnL zk=v{eRW*N_aeUJ6BZL0>y3=3Y^^e-kkkXkki~;84IO#S zUj)sVadOGMq4{GB70$X+_F~^Xdk1$(a~XQrdppw$j&pfOWrw}=!j+BX7gkiXOr5tP zaM30oZ3;_EELZu*RyZxp7(H`0$FwrSQGhtlg|VyFLZ;HW>a1eQNS8||QbxIH?B)m# z+v)y$-JfIDZ7(>MVJ&E?K2d)p-`-JU@3};OWT45I4aW#Uv=gCI|2rZz5QEG|Aw{$z zR3%ajKnL|tViHG%B#A`4330>=De8wnC^i0o)+G}WE#>-&rXaPH`6>+qJp3vj8IGT^ z#DHYgKS@^lRS!81ty7aMX-aI8eyLr`Ktcd7ejSb?uacp9R8A6tpQ(G2RYyv|oO~Q< zATJ)mB~pW-YHE%i%B3KhW7wDbRkje76nNw}co-6>v_SxVXn?T69wP7)ac%>trSw2N zC}tk$YmE0%=7gCpQbjyHNZF3|-cJ5YyI{XR^kdF`9Idy|Z3PTP^~+VHBI+~JgK)sw zK_?XkX8$oK$t9)&3E;D6*Myhe_~Qcew*4u4vn{$0HwFJ~iRavHK}(Og8q1s(C1a67 zvQnQ#_~3+A4pz!!Nm+6HNgzLYYj=-(?e!%o6_(ST>Cr2a!*)>XKaOk{DIL6(vWXLABjlyiA+Z{ zApq|(mw(+c2uWShNu%dmgrhS!ZQrP zvbrCs#ay%EFyE?ZwNIY0+$$^zYjeRyU`|oQzVr=5j+(n|>?#M3Rw{~zO zoiN}QPC3j(3tKNThe3OQqRDXzLy_TYQY+2Q@Cgr^Owb|h!y6`CP9Ehv>#DlqVYIM^|ODt(w`l_$_U=s{kyM*+3*9M3e}3y=!pED>%crN#Zqy9RBkKzV~xc;ZXngY7l=bHOod+u2Cx=*rVK1}uh*61bezcX)D=sIgon?1ALzNOawc=#s&mp^{M zm==Jo2*V_0PKo7y4SixpaGDQ>n1WY3AjULe2c%S(4eLd0y376;H8oZF)DdC z^{7NrSVuHe%dUFJ@k^2V#w=8<~f z>LOdlx#JZ{Sq0Poo-q3Pb$89&^Ph`yJtNZmwCTv1VJ1#AX05#!toh>yDSM9fWER!b zRf|IkyRWeMgfp_QUFy9oBmp-OH#05XSJQNURm%SHf1U62SMvlzqU)mVK}*WNHaG3- zv(v>Evj`!|1X4$(LNdJMc;E|ICVAu`@F}zqF*J%(j zO@Jcy+c*%i%|2CytixFFO9j+)q4T+3gxx zIwHb0GJJvdTjA640Zv+{7@ zoNePZsV=jV_!UhYbY@Zuq`vONI)WVhpudCEBlM;B=*xNEH8<14T;jA~Kka$4Zg0@s zPrmVM!-Frzy}KbPKR>^^x*G9?M4~;T_l2)DR`$^K-d;cxtz4Q!*pY`*-nf0 zVu8kt*4#-ga^8k*eu0 z=|=u~{yl$=A2aK7jzaE;atx3H4zF`8V? zEOm{_aEVNHiA))zNgJaTsf~!pbd5@5R$=s0Z+QMX@|O$WjbFPrul&r(Gu7B0GcaR# zCSiJr7Cs!LZoS-()b3$BL2AtM$$glPqeVviBU1OZab(btNDYVC8>b-I7drKotCzVC zfy09v(gWJQcGAf$W zMJCPq_@j(tg-6e}U#z!ZZRf~4@R$?Ful{> zUMsF=NjcQ~t$9oD`tAI&(c1#w$h~Xsj&Cf=atbf=GoN&dDju!1vPPirGgCG;8to{Z zb(A(A=cLKU){eIA9iAN+w*NlOF7FrK`>%xb8T&7}zPyHk%H&wf=()Q*BD3Atd?DGc zv5rw3e=63S>5MkXVzf4YgtizrN?SN8GA|^d)P4TWfccxbP{#k+gh_voU$izg*;bB) zo>Vra)cuzU&s(Y&wU;@1=zuB;50I_{!ub>7%mbjP1(ecTP4JfJ8GdB4;{gzPAVZ~d zXb+@H0Oeap3RS=AA;N7SH5dc|4~I_T+%cra#zX9z5UK=n0-@B?+uqXK#XZo=G7bmLd^g0f-%TSV?JymZmZ@)! z4t5UR|MkDE;xL5g64qxGl^s7++E{z8rllihOMc+r-ni>`Z@J9hD=tn#hq@J{23h=c zyT$p&YiyD4?6#Ix)-|*;>DqaP1yZha?iMAXK%G~5+dG-VKi}Pcysi5a>!BxJ(oT9l z`tIKvJm+k@_qD{aiw_{s5JXNwK!F#+w%j8sg`1-(!Y~UHO4^&xR#u%l zT-Ulfzs38>cl{S6qxy~3r`@C3uatMV?NcB%$JoBS;??)}WF94(k z-5%`&q(;5&;y5_jDQ;RdcO;OpF}x!qZX@S)t+l7Uv5QlE4%A)#w7l-V*-P*GU8M7z zwc^IQnBq~3Y@;JfM=7`|nl9VWl#!3pVzU8ju`x|!#evieL_H$%eA#-iaO>o#MBjNE zrpKf?zqWz<+1PN%WqzK4``V zZodr=_}%>3EB9qxaDb2ZIB`9bpka1w=}# zpF^0^cfU|q?>MQB2|_B^q+;2ZB88lxWe!|bT1gG!Rr*yArMNw$h8P&ax3bBeq zztQ;2-!f{^-g~vSZ|I6~_vmcSnk>)AeF5P+gi%&h+VJT?oA!%L_l-z%3s1*CTAw%4 zki$JD&XLS!V^t0x zsVBU&6r^@CSVn2HMr(%am;rD^>c*;SkeY$2z+dtfgC3m2>^Dd)Xc9E?QdCYNVEM-N z6Wnojxw-Y~*>3y)n$}MaT_2#`&swT$WY(Cd97jiu59UT`bM7_gj*8sN-kER zv$;iNInCb85r3}px7;&xy|*rvJ#k-~oydKxd^<{$J5u`(jzG7_G+5*onL(9tKn;!r zNeAmS=NH$Ef9>N3X1?)T-HNBQZ*I*$l6&aX>8ctKgb88VGb}=8;{R7l&ReY)l{Wg| z0N@*d3&>$9iV?QNl%s3M?C7~Xjv-&2A8MI;g$zaZ_fLJ}A3(GEC$k**fj@PwUecx( zU-eLg+dyhKqs|JdrB>5aLx$;rNM;OF_>*i`%i`!E4!=?tvb_x`)G)LAXQCmiDL7>C z4BdVpTUORTht${rVTuV-vs$ejBE;;UVkwk=zGX*M-^AJPjW;Gch3yAc_LX-V8Yof@RR(#|MiaHM7?O@bHl zNi3L4m_`HTDs8bP9B3XtQ5rQg(z)MT?!YgG82aWg;u z-i+mm=?BUyjx;vZw6!;4bk%azex}X-a>DkIXW#akyJfT~@9QS(2oPu3jgw5rgl9}N zqzC*pe%bDlyu+t!E;InsJsqvecvY5&LWp^9{=+f2{YoEU{w<(d{u9@fb@uhPa_h?Z zmcy;~8E+@~{Xy^c?AuN=)?@y`ab)*I72d5W;yohDIxogPX(DvK}aE)n?QZO*7j z>!`?lr^r0#(0wl9NnZNYk&BWz8D>OS^2o@HyTjAr8;*>hTV?4rB zgTnVt3EkxPRLm1E#jQv!U7eI}DL-`R1ZVp;Am>#U(W)Iqs2cw7<5Bw^17?J+Bk)N? z00?;SOAisGOeVhLh?;cd^RFoyc#0M|0I4C&5yc$+l5F5_z!WhwOM+F;?IAT+UGT*T*j{d>w;#PCK?f8_DA(PrF9BI4JFI(3?i`0l!fz(`uj9QJz z6>xWF4j#L7p_zT(!-Q#yAYk#!kh-O}AE{jyCW@u@s9WGC^xufoK(3-4 zkw0w2Iq1}i{h|1k3yz5g!<8jnfz(~tMhUyD&nnvdXMKQ`J~m^c7G%1FWwXT(Hzu5w z)@&TdVc|wbN++q!06yU1h^UOOvBg`n$NNv_7o*pvq!%AMaHzSduBE-{B1hZwT&-^E zTd}=(%9AGFSJsX(TmCb)^llC5+(MDrKFldz<6c|!{5!kTj@F;9Z$jW)?&RKc#;e$p z(FsJ6DWja;|7ww%3MK=F1>(B(tKHW)#-`_DXLI+}J}y74Y`&VXI`x77(~Ns|IoGZQ z8&mFjWz&dA%iWO$!bREcjmjMnnGN6A*WmL1*n1D~If6O zd6PVGoZ>i6;>ea&DUlLM^ov_i*wiV>qIwr4u{W`T=)DpE!3y>Uk{~+Kd&hpi*#oSu z2oeHm7Ws?!Ib5E*_hL_<|ID13Ink*`N(+q1pnLh5cT5R(cR22OTH}eNhwT}5XkJn2 z#G?0bWO^^i9i5mwtjBJ2QDr1Htac0Om_V)vRGVgz4-rkT|5}%n}yu0As znd1%hb<%-OaU*YaSyeN0ZAeY;jh5EUcV1N|PywcpsxXZ*GoyizC!jg(inHq5 zxlvbD?$!QSwT?Tbo85caN}3PV?79Y|Wr!6(WK~XHc17j6hWZ-Oj_Umt7tS9& zU!8dL;@!VlLilS=4uTYn|NT_Pb5WsdWXj!(Gyll8;UA(ti96bOpu8TB8^P%QHod3C zU_1m&IwUZs(A~bKHX@`n)m1mOH*e1?{OSpvHKs5p7#H8N$ zTysW-`|+ zIzKQf{W~!`{>J|4&J)e070sx6dOKQVGe}$^WR|LBa+8pne#28scBcnAhA^B*7vG36 z8`$02JaFhlOUQGp@B2mcT~E9|E$q{2ixXI1zA?LiVDDJcF10-2xPWOmMiQ(hYsvuh zy`HgR35L+^X-)ICXApxFM#a;SiNPm-cu5-Jop=rdK(7iz#d4VHNWH_p0H~%xaq%UJja@;4;n(e?mW)Z{}_0 z3(be)$?#Xa$3$w?=VNdn%65@PnWY;g57W}|lz7d*p`*Acj+p?rpctXCyGzZkYeQ;- zFo<8Qag?w@Y$Y6l93+WA9aq-#{m4&d1g)ALi)fjv*|NM@^)cC_6L6-qj(p`Eo#hpk z$sLL@$)0>?*y`^+ws1?)p=}8}4;8_W+KYAjD_b9YdHvK`?@zHN zpl4HW;Dxexwm=vI?xRcOiC1in`=S!}n0(aocSUXc*1Wf$-LZF1RY!eWPk&dt-UUqK zS4~-cY`fDUX{=K1W3|)XLTK=srkYK8g+H7hGwGql0YRVmIFekWay4v;@q&5wfWJ*d ziOV82ty48r_GZIXU6|>+B-Q)rRF8$}NGn*~_|97G`>)Uc-IH%^N;sIET6A<*VfE4d zEmh|_+MC+3d=oUgifas{rd^2KLw)^tX<<=z_pBG$r}m1?_Kv;GU|qH|dFUUV?mB3LLe6?cXESZkLSVqmj(I?AYCvqVw`0eo zpyhx1KUm>8rpPs`27r`$Zkc2SMs#KR5^++tpV!URN=+>ZdG2k>KS6 zh9h_@^uS;$d$x`?9-Teec>bdPFY{lS_8-;>k32Ue;NZ!$f^toSjj!OPfjKbv;Kk$jpbFt=3|Lt+S zy);W22V`?(_QddQcSUS)`&rCi1ic=!GA-#~`GFJX4j$N7U3N?+z}GM4*p)^>QCjt_ zl26AVvkIxXQR3(ipQXCFi|F+ni*a@ zHc~rtEEK0cUdNVFI+diVyxgp|YL|MbO5_RP2%vlt&UI0*MoipNJCpBKJ1;=w-dSWqrvV^FEpo`Z=bdz6<1dohufr9eBk-VUs;j9_i#pLa>bb=tt|~0%CH+Ki@L7^EoM!}zwlj`-~7FKvn|tvy=ah^3a! z**$_Cg49OPFCl^8HQz{^sY6T6U|(x_L-q2MtnWTzo$%`=cg1Y?vBclDv{Va9)#j%W z-$}&1%gNMc4OJ!iDEvuGnijOmWAV<(FXT*!O7xqvX7aD!`8WHfmGNao`DacP9;rQa zr2YJSt<{&kkknrg2FTfi0i#Jp60Ft1D4Jq%{ z9h(l$ocDo$)DE8|`M%M+{cOb`b)X~LfN8)2n9c)4R8oSQUrZ(p0}gJJVpAr^CfxmO zO5h_)pL}_BW`61E1BW~6YPva-X+X9@(GTlg9bL^`o6`>5d;h|TmMt8(CL1E-o20agyPMQD5a6j)PfVU0%dB4+sp;W?#%z60z*B>~DJfPwd^c&u7?^wWl__MI?JTay1Jv*@~w;w|heLFj7y9N}2%M z9FsSK)Wv>L1(Krk;FK5$l@#x!?&d>A$M@;|T4c6n%L!au>>d_J;NSbAwoiQM)q5X) zan4&i*B6!*o~${2zPh!sVX&jIul3^ZDN=(D$fuX3uIeEKRw11NL}zHY{93*7PeBT* zLCukusTHs_MiWfPqZRy#svQtx0<@VK4^q=7bchmlc_A;qUd^R+Q=q04v)ax>Vy=Gd-dNyrw z&~UeB5mCVzD4p}*lyg#FK_w8V1OGkZ!_<=e(j!F$+4YrYx;iCdJUA(fdZ25t6Gu3` zq^jpHgWi}v=OYdy;BNuPOJ45$(ab}Cw8)&m7fRjG0Y)W!V@cdM=Dqn|#_4@$*#u{| zvCR;uvEwC*gjgvL3<-iXbnCq!HIKTQ*aqw$=s4Hdn0WO3pFh6P^WPoXuU_{I+B)^= zebbko&?0gv!Ys}?W7bdrIx3Uo>B#VmO7U3~KlS;P0LSO|{cj$$!`u80x?{IwX9hK-Boe5HVgy#whL}eq#DUnSu zI=av+rohdf17fmY;Oj`o6rb3$Q=${6SU(R$*{xwiVMq4q}3Wn+0Lq^4Y%LpSu|^^Bvzy}>u*Tiq++Rt#Hucp+HKKE1ZO zqq<#Rp1k*k_@cXh6Lr^xZw*!q4Q zkeZrPf5d9#&_u<6?8{c0hbH6!bD*2*K>pkWXfwk@=<}7{9rtr=CestXTKTrL3+;7mWt}m_STL8ta5bBa=6PW32-CKQIxZ)u|vI`{T&T` z_&T&Uop0_~lXv7VWg$MGX|9o3zEb**}Ho8E~-0eiYSY$$1@+ec4?%RKo?q{iAy zX}?XRri;ACo&2IQt`e!m+5n{Hpi#qj04p*)2IPdMWeNLVE^M3`^66dAW*{bO5h>nL zyS%JTOF6uqI)99~imA_sI`uJhAjI<}6Cx zTefG<(T4Jxq0TON8wRnB62YzRcA`qP_v%YlWlx{;mUrj|Z+qg^%^yqZ2sF@iaj)Bw)ohgg=kVmXm z9df;f7?|dTymmBFt0r()Lqi4~f?2M>^N6XB`S6Bj%o6Fban2vrd)J`-Hjo+v*Ioz_ zf`cJwGH-|42XtIQeq?!nX4odUZq1hO9$O5(W$pV$UmmO#RC(ChpB+YOGLtNy-~G^% zg)4VvmYzCs{zCcrGdO3pw+=I4L~R`G=^z|a&wyUnr)QjQ{*&1+5siUAM5U}=sF0f1 zs?4Z+Hri=);96{^wum_1+opxB_=|b(e42LV__+=?1c)r!s}s1|Kx%^qqQHdC(_R{D zG+)AWbau4WHZ-58YTA%@eEX@sKMVfARI{%p~QI}!?xoIZE4qP)7NtqYGQsw2kUMzn0I!3F@ddHmNHNUcJJ zJ0mq-S{~7vHx{XfBXqU~i&@f{${_aKUkqmB9x!r%Oxmv#nPHuyLa5ue>7G6fx? z3V;k_3T1mm=K|9Pd=$yukq>bDII?`Lsel3pq521J^myQvyB~^Luwr|`p|aB_D+z@S zBhb>9hOY1o+kQ3kCkwM@JduGmn1q0!jo+I8!Fy>( zHY8@1oj%iiv8K0&4Ix8*mqB80h?0f2->6FlcsQZ*0jv$ClG(~E#kzi=tA(8@;>iqx zk7w)KPc#qCdwuit|BCre#OmpmZQA3X`#p2eb@4uz1-m^_EJUXTIuZ?}PG%ab-i9fn zpMhXFCHN)3sH^}-MnF^=U`>XPB*jPZ8-A&UrLghsZ%djIwrSF%uiyR1^ZyX>>YH%| zMW<@_pC~V{zDUSkx}>|aM;t7!YBt}fP8{!hA+TJ~Tg1{aFwVpU$SirF1R%RajvH^0 zH|BTL2Xv!uW3)oSoN9|RQkdvwX6Tc#ks27KD|jJywHIJ+eE;t4Q$S1+suWdW?y5wZ zsmkREd1qN(;ilP&-@PVZ`3AErdhEs{HEb}_P&c#y!e`Jv9jj9`j2UOU@A}OPocaV4 zt_5Xkj$L?GPF|2Y26BN}&d5c6Qs}yGJz(FMzdxa{q^zo@rmh-HG&#EdUi^Pp-h-_5 z>elYltwTQwdddH(75pJGHE(mbrGb**AWtp}mymq|9=b-RY74Wp#TlAo=iQ4F?|x|6 zb8AcX9B-|xMgAb*R3}L&9@tDf#gtc6b>hdYwjKH0O)$1j=*+S67fUL-Kige*_aiTQ z-~TeyDZri#k7_SpQCn5v31Qpsee8qpKlBU z9lh)+K^7E~08KMEhpQrPLd6ZufZ^@Sn}kZLvAYDR?|k(6n}gJb;nQGCA12?7roB(IzvX+!9RG$Gt_;gDEhaj9}94qFxXnO5>2bQs;PT#&A<=my?pm$%kGHS>}|oC@qlJ6 z)S?RAV)NMuz*qvYI?#~}7Q-6R;YP}(^9>eGxF)}-G?hShJ|c{R^6tjy@MB=wGcxhE zn8fKppSu4v?3?#n7k#=TdH3OiCr(#Z67#Rk@Xj-;Z15H%)%`vAUvS#E6w(0=CN7N5 zD1hLu+>yRkNNt+KDZCzCdG$nrAb9|e`l}H#;l|9+C1WGCl6F;DSh6A5@+a48yg_91 zQq?v;Qh&-)1HnV`;G3*DV9^Gpgxcz zLz7A9O-=^T-%dXCow@JMT#)U(aK9Fo=N40psTEs?zK+z`9pvYdP{~^ zDGvsqxZsN0N%l;yBT9CSS)@?o$uJX@Q@E4FjzbABFv* zE*+NV?HxzHZT-a8vB_g`nr2Oz6jS6Eo=tFdoP#ilC(eck(<3^^6*GgF0xhP{HM$U> zbhBl9TGA#(W#Jq*DQwH+;7#8O`RIp_N9@QeC@3zyaK4@ZrJ^4(`cTxu6ox56zYbEL zZqes|oH+T>7q!_d#y@|kjC*7PMrfKX&vVIM0<+u|zW%|NHd$Z#aL>Ub7cNw`b~zz6 zmX?E9gWq7Jc7|yg@8N0D-9z*h`NWPGyXP=ygKaHU71g^>*FF5qa=(AJ1U&XWA^u!r z_h`|3wb*_1D*f#5NSa{ZIl-Rb?||XVV*lDTCP#~vJEk2TF^om3m!xD8dC%x{x0p=V zm@IyyVXhe?=Y438ubdRT+V}ovXa2YKhqLVOZQ7ZVlXvo1XO_j`kSR`jtq{4RWz>=xu86&G(oY znl?64gU$*l=`=jhdE0gD0W}I#)vT>TH}3ET3aR;xY6SyFwax1~R^zH(MFrsBsGh3x zm0+6Zsx8-o)GRQxh(mJN4Mc!t1{rJ~)Xxp+zg)WcTb8wM^SAjg-ly4%{Fdx@4UWU} z6q=7S2$UAhD(jjUNB;J7e|sh&EFcAL2*ObrKC$TmQOSN`TV_7-)?-hesnZwR zI;t<$_lTk$cTq0*0@1XS)R|YOE2`J!9hv;#i-BRA1EW%*>g*n(*%sq!M=GSoH!9f& zI&TmhXpUe|6fqej+Joma`I*i$KmiFG}L8v;- z6W?HV;2Vbe+h{LU5x^9Yi8}T5qm~~Stf_6d(9*v#|HyZKG4IabES_Qc9MzwnJ;lc^ zE~q%4B7(U`Wn-vJ={%wNf%cRDOT5Rtje!rm{r3<5HX-%o_N{pbN=i$MbKB}q4)j&^ z>lX=tt&p1SRiVDp*8_SF3e~HCYW`4=nm-p{{*p{RjMM{z>|79|Opw~T-5p-yYLMDT zkoxo6o_x>AON&6h(o4ogiFB5P0TGH!JqVQ43z^ni2iYqYu7goM-=c>v-!&!VQ#bn- z&AO9_rjw%cT<0eEM&(XeQfv%gmcnS)=mNKB=8_C0wq)+sOfOs3fQDl^vP7KC9SX7~$xHMj_DCL@z(Ms5G|h!1`m@p5|U zxsw;_TRLT{!Vstlb7#atk-2i?E{YPJkIYEvUZbPA8-p%W#<1M#fn^!$@2tPb56;&# zrj?fe_3Y;-|K^oD7G!84$?i)^wT1iW+fhiJX>dmZ(_k@(3{oqwHZU5PPUWLBQnSV< z+7f1jt^Y>Er!#&XJNMnq3*KK9pOtg+#F2*b)4dlfIAvDv=GZS8da6f~$@zP7DYWGd zF@lOBDvm*8p~DKPK{1FWf5mkR8!8lgMBo9bRrSWGKNw-4pQxwx>Pc-CpeC*sDdAXt8qio_kE9pCg_qpi{%s z{KK+1fKQ7^cPH>sOv22VZBrgx_MKlk)+Ofc-cwRhRoT*p-3dXYdxxNXiV(4?g&fgP z@qlY>Z#!Mr_Wg(Ke?0%)dmK9h#jkmnX4{2K9bk(m;3q;NCR?DS7PCu>F2u&w1e(|CptcQ{@j6 z7c{q2Of~_#*?p^QY>Ue({K=e{yJx@UGy5~Ir`F9_km(wh$k~7Hv4xr?3!8JINua8o zVo979wCT?ItF@mj`0KfEZAdLm%P20{ec<%TGxarQkTUO%LNeq!M6c^|_kcsr8Vq-F}S zeeY*WbHzL>U!#zflRjv9+V6r~g>h#h=W!fAg`I?+RW$Gi>t|OZ)^| zx<^DR=r4F}PoXCM_IPG26@#DDVse>CRE8~bK6*qac|^ziL~WaFTYqoF$MZhP*i+qK zexYWl9bZ2p(~8QS&3M{-<1RygY#=o~O5=>C%ALFvEjDIwL_8SAM1I!We(KEW_3n#-RIvXQ=W`#;MbC zLZNYM0ou6-gl-yOO_h}P^-7iJIrTS@n#L-AgSV+SIA?g<7)Y(qlNXXv#a)wxc-7@n ze;5o3Rs51-t8VRBn5EN)s{hp_8G97?%{BBG%gV3>f)w=V?R9!r6GY&YuHXM*(UeGF zF%kF^`i4+xV-LE}#lFwQUaCc*Udz`Oq`AgI_u{5TBu)>@m~1HuSa3jd^UQV&1BmCg-kkMGauV`pr{Ql=N{w;LIyww<>x-Bf# z93@DvevxrF>_~KOiA(}g7b-e$AoT(2<73O5NQ}hDZ6waM2dw{Q$+k5|+K$z>)l^^T zX{s7%Z-A;H#d5#W1&2m8;2GG*p`NgdYvOZm`&rn;U%&EaixONOdY{7qwUBs>>s(`Z z6CK6FmO~t~X+ayNKKSOh9(ncuhQ9ySj(s^LNA~aEKhE=}uT+yOJ*V<28O#PkG_rAvN z-m`;x@TNl(gI0lzYz;7Z0&Q_5P{SCkVpqp5lJHm2B`(pq-i{O)Fd5va1W#Lv$AaBj zSjJTA&S?+4^dFX`8CG?45Z%WZZC1S?R9k&YO&ec zf)w`{c=h;+ktq`+vM1Q~xHO@(2V_T2-N}=v$ zuh=M2-6`74pxCTx9ZWyoIQ?glw*{~Fu~Ec9&9T>Kafyc|0csD;p-O_((UAIlkj0%) z53mhUB_K6aWwLcUiOiJ9?Gqk(?d7cV1!wDzo;=asP}$#BPb&$4GRB1xOc`1L*~tEE z<&@WVY}s4!{n<-BeiG{TA4~q~wcUP}B<;y<_=Wi{B#uYM?NP}S9(;4=FQ5ML+?N+G zPb@fEb@FT_=S{PfqijUY(Hx`P@qfj#RLSVJuLV+5A%N15@dvBgdh%-qzaO<`nh4Zs zBGxf^M68Q9kXmGFPf^ZfyF`iA6XD>LOpP)mAT~|2q-xU+)+zg#$N-baC9pL1>(?$RDH z#R&3jTOilNbCTG|7^wrC!w6F2^c@@TvLN0yCMm$a?VBOXt;^F-U1;oYY0}&3ap=Rd zh1D^PkK-S+tNEouYO&3O4PvgUmU5?!q5wxN1C9%n3xQTsLAs#-beo=1t^doL`KTk< z>z5sWB~u$}1XylZk!wI|`igTc|2XWE7gEYr7I4gH`{CoKS{q>LTXiBA!8nYl<&Du0 z2I^{>dnUy=)(JY;=yU{W=YaKEmUQ)si z_ps-9rcICBu;;ekzv@NjZN~97QEb)G#As-qFF= z_lS4cPh(f!6}HhgGDEW#YxX@}OZK}&rs5~-YfErw5S|6M-~Fmh+$><@qSPRh0e=Q$3$rt+NL--&XYJ@GMy!`!&)oN$r?tP0m=v(0qCK{H!s8zX{^!Dfv%mZDnv^{!%1@uIxL7ZG zA+%)7c5t6TRM!~gj{hq~n~gR=8pnmy4C43`U3#@Lwcv$NXt8&y>eXLP*f-;ex2MM> zQ>Y6j4KjHW{j3Szwq!n{m1U&xm?q8%d7dz!;sI?>L=CH1v)vXS)I!syM8>h{@NxFZ z-6yN}?mty^uCAv|1kEqa7y}ywpp6OC+djw$S2Pb6cj`ZSdgX0F@A?LypS{_UG zxx^H^+4E3?`&!ePu1qa2YYvmy%~s@Qga4Fzx<@5yF{ETUI@7-MzR0!z7W--DzB3i) z&i6F4BixNb0kEdD8+p-{=t(GQWS?5K8UU10XZ6Sigz#w?w(*c(4fgW+M5n&~^x!|d zmOnW%p7^(#g+Z4ELg%w;SfuWbR4rQL1os!zU#NNw(nE2LI;v(DFN zPF&?%ZYEMwHRfwa8|L4=1O2^igZj}<{jcqxa%3~)6haChiieaf)j;YT=$mh37KDz4 z?-rFvBEv%uYmpYYR|_xF79G&+nVyy{0gu1^_fadh?yW05ap7WhOR{P z*c6tG(?jI$Q|CjMhMJ0V$M$u$%3-NYbwqOYPTs?H zm9yaTKUY0xyzA?M)Zms-YyKN-?CP)7^?zIP*|fRK83=$F*C)kL8Ju1!*g@he|Hwoy zTLxc&*W4Ldl4j3xi7nC`B6R!BS^dMewG~0 z3h|08V&1}bdI(3#d=`w>VqrmXvQEC;vgyy}zqvB~;NcTzTk2~Ex^Y7r>=4Jk8+rlE zFkmDy#xgPBctlj?A+T)x02Koc%vkgdNRXoA1G;7N;cwVB`-R340#pmnpl@lHv2v4* zg_90{t61FeBendYWpiNIsvkeSWqD!U-cuci4xSxs>*;N5G=ebn;U?E9T)u(O)Q)t6 zJLr1#zFLxhKx&gTnHl=z_X4TeZNFZV;o9CqN2x!g>u$76Ez3$4nUI5~uHIvf{kyyL z`$9gRXxYlvp5`ck-U_j`r5h>3+nON~bYv<=0JuAn-J%3K1uJd4HB{gBJ%n6vu_pP> z|7^-bOCNuI$Id)#7{^A7tq*N6mQ8Wsz?1#ki3j?n=)7?%l=s6G&}0d7GPL(mok(QLWi961`6 zKEami_wbvKyq&Uf*YQ0k&K@s2UDHs-Q7-t|;njxj7v(T_o~V5H07sI^ldj&j@|OBD zy1wdoh3C)b2F`tJ=5rYy3-h&*bZs%l6}w&RMFdInjRdSodA^oi-jQIp%oZTYB`Ot+ z7Vo4OR7M#AAsfFP^x2aB*`x_-ZwIVSQ%#Z+->OuD5k<#)c9BuC(mE?&_{V;AMD6GR(_$n zj)NwL+5aoAB*jlEW=VwNo({dGw(7{<+R6&Z;-QHestC zdow=cWIf(m?I5+d4~$5=*EoP*`DepOZEQ)4gi1nTL6VC$B1%&S@$4p{RnTj6y>v)l zl6LOQ1km|p{o3~y_*>K2ko~SBa>t)8h9npS6I)tWYlk9 z5){F_sA`KCs)@rw6%80$|*;fD--X%Ki2#HrPzjH|05?+LdXYfYnWBr4NJ~F$|*c${jzS{PC{A8J5UJFu-UvvM3_P(Qi`adjL^R4L3 zV7<6YV>1>FQVXXCUYJPjXGws+`U0s1ronV3TNVR7DSXrPS<8Mf@5MElCHoE^Zf&S; zsHnstei*KltphX1NJE4{QF)#tZFivy@9pmGsO;{1epAw&561XD`oJz-%_o!(KBiGM-uwmlEOKa27{f?5@tmJ&B8bh zGeuX2)JzGy-L>EyQ>{BDJp9%}?_@1ll@q_e0^^OQp1#h0f+Jx0K?Q{cmn`WINPXjG z$Cux1kQwQ2D9r!wWom46on>l-YkaG}+#fgllgXbj5H~~njn27Gwz@tkF2CogSEh!q z^oiUigbSn=m=;L{`I_K` zh#Tzb(vAwCcqFb1>pOYUOQIy8uT)c!M7-}}XEzn=zwD{>v? zNm_VL)i$o&8Sq z$2*D+9IC6RfJJfk(i+q|2<@#9L>el_286xP&-Ll+Pqg0?^!}uXEgsfnEb|SSS`55R zvD(1L6obu^fg6^og#it=f!mi>AMO~9xCo_u4=y?V%u?7$nuBZNyt3Y)W9*Nja48uVd_T@+NING^e@Kyga)X^fu_mG z8DK3_RtBCOL<}S8ew1KCz%+V{O=tBVJiT@D><{jZP4o?ma}7`STU3Il+b~$uD8Xoz zB!5*hHQFjdwYvrL<{i^*TV~Av;Jd-ESypEj)%Kom?XRwHH98z!hk!NqsMPWI>tbOd zQ>!2z&T`^ti4thw!lA>Y&$qm#&a;kIQ0Fm%w@`V0fa;iw_L|nS=1a^B4ZI2a)T6r* zI;ld?jP87%Aj0EMO)Hde&6EFiNIj@`_Ufm4^he)I@p|}`0LK;&N1_&)EQHHeDAv~` zm~$jqp>GL*xR5){bglfr&|4x9NjQZ>|FE?)AAkKXpLp&c9|>E#b>|V3##LttoY7?* zNTJC4*mt2wgB(BHc;>=|C!(MGS=3vTfA#bX>t-!%he1dw4w^HpzB6dfu&`!G4G;MA!zXUfiUXra_V+NjB5itq?VcAjk+( zyGEw?&Rc!Qtfhba>#&cu#P8WxTzmG=V0#VBD#m0W!FZDNPG38A1;;KlJ+%0v2|r&r zJ$R#cSfUo3q@+s&ofF&~@vc$vT6BV|1GS7oYLvswE(58#JMvv@X&zx)ri8Egn}uta z7o9(Gv7@EFW{?BTxh&uyo_%?ZpRb2O2RZQ`~m%zz|0z6X|pShrQpYOQFMfkQ!)E zNPWHZW50VhnbVI9%S55rWnoTLUfsX8NX;S|1F5OJLTc)daLvd6T}aJz8Psdq^c|=B zzZ3S6+uTpR7qDSRkctfSgl^V+x5#2wL26cgrYliL9LTmpVBI70-6IQJtvp9zn5#vn zc|`4)6!zI|4?Oe8^DD!jej_;}=Sb)nkXoQz_zJcfsaWt% zB1m&UQuLafy=66ZjdF^*qN_}AlfasD{*vVb=Kv`ZYJ{N=x>dwS>I^1#wRF|jbT-wB zrFU0nd;bugwnV=LvxKf*BA8$D(%<2uf@y;oeoc^iko`&&GO4xteZe102;Yn->bW3a zi!jD(c*taupq3GBb0o3cbIAkKB;l{b`~cBAKX6g*l(5zJKJv`0=iW=qFJ$s`w^Zx> z&8;2v?R{-T`zHPhcaAgf9^&9jLYx9!mnM8}j5D(PYukoaIRtMg-cKT38#79#3@d1GsJpAbp0BucDTNFcMU_MeOi@pDqTD;0Ztgl%LDodsQDVxhteL^<(Df->L?i z6@ZT67E1L%u}kXg{84Q&^BdaxHI%7o1!Lh{;Y;#BvudM4YVKwa+>#-1hL4+|{RTFV z)#zcXOQy{I*l%H)h6QY7qI+z%M`W6(CCejXm#d}7*yh6&JW+GRYoZv>akJ#PS@K;i zMEgXb&e5XrmfAAavf|#yUVLFw;hU?IGK&tLxKL5kRMXSlHq^^LBW5s$OGjUaPGX0R zC!-RkZB1>RZGD3k^^N<^Ru$Cref#le0%m{c84*XJ5&+Fcz{ynLfWxw}K_a%}DpSR+l7p;!pclOx1%I0=lZA7eQl%2c!lCkDnE?^f)SqaOA zyw9N!?Rp1stD1=CCh=E$bL(G{OQTfD1%r;B5!CNg!h7M18>+v#bICqRmXuC)?+uE@oT zF9QcX=ejylJPC*L#0P)(+@>AJ>cv_9{MoLyOHVgoo?JJi9%04!pScH2)76H(RzFk> z(=8?;+~B?@-LWx0H16Qc&<{D!okQ;Y@tO=zkSO#Ei3pU73B7czjrBqz{7a6jHOnnB zLptGV5=0=-lIa(b>4K637TuAe*>`w^ue&YyqhG$fZ9^Uge|_EUIzt3fQ#UaJzhohO zy+1+$VBOJaD~$e1q`oZ1-Kr)s@l?@FKbioFab1FL&L5qTdNjXbzD@Os^B+3r)k}C{ z_7xyy64LQ^h509Dxn#!Bx>KSvQqxi@aNXA3`0MTTOXnusXryMO+k5o=)%suB)_Bif z>#`_E;{-`UN?McAcln01^$a3I!9ZkOX%dCL0p+$V4@;g$M813lQp@Q)$(n7`Wb5kx z6S@3@ysFiir&148@2l%9>*%X%ZEtODZf|cTwY9a7SBd=S#DUV)z50a#y{u*Ec#iH5E7s^8(jOGV|)M*~pc#>vG(JYy6_;*KS zPPN2+`>A(Ui#cfAwCGyMAwigT=I>f8R*606*dEFc4dbw zUn#l@X&qiXUwX}T`@qXp8vj1^)lufJLTbXIe}U9}7;p_$b`BiZ^?T>NH6i?Sj@yt; z=kR3zB?ZPPBr;wG2PN}FkOHJ;)C9E|CP7bQUSZh3i}4B!UH4~UZ+(z=H0AKwz31yr zwd$2!dUH!hcN3?qw32$7Tgai6^`{VNd8}0c$~O8f79iY*HHOs=%7xdxxj^SPa~^qOHP(EgSdDNtTT> zA6*vwerm~uzKgATQxivy^>^cmDYgH7x)?YNM-fPsnC1*gqw}BxU?GO4#>LRz!ltT; zrz(Kxp-^meoy{lU8W$gF1^mX>2dNnXvnT0Wv%;5TROjdg&YR`x~?{Fui zUVwPA#n-axN6*B)l2-L@TKS6ns;#FxQ>yw-b?fK4_48f&`5wL8$e-)f&vxl&JM=O# zU%sF0()V`i`AvFJot|0Vz5PtDCGO-D%Vy5Z6=Lq#CA){#M1&wijvhg3k*^g}XMx(@ z)*U2*PHUEIZBeNfnjL7*m^u4{7q{&_T-|Zu;&7OKy4QJH7>b9)pIO zHcZ1r)x=KTaHE$l?^o#-A~l}NkSgIxdIx)YhmKtAJgDmvpLla3R@Onu+S7;7W+1() zQ7{-P*e8&B7h)YrkeZO`1f7da6hO2yvb(h?P%>kxeaGKE`}v!BWgGUMODk*5tkd_m z>t*0|t6tTjSGCEVd}XsvnO?HaN2#9|~z z!U#lVxrQf!+Jwp%ErEg5ra;ZfVx+4=YFTBWahMQrmWp`CM{}em!H9BwEW`kO|DRvj zy!B|)sg@xW^5`+zYU+o>8C`X=Z`mI(d{BGH?D&xyxz8B(;i11(RabRTrBfy94}>W! zz69gcN4`>R1mh6EO=*<(sF#=-sNxv1E$>k%X_oan%GA`vESj;nY~^`qA~hM+STZKp zbW29zW+F9`U_B8ax1YK_cpbJVa%RDjy)G|cMHcTLzI|dyoPS8VM_8T~DLZ#sRFW2j zY@4L9;TV?f9h&DJULYhcT4I1}OA@vDpZ(Rd$@jmO_rzOyPrRG|)Y^S>KQ9g1SQ@n9 zV95G|!5d3MHenP!RrppUw`0|`@Hp~AzRPQU3)lc;(?rfE8)2N9$8mXBxJcQw74lrFYml_&q85(Hr?`iJrAhi(@yr+AhyKA7UbFd3H z6;$aRT>~9$gYB(DolS#XEu2V*%+AGM^AcWV4(RVbovs0?3B)@7B)xhC?Kdi36b#7J z&Pa`$)W=DAujZef%~I$Qp6eHu7kCU##;6o*kswTr|RFACHMq=qFJ`MzO+}SeRL5H)R<5T z3UfS1geWVdjgi?}WUkThOj=E!)8PWUEA8#F+I zF=DTxWHW@LLoNCbts4U7ZWIFh?0yZ;=>I7NST$c zkUG~r9QuaB6Izk(^?bfI>yvLRNWJ5!wcnb%=AI{4+!?ZFTJWmrA#0}wuTzN_N;ASX za-SBm{z_?T(59(RuJ~T$+S?yl_NUf0*tJeVOKCxsr;s`wYU5=|z;9HjkTqA49Rm(P zfpoCO+p^s!V!KN?MPj~4@S_Vp+h7PysN89z%R=u=Ey6$MReymwP z)vTXs9xQ9_=YG6RKi;mNY}d=%_4;5-+XTkGJkVaG<{8JYHJtOtS?* zN6A*e5HYc^#WuveKE1AA|NF3)?tJR?fUr$k7@Xc-k*Td{U)ep`%0S2q1*v6kdKjrA z^T2DOrh7-ILB!V&F>N<+;~ANJU(|M7;J-QVU50+*tPf{|eLgvKV_@h8mGHKn9Pv5# ziD4Tro2G}Xx_ADY_dNOPx2&sgw{3QtzlEJ~FAmHK&2q8ix>~Z`BQiKGJA&HNSlsn%V z$yK1-_;XvT*J6qAkCmqAJshQ)^&oo$uC{zJ@}K+RH$s*zO*ycqs_V$9+KyWGDtZmE znhBzsF+AZ_Go8CYJ&{)4>I-xj4^k^x5~KzeA<*PAqfy0`k(;SKqEb zo7p_o60gnve8OUIEm;dr@L#gaD=Jf@p70c}aAc5lR|_U3vYcf_TUhnkz&8n`b^*iz zYlC%%8u)~z`iG_jh9m`sB>0CV_=WET@%_TLk2}Q??%O{!2__*hG;RW{LRgB2kk&k? zC=3Ji7Fx;^=&fr+E+m&i6=9)Ta(gyi)U!gpYt@k=?+7-hpPlx>cX~$kIvSAKw=7$?f5vP7nQbTG)zdp{u5a zuEscdO6b}tq3g|L@EdEVhpYx8jI?@k$c7mq8}695{JXQ3ew4CrfXtt;1VGa# zB5s_CX@>pzgs`ptVN9eXW}|mlrgvyA$tz5fM>rD(O^>Gc(GXPG4-sphEb084fJa+l){o5~_<{8XjU9WdpB< zaa_8O2P!dkmre35p8MDWuztImC06JFr^chY5TC4^2K`@O+R33X^oAD7J`{d%2A@ov zK$|R2fS6^gWM?frQL`ko6M>B-h9xWn*T@|B7CEzQ?z#z2?{eoLkEh}^Obgfu2v20m zpyiO>4i^rJWiIO)l!rOD#|f7%h|fqBgVd4$n5 zSMTP~>Som;J$;-;FY}W`dqRuKsh`a&JA=dFrkX^y_ zEd*<&)uG#{1KTkG8TCirylmxpXjYyK^;iAP-*TCGm7zD7+he>(m7+kOpIw{wTa`8X zj>6OAH^`_CH_IAbE8aj8s56)OHs`$g@VaNru462yCqpnsJyp%=IV#uL{HEYc75DQ7z4!{m<3%@gc8l13K~{vUQ$)gfS@fTJWaT3K|3*z z`EE@7=UL}!&ewJ~R<<;Pd%&!>7Ja;~w6y4A`JwKPdTiQxuQ0DvyXT_b z3up`i-{*Awzn3Khgl;jQ8Fc<~x@@69;TMxf!SwZ=Kcesvp3Ne>9L#`h(-`SXFwHQD zgP38@j9a%MSB^lo!H$Z#I3aU6>{a%xVe{OAw}N5>+Wn~L+_A>?`mR1s#5PPAI>nbk zqKrx)`!9x=?t*d%J`GEk(tjgK!L))ZbyrXL0bBq4Qr_H+a{=*hv1c5t?$LL*>QAoT zeP_fvSYI#po8X9onVGmHs#dVd1gVK8N&v$6t0xA{Eu z_CGwcz$Gy)j0QUEi;qyN)3Mse#}z>UkNYHvEx?l~1e$=!7A=iNt7l0yp)5)OtrZ z0b%sC!>yB_T&V>mNH7ZIi?9^&$3&YQlwg1|6z@w38fYLFB!aDB628@!OM-4H@q2?x zKq$tO1Q4BzxZKMr(djn^S^iQbRh^|3;n>3@V+u>740S=`)cNb9KTJJYR?9h6pc|cQ)v!T6B*m-qq~efoWH3g0qs)iKIJ|cc(n{kHlFx4`FcXqi;XI zA-nW+Sxfb)p|(njP$Dp6B6L_Hs7kq4cL~HBF`q|}8fcIg%JX(zJe&LK2K0h9ed2>l zeZ#j%=&dhcXngtk+x=&~v*2T7>fLqaM|wKyl}ybRHMCdnZ9vMS#OeV(`Aqj+kGL@)RTEWB_hc^ zEDpS$_|zx!KH6Da(NNyf-Q2-m0IUlqWf&fa22y`X%Q1}9Um9U!rm6X6z_H^=IRc-2TKHeouZjF&eLM!yFF#J#lt0+6y}hQb({EjaV&8 zY{Qn1H3(8;$DWQK1W4^3o-)O@ePZ}p?Z02v9)4eY@B?r371o4+s5Fq;5XSji(VM|g z4exn@(YBq#>JeefF-fmfX zgZkiJ#t|ygWTwp}iHEoFGKno2!1pUDEvTVLF;H@AZJEqY1EJ6WD}fHM9?f8wPfXOK z^5*ug*#o?gyn5}eMQS=0k)N&>;nPqNP;)M`A(vzrIGSTt-prU?bb~U^1ySc~L28z| z;^Niv80mgPz=q4ka2JK0Ue~3UH4Z-c+E%|OJ_Dn1V-YM1Ndo4SH_as&tv(7tlilj1 zktAVK#!R63$Tp?gtQ`B!k8z**ig&6KjXKyxhPrH3r9~jM!F!Mw|Df>HNkJR`G5np( z{b!GzJzrjNwz0LPR}Kde=p549df|*3`q_GRfBY@Ywp~1WP@#*(nn}jLGLxx=XL;Il z{lgO{KJw-w!h#<;)=+s;Zx@+bsYYc$jMKoc9jQfv69z*`aL!1LKN&~C?P}L2KfKg8 zcmpwEL;z|)mA|1q?)nQSHh+ijtoLF+-h7~RFWPUA8UY@#mQs-8dm2%{Q|_LNL*buf z-Z}dn6wc#+zro<$(D{Q5XrQn-|C(%`0nG~0z-9H7+?i?2PXoT4x`p!-@=k*{wH-|*MLuWZ?Svb3tHvayY`--bHcWHe<9MP%wrk=o#sN7D+mD4p-a zzcD5U;dI1~!ie|P&^?IL;`Y;Be;N7lgvZ{Q92qAu`9qWB3^Hu#5r-990#eIPw6PhD zL`?m~nH?sCJ5HCP?f`s!B9gslz32Vl%Xde7_QO}xiJCHT-ly85ANq!F1*yU45j!*l zYC~y8R~Qy|vX?<#1Z|8%P?+Zmxrk=JBX083DH9{tPYGFmSI9^AzaAfd@IrM9Cy@5F zwG;0M#Zg~>7t;sro+!PUv?S(|YC8`{cg{_F09)|UXZ^G9_}ezOb=`oRAqi-P}Q(YvrrX6-OAP5pYUt{2zp z-+A5$Rf3s#kPA`O!&evYa|Zq%tG16KbX};M)nuk(<~ML`Ns4 zw&S@&c@$EcFB!>vQP4=~Bj#&X*$yF_~+Bf-{e*!^bmkwc~LdFX`?GY;Xdd*VXn z#rl@679z2LdF?}bQ)hqU#fBbC#ay3wg9s0}v|uzY;N?WdzbcB5Nmat$&y?*OJHy12Ye;exC*L@;D+*$wX_R2nk%ZL?nS zoxjd7AAo43<<*85S*x9&Z(zqb51NDW&clDq7!6hTVcBMg{IPWu|7v6tbNJzqyA7S!Sp z5t?A&b+UUz^2FfvcR#e~&7|GC&NU%C_Vl7CB!&+f5;{qEKE;eNG;#?CD3~;YO6sY) z8z!B6E#F;oH&&}YSXO?as;w{MSk2mfb>Dg76~EssyJt}<$JmLQ2ql0e4Pz1`KEH5c z^z8^z%jS{M)dr(N^MP`HU=z(!pe13(6K@Cpr{k$rg-@rS|C9M|OnvZquU{?YFn0|6 zSR;nKEGF@2z<_&^%`rc-a!1gn2t(FJIVQXO8QQ`uEo8G66R(A>4_LSZ=kD9XK8oE? zy!%2|UAJD_*s2pFou0vbLX0bf^3XQAh`TXqnapHw8CaXdmN5Vwlw>-Zx~eC9tLU)8 z4iwJlJe^1M=I7D+Lh~;XKd)4ORe634u9Pd~Hst`r4hARzVw z&IWR3({A)|m<3T=m>-4ISL%H8`InH|nENaQR)j&xF?8X76m%VWTQmFDC^^d8^h#Y{ zccOd7qS>>1tncbUlXwTH&>{E-aM>a^B*dbKi+vzl-Q+`_IC#_4GDi0E2Ne zo3Y494b_dE`&)GPCzhf8mV*()FhFuvjgAAg!%}^0nIQFqhu?@=kzR24R6|u6)&b0% zVNn9e<9sgCHx{lLD4OeBnmA{m( zP-yB6pFiT7q_$d=uG^HXjY%bD@Bk2s;&iWY5kh5t%ASjnhWFNuQI^O#f>7W!HV+&r zf@_k0@P=>9dDXfyCH+kE*_NR;VzwbEN&p;23hQ>f5^`DXdVpJ7=t2)DbK!7sYck61$-$ex`S`Lw`nCPVZ6$9cm;U&vB~$+C$!Yg5zCCya z+uzb}oXCS6J|Tjw*@k6if-!#treOf+t}oaCcz`7s5bo4sU>-KPEkSsX^A1`2!25YS zj`v*X*X!B9?}Ckifo#%yTNP5P89R({z_j$+Eko)r#>7AeK%)(Xj4o_8ykB0tDhz1FYAwM25 z#x@qd*t(3FQj9;8KbOB1ZJre5T*OGZ2Hj9`4lh?#>QAg=iRa9>G|*@xjlIjU;r~9j zX>(am!hy=V+P(n@N>`8G15!7%4mDIXwd`%tJ!ik-X5Z!?nd=jlPcGH)5YiMuS{9&UuOdJ#3Bg7|5ghbM?m^>_XdWWUsdpIFDGcY*Q zFO*q20@Jcvt&)M%VaY@B#i3Wd%m=_(teQ|N8W2>kiZ&s@JQVI2TnP z!q@@(Ksm@o{sW9IL27z$m>SCP1IL2Ml8m7o&Z{TJ!_MvwOiAGFHXNw?rzLBD@N9zn zW1mcn%EJCZtjHpB2y8+K7tgRA%x5?s8YoE0dI@L6;SiyW^a%ZpVj+!~sP2(FJwms6 z&fhfY@el9(x#f|CZ>~+>lURK0z0D~iet5|< zPM~w3OER7K08F!8AiT=0zaYGbW{~|W5nEGeBBN+BI?r2MZ+57uiIO^1^~T^d)Gztj zC8}=|+RO}H0s362A9xRN!?&sv$c$JrU$@Qxsnu5XmFnR9oaWOgevfQxHo?qXw>ph_ z5tUTWlFvOpL@Z3kTJmI}`9xQ{nOtAZv{6u%F8? z1PJ9f43PAGqHrJMaEe3Cx6OGiFns;hA~i%1N8bafiw_^IxKP&9-iY2?fCiuN zc0y!{pqJI5|FIR<_|GTX6Nx%I8m4)2S)>-Z%<%8Kaq~wky$zo%!y!u`MkOT`!eKIt z{6jJWgR&>j&z=x$=uE`!P67Hbtb=_3G)eT#oHi1Yqy-bTECu(dnIWIvH~Zz+v(M#M z^qr_ek;rK+tTRDgbpRH_GcqoMM{3-;8+}MWj=;1GnM$S-SmbNqo=&dl*3ZC8zn41g z(bw*<@9>4)<*bdTlKq}L;vQS9J+<9GIukEEVudN^=nQ?K?K*xmks2m}Dp60a zt3zr-rdCLemGBoxjSz>;OTS*(q`$o5h&8Eda^wat$4+;91}ft5CL&FR@A9wB1sM(7X z4xX)UXz1^0hXfn68ht4SNUchy9wzBmH-SV35jr;v{e0k^jCvnYR_goov%3D|Cz*d_ zUp?8n4U1)t{zQ2@I^nZMZ>vOJeZ*)=o3&>0!>_-(eb=sohia-deKxD=_DHFpBy+f!^j+`9FLEa8^&%(0$ zl7uv^lAkqsrhPNVaQ}VmXYr@H%bNA3Ht}}U#af#+CxLXFks2IV!^C(QqtDPOq!x_s z?GU>WQh%R>y@G`Db9SO=xq~G0|ZLf#5$m6N)_gc38AZp#(eT}CY2P$eC8fvSC zdOQ0J_cJ=Di>9mY;2b^KQjz&Q{_9FanCB+em~Z0=6!ns?c&J`tX4LNiK1FY#{J;cv z6BN{QK0=DYJMKI|=LtZlzvWe2&gGi<8fK_#D@55;(*4TR&P{1xCDvF9-lic4;xyg;`#U#c? z=NvkR-mAT9GAg4g{NLFF+Y>C8-1vOC-+mUu?0sg>tXVU&-Zf>< zP&tEnYK^ePq3J=s@GCCO*=m~2S15VN1Q#nJHfGwP2A}Mu$=kDj8mwy+0*!(BmKv5h z&X2`*7}!dIjDABcKr1{}=T)iSb2vSld#TTkb2!NkO_J$8h|UGeLh#F(C_SKTDAO9ZSXARvuVwDV=jH$I36Gz`Wt-?6;@&d#&rcAs5r zb?SKZ&5EMtNB0WVjb)G2^<^DZSkRkQryjD!c8K}$!P{f|Zxi*yagA2|UQ%C6K9IV< zc^q~cANtd&PlInVG!!7d^qM_&2PRUbjg@@x5W0 z_?D&eZ422u=HgdXe^9~tSqVX?Y;W7}``E_yv5k3?L+BlQe0Fplkc~d_P^aX+7P29> zDFdvPs2Fcq$M><0CoX9VERjAnB{KTWP(RDq!R8l-{d{ot?t=mGcaw@bi>o^@E%3M% z!{8`_t^sh?0E6;|pO!KyX!6H^IeOFNWN!wkvC$mVCeR+Ig)yJ5XEdojuBR=vJv!#+ z!^3uC6MO8@hq2|v*K87Bx0a&~LcFl423kac`dYK30~WJ zc8JZ@Nt{cAw)nojX6K|&?CnpAFD0bj%D-3j@WG?na&>bRtc9YQrik=Xy`O^K_}Fi> zy%+=j7=^&mW+Uw5Ui;zHYqmHG0HsF8{|B1K4>7|^@2J7%NIDut53!K6kfKH6+vX|# z%o0a%6hpRO9QE~{Eg^9i(ktY*%ZqE8tLw2-43o!4WCV-s+Jg*Z{1B!Lk;#95L3vXB zNj=ZHY}7q|!gD-9#byHlo}lfa`PqxrwDbvXp=kjMaPb6Cg7Aohjp6@G50ZW^QnNM& zm}L2f2Z8DCYHY?S=PduM2QvBFks8bZ&M5y7b&tGg=8OJ{LP5qcao?i|5D%^%5C4l> z$OKo97tw6NBxL{`(o2)KXZ-x%ZNSi< zjt%5swMje<;(=PDc={h*a##|+rreF=kjOU9Z*b+L3FCMji|DtlV*6S}Q@z3HJ#s=c z2*>(>prU)}(zo8S<|7iKf=IN`MX~QXh|%jIdoJOeAZ(wwQ}Eg@Y|tcs(?;5R{t|uoN$uu4HNs{&Zm`TJt(iLt8Za&nV>2~>h=cgJ%fVzv(_dXBYJM+FM9YkCRw)Oqak#`FcXR$Vg-FT;&(Vg zoSN~9>W`q0b!;D-s6IB=-?GJavY;z(a0tES5cN9eI@uU=_mwy8u|Y0Y7-F#*zmE<7 zZR~|>9mlwQvO8ZF5!+Ieh#6oV_pVJerWK}bKm5&}_?Yba+hy1sUfqr_lCWI?+3N$1 ztP6-BHx$+jks2QcVreu}ju0$bE96`CL|vp-2Z-((bBEsL<5TOwFmE^s z*i!XP8`28iwTK&P9y8qR#!&Mc?^?tRvWV+%nZVfR@_}ZmLA#R%nW^5j5Dnga9Wx_3 zJC1(6H{SMGY+P>Xy}AzMj^Z;>oM;Q}kH~57-Ich94(!b>G%(el)MZ~`A2Le%X#(_C z^C69aeG!V6MW}AQ+XZ&e##HOF&+!D%0QdtsXzFmp$wv4JJ(|%{K9MvS(1Z!fA)e5y z2gB%4voq9S3_Q~~*_c@meq!bDEY=`$2m#OGp}%(F&MV3-%LY3OPi6irC+rg%0Q_K_ zfdy+?4G+v_8EN!SnJ9UBoEb$@F?Z``+SMSa~;Uvo2MZ9hu z)5lTr4ln6VUg}%UiD0QWoIed?nK0B|3Pm@;{NgI}1DA!_bq~urYf751ClnS=S9d(9 zQLlB{JAU`xk>=4DCLLf!B?A%tXF`X1fJOWeTkMt@Gtn+?)~-W)gtyWPE6eH{n;w&+ zGrN$QjD9zx0|umq`s)3K2xxJ3s{_C^MQSz9$gX&#PN`FSC)}N|HGH(?<-uGsii?sZ zT)luOq|#sEAG$kY%(r3lzvG>bSLNj2DJv_(78ZaTW`}gFM^vXbsIj9aK1&Bi54GhF zv56mK75}2hpM8$awcc=4_Vvmd=#~D49gsTeE$i#3KX2{){T0=pNK)}EfA42?y1ymp z6d|jV{j5&Cw)1Fz&ZU0#*WTnt_IDM%ZZCM0n?@D9)22R}Uh`hijR`;RAG_=Kp_XLBz<~})*ufqLa9}eZh!g^6WFF7( zmhg^kEQnzhR+Eg<04ovtyb~Q_ChR&s@E;sgtFTjwJ7*Iz_=>E14=Nk6m3t#rN?>fK zzO$|ZWA8BF@o^&eLdxhZK104cFyNOnqa6e&-@$g0H#vgWxguEONE#zW!z^M)n8yyY zK+}k2I7vVQ8DvT3FNT^ahMLLV`Za2VolwhFI^OJp&d%d=wuf?0OCK{F7Y3*K=)B6U{9TKXN#Tq=Lx0pTv#9%-YsDulu9=Bvpp?jpa`|Ym(JtDzV z#EG$1s(YWSeyOH~i!cZYtOPn}A|T@Ik;-4crF^pS&?VnUnzE|N62%CL)D%*Y3z`uy ziQKV~AWmGkrLLw2!TuMJ8l{GD1LO|;zXbc(pAZsRezj(Urnofyr1rM7py-hzBjB#@ zzFB5ouZN4+CzoathtNUGbOU{!Etr&{Z4-jv-Z$8q9_;cb_M18oP{ zCJeF__Qo9u0~-ed?uvNFChE1VC;IF-_1c!8zCVQb`!?|HFTMJH>Cx{C54e55@Ot}8 zpFUst^!d{N?JdE5KM(08AuwLSi+CN8fM|q>{GG4;-}yf5wQu*l_RZecww>&r`O)gAa6xuLwHv|NqT7$$5B z7-?}0AqUw&J`hfCX(&fLgex6jBOYoVrM>;o?xTERUh&=XT6}neZZ#i-$n~=XbK+fV!62&yxbTDE zAHM67_76eJe{{OQSL7Ak#sU>oNJNglBF?0!>QM6^s^^#;8M5;dj)54?x;F&G`{v6Sp98q7}*ipOA zPTv~leK9TZR$WC!OJ#BSla{6@otS1KO%G)XG(u^E82|H-nzT&vYjqPQLdZ8+1vQVe zn$_?7Uz=oha>TCRM|0z_$q8&N9N7tT8Wk9J(NLS1q1Lg)K(Zw(!25C~{kZWsm$N@7 z0lW>gkqxv_z=iyWm|fShj~u$iYx1XD&-0Rt!n6c&(!JY7d5qz~Iyn1xLKE^xxm)5FZJp<)c=$}qnVf)EhraI1t7R`J8F;&EusVB2^M z%0Wbol*q3`tq2XX6%OSlpua!LPVnyba}#&|w$|-pF#l#saeZ-hZA&B8wIW3f^pR89 z{);gssxUQSnm*B-x250VLMuXHLfZqiHNljIhs%If7htgu5uU1FL_(E6BB4=HHA`JQ zL@;`xjj*q?z{fuM>mJ0(f-L;V4x2jVjb)79f-8VHTs)^Rhuar1#y)2~|075Zxk0eV z#eYOww!FV6opc*D;QR}$p63i6?>+Sr8gz^zBDSTE}AgdpIX>8SyX9h=19R`ownZ$JXONvYzlEq46KtPT9g6_Mv0n4_!w7 zw14RKE!r>3% z^84HI``O2V2H3?7;>JOGpfOIOe%Quv$MtueRak^J#x7pp=DgY2!)S7(KZZ$H3OtG1L)}x8k@W03~L(IsUX8gVJQ^~U-X>XdsG?lPsJ$X5wG$RN@ zks9-@?PLiV8Xz-A4P8K1e3L^KG9RnAo)(P%HE4!=%vfg$R*DYfBoE_AF&EZL8fzOn z!{+LYohK%K9Xk0-zbT(O>woU7`;pb`4|f@Uy4&c}os0j~MMj_Q#uLNOb{c-R-SFSP z7=89@uUrIUUc~EcZ1CXW%>Ual{ht;{ZuSrUTHgkZ`NDtl4+nAL23YDP^9VMABN}I; z7{y6`gOh||%o+B-ee88OR+U;K-|L}VJ}1XpLB&dV)#MuV|sBd z=g4Q~ycn_K_U+rKROm{h@?g{N>V}rWCbjKp<&51Y$JhymI>_I(jGX9Fbg>)mf;&`{chIPDRS^7Tl>opSr!i_A&MVCw*#y)E&&HZGSAU zo=A;gr~`Nh>-3cO>b*`zV}mbkPQ)lD5%3WoOAd5N9q61g&`vVKK`@pRHPQA8h|F7Y zFfJ|a>yXmNDY>7cXn<4vKnKAfd&yus`4FxgEqau#V1jkzn5}#De)9X;^H`)jGyi5m zVQOMkUS?}!6G<0i^!OM7%c9%KmUpcURaoCv)6#xcm_F+>tFc@BwK=hqJ#t>#&WEvz znGQ6ZQMRJdHpIm(tcU@Qg1*lDKCba^yTtZ$jve3>J=ig7h(pvc`{;hwH~Kp#_Hj&k z-9CAMoeUeGeHa{jMpoA1H7=f%B?4<|F6AF_e3tWtH(@9%E z5-xz0=0%k!0zf^|!Emas5yNx!HZT_r;g%vxp^X!HE z(hEPqgE{~tMRCA3>rupP9$zGlXP@I0_APi2Eh480fh$NDE}J?P__G|cPiO(5M8Fuf z+`{h6q)&~llkiy|huxsW(2hlj|Gc&fj?~Rn^J*>J{*V+Pu3nvZMtItTY zXZ_+n*5daOb_oP`I8ur}&{5CGidEwbrgNnOt%Vc3vfj3mqO&>K?7a5(0l)5zj7WQ! zQ>VV)sIF~!glR!?QpzJ7#YD=f+oEOa2)%i!iyv8nvc>dt!y|RYV|C2UYLj1mj5#N? z&3+qhc6q3SY_MC_Yv^RzONZDIw%G!O9FUQb4ssYFq`PD%8D%fUqTdl#v6Hr)`oiW?^y)IDKt zr10i-!Oa^9`O*CR82(MT@sj(O<8NP(6bD}|n7PGU`@8V@oNHP(*T>odrsGF(VnN6b zlOy8CLsXtFq-O9Mc?3ee%M>Kv%gZZlsl)0l?8Jp41$AP+ z05&p+npL#Om@;O1vdla+mK5Ub3Y@5Nt4$pkoo)D&&y*j6M_XMT?kvO11r}hu>zdNf zPKxia#<@twa;}djFnwhlkeVBh8RUKriG3ZFK+J)T@q@aMS^`mzw&hQI`VbExr?%lvYM)v#wzT?1}(~TCkQ89Vjpab5bF;foVzS;}CQJVxjAVoH5O_nH=lx_IIHfh2wEyx|1p?Rc!mN)j6^&p|Y z7pYM+xG0AxU&t1jWwZHQ56v&C9R(wu_@L1a{IT|e@f^`4u51cdKG{w_fh)u~=SaJl@!Uu~>kIRC9@hTQ`i$cK zkxOxrG5pNT?7X~NIr(=p3m&Ewl!Gz~igRu~xOMXmEO|_K<`&%TB_VKre*Ufe+t~$$ znYT;Q?o@!X3QBVGiyju0B_*ci78ELTi(>NX*O`aw{unaT_QGiHHJI@u?ZC5eqMZaZ zfg>1e8$Z?|ZnR^}D95-_j(p^9w7qmJS22MjpX|V&<|Y~9ARgu*n&Ql#w)^=?vQ#t*=9Q zM`FSc|1Og!R#ueN*HyK&wL+s7b*jT+Gq#_Qns`J{vA#CSCJtGKz(?7}Ot2?3&K}i9 zfQmHIkyNMA_QJ8;1jq`~9?ykoB$(hR8|S2$U?-Sveqrv8Lx$gb23%4^D|3?4vvYFt zURC`;%_+E*kB^1(@(WRIG7Bm|Sp{Xe`Najd3v+MXN2R(bxw*ydl+HIkusQWyMB{9Q zBW;9ZZTOSy5~kVlr*LB?*xne=VRD2FcISvxA(BDCC|B_)C*fFozK&z;9PXtx4!>W^ zZIR^^7Zw&_9ksf#gq%J4gqUIIFrwWxcRa>N7bq_fQJ1*LoCSuwS{myrG4zcRbcjgP z*?Dl5w;Z+sn&EIKkZ>3wFeHQMCTLfKjnmQ(`7keU8BHv=e8?KNcUO(Kik#*snBX8D>nO$S(r6dKXqPz9SSS7jpqQOhi>uJ)sNhbv7f)~$ zjCGEk>=+4f1VsMR{?J)TcC0{>kt~0hpHW{{2!>0m>WZpc3#;3UtC}h*YwOEPu~MtL zs>>XuOupPj;JV7<+N$F6>Kc58Sy+pe*d1k6&8T`!0FIIe&^E%;WQx6Ps=aJ7SA;xHaEt@PWAGEnkq9_D!7gc%of5O#Q{Cc5+9!-~ z5KVHCVTI}%mrG$cva;_yY_2J5uPW+jZMa+8zH?8+)OU(Dbh-Y` z$<$y)Wz>Vtq>4xP8Xr}*wAHoX=ux85pG(+N8r0bK1cdpFZhG9(@wm3N<6(XKy=L{@ zC*^44bd0m$Pmq%c zBR}JK3UvRcxhtn|qvzUP*7@3V`FHkC;U~~Sb91sPOCPp2Hng?0W3Q1v+6>S`3{o@j zS5?<|rv&F}s8zQsKilQ9=|`@?SC0DTCv=?R#ycd8c9M_erNjIi>5_;Y$YFzN*+);e zy9%0SAB|SP6ulJBNud+ziBJ`#TRx9 z5fTH_U8m1Y;j)MEQaXkpmsj z0jICLJbq0LjI{6;paDqt+_+x?2Y`$ozv330ASz@N(IRq|6E;)N%{79dHNge{U$m7c`D9R)|@qu_W z4S?q+t@)739~g~}IV}Rn6Kv3nmIdolmT*fwFLG)4E~I9*Jt3cJ;`|z%S^T6Kz+LoM z?Gc%?*#5k}W9(FCF*L1?N8%)IoVK%Qva<{Z^8{D%c%BezY(NuSg_E77T26`Dj>$Uq z$yyFc)0|{eTqRT71UkGMGp$bRf9vCMG4Z@8Ejc}-^nQMIQ9e$%z_KP7<>(`Tu&NW| z?rMC8-rkC%mmr^BUI>i+s~R42tWM+LZ@>MWh?BAn!!FoDOPz{9W7NzSUtPRUc9R6uGS4?czy zM8VX_O7M*IpSF~LPO(Mb+Jn3?1xo#Y^zY!|QX5Hr)^`t)5V7TTOx zV}JaoJ&~sp3)5=UHyhMBRUL4jONE_k9CwI<1Hp5@Lw&DZeWz8OTc>{TSe@UYzK~V7 z>zHVb<7q?A@2~`P9ip^hMK}q7iGb1ZgydsgrK8=YW8B1$hK^H$o;^sYOjV>|l(tKqQps<=iYUEhD3CosR)GIDKrvHvgHH$B~K-Pl5p% z7&%C2GV?AYiiAlnV#s;CE2&PCTp)k(H0OkAj{K<(@mek-ZJunry=aX26}{c34Yq~a z9*w`AbnEVeqK3+1?7#7<>JQnR97~Hk$zDvD7l73Y!lVXzwb&*OiodVX%#TbkUI44XrKdbfA9<9%~mSJaq zkC9~N-YPD<+d_`f#78=$Q~x5QMkfWoLRY}Nxl`RC$t^w}ojCvB7BhYdo#Pxm&L(oI zn{te6GQJd>?Sd(Hh>_H^X-=e3;0dV@u2M9UxgPOTe?73? z<+S@{WpYtt&fVhnR?Lsr!d$`jZ0aXiZHYY}FlmksFHBd)wqcMOEJ23M$1K#OCAfp~ z1qOjCc*$;5D6RSb3JULtmkh>YH)(`)#QiH4ztCL z4B`T6zXYkNaA-(~g5ovm45GqCQM*S0Aw^txNF@*L2La+m+J9%Ijo2V$+@dbwf(K!6 zQOUExp6j9fP^5-2M;aqGtU#TA+=L-kD1^KQH5MVyv;1w2s}MR9T`FyN71YsmSBaLZ zdyIjjdr0*6zbLYV|mix}A9>k^G z%DZ*5p|YsCvXC4P!F-&8)R7z-7pZeZHK3ln%%Xdy@*ptcz$qf+A0kC;#G=OPmqzR! z-14NEY(!Irt;-*&e+Y@3xpTh`FKVKPaH^YZs;gp}vyvDX&MIx5Vk%EO#SM88z@5sI z;#V!_6#S&+9H-|knd~Va@21r9N}cX3m~V6LJ%=L^vfR5xCFqm^uZ!y1@|x7|+3lab ztd6rn$5pB2EQ9{Rhoag%$rM)+;_oIzE(c*!55m-Ol>y79^N2^=MGBCD;+pOh zx7bH);wvz6xU|6Hu&MotkG#%(6?l2u-YDmb$qc3TaBY8+b56@RrxkFmPf9J033eUg z?>G?msrwmI%l!sF2N~`@VB#FH(lgG`End$dM%Pt{bio_ScbXd^_@}x{CU}TJQ+Yxi z7oonBSl3AkAxz?7d|oxiJ8hg#@)*Z>9lOY-F4w1h?rnV_fiKTdN)&f)km=*s5?Zx;~%I?Rl&@| zuBg}-to_N|cJ=ms*JuA6GJV%6Q~+&P<#e7>+gYOHD4gLU)O8i<0EU1sq-h{83RE6a zzJ$b6oa3js3ILHayc1!EXj@!Z?{;mYdB|_ks{A_-8Y)WF&9#{MCF+ixV27Q@(DrF7 zAOOwOW%6ZxMVmUMv}H&5<(1r{i(IdbvxxxOPWDMhLZ~*qBru7FIl(z$x|agh<5Zi7 z(cgz@f9<*1CggZra#HT?l9H0Ts&aBPC$rG4gE8a54Vouup-d|!jTC2iwUTKvw6&_n zb}UOMtbdYQ-sW>or2m7Dp4DlrbJO=i;i|9~!9>ptjMzXdkcN({fRGD5pcbRh!94sk zTp&`SLr@dY`-Y2_GRs|neG!-0o&Klm$?)jZQ?W`MV}0*oSwl-}OItHp*oJvJtg`9u zR)Z6$5lWQd?!hM_LugubGpXKtu1aJdvY-YJRqxQKP{N4hKVHz-(A5+m*a&-g5G{M* zCnN#w4G;l)P{>G#LN-N#m$)o52t$zqNn^70**re`M3W`_3Vr|_KqbV(rpU(M!-D|y z3G4aWksADf2V5+x;EmYcZEX+;1w>>MxkgSk^Zu+K!B8A*V7!acgm6$ghzb&hlu$;9 z86Mo?LaE_b7M<}fE&|Daj0Z`hlyOl}<3+rJkk9g<`GkqAYwb6!)npUMM=g)B*+6>> zlqdT^;hv`LlB(qhbW73U zsiwOtblgQ4!qWS}4?WO`q`TO9t04boJ30~Q6X8hBNBH=IED~n46X`xMJMhC)Ce~3e zF9c?+Ytkb}TS8QDv6_}FR7DpA`~0_}oAMZIsP46^k0~GMeCwg>9054ia+hiWd0kY~ zoD;QO6SdtFNiN*FG6l@iaaHKJBu;lx=(-E_eWcU8loLG?r+KI9c`D}HUo){fOlUtGbvy43!{ zQipTTy2~6dEqA^MEH-huwA|@3!WePRF0?&kXm@#u>x~sYlI4D~xi0)E_!tKR?4F5) zF?Ts!;Nx^R@eDVS9#1gcT`<{0G|5w>?It4ZxyT@aX|BnW+)^iaWsG!Hj7NB$aJEB) zk@bn0TX_2;)1->@45jMf-TV0J7FbiR#_&bEiADHQ$BXD&X*&ym(UV=}ObwCgdPsG6 zA`m1DIY1f=DbfGJpbe=rFj`ziv)!d2ZBESO?WgAb685pf!KjRf>Gw)%swzy*qMWSmTyU0Fb+3vmGX9O6QDX*yMY(aL~ z$xsr2hHmx_fF|cgVeppBmo;~&%bDHed~akg*dAu+aB-n0e~eWG<{)70AZZj+FKN1~ z45lDv8RmFNXS>Es*?xG!7Pmz|xO@H1k4enVzxSZJs;s3RgHb>{bvss;z8I;&8+N&A z$C_*gA8(h`;%kMBD)maUVC^6M4IC~k@J!J4kk9bToZyx+(LHsNTQW)++5<8nVqr`~ z+`?i+6Mz`uCu3Ibi6GPpJrBtuFQGB-n&Iw!-}qnp(eqezMsZeAT~%{OQyUq1BMlz~ zM8KL98X7(21guk?M*eqO{(wJdU396SKcNXoh3P`fkOxfazOTR zffLBK2Yc)-%OsT^p5qk&E1uJfhNQnDPR(2R5r#>mt9Et2)MXyvExdx*5C(M#(gxf^ z>@<>>xHKLrF{XxLppER9)Y;L3dS23@J|w)k%;La8$IC!!=ufJDfFS7UKus|uf>zg| z;;If2z<>I#97>#S}P4i-k)fz#kT00jWvPs1xIvx2oGj_nY*-u+!t7)pCuU z;Vwa64;BRj)5+64lL1&TEs!bD44!xfPddX@IfEzH^APEJil%xhCV8qRdnHfzQq6ab zU1ED`*S^S@^!pXfoh6kur8Q0Ws+uC?S$ZG*VqkW{z$tE#hh#2KqQ?{Kd8o8Klh93= z?2$CZJ!zV|3iwD=Jx{FfDw^dgnB^Ql(>X@pIZmG^KwlDao8bW%RqA@D>J!~gG@C(S z>O#LHJ*RkW+sJvY@$+0`pLO-^qcCPZ+bL$QOAP&Wu1nl(7yd$T6>Ns74hiU@lF@j; zhewj0Upmw#gDHq#qzhBQHGZZ`tS&DWBO%i~#5(Sb1bFi4Jk>O}l*#UCSiC*T3Gga0 z@DVO?zF_c6pvjMJr=ye8Q?qWRCYKf#Hn!laZ*{R+eNb7v(($*2&XKw?J}fxWsJW!FmxwEMQ*OCIa6e8+`9+9&$E5^L{QioT(|t z&T#5ZoJG}j*3v7eKY(bW&q?af)w4g{J?S$?U90mD z*KEwx^DwU=0vMr)!8v-_48bEuwIP*<)E_BY0qV~rXMv7a(i9ijEDzaS`^aUS)8+@` zZlphaP>D~02q-fz;cV9J?YwP2-*6MrP{kQsk2$D}-%4zuh)%~<`e2o!%D9bp+ z4boDOwaL?sjRwxo_5*j)x?R0kP0GNWqKz0IV zu1K^gtDvWk6&$YPFv&64PDkiogG<6WQ3&ZHF@7qc6-cC+dlp70e@(JI+?@wQu@ww> zFj*^YV}@#*UTw=I?rh4ykQQmTShsPL=42K8n`O6DDlVy(9?_NOZj+9^D*S2J2rbv_ z$~y?l8@mz@J;w5%5C7z_uO762W^l?UKi74h*a=+}hB`St(FQHVQQPV`{JI1AV6v4} z*=D#0FQ4TeqgNP(nv?>n9;q0EA_|?vEKNy}M`xEKoqq0j`nBvc>6V^iCui>$&)rHd zT}uW;=U<9(PmC_p@?Mgx(z-+5o!ERu6+>(4+FR=`SLsrox!2w%*4stDE`JP}ukiN7 zu;qvvkE%Q+RA2mVwr}qYuV2U3JM&Obue~m;_okC$5u=dMZU4eLon)zZjLo}zEgf0~ z5MgATmTT*!>+98J%pHL)5?*NJ+h+l-3a%_-(uuE87_Rci?+gqOs#*mPWDs!pLZ6Rt z95UBULiDN{g^UF6nYvR4RA_FF&1W$Umt~C0EC{iK-A6`&}m)ax^VQ;Gty-kBn?t4xy+vvV_Y#X*yI6EgSW(Pm#A*yvAheKKson6LGvIQoN!tx%6j0$$wjTgZR6)9&S>`lh9E7s%WaK?!JL#K?o7QBZ_;Gf>yU+ zG>|KT?yRx2=+@Qq6LLKz4ZDIAXk)17>+WSTDv{w;h3>Pcl|`mTtuk7Jko@bETEGAj zn7i^&2BlYy-5walUAv!DHzQ-Uhxu!Y!mjx?q&loP6@JaBf-sql`E+V*0fa1+9kD2s zOQh9nUet<2!i+lLw~7c2Sb07|`P2_}nmGzp4iZLIcAW~{e4u_sNRF@0PlKkByPGFV zYM3B02PKPMx>tOKqi~u8-;0nO9T$ynOgxi*p+oxP`yWF(ATVc z0LXn~&evk7CVMZ&1n;R(`}`&iSudEi0t(~f-Et~S#fY|zP1BPFY`;QKyzqJV5gLTx z9wi$!pFcy+{O&1A;{lyspICgx^HrEXfk8({aier~Opk6)pVy_;vdn}Js$}W3Of!H} zW(!YCm3>|&)Lw+qg?(9ucUeXfRsp8_sYw3udl|i3m=?oJ}y@4zYxVR$}N1U}T17o#Kv-Ys3$X%XgW39e-h&lUwZuld_R=R=4? zf4-TwxXxA3bPeCw1!8mEEfc=2J;IABe^#GQRiBO!x(L@Xo)(=Xc9Jk z+F#<#!=MT(GM`BV-mgJ%!f1+XH!+INS~?6?mtc@i_Wx7G4`<| zzhl2woFb{*rcsNWB9;4>NtbbH;4jZ@E`{6bURSTjOV0WVJ!EAQ!)KBH{DBIR#CUG@ zN-lB}>{(mHl~eId=oE^6%ctthmvGR3kII0cYJ>nS7R3KIaHbPS9t=%?4D}SPTd94Q z=bM=8Io(PG6k6?`3N39Zne`a9cQV2;#&UDG-7=v<yo#}fyaq$|00CbQGIhVETnY|7v!e=yAU5M z^-ocy`BdDwBGUu`GbUJ^@FV^ZG;zo$vn3tF#H5=MtJcKjRA2Mf+3Qj2W%v~b8z~2F z_4cDD6RTH~0dm)A9@zCj9PF;7nI*-oEBu~>l-+E^S2th5P)CdJp%DmKh3a1MQ}?mZ zko~Wdo~GZhCjz@k67{jUz1PPP{6B?Yk>znhz;wS6eE~lueY+3uPAK7DxKr7Hp_6e$ zZuPgZ@J8M8>&TmtOlLwX$#ArKv3#4kz3Zp*6?3w|=Iv8x!jtq4yh|pe@2|Vubv239 zW7Pnj;TowKT;UzTU0a-Z~=T%&Z(hB!dzU(05gg5mK4N+6vkA5mB$b;BcyLN@!K z`JD=`f|w6N_dp0RLre@s-HUsE`#T#>xo^JKNTI1(9w8fc7c}P|z{W(392%J5AiXdb z9XH+;bX?yYB8(=AOP5!M?hvKy3*H;5=E`=&8xBU6q%_^6aBW?ww@cK(Cg6HS9=v`B zt3G%##}3{5eXB&=2qH(Sz_cE+X#{S+mxSEF`v=H1!2vstNgr&mH^kxE^J4#5X|6Ic z*eYEw$8m=21TfGn{uDcILaGM-A=IAYYwTyU3Yd>x^mb+xg&oa2O|567w04vn-t{LF zAsQ2Y^Z@6m!cU~Xi4Q{XNrvi_GqRp9dw4u7VyjPV<<0=ZhJ!Rli*{;JJB zlB*0yl6#uVIxXOs(=*qrV7E=dc83;p;1OwN81Ur_19ImW8BKi!QK@u@77P57RuN}2 z-^5C?(4xBcE*|*M$z_I7`-T%<4&U zBm0WN;Pg+20};mx1M{^z0E}p!!Gd) zt8S{>&P0UHq^KEa2wbmmEHA2Woe2ltl`}M=Vu4)28HIV7+(@#CW zSw5a#p@_1`r-!PoNRjGAS&or`da`#nWS5$?^|UZBK$vmjkS63!(L&(c zdd#pi^NLuCrEB_(G|VH#J7Po)|Fb=wOH8zAqxW#c1+PQhAJv$a770ppop4qlrpDx z#Bk`%V6DHTg*?Qtw!_z;UK5h@j!^=iM7>#Dfp-ls+lE|R@falmliO{NeChERb!&=; zpda*i=@YQ_0O(Tst@pnHg1G!{0vV6-stzy3PO$2y8^S=6MDEO$@JIPE;NRj9baW`e z#I>fGe6Qx6YYD{$LJdiS<1B@d*|>+cp@+fu;pnUJJSru4&*-A#Hc1#gy9o5dcte$t zDw(c*qwC6iq8{6$?NVjCc7OT|M!l(~5wl%UKzx!23<>+K_JhElJr{QiLui~tF*1Yu zC3nXPe+{f9wR4=j#`UcZ)%Jn;&$H1f-oCLauS~ zr_`TVupc4QmhNv(Ncm1_Q+M;?NmJtp3B{o#uJ4!y0tY|X!NkMgXoL~ zxbVSoljQu=#zd=5_7U~5Ca@hHzRU@lp$K5;x8SP&bTh(!kPSWkEC+nK))(>VVSncn zZ==R(D!5N7>kxIc6vwzwgOFs*eUCeacd{aG)zFZ3PG($4^(~whdEK9R-Eo>)>w9cW z>*iQl9qW76M+M>&3ag!3$D5#8x%GI#atgf-ThOd7*8M649Z~1-Y@_zsB zNKai=*Ssq$X=slAkwspq=-0>r%4VL=Xq7u?+O4b+QE7wtNo0QcaT;N64}&pgi4-MM-;kV+2gwamvV$rUyOiCd?6(pr zL4&9=ja_u11&i3(4|gQ-)X`Q{!(UoqxtwnuYL<`pW{=$=fdffCbuANo9kfYQE`V** zH_k`Iv|h{~Db_6o*haYthhk;`c)A&I!w~ZJk-Rja@EaE;sF>kp*%R*lOTM zyhtldByFGOf#`Yg#OKG;Z+L>{vrSjWVkP)2JRJ&q#8Y^B}PMlZ; z9;wXRu?2{hpko((9}-&d)fAZ@IFL{p^Zet3#PG6acYIN|Pme+aju8c>{54CTgdYvH z#*RZYc1`cGNoQEYbqNnH$NO1vEt7qj%RepPZ0OKp=ul$l(4pk8HkU{C7cg`KcwX~w zs|6!{7&eK7s~~KNi@rX^!y7FFAUHV%AI(!C*uV)zC7g&0qN0CKqEPd{s-vzCgI>c^ z$TQa5h{9T}QA|bfdPK^=Vc2zzgj97^DH42Z8wzRCP(YH`+o8J=o)^`eOYmd|l(}P+m*^}-EkJ{Vs zX7f`j1EaAlS*ugmD?zEfYD!ek%Ww9eJm2h>V=h057NjjEcTr<=^|hhx?czd0v9=G; zNxu3~fe}_68?v;DGcC5B^KWkw#)nkNMr)WK^q*(Y~#~-4iz&Vha z+Ut&w$sCO+A7G)XC;2|xxofg*wCj=9@P3M)8Qv4pgh5d420Lfga~Q)`xVNXX#dt=Z zNg_yceUDLl52_X10|Mp)2wHSt0u>#s?C|*TJ!<&J>NUzYx*1vgpdY8j9&k+G+4Xg0ySMx`*jS^kVm zWm)Glulv|tt@|3WR!$EqI*TFWLN2U0jBt03&$CRxf}sS|h!wvn3InuAJpUZvZUI0B zLxyf^WF*^QB>T3?aWD7O`#9VRnriGs-FOLPk}1=^#$a)R$;9FD*sSr{b>{x~UUe3}JqS4j{$g&?Js&;Z<8e2Qo( zP$dkA()vfKzmXA)=Y;%)jP@v)t|MMcm-nmtfDa?4#)bX~B_r5FU|}=VX|bVUYZ%-4 z(8}|A2v#VSu=;z3$t>RxeBgCn8D4T!jc5h)fKlk6sYliGHJGX-=kq&Uizf_5#|nI< zN&%j5+&1)ath=CiO*E5WHR59r;}hMZULRjEe^~9eaaN(Fg%RTrOvL2AONPQlVzBuZ zV7(Tl60!@A=1OP6!O=quz4VF1qI(a<>aT({DSVS@D{dzE6T7GG`s391X@rkssXc2e z9P^w3vWn3wv<#P(oKh`Pf4I*=e+E^QD&Ptqru#{?;(0<8I_auS1$i!HC`-0rZ0F>&c18F#GJQxe&9Y|(Ta zG&w(PFdlN=>znOTflx3%!HT|nH>QM^&>_ic?bm9Z(&!)3=nhaKn>ahdTxkiNKko}E zCjywlJwTWOlvM;i#HYg*HslH0<5jQf8fvN_@Cf-SYlm=@af&Bz`cv$6kQhE^t(%|o z{h)7_e@WEd?~)#{^;IkqOO@nHRSKg5Au4|csiX!M^|K+$L(##@v%*RTYl(0SvMQS4 zQfd-VYT^M3nz$94m?fdW3saj&!iNFh=ccWG1#D@%+rIx(17WWAf_rlT2T%cHd!Ib+>h?(ZVXKKv_=P!fED!-%e_-)a8 z_Qs~pDsF0j4ySfX*u9s%bhUdJzM(-t1sux=v&8dgR9nA8=COSUV|$OH-^lzy^v7ry z-!#PO_Y#U09{xl@ZXCOqky_Oi)046lc}+C?@v#M#L{*`JrCRx@C-V~MzI*F$efd08 zBf^KE47y7-!vaR84q9cpAnt$PXo6ayg_06ZqIbpsO7|_P?@sF&qw9*NHFq6}C{~%$ z`C_vRxT2wwZ&z+xOGEJ&V*`BjC*MM|S#a_*k(kV%>qhz(byCub4=|9sRH#ddo8nFlvB#@%MOBiO5uw@z{$$yN~?G{N+?y@-r5R$JL ztRWub4uFdkw5A^;hGCVb-UD)a9CJD{YXz=}5JV8;plle?K}|v`@zT9NN_!qQ#X^J( z7FY+j{;Kd$dose!=5r#Sk&DTy6oGccWgx(}8uk$1L2R`mK9?Sfxs+|eD?lhCkHY+j z#PvrwdNw6yMn;BMso%^+<`z(awh&X!yxsh76g;TMGgw@v6U{}j;UtE7xTwsjb50<%&R-4M|dJO!%SAT1J*|PiF(KRNv-Dh?(pmH`Z%9^ zj|#05L>^-HH)u6OqwTrq@B7Kb5tWaowD3kC+(%U6Drsi%8G&rU3b2x0B$Bh%B;-S= zDHf`eK8Vl`;x1LBcRqfeOD1v9a993~OAk)iphWkzcOnJ{{6eTMMh%`3kwQm&g+u zG{PqlY5R@xUR0I|C|F}f#Fa-Dg(h@}(jeIhBIp^bk?`Z#SDdK6X0_Lw&|J=61%ES4 zQ;~#_H9o>?7l~RqBI=nHaMKk8gM(j$;u><6{!JIp2-B~RM&`98U{?5-=~9N;QGV>a z;G`uqQzM>aTNG`1vEsD(omOfqkOsO0EL|ZtQ^jvUP5$2 zYMqewI*h+`je!i3XR&A)BfGKdW%%;&otk}n(CzEPTJg=w;+6}J{5{uhnP460jXdN` zum1KF{jw_P0sUNNZB=D`I@%3P(p3IzKFvwy0q5}2(LJZoz{s*eP3UH(giS#(z!fKe z7}6*jjWTitAuqP{Px##eQ7Kp{EEt(wrj*aD(!{y-g!H3O;DIxi>${qg%35|p|4qf( z3-{TN@rzV>S81e=e2UpO%hYFbY19ndufHZqWcPym4eh60&|^Du2nx%=)(?eL)SaTb zpY8&)v@<()d+1bPoRk8+Fq4(gVHxY)qp{1!3RTeYZ_^}fX(lY2q!J$TlN4IytYUIX z32aVBwn)InGp{!Ya1iXt@i4hmpTMGk1<81ImdPSbf#}3dH_~QYcr6FF0Vbh`o^{_> zN`RM$zlDg$_(`3~e4T2WwQ%B67&Uw7sNiY83C$y=;FS$rN*58Cj{wXxM&;K|l2_E! zOJD|JQuVj!XG(z41|kvsgy`2|74K0=cAnTQEWW4Ijf*c3H@x)vTt$cdu)}4;EFE!V8dMfYVi&$k#iSLbq!Z!q0dX2VVbM;n3+?)tBy7s4Bsk;y-4HHC zy@2!}x2Yc(kTVsE+~>VBd+IYq+YF;|_09eIP`&cg7SjPhqL&b|Azycu_t#OzR)nh~ zgYz7>G(A^=>NC#$V<0XV>49a&|jqa^%sl!5*{ptfHJ4b}+~ zOO5<@?O%*h>cBR^T#6OwOC=R;Z_)$9=_qBnZuci%PTUy;Jp0Lfu*ABbY=#wb#G^`Y z(0z`XBB)DY(n_}Kq4SucxF~CqSRph^!DE0dBrqd^>n zw@<|OgqQT!5I?A^W$17YqEQ`;l(q~{Yo9c12H_lwgm5$`k<%a$4#-Crxh}}dFse^` z`|$(h=L2N&b<@tY=Rc1=Mi^J#Nn})fk7jn8g~PbAdQEDn4V9y1!SSZd$1=2}Gep~= z>>MY|M*01oYk{X3j3Y5Su~Q9^b77|YYUfsVD`R5XRUbRPzKQy8p)-T7-pos(#d)y) z=a2n+ry@!(aN+}kV`c1+?z3wkcaY((aNhQ&aTa2XFqjQ6) z4Hp~qHNC^8MWKuvp5quUa8V0Yp`uu*(nz@2R&i<(e7uS|y_{_@L2-(I{qrxRZ&E)* z1VjQvq6^KVM-8C>#5z~oCw;?yKJZg0c*85lj64ng=;igGTy@KS*=U1;Tc&)Y%b)zp zK~g%~=^d=_S3%CB(8_`99}7e1TB%|Zr?8P2SODzeDk{AU${Y*npCtD( z^mpzt3-s**^2dBvck{|HHnBGU66im&Fub)sK`6ZhK_i`7(P)pYMnjb3!y0$*3ZT+}-EGsz&^J!AgfRjSe4~QQ{&ij^$tPW(QR=)IYN^G4Xu_(T!n(yWO z3$nv3+vY8^>?O_a5zg)bqwalcDgO;zEb6^@*cWxZ<{@Hz+s8C}+SEh+X^8$ozV|kH z^ZImy#9>J}`0U`^o7|*_Dr@skFbftT=)?st<%FMxyPVf8p54)neO9#Z72BGlL-{-T z-S?$S8GUEKh>Jd^0X*`sBC1R6ccvLA?}#*6khW6v9O<09DP5GDDP&lr${<`q2N%J{RN!Jycz+W zOFUjdKr$E%%aB+LO+k{-Zn^jUi8gbNG{{%N0f~hKp7vv;i~Z##RRdX!@;v*Xbk!uP zx1xr)20zIAuyQL_LZ~XXxC|03PE@pF!=Z-1?*af zkr>CV7VFE&1zvUDM!!%xK_UXI@ol)O1O}r@x|OVbYN~I$p=R@?5?YQ)bUNIo<;0`dT06jEy2r-un0rlhtk6IS80qhJuK&Kt@DdX53o|3cvwirR zX>kPi10yhYLEQ^}c6=#6^*pErD%B$ni+7L=#iEcXR3{iaTLVuLx`8nz8Kh{q171b{ z`n9{B=z8i&FX@%ACo4@wabsrvXIDB=eBl?Q@L&)VC^M~~I@*qrlVA%*2)7R`qB26r zoH%1IcgN1zFV@h{wPIX6EBqt>G*Dzl@HqT5AtwgIMer0aiiSXiy$bo5zGuCeGA8hnYZxx zXV5I>&V?Tg7WL11;1l2g(kP$dUytc$Ypphq-Nk0m2y}?Q*9h$P98~RpJqGIYEuGzY zTvFKmWaZ#_6tcARR59i|D4i|HH=y!&JI|2B#mGP>XLt6Snx{htVG@xQ5oH&xwWoHSMUAP2WgJ8c)JxEGfU?-k3{!3sAWl&Fcz7~f%~2v`nSyk^Us0O;BqFZ z)~ANwNlk&??lKPJsPe>B<#b{SXx{xxExWA6C$0jVHES2GHs(i8mEaS!k9e6O3@q@v zW|#=^A+3N6#49$zKgh4^2U1 zoX0At80bA6YV*4>yL1+aIv#0f(0oe-^)27?D^uBC7RqXp6tgW}IN_nxj?EmKZv$?J zx43X@kys9LhNt%6KlHuLKlIe%53WB=a-J=7d=HM(57S31v9L|Q!2+mbc}7VB0RS1W z@ZGk67LqjpC`O&_IgYo=pLk5+WZ-ZD0mc^;Se_h=zM4E1@ge`}Z9X91GQ5F7D%GpTs3U zW}giSN1CrO!4Hw;-KoA}Y~C&1-j06t>LW=^`+Mz+$L0(+15c)He#fc@~51T|Ge;#_$`H)JcA)cBx-(vJmvQrzV8eQwK) zLNX}TvrvI%SpuO^P7^DftRv}7MTRj!UoH3(5P%6>LQ_g!47>!PQ-U8Ec0A@Ca)cye zYWZ;#HQt||myem7$xGf&i^((c>&8^O7|qVv8(5|&G&5Q~`^R~#>VXkjEv#QNhY^XW ztu}v~hE54HT8+lvFm9JSKRz~V6Xf@nS+AO(?ZjypqKD!18}$PgFQ4OYH-I0xg?IWg zizqU6Rw+I~%WL%d6JMZx^lXRiPpvsRufrnKHKLPgA=mZrwD!m3(sJ7PvANxpn{)1R zXZ?#Q`UBJHGWvbf8cB?{o8#>aResJRId_TA8$LlN+7uPB%4m>hhO-m%>I8hLS{+f; zPe0t|XV)8IyZN8)UfjR)wj1rvS5nk^c#j__5PAKrw7mTAT#D(LUUfa19W-`+AQR}M z*pHuXF!RgdbKWXXe|6q{$W3nZK5~r75PUm`U+x*7zWYPza zQC#$nwY{%8zA_VT<}!KP-~8SPGo$!mHNV_h&3)svebq1R_5_&SLnmU|bbdx8*UPZi zc)CxUZxQk*Wv8lXD66XLYN{>c0VR1k18A1GzII}csP?p4JiWYl<~|nP9O^hIQNL%W zbPu)@Ktk60qGoS!L*c86D>+~)nu}f?8I46w)_SE}aM!e0X)Clo^zD$KhRC3sRdp(zo=&kf-WB=Mq zwqzeXqf;Clx5aK1{4%$zokI>;A2+q%ovDYk8=`NsSR53cJ)cMdC0`+^lyp^~E38ri z7d`H;!aEog<>u)fC%%CXrkcH@$?6DSxEWHE6lr&Lu@PQMyneKieM}xJ&_`vrp3IWN zHey!Acs~?NW=7#2qQF$>^KPIJ*}SCi?1E0X)}L0JkOgRAokZCU|Zy&R|+#$#D{1cztcDgkOk&4eL+(S^+$t z0BT-reNAb+-!05cQ=6WSP>s#ZPKu6B`$ZG9xC{C?5%}@&!^9!A)h)g1L8|%zdJ1{& z=rh;(Ui=-})Rm;w!%h>exd-Py#B;1^7Qfq@s`OHNRiju)FYs^^ zN$_rhOu7a_qorIb)=-+%46U#8-!jxzd7bl+#akaqO|Bz3hfB84ts}sgPGr`FS1t$`=&8|hCYBJe~q zzq7K__*t09?cAN#YYH8CVt>DF^raKMb6Sr)s%(95yZs?D?|O7S(|#pdf4c5r@OjV8 z)p%EMgwOTzoEV?fZawF{>hb&JdUsJ0lDco7gX0ffSt-K2)CdK#PRb}-iO@B_hcml+ zF11?M9T`oQ|7cFvcvyv(U{UBOJmk%AtN>7*-sSIA1xX!mdv-U(SPya(cIlq|+^F^5 z&NE&J|0B{yG3VRy8kQCms636S|C?7g&6hitT`)Tvx4o2%Xu5cx%=BO;(jv^%RSw~> zB4dqr6Ew$Rn{W@2J4c1gv#oT!m@Ag#xim?3u01uvd0JUo%ocpwyD^X|h-ksRw9(;O z2`uEUT9bBH(d}}-?;+-*<)Nm)ncVVN6DNIjq*1=O$n1NmNfE*Hfn{*sdxQ$9@|Vkz zw(@dwdzdYhP*GNfgM(vcVNuB91eF+22R$FuWs@a-A(s!{*yhAfyGj&AT%9H-%vP5W zQpUvSB^g%2vBFqzgpnX*mM{|#cW|7fDhvc!jym8*m5|{cVBB$Za>}Pl9T`iDKiEfB z0NNW{19fG1Dl4DK_kSFJ2%E|s?X=HP-{@CaR+ZUT)YuEjSGG=jd&Wud-5sf}5$}{8 z;RPVW4F@0Ls%}x7bU97V&rbMmB)d*}4w>d#S2$w=7gK;7NsCLQ`4zLyRA&RkM64kl=Tl0mKRt?%Ab{CFPAxE$Ke}vDvgw#JB6fFlT|clhL&;-{;>Q z=S)$0-rEt)pVuoVuQ?kYpKm}4+8@@tx0mu-Ej}mXvBr9vY__($3r}4ts1Mu&W2dMT z)d~nO&s@d>=JQLJIh|&Qe$`J7{S9049y{mIm_1yM*D0?D_HUE(rx%_-?)jYcGddgw z5;(p>*QF*AHAH>7JUzuqQN$1mWV*I+_B3@gbQeb-x~^cC>bnwjURg&Ann0>Bu}vq| z*J66i`3mNB*5p4K*+O{aFjQjl%2b?I(0gWZ|B4?QGEz_MmefDhUhyacKM$*zaq4)j z^@0x7;$|phU>lKNtR@-!71{_lLEWa0yVf;ocJ>q}S6gh}$D&ED ztuQ^qB{8xPJxG|lIXO9Tn$V1uV_RNiTAUA7p39d~QA%XYzh^NaZItmH%hNVUB2Bv3 zEzrSHSuXhBm_MTbHO4F!1g4s&(5g|M4qc{PWlH)av-m?)2>5#f8m_djVL0 z{}qmX!Fw&sP{!L`MVsRJ8CAkZ1@F2>uf=eW1-M?joZZxM+Ea+9;uFqXsj1sG{A=;Y zM+Ai)_peuL+>C$BEALDBpfd^>+FY+{=6cnV)F$S~_wHDl*_y*s^z`cRR4+dmDGSVp zK}JHYF7P`QmmF%^hCsuD=Yo(1sv-&=zy1fF-dW2U?P%$IZZJs&5MYsu-g zUi%Umy6;ElmW}mSn0+jf1@@mO-bfun;m11eu z$yZvJB$BEWxK~#v|fNV+&@Fo)XyDW)QTrCUxyz%xbEQe@~QV{yhuKY>K zor)jYIuzn`B zpgr?3SdKzvQuAv8K(uBso>6N#KWm82k{Zs%OYH?YW3-T=-UbP|pz?_Tj2R>HfxuR7 zFat%Iz#Wk^p~JEGGgs$H68;f~CmklMQNC!B<7O(yxQG0wA{QE=+Eg????FseoBo?~ zYo}N~l{PuD9-(R`u9PI5$g-*v)KOG<$P$cdrSA-D&Lv5GcKLm~t@1Ikp_MocLTr*Q zyGwPmci!v(kM8+q=tIqLOw3D53hs1qL&r_Q_^oHLn7Q=rbkg>%ll1gn(q0bz7?;|Q z8<*?pbkDFD=&cAm8rh7&B(+U%#GV+sr87?;~^=CyzXk%lm>v5ILCA<3EBcbjp1M=M(}ZEiq8l3`%}dvsKE zAd9d|CT|~Vg<>&q>=uUn9e;4OK2q?eEX$}ilaHUeKRQl35M+Xtxt&fyx{akd2Q<}8~7O`htT^8{v?;bFUcc~D6Jwhnk&PFI!oFYCZFi_Pz zz~}rN3iR%uFM)pZ5TTzJpqR$w8Do5>$%sofbcyrR3vn3=rj^!4VC#QaX688{V5zsJ zfr8rJcz9j+*!5>A%Cm~<>e|X$K3~4hP{~us(9zC!c5Izxq*0;R)Qr5igh)nSVS4YL zyi`GM!r`T<>1UI1`SBQ4dbuS9GqZC;1H6;d)FDO^IwmR=cee9~th}b7uiEvq4Aw*j zHO)!oirfWr3Q)ybf`uk(!{xSu1Idl8I$09&`Yz^Po|hO%gl{46KjtKq@E~%$T^kmOH&^$exNDjRp$gZSV86(2uC(Cxm!*Z>OflW z2sSH7D}fJ9baGd;ytMub2XWwu7`L9L3zb0W1dHSe;ht%}`*wu}qK3pG?6;tic7!5N-W*3M)PKD9GTF_-O=VR!p#RjjhlSKKZJ33cKK#mQ^)eXkw+yl zEEQ}UV+%RySA=0v2I^mL%oJ7>9Lv%3Lbm~IY{BpDiK+~F>8q91r$pH><4)GEY5wl^ zGZ|CCUg8xDhjY0VM|Un>+MT*q^zrn%U4aoK7S8t-cVSLr zKd7}LsjJ^&tgC4WyiD-ZNf6KJ6nE7L+N|2NS8QmLRRJw{FLRNML27f8M?7yjA+9gx{%sqyWWWmV<=AR@5yv~(7(K2yMFsTAbEJNR&<7O zY%n_DX=yQd@-}bK$?@eV@}+BQo$%W7a*UAiC|G)S^3f)=?(%r8b*A!kymoB_=|1J? zcf8g-Fmcpw3aib71*C@1l+kb9n-$!Ne_P}UjXi1suJX0%Rgt`|_8tTg(?k|Up|_D^72`mS)r z3{1)X(gu?(jP_k(FONAh?^q2+kOT!fj5bBxM?Jo~&srCWbh}+#0>{4l0R2sF=K;u= zU>#j3hQiuu8O?ZD8JHzzNf!b@v~g^)eq~Cy^byI)_@Oxpo-79}KCJf`n+|ef0lMi@ zZqKb`ifSBLoyRk1H`Bb_+Vjw(G2UKiji;y0v#17z$+n5WeTTy|#XwcWkr zi#!v$+Gk^xKTribn^ZdoMD~DC?a$09hCxgOs2BtF*VR=l;-P~@la7tbKHpI`lEy1~ zmAAE9NxV(HGBew8wK>;KL-J>IWZRlkQ5%hxxUWSe&2FcW$sQ#j<2cyJx47=e;K~n= z%AWFAA%H5xw)N_*=n4)uqVznORbeI-L9UDUG!N#rVsf~8cm2#PJ&P(>ATnKY`k$uU zn!iFkjDLQ&|IYmtRsn%>lvD!WKrKjMvp7>_7mX5Xxz{Gk&Lt#!ktuLOd4)-_-YMRy z-k&ybXk%4FwNt=!aL)mW4KWM{s{Vs9anW6~swcG}>8lB^wHmNW+i$tKmA*?KNL8Ev)KU&Y)gh ze}C+S&J;+MQ@*Z<*e3aJD*AqjYyIXL)3$}-v(iNNScXk^xKc6t`VxK^qmCLSMyD@1 zhej-nJ-}M)>p9F1tj(=vPj+(xyMV22iWH7g3s@_AU@lNhL!Yb!@g;znbmXfOL zwC?5BEz^UV(Z+-cl@_J+^%|eylT_U#D~t1iQ)`+X!5eOlTuhCE)?~Q*qXZ(T_Y366 zmG;u4Z;CS<`_N9MQWu?;!pv2pRSF_qLjN!`5jz0RFnhN)JE$CEYxN*HJ=7=Z&nX$CU4C$oPz;ec~=Q{*M zLi0_Yey_B71TZMjAb+7=fWs>QM3?!H_ScT(!va2TUYKHw*&qMH{7=!Cso$g~4)n1O zv7++{HD&|V&ko(YaE=3KYZ*%gvV#BvWJVZlh%ap-1Y2pmsbbTCHSS+?!~He`HB*PE%T)Q7{kEGZNMee4b-l79BcQ4}cecaR zwdtM!8D-2!ZlDMK8>GsMq#2v113oz(F%%nVWM*wn{Qt6r3b>91ae=+=^A}D8IT&tSf;`SA0)XaHOyjY0fHzW48#j*}$K>E=+*v&zY9<|8_KAbZ`* z%Kzu-{nMGBA`l)la0BWJJn+VF0m3nF!3|^n-zJhc5i5rJ60k?zT+bdF_-a6{!f=mN&I&Z-VIlbrmd_(#m~W%oF;V4L?$9LIiNF;*-sWL{|xr(3>| z%uf9Ko-PO>&YXw15$oZ=h2wYkN)ssyQwpFF79_BwtMgokk>a{*c$cTH?ly>rXWw8MMCOByCeQ*3>r0q^N3;2iaHtmMed*CZPr~Bs z9Dym6wo2U$Nl7JVHsO9a`?=|F!Q=i}1nRQ7jl8AEwD5mPu^}$VAetP%J+7Lkv5^`N z?A}dNN)%aGWLP>3BP=LlmRuIe7`QO~N5TH-4LlgAtSv`z#K45nqIi0qtE2GDTFqey ztvGteQ~{QNS)I?+VmhAO26He&^_USWg%4|CE0kHisl0o zt-!>uIr9IA6QCp{*vLKyu#>eZ$=kRrIV?Qu}=D;%L`yo^>i==Fenqs+yiKy{nxIfCa!HV`<_H&;~Gnl_~?6{~`KH*#Al3bOHSQ|7GwG z!9Q&OKL-&*7egC+^Z#YV@}H{zr^Y`S|64=W)Xv<+0>HxhA0meTxn=sg|B?Z~AZ}^n zV(Rpj+8DZ+ikceRo0$H?`d`64Ko`2)f9MRYvhyBhop%AHepM#Bkym>$v^2FW?tdR^ zAphfZ+2+3f{{V47j=#ZF1EG_c&>=JvkYyXom;{qJAtW&+p`=0Jc~S_838@f3(s#|w zjx1B2_x=68f1X$P-s_r~bIzW*r`>bU%(8X!w&lb~4iJSDFI~5IBVm8#uK)&?Zr>W_ z;p}CEs0}MNu3X2%dALp=Sh@Dn6+B#-MM!7bs^yDu9sBzXpOvc+!GlscFl*Jitvh+R z?0Q0^#=R_KAbSMaEyylGE)`^_AUg!vF32`PwhFRE zkWGSY6l8-S>jhaS$XY=z5oC=Zs|8sl$Vx$02(ny|Wr8dfWQib)1z9A>LO~V?(l5w- zLFNfESCBqIdIgyy$ZSD+1eqmBw;)}DbP6(4kQstZ7i5|sQw8Y|q+O6UL0ScA5u{m= zCP5knnIgz!K_&^36r@3rdO;=%GC`0!L23o55u{p>DnTj*sSu=GkTO9^1t}4vSdbz? z3I!<;Bwvt(AbEo13X&s8T#%R`*@9#V5)~vwZ$j=0MRghN%d0CK`1UV>%8a#oP<3-Ucd zo)_edAkPW%T|vGh$g_f+7UUU0P6;w3$Vow-7UYB=#|1ei$e>K^_(45kVdna5)cMHkeV1&;cIW&tczSh6#~-d1w!Z-5hptxO6am5-!;}m_7xtgTrND!6A=BE{7ZrasKEShiv}L zEDli)nf%ca4q<*@h(iX4bPj18f*b;af$30|pM!5OFasek2M>>Qb8zuUCkF=yJ5RH5 zu<}R?2Qvo~Pcw2baM1HK9S1E3&7glKzFj@&?*yngC_GZ;A&CQFAdPYuVV6k5JoFid zPdR+T)BeLlA9MJK!@oKFYtT0YYxBSm;924e!=0* zLGK)7<&8n_Y{2UrUgMEJ=kPNQuX1>WU-B}Cmw4nk4nO7a6AnM-m%PZ~M?CTc4nO4Z z0}f|7e4k(WJsx_V!x;|G@wD%9_zsVJmcwZd&u}=!VTfOOl82t=aDu~e4#x&P4aoH1 zpl2T7D2D+KPjPsX!?!s+!Qlvp#|J&=^`*!7Qy%5;2v2*M!?!p*#Nj~>4{*4j!+jj? z_3y*9bbnQc0)1d2WK;ximKVZtB>i}T#praWui9?b@1Bd!S2kZiAA`eX% zwD%!Y$Dwx6PTNrphw4Fl3qnpC>ylrBeIlVSu$v+87m&N(+;VK zLm|JtfPX_ihXj9E9*121upAC?4lxedgLbN=EDllr%uN2w2!B|ZKPAK=gWs3VA&om)jzajh~hWrZhOUN(GmxSIlmxSH`zHVL{dd(aQ{T%W$@K?==&?}IaAul2Q9O8az zUKjca_>aL~1pkqFP3Q&l>d+6(t3p38uMC~Vz2C?4z6W_8k{msQ&*vcDg?z`fDfFyq zbLg~bOXwNX*3c=)5acA{pN5=3+Hs^EL);+bC}aTgl=0Hglg3@4ZyWc7o-pnW9Wm|; zJq~#c@+jmH$it9t84E%W0Uv}sfP3x--e7g49GeTc8tPI^?_*Uq8!y}<9mF&tTX>sd+S;?ZXUmbzJ!JFD%?CCQY*y6`Y<_36 zOg2k~q0uwPHU~4Bfyq6a&9>%EJsWy99@)^de#N?;HF&Mn)hl~e9a-74qIy}+@*~T7 zmR2w6SzNuSXJK`J&w?ZUJ@c#Q_RKpnx2LbVw`UHnpItqxr{~D5p6=?-o~|REJu|AO z_e@9pwCawYsYg0`+N)c8+K#mLv{X0uG$G3*&6XBUQ*87Frl;XeNKl$w983n^34Rz< zk>Eh^Oi*!H1EGMNYxPT0X85HI{{8+N{fgE1vQJL>a`T(5-j}_<_5RhXawfgGh0Vlc z^MpN$o94|kZ5GYjF;7Dy$C3(`*J++;tl8?8tnQFoZVI_2Vt>c}pws(3g*!X3lE18be08r@=VGC?|~# zQ<{^;g5qYPNMQ-1VQY?ttc+0n#&fUhh#!`dZ&nNuDxmz}3+?mxr&s;RcdExnm%`yLV8z@4ocOeH{Y_ zC{HFCAElh&lD@=(E!(yv5?dGGW5JfK3HA>mX&VjU4+;3UWh=t;KLEmnrhN4uzYNzc z+=4&$7z8+e^6dp@Av<}>m4PiroEF!gAafyokY30f$ZSXtWEP|w(go>+%!JHLOy_;hx`TdXUO}IKSADu{1Ng8$nPP)gZww-zaZ~I-huoU@;2lx$ZsIO zhWrZhOUN%EZ$jRHybgH{@^i?~Ag@ARfxHZP333kdQ^-#sKZd*r`4Qv=$PXbufSiSV zAM!oO^N=%;=OEvOdSkY$jikR_1C zkVTM%kOh!_$b85=$XrMtq!%&=G8@tZnFZ;FbU|i9W|V3{Gd%4d((vdf7+^KTJX%S^^3~v0_Dz4&-ZS#l z$RihJU?z5F%_Z~5e9})Ak;TaWGO~)ShGs4yYsosYo`u#UZ6){$gcjl|bS8{nxM~C0 zNH&noWGmT5w&TBz;9F85nzo6Bw~-zAZzs8w>>|6#9*LCP)`yAvt<$bOW} zW#n?k1oD`JT(yp3)=L-a%YRwR0#{4)iH| zQ!zplHz8-7U&trb5zWJm7v)pj@qdb?Ii`BL3;Gh8p*p(*ad&Cd&aK4kEK0G9wOgDSv*206Ubv8M%*LhQMB#H$r0>Hd}18G5c_B< z^-1hpq$M{%j*>xgj2uTvK21)NAr}8XrG42w$5PK49DB+s@(ekR8uDFo20hL9@SlkJ z4&t6m#hztX@$mP^_sLmy6;1sf>edVBp?*w$LVikKCO<&vCHDCvgkB*(BR?l^N@lQE z$)E5!3?a#uWeXSd&!0E9ueWDbcUR}k8Plgt?PzanZE0?5oHBV*vY~$Bgu2?A>Z;0$ zqQZjwoLF{NG&AIL*=<&{(V*99HENXtQ#QXT+Po+{5L+~$ibY#n3urjH7!ixdMJyT! zBdYo0YX-vfzQsto=*lFnT=BUpll;o$*p-qkJb_Fo$PYI~!vp6Uqv0WGZf7s}4UN&h z@W6S-r!lUIv49zYNCbC;n|!Mp!voTyaMM8Z_Em?P7Bv>+OGk}{DbXp*4F&n+sKE$o z1RKbSZagaG)Ju%WIZd@kWui0FuN_dbn-(t{nAzFe)EJCJ`dA#9!k#stnKGbd&kC;| zz&n%c!bkJZ9J+qUMwTo}n3hGCEuP;ype)8shm@v6hpry5CkAq(jRU#6e&>S%mk;De z8=D3aQM_13*Vq?G1L|yBG<@h^1TP;w{};UVxR}MM7)`eAUxX&oERLyZKw2y~!MouN zk-tcUzRPt(NwNfifdierJRBxVf`cSkl;|6f7txe6BE{W9Qx1rfvD+6#q1mQr)1uVB z?W=qP2bP2j@=>zvU-p118|mQzCAMhE(p3}}FFzD*L=K@#GOKqW*$9$coKj}f(c&Up zzjzTcv6`x(vv;5k+RWuj+Tdm$I3`K>7(y4;F*F#i8USSUAAH%v?#a?^>anIHy9a6_CbAp z(ca~Kw3MQ@f!ufSb@)R8vb&JC&s{ApMz#mE*}8DA98~&fX(1xqjF0H#2}rOFXn2s8 z=;R6EUMWb#W%!oV6_j1{90Zi?DXq8}h+C($1|z84?C*bgr6A7$USmKv_D(9ig!;le z@$dP{SL0XH7s?GcEpHt6f)_m$0rrBar+xW*%2XFAW#AQbv^ZO79t!eh@Gz2f12Xc- zqG&1l!UJSxxHq~y+80F~O3v)1g+q1C%D1CCO1*)sv{SWY)eBz(S3-1c{KGv5=IL`;b>xQi?6G8l%ugWqoa&A zFOG(7;pRh&hei)9Idn9cJhZWC(W+WBgG14_Wrw2Oy%SKDtljSo?xJ7qARSW2tjPuW z=zAs~jY`*a9!*NubkFTQWg{ef&8*%*8J^HZllzWlA+7gR7@a$dm1!)Eq?d$gfIg`U z0Uf(Ocq&QA0hX#_5iGoPNFpqbUxYY`EFF@0oK0LOBTmKRk}R$de`sO8RVV`V!%g93 zw0QRPtva-*k2WsiK~dtLG$2Lm$$%WKhyPY%8ZbncPaZHvC)4-_8sEU~>t& zLS+%6TLum+T}It}_ncYLHBW_xXvOxi|`wt*6 zaG-CXFG0VwcQt*ZaM(6LTBEfncK%FtjDAs3-yuh|lvZq9I$+4Ynt~qhM!I`>Ob|hQ z89H2=BdrN3Z!N05V^7PW@>0>&FNLO?x zx<>la?5ng$9x!LOEk@_h?>8bQS}ktIvvk=siaz5kkJZwgo1k|kd)CnCBhgD~46W2l+O6LTw`RRG*P2WEIkK5Z6zh(7cKGJjhhCRF#SNUUqGZ z@&{s7XOhQNhe)P2gG^M#NipIwl-J38RXI7VEFp7&ihve}r_(Pm&12w<&j%O!W|{PO2{s_n4g2p)yA0)E`c7pAgz!mA)6s9A;pm8 z5SqReLa*tP?KDkl?24XGs)NhztoQ6nR1A}yqm z)ZrVakT!gi1t*MVk`8=VE2@i)_=uX!AP$_X@(>-#CGEt8nXsL>agNAKsz^1dCk=Qz zg89Y$Qjzp~d5Qe8(xDtz%~O49_+3-Xbceag z{I+Ec7RVm3W!oM0I~-QW9nNCs7S}A-@7-HG2G4`uH1B`;7Wh8!e=D#zXbf%)zMMwV zW~begb|&4JJ|X?q^gm}D{RVABG1_BMylNFj96noo{RB*gOdjovY4a08_zf?5*_IXE5(Rr!pt#{vk*Y>xU z>@`JY@4ohKNwH*)*qOL2vR3QTL^BKJig>KDtgN(Nt|*U1Gc7WUE3d4oSISB=WCd69 zn0lFpCFN(I%~fU$Yvg^=hS_E6jDXc;)~Mw)pQB(xwyk?!_JqQ8t)kT^YMnNxYI0`B z+NR83Y3=E5Pr5^=bEJFR>2~e#uho`M{;sxsIz_ei)7unH-Ta0utJ9`3I&F53PV2CnavJ9kU*%4t&q#B-`Ll+nK`qhIPgMKVF4VLbx%(8!8h!7$ z$tF#W4y8zJX!OJ5M#LBe!OHN5$pDSYw$V>B`!uo7WR8?glk<(zw5(_>`=2JG$(NZP zHJBxj%0x^yll)Zlx#-JLC2ESA9O+$-9(50CXlQWM)D#u<_uIWSc2Ikn?R=@d3>r`L zb7vY>8?!wg4O4ksi6|B&ni-2#R!LmXUTsu~sJ7`OTXrav?bNF_4F6$`VsJ*&(zC6S zP8w91{qc-&UcjQ-E&W#d-b7E(qEfUby;L{yqTZ}msVzZ|YS3uWDT>Z&ykU4ZL7jR6 z?OsCd%0OGJCO=9BLOz=`Eo8IO4>LY|CVYgESL{wKOy&gKNu;}zNO!x9`Sjv^dT~Cz zIGC6dm5-WqIkKsz-hsSU+LtGF1_c7eU(s5Nn~ z-1fn3r#vy51=I}5vCCAc8T_U9wAkzx)FUO!2;0IJIEFD@& zd{-_*ALo;b&}+t|{6S~8>a>)H&ahZ2JgT3KCjHuZDpC>8zU_^(CB@k;3vayTtXXQP z0%$X(4cP6>HL< zRV=+}-n1>9p~(9iEkrZ+?+C#^Y7T63H(TxN_2I)K zAF$%je)PS&J5Q8vc>JoTj_!GUbB%oGqo01Oix>2q2j4rq`otCOpV{jVJWt0vW)*9=KH$1*$pw1Z5INJVGusb-Aa z@j@G)88O<3hONv(#9kSZYV$V9$kc(EWE$DUz?fT*0Yt34< z8Xu}B;~@+=G)MDBKTz#dhhZ5!kW5cYv-)Ta_0byYqkWstfEwzvAs0ScdS>!mTnfjN z@kMbZZcXJM$npYw4&J=|t5iExI+NB^ zz2M;7OCI0e(6sBZ;+ue(1X!_MEw*F+E+nG&2io)ah(#juB@dmY(S|^*{09ZFhb$us9IS4P?@G zfiZU`#@r$@biAQNikea?0x}gbgj#{DX|Qyt$V8Q!=FKuv?Hj4~ja2(as(mBvAB=R2 z@RFn(1546LKWuhsDoG-pclu^uib*nEJQ^4EZ#v%~Vbpky zjwGoDb)jMPqX*@N4NRgj%C#xG5hti>rp^`d1;Q@f@G&qyt$8|Erq3U7>EvmwE`kN1 zeN;J29A zr;H-EOQV$}k4O1f>&gs9^F7*;ERh#c2GWl;Hg6;l2s^cA$4IyIl3kldJ3x)iAYVOv z=~!2Ap)8)48}ufvN{s?B2fV|h!*>RpslL7gxet)mQ^d_Pi+y%1vkZ}0Aj>R}4Nz`m z_Bhd7yWB%kBGs8oMdw6eusm`*g%8K5Sk$KOK#!~+KI_dL%fu_xgzInxoqF`mPl~GY z>HT_pTB>9;3G~Mk$P-E1qWX>Xvbng}TU2By^!eCeiRQ!xQ4|bAyep8sD@#Yg1Zcrz zWR;jq2HN@zwDlQi>od^SXP_l*pmhs&UDA&L$*Sx$`n={MUrC`Rl+zjN5vFc~14eEc z%2QZpuyjSsvX|LwCKi>IQQLQ18;eTR-Yt~lQgmE#(|JdR?3K!Bc~k1vBy_Hj-y3o2 za(qtY0FZxVROs`el0a@ zUKlA;b>?`-@fgZ*RN}AzwPbYZhY;ArW5gb-`KeE8w+z|bHBcM)13=) zEK6Bl)SvNjQEnL_`FQEOU!QZg+ zXqG0G5g^M5Lu4GtnjA|&3tH*NL0sktZW=Je;^ z`_1Vqo3oT#7vHsh!bss*yFgKEy$$m(oik%ixn=l2IW0?R3DXhYh#XhK7jttm!&Ydo z(&4SEXfCQ)E~;p*s%R-!p_EVN(wSp!gPp1bj3KUN2-N_YYJjZgv_mz6X@xde$4_re zO39>mA~bL!(&7d7(p`<2+UZ=++ zmB-?-SZZ3RGHP5|8G(q)sM_H!sGn80MJNk1LubjPK*yHp@#y6FHR1At9M@KhZe+M| zroW-==0_WsP7a}y(V-2XiIAh0(1yE$wBrfV;s`#2EtTlSj|G|aaORjlg)WXyTd7H9 zDm*R4;Vv^sv82%+u9B*fMw2uZ<#Q%!psdPXW%o>gC4XX4P@UWD8Ip2S?GQz9-cH>e ziA2BcybaBAoQ=gMFv8#(YoIF8K)Iu-P?HLOe&VW8mQLAmfB&QnbLzZCn6x@e+00Gt z)%{blO1oCCU)5DsxBBK;i8<3II5jF+(HOPHqQ?H(%9-VX((X0u*L0Ujm(2SbruX4Y zUv>x{Cv9d`nde2xzT%xn5 zIi1`+MlFZO(NkXvt0qAXC({=dNMYJ)!?YELY1IkSu|G^}4Sq|>mb8zzyiwDLC)Lvd zSx?6h_W@akSvv0aJcBK?uu7?Y4omP%QV#>&5bLsaVcIV04Kv4ibEXxBGnff%8c1_J zHlW#4E{qE?s!N*=3~jq)U|%Dj{yBB|-P_tawspc_fKeWC>ZP~0pE@wP{?ey+C{dw~ z&;CC5Dy(AlUOq?hia4s3O!RK6pp`7LKAE0HJGPuGDL^q6kaFN7GE4b>Dc>jgk$=`m z8KIrGPsC7?bkHcj&+m(6hq`=f2e-!^H4S!$#9K%LMNInprT+eYxB|188KjEC4^UY- z&iE;XYfvknR9XD-bWg-*H))lTKAq&q$xMql^eSnKB&}9-=(<8#W<{4l-Fy-(Sffrg z$Q*%~+JE|-s)5E+M~?8c=fhqYlp0e>`*4#$(=1YVCbK zn`71<%dq;O%9fU!5lW<4R3m?rKT#}!+;Aj6&8mz%u957qa45^Em8Ga8xfH!CJ0mUP z(koJ~ETtHmg?ib!!XJ-0~8EtFzDDdv^p9w~=Nxm{7CJ-y35ZVH3eO7q;`f5DY2 zG0T>Da>wPCO<-u5O3LrdYDaEnILmERjl47RmfGab%810QYO}O>QWn=ndzapU1b^>sP_b{YDH(%%gXRD%q~T34S3{kxxo{(!to1_PMY*Pof+{c@8KWN z{A4gI#f9~kJ}j;A84R07qO~(b!v(U23uJ=}n@*b0aJ_7{ekO?uJcTQ_oxQEiP!GO|5J^)Y{GK=zjSk1IxJ zW*{rqrZ!3+jf^!`=`HzJwAfT|>Wo}pv9+#dQ-NXvzu2;n!2$)ySaR3MKC>@uCw{A{`5dJ-I?FBZ`N6FK|^kH z_vA)s_b{~kx_T3859UHA8X6=+q%u`mfXqSxvPwh4Okb5l(#Of5J3$TpL>L-PQ2i(9 z7?YqHPYlV1q@K79l@$?{x_C%ZKOJiiHruAwfF4y(qs}nu8uY@>OU;Ka=xl6Uhzsxb zh2g-?S51VuueE!it$JB`y=>`C{fV~b<~Y2YZcK1AT4&hj$80C3qqQ|>$#rvbo^+Sb zPKN7~P4UJ(Q|f!G{L&w{oxY;k9;?k=k1+z(&!kgVGfNL2!@tk1j@qUl9N5-$`LcMr#HZDY)qPqERx0l$57H>ZVkb^B_DUTD}OGb_J`iwT9Q8`X^!flw&B+j)Qy<9 z;6gl$5tTcPKesTzg3(M^S{Y-@0!mm`YyA^CdW#m{vAkl^ro(-S&c+I#UL!lq*7$^; z+8z5N$^Hp7vl|j7I+=dJ?zfx$+3Akt?ql1od~R2rEs*K6IDL+ID3TL7`Q)5~y@{+u zROf`RRVIs|m%FeZI)=57>yn{{I>{KUp{=uqS{pUgTCJhAqlQ+Nn$tKQLr4+VS`n>b zNCz@|gCTBW@wmE(Rw#or(rm1W2UQj{OZA|y9Zg+z%rXs2^{7m&I-$=>85$gD8@%9- z7~cdjT^KVv6wDLGO&+V1yR`N+7hQC0IXrLa^>cDcm)yK?#=)f46{2-Y|L~N(jSZ+l zs8N$56O+wxzo|&fnj#y;yn46^b!W+*WaH(_QJ1E`OqWSNv~?K0 zS^{g~PbTwL!(ZMkT$Xl2od+qTj^YeeW-_Y_!N0{rhRGg7x#& zIKD2yv{?F9f=|5B*-^6w4OA12jH^~?r{gQ1?2cD5g=&?>ccjll`$ydQv(`elpxxwu6u;oRJ>S~AeMIE{(xU_WpZ8kd9*&l6P z*B+gmWr7W7b$Tsoy;1Kg>#SX(wFjJ8;m`g|%{{tor?|se&VXIpzu@ZGxn`@$i8ULA zRE*rJT&w&DyC0@wH~%Y1x1*qiwz3u-Do;z;=9H$klr_K#q$41ZwJ+d1Pt&9Z?F`VQ z+3Jv{&Iqck#Y&l0OKTGvBlLA9X$C1M(*}duvH}&=ak3m0i}cd3=ndO&TW?-=(g@79 z7HgI2_FtL0-*dYcRV#m*(3%&X{LAY0dA|(LNGWH#O52D@REF6q$FHYRGJ;iDxZJZ z)ZCVkWV72xMwa&%w-kAo&nsyy@^&xm{8KpBr@vx*$MX81vNamYno~4=XLo+O$5EIO zEtCy%WMW@k{l=b>>||egq`tb$@1L4KaZxP0fAX|lvkLUO$jIO3uMAhW<@BuxRkaQ; zsBMsS{({^b_oON5#r3p)ABJ6bA4cX6#QQv827K=tZ&gqi!LfZL^ z#;x3^bMP_OSJ+luzo!vF=DHO_am!6@b9YaT_(gq|t0Y>3W?Zip%#+L)0=;Ds3}CZ7ni$_o@TSJvn~r?D$54Gw;$ zsV_S8Q!0f+|Kq0(A-WR+Kbuj1+;3}R`g!AgA~m$6>=oJ%esRskN%z*!%7|Jh)qh?A z&iuOC1eGxrC|AJhK;t%PrQ+JW+!_dSJo@^`tkx#ZO1^~ zv4ea_m&~*2FRLX?XrSympfLA&ABYHU_oMGi8vK4zT1fL)h&&$43AJI7Qgu|#S}AgB zFDpxB_AJjW@~Y;}wv=m#C}D zvo6~`E1@%(?G7_tgI2o=THBN(UsMNg2Yb*C%E|3XQ$wYcTOySt9nv(IN3XCB9)#Im z!1t+kSQttvIgP`^nZ%ST+pk`oMAHa(3JM5S32!2vOrtudEv?xung{$_QW1q0r}_@59y)WABwK0Rz*ZVr-5*ysQdJ_QAA-7n z++b^F6+Tq~zOY8w;a#ay=gMy^tl82;TMt&pw4VGag*98pdRC1i z&Fe|GX{X-UR^8WFY%A#OXvvzhy)86W9&)tibA9X=W8hLWq6+Dax*a_;0!5Q@N*eQ= z=zQrePc{aj1WUcwT8ydT=<}tN8ilypQEI8uq?5%ABennevOl#Q#;^TLAD>JO zOmtXE8VcI;{8?>6_3%VM?Ly6|b&-^||0i8vtlF<0p2n2;^=bcy;prkpK|zb?=tO6O zZ$m?LP3+NRT0^dspy8F(>9`*u(wDWw6zc-}^!xRvuIiY)@Azh5J8)0i zRX6Ze#!m;K0;mCNI;DkH+L&A2LoI2 z;2wrA^((a5W_+bz;mh0#Uo>IdU+q@7WkF8kq-2)ps!>^7?w~`PJ9S!T!IDGNtx(3? z3eEAxT~q4&sshrVwm*BY#gI7uHBv9nt0(ZY3TvCWuSLaie{t@t zr&eIdrOj<`ZHrSCl`g$`VNP>XOCH_A>q@h0zc7CuIW9CMoy)C>TE!gNo?Vx_PN;6= zUwjhH9Wt0iv))O51R5(NOOJ1?kYd(Uj}K&72lC2A3AGlj)CzW_wiwZc4%)0p0Ha2B zQlDs#S>53_H+3hl?w$?!yb;mW_tZjNN7n^cOVEb(O6^?JR|RXDY3ct8yB7do1Qm5p($qB9uu7PdpLbM(CY5^~%| zUP_vZIvP4=bnNeVszW_)F_DdVER1dzc;*<)Vircp@lu0%fzEx%Tvwfz0k$t0G;R}bqrmKeS zp7*$u4{GE~hN%TZY>FPYpj(u3)^MMKh3?Dxzg{quUn*O0`SjvBO~oFAiY^Ey8fI7L zHI@eB$(cQ!$#`zp?yjuX+FZ9*fpuii=rb$Zit>`V?wn*-Pj@mdS(?_OyuE%`R>%qa zGZ+p!qLtaP@|;j+qJH*-ip6dDCWqT*vU+TGzfJ4$dz{hYw0K2MI5Tg;ENb0EM*k|W zQ+*q!80H_(CH81Rsv$CjPJyf}fUH3>gc1vAB{X@>1?Qu!>E`p^))H!cYnfN{{5d+< zm8HB_=gxB19^dn4|Ga}ic8_;MFq@naqN^|MddbMg^dZx{y*JNV}T()oz!y97L#~a)SF=FUns5j`<79Y*`ZPd@FJPVuP z7I^u}C1ae{pg65Tak`ckXPs1>+6ma~`k$u>HOELO)dYb|E5MJL^-c+$!q5vu1e?=f z0`?y)C>FHEjcR`z3^VlwXCG~!!WJ8=QWs5Fg|lzW%f}ZNv7=IKpMjgtk?!`U+cnef zU_-yw#T_%=qSoU2-A!=!VgBmSj~P=tdZtfUdF>K8Q`k$x|D3UKN_KCLyiLSV{a}?* z*$w^Vlm9-2V+t6}=+at1*^g? z#cfiKTFT5p#KcS~D^rS4irv>)5h=`K!%|jQid&`a5h+5QTzb2^H4;XvMd-bx9^F7B zj3!M(bh-rmFloXwA~|glW1!8*J3zMngGmla^fSvLL02;S6Ko}n&3)MVUxN0E+Och3 zV_Q>YuhYvHhOqH%w^Q{O8HcVcQ@$Guxpij zReFO-``Kf3QB$R}7?e3ChhD)HS;mKcIAAi#f6&8OChLq;+ZCgqsIP#wo5AHr%5>~DOZtd>!i9`sjfhpkT2Q7Sj5JU z_A&PXML6RT5ylg27(ZAvMYdFCrP0<&ZR|R#%m&*G+XmZyo644Scv@{`ZP{(LH|0zD zG%cU@nl`7Wb!GmJe7Om+-l=-3F1%@(4xRE# zS$;v*J5cShgG_!?mfn!DPbT2Q(H-Spt;>3$P~;o*`r$1Xipc8H>WwHN%v6U1dOb=A zOO!aLq8s*!kgS8rDv?~Yjt-Pp5xFdB50}t2Y4{;%XHi!uVR8M#r$Nho61MxYZh^KE z7Uhxjw4&xAnb3PC5UDyURT?E@n9eL{ff$V?#kp;C`L<0=+-XNa7v-7fnk~pf z$o8<+Il7_f!oi$z>ziW>o02j`=ZuFkqFBxS#hWUlI}_(~?2=ycjeMk&obhma)MZee zdqriihl1(Z4p~3)pL~ncq{hTtD=i=SCO}b}oEGV%^oYf2Rw){TcI2ou1E8pkF6#(> z)doEWEWka`O%~}oMS{p|1@c)HlyZZTk1hkyWok>MMULyG03D8N1CqZQSm&2QZGMBZ z&CsEmfirXPVABO$G+ShoZ$ao!L=?UPS>>d=Z)4?S8xfq$Y3gxl<+7cclF~rfE^GGa zZOX`VI$KsoMy5-zmL%n4jXg7*mSxwBoUqx|CYMF3Q8^6Ce7Dbn^=hkmxKMt>X;fp3 za3CjrFlgVz@8Tp#-6>*2PCRtSM2zhqD?)m?zELmhv+bC$9P_tYF-~COf)}TbckEN> zKZiaiwON>Mq@^{yO1fw(JlpCe(akdQn;M-(H~fY>NV^N^hLQa?C*5f)tBlxCLE}cY zNe^S&jHVeI+_h&xo8+P zdeeyQwR3#)nO4giV3kv}IcbZ=;%s2d^zDzj$f}ad+pb#%?`hVz1l&OH_PwCt101de$Z$P z=7%#2C>9J)V=wztok5H36GpvcAA4DuoF4rs^{#OeJW8;+bN5L@MildND;7)6HQ+VN z-WA6>#4aY3%h)_CHQ-8Lc)!oT?-$=IC&FJ8XRgul2XLrYB45Y*tVih>iT5bonsw%B zG<}U;L63@8Njy)BYMdK(eNp{{LMrQ8iVB+`bk*dJ(T`LglDFwIaDp}OIpUM|;JBO# zzuf3RG3+_1iMaJaD}82J*|}0w$#?007e87(?rX+#X?4+r+CnPQ_X{bj!w7R$#I0>E zDs21`q4iGLCT+orR*>jX?^=)_UiM#7)?Zoe)Ui-mQGxFzE%uJEgM!Zefv`iPaj<%K zjj}^2WZzIl%*QpEo>F`ZGKlXPTWzOpEp-f3`z5g++EYAi^hSNYOpg&&%yzZfgeqq9 z7$o(G_e&DcX{uWGrQRZtQHEx5j@2|Yi;?qRkw9BXLfIj|I`+24xVLQVZO2+bELMJ@ zHBvA27nLQyO5gGtmD%BQ*xW|t3WGQ5_eMR&kvqpF;Pq83g=R|~58*X^=X6HeAaIn% z4lUX>8hbeKRS77+Ch53bC{M(>WXo})HJ-;-k@GkgKnoEorhH+5^;m@t`^W+Z{-g)c zFR7*f#4|#%Scb+Pz*DXqc|`h$`a0Ch%%oePBcnp6V+!j$6?e#ZC21%^n`4H8q`|>I zhj;9VX`#aUO775*{<^S#;XJiuN%uPfPLopERh<^9=_-?O^2_5*v&rfuFOKxR@#e_f zpP1}MH4dw&SG@X*w>EA1%`bnp5@&KTO5wLDB(e){^hdl=gp{2k4os!-POwgy7mMNv z+POR6SUy8XYRsqk8zxHmE7C%t{U+TlRq3cGm*X++ob!4d(jU{RJ1Z3v&KU;M&60Zl zf&~jyvMtT)#^Ek`8)S9x&rH{vKrm_kEKW6d_#KVMZFCt7Bw2xxse%ozvo8I z$U*fEoI|vn@c+mfc!4Uu=)BOo*kVXkkFzC&ods~+yt=NNrb)wTn3}2S=<$Td(LD0Dlmev6OTY9?x zaHD#yqIRgRR&Hl_!@*KP0IwCcZW1*G^D|V*u#IkXWe79f`il)YnNrOq=<6E1$;8=I zDjcfKh{CGilWlh&{DRK(^7SH^TW|1URbNQHN?A=}k98z$+ua-Z$>FW3`Q2@U>Sou) zhATnYtiGd6SxN!vzEwnAV>lM9hOnS%T5_3UNW*>(52+W^PgKp{^Haw~spl1P`3pLw z#N#raWj+^C=FQ`PWeuxI^KfF)B;#k8L_6olgW~O$k(poG093~(8jI#h6>bt&2lIkK zxw_}(v<7(X&N7P0T$YwPJOz=et>=UU=Xnvw82=&i7R;+?P{r z#gNR%aq0k3{F7-_<|m0#EQ3s+0V;mgPFF{rW5zTC|dvg1%20 z&+{Rd?*sFrmZocWHz`Jj7kL%S8QBjh4`$L@#{zgRkS3#>-H?3_GZJu_gy+dnZsj+1 z!obIC&49Wb{?r+K0GpUPtU_-LH_0($etwFJvX~`hUKCVugMfsR7>bx1rp*R@31>!V z7E{)#JJ~h5!fzxy!Q9L)Q6gEU`6yJhQp2b1Bz{xf-IzVz5}jlXx59V19K2QA*Vj#B zMX0m=D*NCLJQ2c`qo%kHGv9^>$BpT^3HW`keM`KJxn|RkKC84`yMd^XMN?Vn1H;un z)cPzV=%wi@3%<&-6^O~q)-J;*X)gw{9#n@i6E?OM5JH%!%*1GOg_7_OYo6wsGOsIw z@H9t0Z+}izWTrH6L~7^FyW_GZ3>u|)u9mzkgC{j=-&Ta{p~*~B+6e}YWh-dOFSKM< zMbVsIVIJmZVb5u1_6x;GoC)+qMM*gGck2{OvH}O_1q?@oVThQ6Ipnr;^dQz7rhR^+ z%BLw&|LKKT*J0;9z*&Ju-Sy>2xNCJ#yG-xZ!lRIh_S}OR?l8jd#T@@hOW$vbhfx6| z$kN)8Dl@r$oLp6dr5JlRaALYgVfI;xlN;ofJvE6fd43>!&cPMG;^-1=?Va*_Q5w_i z4=LJiHuDfSXhSz&EL7D7QS2AH zO3u%``jB$Z>9A6}*cygVcww(x7?EEv!rPt@M^VhS#w0u?bPq;Kl#^0RcUL5%7wWoc zv(+8uJ#R*NM#tMIk~U|Pg;+BhtWJHtu{!J8)h>cnCKG}CmbZ*)Dy*#3>F6yt;h^91 zi)-N~XvR)gIIMTVmvK_E3nrcckz5|5;hc+X2{g&`s8J1%)Cp(@EU2$ZcYTFYMUa3? zET60@!+B)!>QEfW2UH|ShyvtBSpI-Z#3?q8SkuPC@!R{eBhC$M)*N^#^)*~G?3OD;RfxkE;jourv8%ozAr+uJmZcmGC)c&rx0n)| zVBch~etJ7yrw{VBTsB0b^Hx7iobxDuq%88aJ{)9X7mcUZ=-mR2I{paNwyU1^+jhP2 zrT_p0#`%)!<_gT@#$b8Wz7}{cw3UW{}0yQ*B|q6xm;!774=W7vZ|Dh3HD#@1TqJR-38P zE|Av0m6@9N(vxCp6^1!3b@w%fk@$2mOEyLPE={75(_vo$(G=)yq);}#)tQgXEdLd9 zrUN_C3O~7+`Wq8A>Rd8W_DF_4-Dz6Vof7Fxg`JS)@|4=cndn}{(i$Xvt??9~yJjPo z!qn!HIiBY(Bd@QD$GYt8k&7ElT-T1V(gE$PAy@X+(NsEltWE03`C3H zp%pcQX#d9jdFKi{m68R@A!-ey0-_$$4JV?NhkZi*w$@-~!dvCuk%$xCELq-o5<*37 zQ>wzCCY?E3!35p%o`Cm^U#wFgn4;uxWatxhN~DH2A0}cv)xTt$&7X4|oPq$&qaWdpQNn z6;=VCTv9|VceILyz5@Vqxov^R<$)*VMq(9Wm<6tb1+tIbi%=+?Nx!$_(49d@5wIjF z6Y<;QD=VtF0`6q2>I{`xA;vTHI%t?(&o2328}dr1W9D79Qu2`c^@=5Ts-5RBIO>aJ z43setke?ysOe3p zrx@WZvdT<|bQHj)I7l?0r7-Eu$xX;ltWi=R6dMm>690Z#4#my;1OB{ktH&lx|9qsZFV|XMSAuH!`?X)g`7!t~5X%*lRW##Q?VIvP@m{QqZ zo;!423%QCCp?Vo6mKKz+*-u5)rK65{|3NBGB_5If@pwU^MH^d?)zZ%Z866AeXfHI) zpFNS}h348&xUTYMOHD@Txp~w+f<1-jtz+0^U~M`J;8WmYvS%tJ!D!XEv`+LmN_3ki znimhYj9Ng&BDQL6mbN5`H0p*n5o$|2_sr<5YNDja1javVJKo-c8ngxBK@P8NAA zj0G!IN4EYpbw(VXc-l`%;EPyiz#ofH6qf6S`AhS zSXW`jWixyZOItYqW!a{6V(pGois((CXW)MR<^_vS6Ntl1$rxn5~e zDs~GF8n6}(;ZFs6oBVK`Rm@9il|Kq|9^+!!D<|VnMgv=4k~Z)<=8u)Is6C!9Q5)rR zIZwslUuZHrjA~9$A~9&+9@44F22jo*{8$y45X>AI>nLikdeJ$;5k6#Q!iY@VEhv)8 zIrg^~f59jaIRw{Aq03-0r2j1TA{O6NCY(>G1C-IqBQ70?MSnRB>qiWR{O&j+?fwnG_B*Q1XEP}y=C+SKZ@92;>% z)-kITrRWc79oo(A2Yq8w9NIYjs%Mf<#fA6mB4lp~Zw`~5v@7_JsKqV955(4_NR6GQ z-)-Er&v6S4%JG7+1ClEyT5&L1wh>AuqN7Btrgel&h15og8U^R4R5a zF7?Wj#nQ5+7Zo<1NmOmq7teXdhXxRIK&;vUnvr2$y3W;R6L67~KU((f-7?=LBj zk)DB#<-dq~EdPU__b;ZOh^>v2kg=nogSnlPEs&ST?`UWYr1){LFam*o`gUT*=B8#& z_^iy#_;i2G{^rpzvU2LT-#Ao`yP=SAWgMTjokV6P$4>Gf};j=KZ z;4`yv{AU6Uo(&2Z@U{P| zxv>3@=JFrhB0Dfm0eI>EKYT^)gi)JS`X9oNFHp3z!g?CS=iooS0oT`coBn?C0BRH_ z0XA2IPX+zyJ&Dt5p4N|I$AaxJaaHZH=Dil#yQ89esMtCgaT-#ccKdwC*tm>yb4!nU zI^!(Zx|aTK89lC4CbpqFA<26&@Ud4?VrO$7nQ+UfyS5&3;WTu4cR9MY?~b0iz8*c; z{=VEPHCyR5w!7mczgRKKGwW?pFgec93drBM3Clr6IQM`9dW@pMbgH zRB?Cu8A9eub27DALNVGB*CtzSGX6_=!**j-gu17~7ztIs_6$6t>iaScs(Yt*jCZuK zkmvGuYQj__ENa4*SROruX@!PoRj*OyWuM`2_=0D2oBNZEiAfS?BmE&2VWG_c-TA69ikMP7{r^`@puLM;trL9cDv z0hp+>{aua3KJGB_AN&FGIR2eL@V?*r&%r*-gU$fExg}2`f@>YW7$ve`)a3 z%n^&|8DCbcK;2PF9h#5abx01iAh<|@EETcul7?C6-fBq;O$`E+4svY!BLyk%EQKbW z+89)&w)rXdIM9EX*Zg7U>93SEePx_%OMTE;4JZk5K)*eW=glCM)_Z}qLGp6^e>l~@ zZU3)NVWVgNPak3U4?Fe0A*O#l9?+dR8#w(#O;vJmHvX5d70`Dy{#WMzc7=aa|Jw^g z0Ugjko$MdS=ZMer4?Fd5pL1|@5;W6y`0MWIr1bxNz(5c5i%Pc2Hs=3OPMQApT800~ zS>^b*?7tHK-Hn<5MP>bOYAPesUl;%X>(zN}kX}mj>wI1l>n54aO!3Q%!($m^QVrsa z@kTX_aac7~-=vVgLZU;aZK=dn%|#-XqJjXLF8!6~C}{-MV9YE}avN3@s_&~;3Q<>b z>Mb;ICCgFc+BO}@vUo3VeK#jx-474WMtMeU`3_CqyMmSbq`)C%=TKDXPKj3N>`?r5 z%a@vThVzW`oGY~#8edMNR?>)t+Dz}27j+WFzlT6HGy9I07*jEsJD}>{V;ULFAm57{ zjnAJ}4(B=gMqLe;E>t8_!WYEo*xlDy7Hr7+MAzMv8>?21%zes0_QZA6pDvirq>22f zxWrOpQOl3_fENeCxZ$FkZ0f zSaP`1q6y(^gd|lI8|E`#OlPnC8{X4y9{sF^ufBSJu?RFH`6rG+Zo;==+7Iuz;N8%X zPa9w2PJ=_qH#+$b@J~+lVir&DC46g-@i(z+agAF~yXLmT`e578tiiGSQEz1me*ne~ zGq)@8-OW6)eBtd0)+RQ~gJcQEL|$Hp;PJh%%~3DXCHQ{F0Qi^zpZGI2d3ecCm!chb z$FDIa+wF?Sk#FGT>o3K2Xq`6fKN7G&$yK)y?YIpd@m=5(FL3i9yhb+rbn_$i@Oq%` z+?+}KDy%W#g6erz>Na;vmx4&v1M@cn0jt1G=-XWLwpIofqqD>_mfRuuTr-HXO;-u= zle602*4wn8@thd5f~ce?s2Pw1D8%o&5(-6f z$Xcm6EbYO(y;*)qu;B#yaHM5N zVgP4L={2ekM}hd(sGYZ+pxxI6H;NmS4~3@urO14>2FY02Eu=i7Cd1IopX7wbf;?C! z%Q2RM6|l|Uc&Uzmod%r-80ODB$2nT7y(^Y|tN4{ZdVc$I!$frXEv+Z_HnA zxTgMFF1WJGx$9bE1G4W6%he=+q+rAoK_U>4>Azd&QYIC&+gy86<3CN9N}JOfek6yW ztOy&4Vu8yY(p$~k#@te8cWk3??Pl#{y}hz7;Mv5pqO;VYX$HY2gaw7=0)1`AjY;?W z64ifOk68_Ujpi)5)%8NsaWkEYI-}L);-J|Jw!!Apj#@rD$Xy;47yH3jb#4i>(B6|F zBmc^^2Pb4#{D%*A1&9qzde?an-kwkB8Xn*1$EZlE4 z3|Qaa@U=kK6q<{#MOld97Eqn7-mIa&FnX6AKMgX9B0P0W0L-oB3&X5v(_tcGrby#R?DzE14Q z$k^MVs8hq+N``iUGBAZEgy?uOJi%L=y~V8obTf3t12ad5y|MA#B4|9)rqFu!cX*21 zzO&1F9C@+?T9H>2aXIpVvT%hqM)#RNUqfO(c!y_eU83XR%HL%;HAj7&O4f;bNk*?1 zLP8`f`Ze(gNfPEee4F-&9WHTcm&3Ozw&O~FoS{e6faox!Q^K*X99tl6tF5CDk5tEw zWq9mT-+7_TFfm1H21}}ynmqU;tT1EKipq6~JQKpk!<{>KZ&$GnYauRxCkghfWW5uY z1gTieg4+_fYZT$ZZHDUPflkMF`{wKDA(4INHEa+1`}!cSlyBQ8gSfTG(jJXknw@Ma#KP>nI-5?@L9zKt(Q-B$8zwM`oQ)4N5 zboM?8HcCWfMGkp)y_T)Vu#t?n5Im#q7+6Zk*#ZPtlrPdO(#&b+r4^LU0Zx#$D`-WN z@?DRN+m&q>uz-We@__U6{~XndkjfS@kj5H|GeQ%`SWA4Pp$%YGz{kIZ6url`BRk() zZEARCGFzDzSwS5WTkKmAaf(MPv^2Cf_a2O^@J`s6j#Nr*bqh3uESU-L#!I!q0QK1(*ymrxWHwGLor5)1jV`D9Ot6vcfwyqs=?5yQG z+7Fz&ySV1vfjPYUA{Uvb)>U#&=3a(5ocmgD;aI=%rNEtL{Pkw5T7qtNxeT%E(71fY zq8w4LE%Sc9`>WFKSK^#|l?JD`=5B-XvEotq=1; z^7^`UB2+#Xr8`wBUdb*5j|2kKf9H1WTH7Y)doI0!<3mm`0jo_ z(!IWqpwN`|(6nzSD%-UmpJOe$%?6C37;lbj)_x@!KYXOstqu+vRmu0o)0t1#!LU(z zpqX8HkKREkb5n0}$5WrK$+Fypa#p^*VsuuQbW?YH{3v8)tM}g3)|~7tHNXA5sTeP- zC4HzUtaJI?)wV8sqIjra{bwtjE39*^*X9mraCSPMjmKD*Uiyi8aVRCSC0NNf$J0ym zD7_eCs4?`4^NHa1%R0qi-Q3YlWaaDNRY6^KT`UR+mwGJ9azioUrE5XZo9GdfqA+94 z`8EczNE=NOTjr-`qs_X<0jpJLw{E8&3gOp0*l}CQMxDAQstk!jjTsADM>gZu2K|%8 zx%?5j{0%94OT{!rE(I<{PsN>J*!3ZowuDC$+(u?w>y3jp9CxnUhXe7lt+)z73k%bY z&D$r~U!*O#ov06#ZI}cfY7Xz`rAk@ywM{|lh*&AAL?!>{4cN2m?7 zRK+ATWo_UDF);Qgaag~Ir7bqb4nKa zIG{(3?OFB7dT(L4x5$`SdQWr@qCI>fBr+>(Y)7IBLcYe(A;C>-dvAK!HP$1+>nBnC z>kxGxFR=^6LE3P}R8}RvtrTN~XdpG2>@3!iE`iE@+_`|l6018&iU?fXXP$NFIMHJG zB_^BzeN#L)KaZ2s&C{OlkZhNTYIfmeoF>DLKH~`BT6%{zC&tSGq&bFK@c4d@=Ok~x zjZ>YT!|;ZGk5`&^*I>=E4Q@9ycG-xcIfFZD-Yq0O5Lqur`A+@?`%mN1W}hoV18a?+ zmMA#GP2rRaJcrb%Ime-&*^qv)a2}E|*N{z{FCT}$jKHt7;L|9nxaGChxo-Qew zIKy!dglk;p4o;!@SLZ8m-e_IAZ-Ms){ZEm}+Y&br93mS%>>t0JKgpi`QFot-9&v1L z_i~0!N%^|e?tWld3=11Es7tcO*~VWQs_K$f#(Wl-vV&T5P_$9%ko`$*gSJeQHPJge zFXF-TwjHE}jYr_V)Jt?J(L=4j6YyZrmUf+bJ%aF#?idu;g3!7#pe95$@e8cHH?WGZp(H`)S={VbD!YylO>)^X(yX^{L+J7mX zp8RCAGq%T?1DY`2$7zK>X@K$}vyLu^(C%N6>pL(M(gfNDNP4E%?Pt4zezN&c`M~`+ ze5(uu+2+`G-LbMyc}llg?rS97NVQ69!>|O21>2>>Cm|NM_`;V2l3LOC^l}9ggEbUs zgw+gs<$$&fChr>9CZt35DZW9LY49BaR(~vM_goe9#3tKy%RS~In=ij|X7L#B`0#A| z<_g(iUJG=wuil}wS@UYG7iV{4n|H_Y2}Q2``!zQ>)s!dxls`R%%2o=A4O(WRPd3%u z_zcbB=grxY+qK){6CUZ1&_iEb*ej_I=XKI>Q2e67o4kU=2>lEV`hLK#?sd06V8pnD zm9e^Un-+%eza5mm^?913Ps#afTV^p47>^a)9tpc~UQ_2pTvO+c9%FK+9pk^#wufy< z*%m%pOoAq_+Pr{zKuq4=LHzm58$1rVGkn4Lj(_0x(=mZ+Yex&mWTkI>Z>2fny6j+K z=Xe*qDRL>hu=#yW{{m-YSd`x^>H7UG;4S(o>ACTl4orp|VMjnhjl2xi25|#<191ao zB9y;cSc{04w1fINKW~mgn}7%Z9KahlaYC&9op>J0$@Y}=US6&&Q-9-ob)oM2&P%+H1jbi5+b5z+Rx2*T{$9K-f{_ox>>%r7Xe9E}-HkmA=c&Df_Opx2mXk4_gV z8e^R_+#=Pys2-otpaJ=D=UDLsb(9g-d?{soz(2ic6zU^Ewz0Eq& znhx0Hb3m8-^?4`2PdB;~9h(^DJ*P*w*cCR(dw-ldqCc}VN8K=kEO9)h;ctEg zU+YErRZ#yc^(|QC2VFDX-N#*D#BYO$%kWhY)9720J%c!Wo;5l#9=lyoZtXo!`biuR zm<Sauda4G;Q;@hvnPTKGCU3Y~Ybqfe}?7wbFQy;UU; zlgKy$KfoGk-7m&_{|}qN+PFLXdx&O9PV$f7Iz@N_f5vO{thdKKg{ySF-S_1x)=kKf zhbB3Hd8(|jceCrEKI)vEXWVD7{UOrd?wnU`g2`Ybo|}6p$=mx|@{Zj|x@1YR8?vcY zu4u9w%*`3p8D3sDh~$m8WSJoE>+Bp-CBvxIX`18%fy8EKr*|k$ z#YtYj4@J>Govy)Zq@QTaOndjN<3AxmEeU>C!23^(f!w#GzQLZdM&OYEkkA}nNj0B& z?TU7RzN(NcU`}j7N(XG@m2kNniQf}k{O20%63NN$2{4P^J7|U3lT!=JlF~Q;%6^!e zy195+Q&AN@A135sP=X#l+hFGTt;d?WOo(=aI*my@5TYuc(v zhov+jzjrjI`pgoe-5gB4e6uWGMXlAC{6$0>g@x`Fk7Zs;`rb>Ll8PdZl15&mN8-iI zQ4J$Ig6>4%?cu<#F%EZj=eF)C2DK3%7b@FtW=DIrEYG}hCeCKP$wX7q*3let-IS3v zC`|=JQgVnl7g8R{z+AS;7VloFP$TfRZtik7bi<#bptg6M##|R&dKwnbTD^gB-CkZ* zvX&3|gqB8pwg6>&-@GSqH(4c!*}PI*QrbM@0dxO`*+j5`>QzFdah;Vge!rdJcI0Zr zILRsh+4v}z#5#JrecXJ~nXFxxWSXPzibj|2{&p1~g0k$U!CEunt|FqPV_^Z$fXB%- zH<}sE`h0yM9Bnh$+rm&oBegZZl}g&S8#-G|sGh^vBx%|qr(KoYT+mI#ZM=cXqncrP zb!KnJQm}V<`DA+-iMUmGxgm=RTY~MWcYQR~@xeIO8cnx#vyigGHZdXbEdD&jc-^#K zT6iq6QdC8Mn8{c}s&vA@8ZA>-bz}hj59~UAd6^u2Tm}7s(rBAYm5mXfmO6ggi%?)hk)|N5~-WyU9dNF*XI|XMB|aILRRh4QwzgnA5Qu zwYJvS7oo*KoPP8|%j1%nxJV)`&NVVBh%DkbxU%z_ix+lOK4gQ{R&ODa(O5BfojHIw zl~J>Aa*;i`q81$$29N5_i4jS_p~M8+B`jzZ{4ZUk9f{N1$TS8lhPQCl~ZAR|Y3mqb=Fr4Z)hU zmlkGr#a*erOYp=d&{H$hNAX5#(ixXj|Xu&gues#;likiA8-1jAxE33rx}9oS8Y}_vMO8i*KIHboNA&; zm_>gdYA;&#us7;F4tA9T(N#hictR?#xu7|&a5)0W0tdAVHec+sb2F%Xb^p2Y!DlLv z%!xNCMSW8G-jgvIGi$}>st>=(+DyUQl)?QyTSne1muc0w;_z8mMPzGy$ zKhi-T_bDvGE$`>h-6?P_=G!#za~mx8KW`W}kDK_)9h6$+seR8g?=OV!A;D~s?IxZ1 z3m#Js&F^?Jsw%aoA%8@@eeXAuZ(rB0yU4Pms(utl>uA|!UAfu2pB)-kG$FZ2+)?jz zpE(axLXXp zKU?g+OEL4S$qQA-ozMt=IrmBrpTrc!=dO%0j_FsJ{8@J+>7QKqm`p>QgHo_{t;RzX zHruPam#AkqP!dl5s$-nJ7(te_K#w%4BTT333Iq+9-b(A@$lB+&Xzt_4?F^pV0nY)k z-X(ESoO&*9=Y7Z(!PgAs`4}Xqn_hQLiu5F1Kv_kZU29FAZTSV;kyAktQE6L8xyQf> z4$>rG@BGM414cdgW#neTSyJ`VP>v}R&Ov)h*?lI9GMzoSwZ@|s0wWG5a)(&A04J+i z&^&rMcBCiV&4i!~vcX%A}ruzsnM9d?ZUL8==rhcz}=d#KVKegZE<=hDKBAF?WB=+^yWo6aZ#^ZDm zr7*CEQa*irbQRqh0T3LFZBp>^f|#hnWhu;7K;ouc+6lc;ycbKR;;rYc>we}C+RZuj zY74T(wF&ud>ld(&BLvJYp~3~1GlAy9&s%q^A6DqnizSZc#Mr|TKM#Y*$HiOBqWBi^ zu5RO)Hc?sjJ-u=9$b!DTIv^(0B+XJ&8Q3rxAe2xS`tWdvoN35-iMWj^<)*lXBTz)4 zplu#WaavTV;x_U`^iH7cEe_$j8Vfs1*W;|FEX&zUSf8Rj@;dbPHh!2qkFx2!OGs+_ z-oN}*Csa^X+SFp98s>RGuih*&U?O3X*&*zmOzopRm{Csi8OCGC{@t5#Sw=QWV5nTHT)*<^*NY>BC4 z(HY;WnDa0dT);b=_c9GlkNFI%9n3K6ItMYz>r9*1aaD^fI92;me}UXlaFXpwX)|`; zFSJCqn7KFwU)2syT45By+D(%uY5L$izIuiOe#Y=)T~uF9>PLaJh`d)!SeD$nIns)G zD7*0`D}VKqQ2>zi7`!7+8e9Ti?jP=>M5UrN@airZ&Z|3UJ1(A^A9*G{ zH;_h>dXjLHA`YN4~IRw|9xB)9j9y1qQTux}!CAVRyo`i!K265YAX3*_)MkcOAQPk9hQbLFGUtl4|8RTCEHMZnSvX)o8t_Qnz!S0>@W<3)d{E)Tl&YD=@ zW(y9{;ZW}fOSl3Y@`w1Elo~M{@wR#8A}!)BB%(;0iR*TcCrc-i($i;Ehao0J4j_dDQL4#A1~XDrr-Rcp|6Um?rm%Flj(jp_XZ`tN$UwGA3M;k_qmVy^JbLxz z8U0?rERaAqd7EHWeLeNXn~kp;h?J8K@OG8$4b@65ALT|kk$oD=h z!}7$_AsSouxI{URxO6Xjo4P;7$~31PqM43>jXSO`U0JnogvJ6LkhHbYZGWZ^=|#~y z)jz91xaqf@7ibJx5sMJ6zb=VHO)HlC?l0*cKrY{HRr90U3W2y5Obw9B>GVRKAyat> zmSGg!J}W>&HznFNDD6~eflzETB^jrKJZ7>Dmfn3WBul3#4IU6#$o1ULJs3UZTdcE^ zm7Ns%;IETWbN}#00zjdSXp- zmAFrkur(_d`N~iD^JBcMiYgu}c;#t{ZwY)}W{*#!Yr(eXe?q5bU8T5%=&<%WJs(&v zuI-Zr*=NAqHbYRZ1-^2YqT141G5f5(X!m+fcZ!gN6{bC%2A-}px&J&Sa(Z6@o^>$WP3j?FY@s&<>^J?^b)W-p>-rIivi4KQJlggBC z#pAT#O?W4@DF6MHZ?$Dd=w*5JPrDJ{IFFF2v{NLTZOZ2BAjUNrp4-JHRJO57;c0W?{Jda?w%!%xbV~Iv)_JgN5{|u<{T(g38S;nY#Tc@bvl&N?+{)CY zFASkR(!cC|Xk-L`7$wsyBHE^R3-D&dT8v;0W@w10FT;RC##Hw+%UIb72i{)nqF1Zn zFr#mMZT?m&;ShjqnRbu#A=?L97{GMntH9$yOV+h|$8n*BcoqB7n zoqNrmdvmk2w8@))Jtn(Rw+~P?YPt#3y+18yO%rAXhv|-r*{k8$xAJV*%-kIZ2;jH( zPE(?u$vTnL)2kE&^$Mq0k?_T5;0zgg)}84mp%y)kPUQ8Q2pl>$a5Sj6yJYdqS!)uz znmB`1RFx+#eq$X8=s`VYT}5?|FtprS*y?Qv+5dhH{~c}>Zj^6=7yBvb9QOIJ+4kGV z=tIR@*g4U2ZdXzR-5#A|Crkpmm9-Bogg#t^kOQb6cEJ1*TazQVPvf82=X+Yu#7$@E zE>bE7d@{00TGQp%vxJn1GNQH9k_>1gdoBFr*0ip>5mcK%T%~c3<$=~UoA!;Y$?kTH zc|Acan?~jOXuGiYa}Z4QZC>T_aEtS*KQ%WCg#fBX^Q*1V;H-;r@L0VYP9n4)p7@=G zKLr}pMhyr<`x9|3Q`j27v{(*EZqNaupO+t~?z2=B+EBi~FCWa*dbl~KW~Bu=VF~c* z`3=gl0n9`^<|Dttc75qTq9tz%Xn@~d?v!N;FGG%7oq28tKRx8Nw;Ori5;`7aJo)J> zB1Eh=`qq0$OmUm;2^la^Mg&MCi-RJ5@5a%?i^o9V?Fcb^iLj?>6qlwZjR4ggF83=3 zz?<-CRFQegcI(#i(LPD8X-QU4H8tF1hkvJX75!80#rC@H?+P6$@DA~q^xiN(e-C5k za1%$Z^m%qeOf@eD$*qg8o*fLm{p=V&9(!=KaQ1k_6}zeI^J5+o0kd9ds7><5)D&zD z!8MyoUS%3FC0*N6gk+_g(M3!o%Bzur(*(s)m*ek^HV7ENmC_ z&ri?&^4JiWAFxLMOBBz19c^2K+&Ws%j83{L-kOT7mY%fy%jZtCC3z0D zPmwp*Ygxk2sHc|uhOEsWBk=(~uH;%61l&@S%GG*-lT;-%#e1VSP^Bd>7dZmagW~`c zMlp=9BqmJ?y7^#CYV=K=*$l&RuW1_fa^nIYYxx{==wf?z92o-CYMKfYiJ~^e4n;k* zeneL?5N%zIk*J<=5K0I|^a7g-xg>G3!_JAx1mV4nYFmdOiPnsZ=89@F4{F-)5qC6* zgrj=Z17OL}vV-^m(I77PpuoG=^0X_5?u)8cBR~BDtUWXm!c@1=?au(_3aZMy?Vmm*nR)vFFTc*B zIMTiv3B>X7Qer=-juJ$FN}&W~9hZ+O&3L6Q_T#RuFBnIBm5keFSt0&+g2jNI?2-{E z^nsM%FBl}>5#A;4x>Es zxb!~VPv<+ku6u8fimJGjUGhD}2hm+7Z|on!eKXN=7%l0|m_E7s;ydpuKq7Cu_iU^C z&?H@G`E=1{%eTv0yYSh^a_&m=Lr*koO866aYbhm4P&7sVYL9ui6!Y=?jrB42&3oDN3C%4ar4dT&f*RX6+`io^`iX!#{5uClpF@)M!_Qh+Ywh$lFsaeWbLav-s%KQoYT((O?C?D%uwXJ8e2_V?bw#y6YUf$HxzKD#Sh#z=)a$xEJYs{|`oyRELsTyN^j zq}L;1BW&>28E&snLw%-#?~_J2UI&|^6CeJxZu*I<$FfxbI&f#sFDFXkrSstR7S0om zj<_;!U9Du-0y{zgpX^H6lUeHpTUHo}fEJt=9B@J6qe<9(;eZd|OI}rD{0Ls7dT>~u z_9z1N(ETF;Y_x>87VPE8Y5FF88gk1g&da7V-2wfc6xVUWFuoXcsTzSx{y#Rgb?wO)gD*-L?Cw z)7F7cA)KpHy1O$G=DOFj0>4-;E@ex-W_J)TL|EWfLj;ZJKdQ1-Qbw*t;;@SsG`b** zTrmWRCc{iidqsYIoJRT}#8cDaf7!_(ho13t4#1&JMx!VWymEwfVHWc#sem=-LRMIY z3Y_bq)HO@-Hm>JAIuvl<$l630xdnS?MrQr?{vfxce`p7dFv3pso0kU|{8;YyF<$Nh zUXVO|6l9TJ;JhpU=$7EkudOOR}n@i(QWS5=pm$Xuu}8SRAMngT+)7r z#owJVYB87f=m8{Q-xd{k`8G`%D655-F=7B#*xyN zM`_u;+`s$^P(LnAv)*0g>?a1q16vr7(V5k1|gU-Ta6<==bmiz%DJSL?P8 zxG<_AjMe&yNBpREQQE|2K2!u_L2fe&o%fYyoOVaTZsFTDbem1)CYAfW@bibiIT*H~ zz;2}lZoK9z2K8e9prTK`OwG}o0{+os@XZdtuRb~5yqg~%36#I?w?W`i8{Ju*_{e_} z%N}I|68@Oh8>yEkihS+=bav(^OaX`yL)H^x^(THamx8)SMK`buEtyq+Eu&NCu>aeJ z!!%Sik#)c{ffbTxorfX)d+~rpCw=hXzv22KlV4VNVrjI zmKJyr!LN~mPD}@1Ht0z*8KDJzKr#dZMm|APzsQzYLU4UqY-$@FVW^#v@OXK_qrvR# z=$KJwk#f$Uf0z^$jbzbX)rB%$8fRew{~C&m3Ezu%g(To zt#tIz>S_E*(#Is983{9gAn4i^cC7#st($Eq?*F%ZR;u zR2y{&5uI(Ik8VB6ncw!nPY&OP4gD<+@Jy3IuU73?q#DXwM%2e&>l4m|4liGb)TkXo zV_Bc82?rYYf+_1mDbGCPk%YBknIfFGp@IioRM+?`<`i|3?^;rp?hZFygVGPr0-8jc1>hpG29pqzN+WQR`6TAWBjsb#2PzC8bxLwyC8~;w zki$2fD)_~o5dDOHgn$e~mzb!VpwQ9N)KSNwq0;>Bj{C9q2I!{rz5jaob<_XsB3zP^ zPFzR9S^RznlggG6g+uxyr%JpyQzfAY&klyYQ3Q92=Z7!-wUk%gRbhW+zsRZVys36k z<^Ap`;it|Esng+jj2O$aa=j9dQWR5sJ-;u$9WfeWdFmZcLJ(+7!g8uHtESDTZaoAungW3Z-8; zK@vyiA4nK5CiOw>?MPVEqN0f6Y)j-sO9GImhC*EjMu(<<ge8W$X7&9m^=hgQ#{xwV860=75 zoD$DJJ^(%HH8)**7{}5$Q1E$Awz~T9u~TPs#aH9qOb=n?iqmE>o56Aqh9tYe^VkPp z+0w8OkHaW{8*RPpe0&g5pxR*Fa(3cL>v7b?Z}qF?c0t?qVWX{SrzWn;x2)5;Tf4LP z25eVK!Tu-R3qt%p`yfcJG?W7d*8&I|?2w$!$6XuCP_r}sX{vJxKQ5n(Rl-0D!pK<+ zkkrOD|K25?l48D;#z3d6Vmu~EVo#%FtI+d*D0>Uw%6UaWGaY7TW@cul4l^@%n3?gU z!$~I{W@ct)W@ct)>`eN9`|iDOX12DrRJM*JTUObs<0?z~z7appNl^KaXOhgmO^n*P z90r$N1aGfeeN=?+VJ?I#^3np+d}p4kbo}KwwQyYcjtC+BW4bhaXCYQmK|~HUUU5Yv z^-`@m6!bGLXTLES8eH2%+2#Xceqii;p|FL&=PWKrnQ0FctK`$nW3)nV5JOSrfP(fK z6FErz8X;PYHF7p@i`Zz_HaAqh*CtC&_+qLg7-4%74z<5h8&9Uf?y1)SBtQBO<3HHT z@DqbF{RKFgTf`dLT;g+=PHwXogzM1A!sG6!o5Jv-!E6{ckgA3Iun->J$#&E>L@t$W zdp;C<3tG8#ek@V_E^hYJ_2Cpj*CAP_2>UhdLu8it^V_b^G=?YOH&iL?VEBht_4M#0Rl@2C(dxbS(*pm_%ntO`}kp!+d}9H-*FKOCWH2A!>6&; zNsFKV{3M4S>O4J^N|_hBRG2=zhoK4fDP@F;j>99!W@jgB)2L_*WnJ!MCT?F?o0o&#HL&mF zFErI3)A!-viQ%vGU6r(@94XC{#pKCi;aCI%nM$(o5KEdTW~#A&`o0yy5;|(RFp+DO zEL4=w{m7}TkGwG$@F!=q0}alN7o9D~o-Waxm@w_c6FZC>XFYju|sA|}bz*H(!U)O4MMQw!Z zP+d6;xg5vZeb9b*n8zqu)Y1nn{k(z30r}8%rI1Z@Dq>e-7d~W^zM1?v|f#w?MO#LxJmxY~p8%`g1$c~N@oM;|Z)#=V{MsvZinPv9btv)YdpITK zPb?tp>wb97H8D$ket>{5VTueI-Es!!d@D4xf&?agX@~f^adMNucdOyohndi8{K&0F zfgWKV>zB+SQhQ<+%G{`nEuXB(Mn^%*ZDmlvpB1^r&MF@4#sz zBn>|SBad?CC|SW@GF_TK5=U~RV1?iANtM_K$-9U23-53T;Wv14cqIIGsJ*~4u)FY* zeGrHenj9Wv-vG!#G8N%1D5wKEZtda%Wik&+@i;AKPO6NH9$46(Js0e1oou&~vMyYD z%{1UE_)pvG1scT;`66bu=5^~_*n&rbuwgl+?cXw1Iz@MN%N1!NC)@N4+`^n&^jR+? zqOFgwkt|@)cJM3QN62GL*Z~fmZr&|;JMLOxiVip<@zbnb3ts7Is*0X|*K;tGXL#K$ zxNf;sSy0<`ni-m$nRTm3jO}Anbs^NTpcB-185t8t$`q}4kFp4Tnsal#8IoE z`qiv%Dafu6POh46A+rEmfo@FfT``Di9u9o)GJ>_8U7r|L-OgSJ)Kr`ML&U5llgSwp zG*n^ehm?2Dt@w9NeDH3jZgYErz7Yd~pc{N{pg)Qgy7sf%)!msUz0s9GOA_a)aPH9L zC-vI+tshHUTYq$hE<@M{(v+&XRavk4H;Og)i^=K0g*uydcibUV>uAN0a(| z_Cof$s*2xVq)!Om>Il2)fkO}dy@J2+W)Hx8Ljuj#-<69=W!=mvW_618qgP>DHx={& z#he08dodkM zwe3Jc%;w)ikoLg#GdS3=4y2?alZK&Hozn^y>Xdj!k5wo+%0$w~wd;EdCccN!*v`qD zZGD<9v9jcIPlTuwTJVW89}0}vb{q_W};NL$^^oVVw#=V`Sq(blaj zX}g2yavJjApYM!=~->WZo2e-ZuG|vejN6Bjg9E~j6JVF)kK6Vk%Gu8+D8x@LH5L>w_JH(lzSd| zU{T-tUrRt|Ltqd|ol@jbN(~2%(Rsy(1=pUrX58#N_erD>tX~v8M(X`HP~qkEJ$l4q z>~wt%W#jc6uLX*o-*qiFm>2{yuU0W($2I>vCzz*>Rt}t}QOFB3w1Xr~DplG*H{R~0 z4%A8BS_&4dFc$eoQMTAd8MMe^p8SAB@TV9U2a=t!Bzb~S1^GTOCYcoP1RB=c5~)a% zh~vySOU9!blz8TBh9oJ|8jlPfjWvn}@h}U7%zEfEjFE?JFFeR8(Mj)`jixBWJC%BP zf1t$H#PNF!E_FI;q+*7#sT&eqJb6GEY*6(XH_z-RG6T)*sYODc8^2P!OrE8LG1e|R z4j*(tJX~SXkp&2kouzx0;#40g{8{&S$_S@O92TejWz-hoI-xBJ_@38ZoN)j=B)61bRoi?fwC5en3)$jUahaVht#L)T1YF`!}wHJ*u(Xd@w_WgX#){59<5p2F^}%} zCM}CnG@3vE(_MWm{$5pDtx3=Ra6$cK+(W=!h2)p{rk}T2G~fCsw@*_`Ri)3w)YdZ{ zp(p+Ef%kgOFmcO!Ar*jrzOCnK{9GemqoKPLNv4b@2f5Ur)gJUW-u1Vc{bF$%P0R};qWd||0Tf7P|VmsccY9UIF6d=LK_Q1|sX=+FZ=H71X zb5399dm6L!Gi=f}!Dx4O(8TK$A(PEyE|{N;h)FkBNVD8JXqO?|%`lJKZNXPCeVp+F zWzNaief{3xTbi0ZK!+o_$#mVB6X*d86SemJsL$juF+0@YgR6JYk%(U_znGN3FRPL0 z9v+`PzuPVHv>z)w5*8lJw|uRyvIQ7#7jk{~iLHT5>gQ|BPvYxprak%X9ZG*xa9Pki z(@d%zmZlsJ&%r9TWc`E2EvLv$*Pzh)8}oJj zW|YIZLD~-{yh~<+IfoBg6Dy8jF=>&hHBytf;I#p>?cfXB6016^qBG8W<=>wi=b|{F zZM3p(xRaC-r?kcK8hg_3zk2*He|x&+bWI)>T5Y6l@MIfiO^#xlgmH;@(&udD2vi=K zcKi&=;P=6X;EVsGStd=Wjis}*)y0Xd<|+_Gp|(=0@uI9|X-dLmKvy9fP)IcbM%~@+ zps`G}%_72cxz{5e%?BI^yaayUEC8bERRL4WJ`dum1iuJ^4iX`2Lsw_Z;erWe|F}dmZFRc1smTdDa z26y*VkK8c0CZwb1srnzSZEYD!gM&d%&{07F=*_w_h{_Fy6t8%?EskTm+EPK49Qey0 zBYp&)#|<}h_gIRL6~&o;C>$5R&z7p1$*s-^sC=$aO5XlYU!B8sR{eol>M2z~D);|a#wmCa1+ z;3;jC?J6;q_=3}2J*=PkRQrf>(&As^UUz1Cci1?O)R0jmrEBd@sp%v-s;arzhdO>eOL-JH*`MU){m!uh=AT>Kfz|1rdnJS1|eI%ql9kP*W0(t)*3s_=5x;SBmSPdvF4v$F zP>6p=RIH`tS8%O|uG!Chyy1bDoDip}=Q>cStziPU-jvZRYqNRNIAIAof z4akAmgvCSnl9?{M^dR04;KR3L@!^Y20?m;okAf3Yz8@Ps>%q0Zy9^w{?xpQy zVcwIA+iI_9+d;7KF*m$^%LQ$drmR}wC=2cU^F)|BOb@e*GHjfoRg#Dy&irB!b}n;y02Z=#flZ4hm5JC2d@s;@xNAJ0H&M9NvS&B1&Gz(*`!etw zw4LtpVpZLhV~Q3k6q(DXt2NvF0xc%}<%G_L+$+)c2eX=lu9F%&1gab~gp z%O1#-DmlR`Nk{eZ<)ya1qS(mx2>Z|3^3EO+%@-F2`9W}KysQ{TRUYZkE7{caeKAC4f!T8EUSDEj4Ee+Hn zIx7|&rzxa1_u?9>Wf^t7qz@skKSPJ1)`uZfJS$|P9}i<>d|~TF#eFF?RTZQ}ngwCS z7T?GvDTN9lZcMG5ak>qXn% zdi(g^p!$P7xYSa~V2TbY8H@h-shFd-%$#E$=UZMafy0g-AINwtQT?zmwV5n zrJV+i2Iwln+0H2IzV`nVQk&atud@` z*m`(rcqHbf75#jpkH-Q61hjvri8wTn8y8GRIyUzVnmAZiRZeCT@tnDuPhtevG`AKy z7-g7|IfaxKUarV|KXcw(y<*o}K62BFf^soxm9AjC?Ku>EL37e^sX%$a2(D{yG-#x; zEr7p?zByQGpluiRaorsdt9B42279>;sekE|-Wz!gPnRAGj04PRw8eH2lC-dtxkG2d zKN}Hytp8GdXAJj8+Go~r&|tN13TCBa-Zu@cj-4CZ>x=06QI8vkg1t?08yzYMct1r9 z@(KduOw4%(yninns6NMS?Ql})V-G3G&3v3*oi?l9X>aJ>(F>QN_DU>dVzT~qOG*JB zy7^5}V3njR3u*7$A8d47Fsbc(T5!?qBc`5Q3r@sY@5QNrMs~_n+S%pg@Z!!?>=I>D zvrt{+Aw8+=)q|6CYtO7QF4zQnXz-bw>L!clZnLBw2vPo}>wp7`=j{jaUgc*X zJodaP{DI{yfmM6d?fjmoQ0UGa$cw0Zu~6bR;v(W)1qnxch># z7?UGZtshD55Hyl#81iY5Q8X}TK*K8~a;@i^$OGmP_dU67M!AWXh;BfZ5yv#j&YLR7 z^RVQTglk=M5SRgr#IUhQBS84XSEZA%-ev}C!-NyS6F-El0*8yR%ZYEj;M9;j)Y+=Z zg^1D67~R=0h(UIh*NVGRU@*_VC8U*pEe_EJYU+9mJKSXFFEd2HI3VCPT?x z%rK)*?Or}TFei{%2iJ?H|52xnU>rbD-js~UZ*QZy@V?VNx9kI{y)6$1hee~U#eFJ} z-LtkV$k9f``v4Y6!u}wXB~E&f?!SA4~Xe=>oKsf%Yp-?Dl%EWULtCQ!jo_~|2 z8mqWZCc$l_r<{j7f`Ox-h*f-urO!q^=>x2`nwpz?@#)F+z2_^hNTzOaF$)Hmv(v4G zq98S777urKtaE(aGyv>svDGjqRhNy9%cSsY*_qWP3qp!pihPRLUG(fjKa=lwe+9m#8_%+o@_Z&U#QZUV5#z@>vd8ATWJZKrV-$ zWiWqL_^C-C`6av?r-{E9)bST&9l*3xL zjzh<^1JD{zciHJ9GAoM0OB|9|xk|71%!K!iBDL&~3*f#5x*F%kNYI~i=g4*(b<7fe zI^M`fae?8+IBh>*xxnsULz~Di?`NH1Ej$>o{F-l-mt>h9;o(z$V<>jg%k7i%y+SKE z2b?(TM*$m~?s8DqkLN&1@F2t&VVVq{rZy{R2ZNIy#1saQFxD^+q1pvb?s_>7*l`A% z9)WFls4!82IP@>XiP3Fd(28Ex(wV86=6mahrJRym`P-GPFCyXQgo(kjMp!G+DYe+Q zD@eCTK|NW;Y+R&;UmQ)8j81Zy9hBPv^yCu$8mJaxq8a#?w8=}&gwreK z45cYWi)d)4;q=^2JH(AlGstx_`3azk9CZ!6I}ey`Jt)^gLXD-jj6e{ z8u{#sB5#(nY&vjbPE*?Rm?=CQoK?p79GrF*_!5UBcg-H%XCj)H`|X>Rmq@lZe-QWg zky>xjqZDOspd=w=v92! z+HH)qM8p~geW0ybX$E~-XOr~X9Z%S7Y%(4=WUO_Hn~7Y#_NzOBY|m(v%gj=YP;63Z z@xzxH#PwQIwUt znUUs19)viNh3u96Rwu>eCA{_>bp`s#gJwOWVtPAgEXOHS`};Ac6nsXNP57jegK02v z{v!*|^w32?=O0EiD(dCcnjV-&5V4l!E0$8Z&Gw?Owsz>L%+JiNh*-YwKl22#xy&Se zV$Zz3+pNzfka`V$Be58PGf;7n+BRnH(cO4Lax&zZcMW9=TiI(5r#t*ajyhNjxEnj_c{-eny(#{JQ4WxQ@-HcLpSE}FtgI2paQRmOpd6N#KFZ!vbe_A!xKRyLC$aS6^V0LO zW?eL}V#CxS5X|eunr}m7h0W`qb7X348y9HOtvrc_go4+YPJNi*1V3AVsKa8q`F1~N z2tvc`TN2hC--Sw&f=R51{&Xjkgx$a13uRwER&qPACI@H zcLXUu_AYuynbqy_HaJ~RH7n;9%n@;}4>sq67)hAxS^l%&!k~LHuBIUhV`jtMu%u83 zH@wuamgDh6A=`#TAm4x1>AaU14;^O@>ysDy6DmtpzZj74Eb5MZ@Azd4J$-l29kiKF zp2FPE`McR2vfEn2KKZd`Xv7dgK^@g8MRCm!56B6r3-TZwy#xj7(a4b+ig~nK z<}txv{X@q{8aN`p3`M|99y~Kv;QQOHtDngJN$v>mo9V84sKL>S(&zd{ar1ipMhNAu z6d-pvde&DI7lk9Dt=}hComb3ss?XH|Is82$1zA{1u^IHd8_xg&zr}XrkAm&VpY~?d zbmcH89B~?_X(dWlFkiQctyWn3y`LJJxt}lx5%;DDOg!Z_K7=YL@U`X8dLTK!sHDm4 zxTuF@)swKurNO7?ypIQZe~!%Bo+J1CI+^8LjtjNdQ9N~Vutqh3QwocW#M_{@e&8qN zL-mmKA#71yOT7V+KO_7BfcnKqyZ58|w@; zOl4lorpqV9nt=Op^v#p4#k$MFzHt+O>y72prn%d>&+}S1hVLy$%%7n~u)Zn&+sSjg zthcv1`RF*8pO6LD+$I%49gFex(Q?rO_lL@g5oNm4V|7V!o-MKv67w_5$DFO`84MW! z@65DxkIHlhRCLgl7>~kcMNucnQ8lN;99t5a3fV>1F&mfX`dAz#&tU7Ox$5=oZu%G& z;F{oKDe0j}EHf}}U977O)MfZe{B*&)UAdNH@fI8OfrhToxAP9D48MazG#5@+s;sMW z9i;?L0o-^J32_E+$N>FdL*gfxk6OCrTjSiROOrDmP5i;Q0lJ(a7L~SMa?Ty$WwPKkLsP)Tzk(u@-#-bl)y0+gEtuv#yzGXYCjjG ziz9G)#knIcZw-`(+d1)-={2%wa-c|+y!sa8-b?D2C14|_dOcbX47 zA&%&vSX5Tt-m91Y^*wh|i@FZ|G93pYQc~Aauc4-OQIPh2|ahJ;I4B>Ls zz6>*xr z+<{f{D)&|e{U?$KOTDKmTYYw6BVc0||E{E0c_4cg?XsA@tg^hSNPt0mWmJ-7KjTp=d8FOa8_KqMf>u&IoC zH&#fo(S2{E#?OAillx8KPuSOVK$RsS$A-8Jy&~{n^bFX zj0A1|VQ`xb=6fytm9f+Ofx+^L#oz<>3O(s+-*33$0xVBF9`=;3rQzFg*LS~eI;TS; z-RdBQOF%F%TYm-eL?1D&D0*K%n+_mPHzCu;8gXJGgatVjpjat7iKC%tyW7;v9qA4| zc{P}U_kvVbHt^d1Iw{_l1+$;=Mx_sE+MP0hB)K>|yEZ8{0#3~|@3l8~-NxDCI?%aK zgP)fK+7tsrwzBq#mxWHa9NA{s(GAxfth}!rzkC#+k#P+xj)kk%9EWq)M6^0b^;6nV zURQpIM5gQbGFCpAWrLWCH_oG0eWTLiUG})qZq*JVC%xF#JAuU=1Ly z#FJq`aD(Grm%YB$oDRYv9fD-iUZ=|XoPJ4_Kr^bbKAe4D8ekIWJBo>pmZOn0jGP>p zzNrH~LLY>qg=AZ*dkADq-@x0b=t^;C@lX&bc_XhohXU~*{jvb$JnZ-_85mQrN;^@Y zq}n!PUF@D5CG*UzwQ9RD{LJad0pD=G1rfCIg%Ivp+dFyE=?OajrOU?TvFKU*2DB~G zP(|ta^Ck{64ZxHOyo!+)jThyEeK$DB>=#ALS8E(iA-L!BOF8`8Mv}TNm4QrwnDG=GR%Q-;p z7JLG5IH5-3?;}LeE?xrEwJ!`0q#ukh=4h^zV=u6z6%gW(1% zof2(lf-ekJApd zO7lClMWxxYj>0{>xgmH1weEstR;lBchLA*4^S$`}^_h)0Iu z(t8Ahw}=!?ii6n6;h9Kl6CEkm3KK;hAudhe@4y^#S~tkxj&ksEp$}}UTC?H#e^c-Kki>*$hmHBF2c(e`MG*r8II-aW?%SF zNP?CiJFSj#&LL|ohL68yWmB~u3?HiyZZoSem|Oi6E|jqje5?EDhWgg$eL8QCU)69b@2~)^0rO5$&w|D!>2pdB@L5bO%z4 zCwr5yV#an+$Vx1v77q2B{8|$^wgaCnD)5Dp_Pk0&YDwClLN*m#iEKp<0@m2OGzd(A z*ebD4NzKeB#-ELVF4oNN@{L{Ro+F>a+a4btdj_DpA}&5UaRCUnovzgch~b>uT5`MuwS+K)znyF4!-{=p`*S01v5TEx|7Hx zkZ@~+2z>{c1)5&#x|eJ6v3~v|=_$OH({@xM%}P`_;KZc9I^Lo}mD)$?zFr9qyD{(F z!9h3x@{P&{bHJZ~Pc9)EtCO@YRoU9U{fpwExY3KCL79I1RL zaMTEgrzY6WjEF?9ZWJxWMh;_DWCA?tmmtc;3v2)eb6ps9ogFF9?Tqi!TtThoamEAm z4oz*GKQ3sG3TxBz8pB3r4?fxUkVOwS+vOCKR;9h)!t8NQZ9d$u0b6x){R<(=n}y3{ zVgr}VsY0ENmg3*}KA4Ik)EEam_ zU%m;=6HG(25U8#+-1?J;S7Q5w>d>XxELw_yik<~nl5dYQ`XCG99S7a;o$MctVQZKr ze77>lCL;1u4s*PIxxWQM2e(gnJhib12r>Socs z6dPbNw)gwEWM;~L2Q6wgxg@-J=4|qy7TKK#FQML*2|I?jX8@ zkSHOSb96^@*JF#Vco;LaeKGou^%;o}MIf>B3&?qBELy=Hf@2469zH!l9WlRO5op`` z8R$5R6d$BNPHr_o#+lQ)DA5r1tCwznYjCAS!+KPpohUNoknAAxrZ5P_u5=!DZe&q* ztTP#9#TDQuMA?5*X8o`z>~$v|k3qZ>!r~Xf8s0)?Z;wevuz(~`$RIz3J$7y`*@gia zN%zbspte9&@^CUj@N8RsWckCHOr=$LKQ5iDN|2VHe*PAJ91bzn% zbc0r}La@Etgmsbx)hYF&q8=@91Z?bg{qGe6{hF)7n>`NtACu9}Ac8l~$}nwh<^t4( zV`qhao#(Arf^eovT3xfgM;SPgqKzt!Ru|fO>3q)yS#27T5=tdADJf}rsbr`TneMJ@ zA$C`pVKu2@D(y8sfV`qCiIjBeB?Ng)7=;Mn0leD+-|5tV$7eO<~rf>G;^cBu2sjzCatY@NcyRYWdxkkH5nesR5%PmV)8X2S9l;Kd_i1 z>UlkGqM3(3-{BtjDzL#z5VW)033-gVIXwZi3+N9E@%C7>BJ@iau6sZzfF3ajxZ+?W zE`SEZ+c0?WJ>m06*6xdwt%+Ihr<6wumywDthm?yUmm^DWgD_lWbFc-a6`uB0fOS*c z7|JM*lps>H#=5lzR%4++v2NNMK|!FHLWGHs z4jbwO(V1scCs0fH(Td*s1@KNStMMIYE^lywQybR|e^{t=(v4B=Q8Vl)XVd6AGDBRC z^UE{J6JQ8zs*F?Rpw+HxJ{ydBTKC;*XtHbbo#SizW3V5J#?h+t38fcr$OHXC#K_40KSUV{YRXa?;xsBhY)qZxOx=|1Yz%D`lx0=^hce@@DdQhy z#uwcE-^vVD#;*p+m>Qb=ur>dZPyB~IgPD=>>%f2MGuXcpf2s5T=rg`_6#pAD{_E6# z=`+665dZh^k2K;7MgKSctFZV#xBtrd=WJ+Zj=%W)e+LfczdDL94aL{?C93!br2n^+ z<*PHmiQ|EKSL`8EC@^#4E4 z;Vbzc=>M;W`fv3A*Ii-|v;E@!|9#$Ht`y^cI?I3OK=bqet55&Esee27e@X!UN@Bh$ z|1T#16Co29Gs{@=fQRQRAG@S+{sa@V_!N`I-zl^SZWx`FV_w+q*Q1~A4vU~~R}zoFhm>mLJb5l0j23AY2D;da6L z?*K>D$P$QC#F;|x*bzS1#($u1PERjy8qpe|n1Zxo_av`~ z(ufgA9RM*v2mlO_DQQVHUyj2>-~dh>d@Srt%#C;fU>Bt^!p{X`!kCG)5N0LDMsz}a z0C0=a<$^0lB}YLLmm($tGy%~4GX1ck9;5}htLmYYV!sG~B8dTnMS&Fkhb5ko_(k!F zF?PiE32Tuw0W!f5JJHGJ!n(|e!u{iB%``@t-|TaXKnx|85l;ZD!Dxm;`NT?yX2DQ~ z{mAh(!KC*xqL_%D!SFd^7KoO?&^e-%j8mY&xO}FNRKkJVNVtK-07&leWWh+1PEqdw z&hTg48-#vyqndl=8nJtn`*+M6q+OBzEhGv=0>VF`m?G^l?g%&ZyPUgt{rWZSU7|99 zd{Up0?mR|;R3e|j&&K^K;FV2?cH%N@+pi-1Dlq@mlaQ40-0>rlPrp?W`G&cp)%k+m zFq=JUkDpWSlJ!RKX>Ri21p>q5W*9~6XFk+KN&A7j=vI(zY6t(0DLs2^+Z9Leh!2pc_Dt4 zJP}=ror}NYI>`4!9%lZbHA;tT#<`gT)PU)@iACN4xrs+s_-Bbm;`#Fs4-#$IA;s!o&^<;VWkt#`s4D1`9pCG( z$rPX@3YCkg7)&V&N}N4KNhi2Zf{X+n{Dq#fKuU$Y7y4C-L>-KrBS=cPj|6w7scBDi zZAWNKcoozRaZ5k!aNHr_|Bk;87rP`B9ncPb%X1u}E~NL(19cxMHi!^H5Ffk+jrEfx zmU1IBbrY4Tx}_Q^vF=+9ehoZRWU-J+9=;h#Ab?tw%m|%*1t2L-N<`mn#8YF=Q+@9$ zij#}RgfJ7B9AP2ON`#FB2jBvDisI#>?+A0&1i}a78H(hS%p$4|swvD%_@H zL?0CD1bqSCCmlYTp85oOf!$Y*l^5g(e}VM86p8H$dPm!5AoK(Gz}c54^aJ&P@w|o{ zt|OfCf5+bc5vw1-3+9Nq|C=yOFcUO9kQcP$m2en@@J;YBaGm(^8h!r8tbY{H1A)f} z;6!<-0j|NVfo1a7_<1aGPn1N6PU49afe3>HgUAQ4?f34-0wCtX>_|K-40!-_f-&NP zhQ&>Yn33>GNKddm=E~B?vJT*>-z-bF>yV*gNG>)&&wuh+O)Bw{j*LscB z(A7@Br3qu4Z=%LqOKtX3aj=&o*erMO=WEF?oMDHG==Rwm`0hos`H{G#iGXEHS6RP z)yK?DHwJ)*t%h;}8r&#J$}$HsahWwwM`DdB{Qv@8hN>11m#R5;*pqO4e)N1esgCHZ zKMJnKr?)RzL}zP2r*}6xa>P2pazffLf<3)Aa$XQWVfEE1 z>)UANPplAJ&TYRw#2khk2KYr(ak09&ITepAAzH3)AX-{wJ9$6kaCi30o&Q?iwrj9S zy9k!eJ(bqan5>ZVWBCx}?&7`>#dga{Jf+3Zs%*UGe%`(&S;+KsIjx-MD^bdL?k-cO zu$A6d!)e57_7<7G4&0Fq3dXeMux~AMX>;~+_AavxzXaLHm#dYKc(NdvCJ8=P!Ohn?GZ9jneN^e`ZrnRfF?u2nA>B6!cL@h||J+O$M^>G)rN!r4E5k-jP`)}x*c?wA$@@i9 zk@^#BSX0fBfr59Y$rNbry*ow~mR_A%gv%&+nCJnk#cG|fod7P4%dPl(zYvZO{h85E0-Tgu6Q(wb5HD5c8mHBP6R~~b zTawx|UO{~FF2XKyhPaqwMZ zfRxyggoGiA%M@OCx6Rcb{5(CTN$zqlGURg6J_~k6N21QVTq!?~2kJd9v4$@|@zQul zRE4BIOrV^ce%G1TkQMNDl>Ol~^06Jpf82@SZA&2lzLh1+i+-lptiA=(WymZ= zY{IYt;S+k2+h9RKIRMG3y4R;JCgXu zn?8&mno&Er!zN(B6UOKx1vf0&I2PqF$U!fRca!)Ez=a#qzC~&`2YL&2FpOb>oT+iO zLHIZ=Ya~#+*@pFcA*VQ1F7W7|_JC-a@i5_&efO5_r#V%9lxE!FAkdEo)-lL7@ue=< z;KewjnST-j^f~w3hp&2nV~z9~y!CLF+M5D+{si#7_N(ZppMn*N6n3dg>hM&_&+TN5 z=!;G;UUX8QUOxO-HP-UQVIB4iIB;mS{e=8ce?zAbI>|knPNGhA+frK@ZaCPxM;N*+o3_3oA35 zi`-SFwob~%ed({QtEs0eJ*A_XXe{QxekUfOzWI2xXyUttZr2u(;@opbNtH;(j^!g~ z=8-nZ6<;|8^Z6KtOITP88{6g(@V*v#+=t+8tNMASR|gfGg=NnfffF76tm=m~8sAot zDRonc{n@S~k+BU)P=bc5*qYselj$}O%@=*0{Jc)gFU^}P0s>!zqQrTs1a5_AxO!9! zvs8tHTXI%5F;G_rPqZ`I&pkxP=fd z{@fZDH`WJk$EjTmXKv@o1BTknn@%&o7}5c(Qr==*3WS~1`VeTmj{=;CF}N9~C4YAk z^D?~tDh~-`BAc$HocuVH1vL+633=hft*KiH03T7Z4{mC3%Ucsl(jp-}etHaU;YYu9 z=k3QdB3j!eQXY8&owm+USi*SI=14}~Y@Cn#4Z}zCr=<^>BbcYRy~ysQo6z|47AXf^ z3$m3|cVowZju-UJc(fd6;z{KF55GmfRAK1jWwpKro*a6q;@bANl;$%vSJ#N|(@pg0 zIw<5mAT=t6et7vIL`odJ+@Y$m2W0hbR}>)$cG2iuNSqn23_D1V`&R6P9j-y}C<_A{eaKvSnOS*g-6%L)xoEcf zJYjfoAFhd1)W60nXhkT_W=^3cI2z*JSt-fTgZMI%5IEi4WI;&5g=bU2%TU0Zp6}#K zO$NXP*?OUrUE&4F@{3M`54^1w7}?7d8uM&DF6yB(lc+fRp$8q`4m}-ZFqljQ(U3LV z*sIz14;-)0{kMY|AudomG#Cmwd-Eq|=x8xKK`}*o8f_Q3WR{FR+1;See^ESsaUq;D z4tuYeVPR0roz&gdznS-6+IOg*t1njMdPN^+I08MDXhb>UpV&J@wevSKcyx&+rlGn36eA?RCgT)9Z9z1ADB5dvkc3;4G z)uh2ulZ*15#pbefatv%unU8w<;v!GzYf`+>lkaj9ccYt&1SjXtqv}(nnV`m#F9ea$ z%x~k)@dPmkMu@Qz5L_rD@3TLIL~H#D;m1U+5V^kqzL-$&lvn`A9tHU!j>Q z2w#KH0$5=Tf4oX3TH}qn7IXXjsxVo4qrl2w0qjCyGAJiuvh*?2(`qFRz5i9&cK}7T zG;OO02nZ@cR6thAna#UIQG&bVoFwPCug!7aN%EVLLgV9L<3rGzr|a@W9pW8 z0V!Flngz7nF_m=Tw#c0)gew}is6w=;E@tSO=k7f? zB|+p%wRoEB>f*z+@G7;QeM+C$Kn&g^HZ;AW^9-5I<*yo6c%z^TkcZ;ig&Pu&{^Iz0 zI;*5J^kuKfrBqvAEn@hFoT?e`X-m?8Yub7rzB=WKgzi(s%6sEo&M~yW%CMnQJvUH= zj>zr6^{!3szb?K06nvxjEb^PNC*y4cv`y``&4K#*^k{bqh6Lg#M|1P!wvL8G(ONsN zTG&Nd47Sb*Y%a{R`;2I^ctt#AwQNG4{=y>xmFf<*9w?x6ckS?-_KCNZ9`iYk{Fuh%NU1Sxt*kq_iJ`z!3mJfk(f zktcbF@Z@w`KWl;|MyP%063@rGH^G-kOD_qx%RksDRQoF%Pdme*O2dW;P<^S~7g;jQ zVVB12K<|9v8~Ndbc8LX-Ikhyuz3WUR^<_TZG{H%yO|vsr2e*f^TIdndgQ~YtJQ8 zUlMD{rJ`0=vYb+#f``TvF+TNarC2|H%st0Q83!x$o8sKeiYS5e56P!(|GZ1 zGadtEN~@jAzzXj(mEtK|MeN-VtBA1rp)?!&OV~1A6->a>IQDL+Y<|$tKKq#SYkXhD zW*;q^peQBk@S&Rb#+|(F(7mWh0V=1jcy~?nZiKa3l3JvLO>BR>@-sw%cE<4CN{wdNNeV`Pm%rp0&Oxvc}m@HW|R3o*mqvlbn!p;~XNZQ}V24 zhzPim1i8jDzC{z-cvNfPhC;ghGgL1>nec; zPgREQ4?a4XF6{s@YugjKv z!`re<<0eWk#rTdgCXJ@EATrE_K{3=P33O##P*G@$lWYC$=F29BnfAdXPfrD%>cf}c zcvO7gGlZGC!eDRJ4F(Iny7C6Zpqk0^($tSK5wVE4$t5<|g2CKA?CZXm^9$zYmAJJH z_tDEsG5(|Fi_8$7a(Nn~f@bR<-x|<+vB5Tdp76fI3WX*PWm)3*3C+~Qn^x`LId^E| zlV~R|uy@i7$8uo5-^3(SqXIcK8b)pDsQ8bTbJ2&O~1BTjqol zuXQVr8s(9T!{VBANV0bLLt24hLU>Q~rdNEIbQBG<*~9uZ|5TOt{xr|_jfQSz>~xBj zT(W#|UP?=wrBUC6!qki0?pm1Who1A}u&dZc752ajJs)?YwXWarp~qX?=wIJ>I_+vm zN?S*jk?U=O-w-y1)}h|z|X4vr-U{1siKRfDPjw!b)^nuy3TmTKQNpm zPjiht@)w!)GR)wL_7X`5=rM)0$5A7Y6FSBUW$O#KFFY>DT78e!92@Fg7Ke6teVcp38>e0CqI%->!}Y`_P-+e` z8RWh#Fon>$?9%x)cWNY|BbQcJYaFnTdfdUy29Fu0 z7os(v*0#zSkO!t8wRdcDt;c=nE2tM@GKqOT$nw~#jd^yKd>`4)pB{%@QhEK3y5}WC z679h}niDZ)Cpx~`*qZ98F>P`=evLG6z|GkQZc37*jVrcniU>F}?s10gsbBTIPbQBj zug-J@R)#N=+ST^h&YFx)+aeMyBRPg=gC|@tvH^C|AdY7*V+-NtbZ4D~j1jje%^NFA zCWUalJ};m(H8&dt1$dV3B|Cj;x;oMmA^kp6=0hBDJxx|wFtZkgbpl&nqR4;&*=%kkWC5icV9fof!&b#??JcP5KBHuzcYa*H5(IX+fLYP_v-Z1X6 z)#kJHeapnFpTbO2_fh~4B373#Nw*M$-q zuQZWtzDyD6X{KPAlDeI{qkJ>eX>3&<+)X|EMgA!v=zGA@sVE)u&3`vASdh-m9Y zXNXO^r!}L{gj<4@OvU2Y04Ys5M$_%2A_NU-j82vsIr9&ADrMeW_~we*7QKmTAQvV% zG1qA?XNc1c?{FU^(#*qO+1_@KrIY4<_S90iSWXf?CksZ z?*H{^Qv3N1ZXw6KvnF%?2YYqS`ihP|9S-!}ox|CXy>QmxMiA@W@>2CnLA9K(`KDzc z(4ME9n)GiOJfH{Na{bD#mk!FFTrSlVr?sZEy%6eC?wk%|v-BO7+T(l4#LvHI?Yvd% zk=(oX=`D4fY}EB+A84-nD|3jbl%g&{aX&FWEI^dqE@8_}>D?I_;rl-BJ?CjxM!db_ zHX+M%JKHJZquye^!5hxhGk%4KH@t|nbT;lGUxGCH z<;Co_TNtip{)y+&adw>V96OV?zJ0T>o38e2y5a2RH_|eFyYY2u6xZ+<`r^dejs2$S z!F}^&DqI7x!kasd+WiZ3}Xwa zox`R@V}pG3U5=i3L@UZZ`0HW8_~HBWyz9162 z{1Ntm`(fY%_b(_1PS8tIu1)b?3}e{3vwsZ_QN6%*nzQsG6WLV6L$rA!X41nx?-S|= zxQZqmJ`)OK6OE&9zvft`Oi6##LXeO(k~LCxPLRn^>SZ$ueU=Ut=G*@e>uV$6?F8)5 z=N8Q`bvOCr<23i#O3Kgh+STjz1oEm#mVQH-l%O4Y5eM@+F~p48=mrs^cSqYGC2Sl89z}ot7b}eHVhk|d1dp}X-!}{taXM`a{ zF+u0L8^^GlbJmaY*Ld6KEIjJ!?z8E1!d_+Mar*U{o~l7uMklK;(QHI)#Lf+!?JJWv zWhIP)iK^KI8%Pp`3?(T`jF2|$2dX}WVe}&iS{Ggce&GUWs&h=6INjV`n#EO#l4gAs z$*kP!Mhs?Pnp2Zz{W2z9&RIbW$rV?=AjW0%Xsj@ePcl8u!Fh_+mwL?&qjl!_8cf{M zwK%*=kc8=C*HKjt*Su=_hz**kSUoe>D)c7tO-`{3*&UBFb~vw0f#XL25_(E=&6sdi z4Sk{A2g>oX-Goy0AMg2eVHA*7wB2-o>yu=!jyL^Rp|b6MQQt0@TRd$xOP&y}_tG|L zQb<$yfW`!vcLr3BEbrLIYuB!&lxuv|i97-~J75kO?{mv2?mP8*ThvGOVKyW!@_XzF zR;qoELgX*tw2#KKwnko63%Dg!f=x7XnC+DdX@vKLcjNA|O|S5!F>cG1sK*I>?tPfu zmd)|p!<)v=YuO4;+@JqqEwf4?k$@3C@;lqKfKV}h%YaUPGp^ZrU;oXs+3q4SEz0*s zLtj|TW6tZB zxqelN(Q2yi#QB&*!p1&SkZ*>-AH0f?Gkkp8G2&|v-ro+KU?Tiu*Vlxr@QK5v9x-hL zUyQOYOpQ`jTPgY1YLZDXh9pxjy=SkoR$4 zWfSI;s!NA$-daQCmhAaYH-+lnQx^4+2CO;vAk(7DFi`DN{Z7;W^v}B3q?lF>n4-V0#CYx({(}WYS zy_mz?rV|iisIMyR`{f?Y)bcg8i3R`S>+WXy`*j_VCkzw`Ki+mCfECTP_E6A3cXO@+ zPqzboW?nSpwdkH~=)`UQJfVys_q$730A0L3?h6;^M3CX?7Bt*hvbwNs6x+ zZZFx^%ud`$CVfuAk@sp;oaFnvt`FB{&UuruHF$fs61A%NvQ%xGl}xSouN~sf2{)>j zk|no~@*tcHyNBf0uXQD;P0%HxdETmn)!qGQ#RqIzm-L!`N zQ{DE3uPl94@VaGV<`kU%kyWqds)#6Bcsx9&$aA)1?>Y}}PL0K;B2e{tWn#sJVBA`s z@>!Yg-Sl(h{EuG=*FOnbuQ(F#UD@0&qX--BoEQ@^_BC(!x9AK@RL)k)nXeb!TjCB> zS{cw)JJT4~x@|_HiFt&3^VUI4r))KxvAoR6Lf6V&ujSbYVLEA|JZ}P=r8w|xC&quz zmD$hPXDDT2)O=f`rZFY~LuV0QA=j_57_G9`jlT=XSx2s6kKba$6E*>eozMnQROt-fR^}w1TT@ORA`XuVyVmc7K&+vf} zblT2mzSCB#0n8wF(AjqeX)dpdG`AXdKQu{wjH>~E&*4fvIQr5lcQbFCw$aen!)~Hb z{(@e~jfQMnBrHSNq+`aW!-p$>i)>Zit-Hhc&*J~TBwnrDGMhb*{CW;Cc zPJJu;Toj;TpIoDVJ2hrlQFws5M&Q-(K-SSp#c(d}AVN|2h&#e6zxzksC8Xb!6)7Sq z6lyV;@6c|S27yo62dXNXe``=UQgNF^TXnxA%WPX4)|l2*Q;M_6G+Ab@FO;y@nc%qG zflP^d-}Slob)oh|4_}3(ybNgA*3sd7K6*B%61uFTwI$|`j3J%Shw8W zybSzo$CQK~aS%ltjRep4(ZWx5Zo=cHgmPi(-7~5JU|*E$Q<4LZ4hCObv4>1e=2!vq za!~UyKY3vI(W|UvmG8~I_q%7pXRu- z&^(QA#otVgb82?acb*>_m3CwQeBl+=!_8K@!0>x3)ts9>Mkx+I7M~ZDjcAJl3z~nV z%9!Wr!XYxG$^}wxRU9d}yln#xEzToC%$UXE6+BzW7|tg`g{3B3RJ+po_!LUlOKk4C zykf6vhWQavCK+3t48Xewbkq1Q$=i)Jx*sNIp^O@VWWz8xKKX8V+Nb6NLtB6)) z$zSh+^x^BR)n{)}6b_wnE+oF1Q7bkY028(84h*)+mvc61AQOlH{;edHN~xq>yX)p3 z!6P3MA+&_t-!QM8iDE2H3&)Nw*%BM~b0A9U3|NPsubPL_T&q;D>AIMASn;|b@9;T~ zINyWSjsajFrz}jd{}D^i)|JwsXu-|RO=l0Q$Dc>n;FIccQQYEN5zXfX8gDU}{>A2& zK7nWS)@$o3cWd7dgt{k#o9~#v?#1?&ec6qwG7hcG1kR?)F%^dRa5YqX?+HE}3zt97 zIQo2xjJg&pwoBmY8Zhu(iOJyk*mzn0C0xRHKTRxHiJ7D40W!Y^9x0izc}h)|R3=7X z`x+m%@S-=VOyQ+r=B6@bHJvD}d+lak4r0&cgYTth)l@zl(=I2JeUmF2*t2+;>0_NT zm13s69{AZI_FF{b1_7id8FflsNYb6jJ8aEM#e{I%j5Q9 z(?nH3zwt(oDYwT~&;`K(t}+~o0zu($;2Q~K1HwR17!sh$0u*2f;wJ_H-tzd_&*u;* z2nJLQMWaCoK?Defgn>|CC^;0M(88ebpP%F32qXf8fTIC@fL;Wk3m^o;5nuoV$|Irw z(RZx-KQvsR-hcC1j|s*ApY{JDuyqH4wT8Yi@+lVlC`axWiuSOqb&X@5czip!B^nPTzzmK~ZXC#u4^S-!i zbHO9|v-mn=*T{IGmE052DPOzKxK(tbNTnF_ndMhr-r36r9mP|Olr(RYeV)$cToiC# zo+X6m#E*<3wx)EWJHS7xU2uzDM>G7|dQGs(($Tf8b0XN@j7s*cnS$wzr6yl(7_fJf z6XkO}r&j%H78S9LdsfBm)0G5Da$0%TJO^LZoy_ zIaQbAhcoIoWl%<|((6ng&*n=Wm#Cooc#m8wOTDd@)*+(-KxXhy9QcW+t-C`U0?zGU z45f+Bk2?!iqa?x2^HJ|t|H}|P?(mlGY9>| zfQ%9}kY(}n8OZ)`Oi&PsI&Syz^$UZ7fvEvd|2ua4`#1sOPYj8Io+u0GLj%$Hgd7lL zPt*$*grkus%7O*a2*|(6{;cs2eNZS00z~CMF$4q!0Sxt1`akdX^X?A}umN1~gdA89 zfjaJ*-^(7i5B)C;fdbMIPRJopK$6A@3^4P_I>10tV0`{r2O0s)Dt}^toZtx?fWau( zaSF;GWx*%}Fl+vSL4bZc_MYG6Ab>s~>*oZ9fFV!R0mwms+3tiK3I@!WCo#lvg39sr zyT2Sy(_*Yw?zJKY<~EMaapr0Cv*OP$U!uKKUL@U;_9|C+AadON67!vVsIn>EM2joz|YUN}dDC9}|0Wkt{(k=jYoR{{ieJ)N$ zR<>qNKNELUt-OGc1uP_0a5xtrtL*RCg|RosfdDPX!4D$|(glei%>>bc=B7aJz)g@~ y6C*eZYzBuKn<0%*fG0!IV&wm~2uSaE8R+Z+Oc+0d9TW)%gVE${Y*LESFL From 9654382294dce7bdde7fcbe70e6f2f2613662d3a Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 11:02:06 -0500 Subject: [PATCH 403/545] use 'defaultToken' for comment/qqstring/qstring in lean-mode Suggested by @nightwing --- lib/ace/mode/lean_highlight_rules.js | 36 +++++----------------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index d5f9a67c..44eb8d50 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -151,36 +151,12 @@ var leanHighlightRules = function() { regex : "\\s+" } ], - "comment" : [ - { - token : "comment", // closing comment - regex : ".*?-\\/", - next : "start" - }, { - token : "comment", // comment spanning whole line - regex : ".+" - } - ], - "qqstring" : [ - { - token : "string", - regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', - next : "start" - }, { - token : "string", - regex : '.+' - } - ], - "qstring" : [ - { - token : "string", - regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'", - next : "start" - }, { - token : "string", - regex : '.+' - } - ], + "comment" : [ {token: "comment", regex: "-/", next: "start"}, + {defaultToken: "comment"} ], + "qqstring" : [ {token : "string", regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', next : "start" }, + {defaultToken: "qqstring"} ], + "qstring" : [ {token : "string", regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'", next : "start" }, + {defaultToken: "qstring"} ], "directive" : [ { token : "constant.other.multiline", From 8f49d3d89784095089bf0885268b4e87e2fbc69c Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 11:03:02 -0500 Subject: [PATCH 404/545] add a small demo for lean mode --- demo/kitchen-sink/docs/lean.lean | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 demo/kitchen-sink/docs/lean.lean diff --git a/demo/kitchen-sink/docs/lean.lean b/demo/kitchen-sink/docs/lean.lean new file mode 100644 index 00000000..40e82753 --- /dev/null +++ b/demo/kitchen-sink/docs/lean.lean @@ -0,0 +1,9 @@ +import logic +section + variables (A : Type) (p q : A → Prop) + + example : (∀x : A, p x ∧ q x) → ∀y : A, p y := + assume H : ∀x : A, p x ∧ q x, + take y : A, + show p y, from and.elim_left (H y) +end From 74800e84ee204d1fd89a82bab1d71c8d8703e1c4 Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 12:09:11 -0500 Subject: [PATCH 405/545] remove single quoted string (qstring) from lean-mode --- lib/ace/mode/lean_highlight_rules.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index 44eb8d50..48241c0e 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -108,13 +108,6 @@ var leanHighlightRules = function() { token : "string", // multi line string start regex : '["].*\\\\$', next : "qqstring" - }, { - token : "string", // single line - regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" - }, { - token : "string", // multi line string start - regex : "['].*\\\\$", - next : "qstring" }, { token : "constant.numeric", // hex regex : "0[xX][0-9a-fA-F]+(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" @@ -155,8 +148,6 @@ var leanHighlightRules = function() { {defaultToken: "comment"} ], "qqstring" : [ {token : "string", regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', next : "start" }, {defaultToken: "qqstring"} ], - "qstring" : [ {token : "string", regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'", next : "start" }, - {defaultToken: "qstring"} ], "directive" : [ { token : "constant.other.multiline", From 906b6c9d8d8c6443256365d676a6e0139046c099 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 24 Feb 2015 09:30:43 -0800 Subject: [PATCH 406/545] Adding cursive and fantasy to keywords list --- lib/ace/mode/css_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/css_highlight_rules.js b/lib/ace/mode/css_highlight_rules.js index b9c20423..d08a3a0b 100644 --- a/lib/ace/mode/css_highlight_rules.js +++ b/lib/ace/mode/css_highlight_rules.js @@ -41,7 +41,7 @@ var supportType = exports.supportType = "animation-fill-mode|alignment-adjust|al var supportFunction = exports.supportFunction = "rgb|rgba|url|attr|counter|counters"; var supportConstant = exports.supportConstant = "absolute|after-edge|after|all-scroll|all|alphabetic|always|antialiased|armenian|auto|avoid-column|avoid-page|avoid|balance|baseline|before-edge|before|below|bidi-override|block-line-height|block|bold|bolder|border-box|both|bottom|box|break-all|break-word|capitalize|caps-height|caption|center|central|char|circle|cjk-ideographic|clone|close-quote|col-resize|collapse|column|consider-shifts|contain|content-box|cover|crosshair|cubic-bezier|dashed|decimal-leading-zero|decimal|default|disabled|disc|disregard-shifts|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ease-in|ease-in-out|ease-out|ease|ellipsis|end|exclude-ruby|fill|fixed|georgian|glyphs|grid-height|groove|hand|hanging|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|include-ruby|inherit|initial|inline-block|inline-box|inline-line-height|inline-table|inline|inset|inside|inter-ideograph|inter-word|invert|italic|justify|katakana-iroha|katakana|keep-all|last|left|lighter|line-edge|line-through|line|linear|list-item|local|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|mathematical|max-height|max-size|medium|menu|message-box|middle|move|n-resize|ne-resize|newspaper|no-change|no-close-quote|no-drop|no-open-quote|no-repeat|none|normal|not-allowed|nowrap|nw-resize|oblique|open-quote|outset|outside|overline|padding-box|page|pointer|pre-line|pre-wrap|pre|preserve-3d|progress|relative|repeat-x|repeat-y|repeat|replaced|reset-size|ridge|right|round|row-resize|rtl|s-resize|scroll|se-resize|separate|slice|small-caps|small-caption|solid|space|square|start|static|status-bar|step-end|step-start|steps|stretch|strict|sub|super|sw-resize|table-caption|table-cell|table-column-group|table-column|table-footer-group|table-header-group|table-row-group|table-row|table|tb-rl|text-after-edge|text-before-edge|text-bottom|text-size|text-top|text|thick|thin|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|use-script|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|z-index|zero"; var supportConstantColor = exports.supportConstantColor = "aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow"; -var supportConstantFonts = exports.supportConstantFonts = "arial|century|comic|courier|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace"; +var supportConstantFonts = exports.supportConstantFonts = "arial|century|comic|courier|cursive|fantasy|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace"; var numRe = exports.numRe = "\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))"; var pseudoElements = exports.pseudoElements = "(\\:+)\\b(after|before|first-letter|first-line|moz-selection|selection)\\b"; From a0fe09f3bee4197231b18215ab8af02f32146755 Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 13:19:56 -0500 Subject: [PATCH 407/545] clean up unused rules for lean-mode --- lib/ace/mode/lean_highlight_rules.js | 47 +--------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index 48241c0e..f653096b 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -70,16 +70,11 @@ var leanHighlightRules = function() { [].join("|") ); - var builtinConstants = ( - "NULL|true|false|TRUE|FALSE" - ); - var keywordMapper = this.$keywords = this.createKeywordMapper({ "keyword.control" : keywordControls, "storage.type" : storageType, "keyword.operator" : keywordOperators, "variable.language": "sorry", - "constant.language": builtinConstants }, "identifier"); var identifierRe = "[A-Za-z_\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2100-\u214f][A-Za-z0-9_'\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2070-\u2079\u207f-\u2089\u2090-\u209c\u2100-\u214f]*"; @@ -117,13 +112,6 @@ var leanHighlightRules = function() { }, { token : "storage.modifier", regex : storageModifiers - }, { - token : "keyword", // pre-compiler directives - regex : "#\\s*(?:include|import|pragma|line|define|undef|if|ifdef|else|elif|ifndef)\\b", - next : "directive" - }, { - token : "keyword", // special case pre-compiler directive - regex : "(?:#\\s*endif)\\b" }, { token : keywordMapper, regex : identifierRe @@ -145,40 +133,7 @@ var leanHighlightRules = function() { } ], "comment" : [ {token: "comment", regex: "-/", next: "start"}, - {defaultToken: "comment"} ], - "qqstring" : [ {token : "string", regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', next : "start" }, - {defaultToken: "qqstring"} ], - "directive" : [ - { - token : "constant.other.multiline", - regex : /\\/ - }, - { - token : "constant.other.multiline", - regex : /.*\\/ - }, - { - token : "constant.other", - regex : "\\s*<.+?>", - next : "start" - }, - { - token : "constant.other", // single line - regex : '\\s*["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]', - next : "start" - }, - { - token : "constant.other", // single line - regex : "\\s*['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']", - next : "start" - }, - // "\" implies multiline, while "/" implies comment - { - token : "constant.other", - regex : /[^\\\/]+/, - next : "start" - } - ] + {defaultToken: "comment"} ] }; this.embedRules(DocCommentHighlightRules, "doc-", From 3c34a9852f54637106a7888ef99e329e82ecd051 Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 13:20:28 -0500 Subject: [PATCH 408/545] add and sort keywords/storage-modifiers for lean-mode --- lib/ace/mode/lean_highlight_rules.js | 37 +++++++++++++++------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index f653096b..91440169 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -38,20 +38,21 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var leanHighlightRules = function() { var keywordControls = ( - ["import", "tactic_hint", "protected", "find_decl", - "private", "opaque", "definition", "renaming", "hiding", "exposing", - "parameter", "parameters", "begin", "proof", "qed", "conjecture", "premise", "premises", - "constant", "constants", "example", "attribute", "local", - "hypothesis", "lemma", "corollary", "variable", "variables", "print", - "theorem", "context", "open", "as", "export", "axiom", "inductive", - "with", "structure", "record", "universe", "universes", "alias", "help", "environment", - "options", "precedence", "postfix", "prefix", "calc_trans", - "calc_subst", "calc_refl", "infix", "infixl", "infixr", "notation", - "eval", "check", "exit", "end", "using", "namespace", - "section", "set_option", "omit", "classes", "instances", "coercions", "raw", - "add_rewrite", "extends", "calc", "have", "obtains", "show", "by", "in", "let", - "forall", "fun", "exists", "if", "then", "else", "assume", "match", - "take", "obtain", "from", "axioms", "fields"].join("|") + [ "add_rewrite", "alias", "as", "assume", "attribute", + "begin", "by", "calc", "calc_refl", "calc_subst", "calc_trans", "check", + "classes", "coercions", "conjecture", "constants", "context", + "corollary", "else", "end", "environment", "eval", "example", + "exists", "exit", "export", "exposing", "extends", "fields", "find_decl", + "forall", "from", "fun", "have", "help", "hiding", "if", + "import", "in", "infix", "infixl", "infixr", "instances", + "let", "local", "match", "namespace", "notation", "obtain", "obtains", + "omit", "opaque", "open", "options", "parameter", "parameters", "postfix", + "precedence", "prefix", "premise", "premises", "print", "private", "proof", + "protected", "qed", "raw", "renaming", "section", "set_option", + "show", "tactic_hint", "take", "then", "universe", + "universes", "using", "variable", "variables", "with"].join("|") + ); + ); var storageType = ( @@ -60,9 +61,11 @@ var leanHighlightRules = function() { var storageModifiers = ( "\\[(" + - ["persistent", "notation", "parsing-only", "visible", "instance", "class", "prefix", "axioms", "fields", - "multiple-instances", "classes", "instances", "coercions", "options", "trust", - "coercion", "reducible", "irreducible", "raw"].join("|") + + ["abbreviations", "all-transparent", "begin-end-hints", "class", "classes", "coercion", + "coercions", "declarations", "decls", "instance", "irreducible", + "multiple-instances", "notation", "notations", "parsing-only", "persistent", + "reduce-hints", "reducible", "tactic-hints", "visible", "wf", "whnf" + ].join("|") + ")\\]" ); From 34d80e81cafe90ea78bdb5fcc05fad8a0076bbba Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 13:21:22 -0500 Subject: [PATCH 409/545] clean up string rule for lean-mode --- lib/ace/mode/lean_highlight_rules.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index 91440169..4ba9d484 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -100,12 +100,15 @@ var leanHighlightRules = function() { regex : "\\/-", next : "comment" }, { - token : "string", // single line - regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + stateName: "qqstring", + token : "string.start", regex : '"', next : [ + {token : "string.end", regex : '"', next : "start"}, + {token : "string", regex : "\\\\$", next : "qqstring"}, + {token : "string", regex : "\\n$", next : "qqstring"}, + {token : "constant.language.escape", regex : /\\./}, + {defaultToken: "string"} + ] }, { - token : "string", // multi line string start - regex : '["].*\\\\$', - next : "qqstring" }, { token : "constant.numeric", // hex regex : "0[xX][0-9a-fA-F]+(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" @@ -141,6 +144,7 @@ var leanHighlightRules = function() { this.embedRules(DocCommentHighlightRules, "doc-", [ DocCommentHighlightRules.getEndRule("start") ]); + this.normalizeRules(); }; oop.inherits(leanHighlightRules, TextHighlightRules); From 27ad84664101be9fd1a19047268a95f24ba6800c Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 13:21:40 -0500 Subject: [PATCH 410/545] highlight names followed nameProviders in lean-mode --- lib/ace/mode/lean_highlight_rules.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index 4ba9d484..06669de3 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -53,6 +53,9 @@ var leanHighlightRules = function() { "universes", "using", "variable", "variables", "with"].join("|") ); + var nameProviders = ( + ["inductive", "structure", "record", "theorem", "axiom", + "axioms", "lemma", "hypothesis", "definition", "constant"].join("|") ); var storageType = ( @@ -109,6 +112,8 @@ var leanHighlightRules = function() { {defaultToken: "string"} ] }, { + token : "keyword.control", regex : nameProviders, next : [ + {token : "variable.language", regex : identifierRe, next : "start"} ] }, { token : "constant.numeric", // hex regex : "0[xX][0-9a-fA-F]+(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" From b6910a3094a30d695757a28b7680ce876e2ca6ae Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 24 Feb 2015 10:59:36 -0800 Subject: [PATCH 411/545] Add ClassName to highlighting So that document.getElementsByClassName gets highlighted. --- lib/ace/mode/javascript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/javascript_highlight_rules.js b/lib/ace/mode/javascript_highlight_rules.js index 767b8fa1..5bdcce12 100644 --- a/lib/ace/mode/javascript_highlight_rules.js +++ b/lib/ace/mode/javascript_highlight_rules.js @@ -172,7 +172,7 @@ var JavaScriptHighlightRules = function(options) { regex : /(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/ }, { token : ["punctuation.operator", "support.function.dom"], - regex : /(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/ + regex : /(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/ }, { token : ["punctuation.operator", "support.constant"], regex : /(\.)(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/ From 49ff50463939d1a5577088dfeab80bdb91614602 Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Tue, 24 Feb 2015 14:10:41 -0500 Subject: [PATCH 412/545] fix qqstring rule in lean-mode --- lib/ace/mode/lean_highlight_rules.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ace/mode/lean_highlight_rules.js b/lib/ace/mode/lean_highlight_rules.js index 06669de3..d4a37d20 100644 --- a/lib/ace/mode/lean_highlight_rules.js +++ b/lib/ace/mode/lean_highlight_rules.js @@ -106,9 +106,7 @@ var leanHighlightRules = function() { stateName: "qqstring", token : "string.start", regex : '"', next : [ {token : "string.end", regex : '"', next : "start"}, - {token : "string", regex : "\\\\$", next : "qqstring"}, - {token : "string", regex : "\\n$", next : "qqstring"}, - {token : "constant.language.escape", regex : /\\./}, + {token : "constant.language.escape", regex : /\\[n"\\]/}, {defaultToken: "string"} ] }, { From 9905267e4deedda4fc4e15458a2f6cbfeb391dfc Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 24 Feb 2015 21:02:52 +0400 Subject: [PATCH 413/545] fix gutter in static highlight when wrapping is enabled --- demo/static-highlighter.html | 26 +++++++++++++++++++++++--- lib/ace/ext/static.css | 10 ++++++---- lib/ace/ext/static_highlight.js | 3 ++- lib/ace/ext/static_highlight_test.js | 8 ++++---- lib/ace/layer/text.js | 14 +++++++------- lib/ace/layer/text_test.js | 2 +- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/demo/static-highlighter.html b/demo/static-highlighter.html index 39546541..eaf0dd53 100644 --- a/demo/static-highlighter.html +++ b/demo/static-highlighter.html @@ -2,13 +2,13 @@ - Static Code highlighter using Ace - + Static Code highlighter using Ace + @@ -35,6 +35,26 @@ function wobble (flam) { + +