<commit_before>define("mode/c_cpp_matching_brace_outdent", function(require, exports, module) {

var Range = require("ace/range").Range;

var CppTokenCursor = require("mode/token_cursor").CppTokenCursor;
var MatchingBraceOutdent = function(codeModel) {
   this.codeModel = codeModel;
};

// Allow the user to control various levels of outdenting if desired
var $outdentColon              = true; // : (initializer list)
var $outdentRightParen         = true; // )
var $outdentLeftBrace          = true; // {
var $outdentRightBrace         = true; // }
var $outdentRightBracket       = true; // ]
var $outdentRightArrow         = true; // >
var $alignDots                 = true; // .
var $alignEquals               = true; // int x = 1,
                                       //     y = 2;
var $alignStreamIn             = true; // >>
var $alignStreamOut            = true; // <<
var $alignClassAccessModifiers = true; // public: etc.
var $alignCase                 = true; // case 'a':

(function() {

   // Set the indent of the line at 'row' to the indentation at
   // 'rowFrom'. This operation is only performed if the indentation
   // of the lines at 'rowTo' and 'rowFrom' match.
   //
   // 'predicate' is an (optional) function taking the old and new
   // indents, and returning true or false -- this is used to ensure
   // outdenting only occurs when explicitly desired.
   this.setIndent = function(session, rowTo, rowFrom, extraIndent, predicate) {

      var doc = session.getDocument();
      extraIndent = typeof extraIndent === "string" ?
         extraIndent :
         "";

      var line = doc.$lines[rowTo];
      var prevLine = doc.$lines[rowFrom];

      var oldIndent = this.$getIndent(line);
      var newIndent = this.$getIndent(prevLine);

      if (typeof predicate !== "function" || predicate(oldIndent, newIndent)) {
         doc.replace(
            new Range(rowTo, 0, rowTo, oldIndent.length),
            newIndent + extraIndent
         );
      }

   };

   this.checkOutdent = function(state, line, input) {

      if (state == "start") {

         // private: / public: / protected
         // also class initializer lists
         if (input === ":") {
            return true;
         }

         // outdenting for lines starting with 'closers' and 'openers'
         // also preproc lines
         if (/^\s*[#\{\}\>\]\)<.:]/.test(input))
            return true;

         // outdenting for '='
         if (input === "=")
            return true;

      }

      // check for nudging of '/' to the left (?)
      if (state == "comment") {

         if (input == "/") {
            return true;
         }

      }

      return false;

   };

   this.escapeRegExp = function(string) {
      return string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
   };

   this.alignStartToken = function(token, session, row, line, prevLine) {

      if (prevLine === null || line === null) return false;
      var regex = new RegExp("^\\s*" + this.escapeRegExp(token));
      if (regex.test(line)) {
         var index = prevLine.indexOf(token);
         if (index >= 0) {

            var doc = session.getDocument();
            var oldIndent = this.$getIndent(line);
            var newIndent = new Array(index + 1).join(" ");

            doc.replace(
               new Range(row, 0, row, oldIndent.length),
               newIndent
            );

            return true;
         }
      }
      return false;
   };

   this.alignEquals = function(session, row, line, prevLine) {

      if (prevLine === null || line === null) return false;
      var equalsIndex = line.indexOf("=");

      // Bail if there is more than one '=' on the line
      if (equalsIndex !== line.lastIndexOf("="))
         return false;

      var prevLineEqualsIndex = prevLine.indexOf("=");
      if (equalsIndex !== -1 && prevLineEqualsIndex !== -1 && /,\s*$/.test(prevLine))
      {
         var doc = session.getDocument();
         var oldIndent = this.$getIndent(line);
         if (oldIndent.length >= prevLineEqualsIndex)
            return false;

         var diff = prevLineEqualsIndex - equalsIndex;
         if (diff <= 0)
            return false;

         var newIndent = new Array(oldIndent.length + diff + 1).join(" ");

         doc.replace(
            new Range(row, 0, row, oldIndent.length),
            newIndent
         );

         return true;

      }

      return false;

   };

   this.autoOutdent = function(state, session, row) {

      var doc = session.doc;
      var line = doc.getLine(row);
      var prevLine = null;
      if (row > 0)
         prevLine = doc.getLine(row - 1);
      var indent = this.$getIndent(line);

      // Check for '<<', '.'alignment
      if ($alignStreamOut && this.alignStartToken("<<", session, row, line, prevLine))
         return;

      if ($alignStreamIn && this.alignStartToken(">>", session, row, line, prevLine))
         return;

      if ($alignDots && this.alignStartToken(".", session, row, line, prevLine))
         return;

      if ($alignEquals && this.alignEquals(session, row, line, prevLine))
         return;

      // Outdent for a ':' places on its own line if it appears the
      // user is creating an initialization list for
      // a constructor, e.g.
      //
      //     SomeConstructor(int a,
      //                     int b)
      //         :
      //         ^
      //
      // We also perform a similar action for class inheritance, e.g.
      //
      //     class Foo
      //         :
      if ($outdentColon &&
          /^\s*:/.test(doc.getLine(row)) &&
          !/^\s*::/.test(doc.getLine(row))) {

         if (this.codeModel.$tokenUtils.$tokenizeUpToRow(row)) {

            var tokenCursor = new CppTokenCursor(this.codeModel.$tokens, row, 0);
            var rowToUse = -1;

            // First, handle constructors. Note that we need to first walk
            // over some keywords, e.g.
            //
            //     int foo(int a, int b) const noexcept()
            //         :
            //
            var clone = tokenCursor.cloneCursor();
            if (clone.peekBwd().currentValue() === ")" ||
                clone.peekBwd().currentType() === "keyword")
            {
               do {

                  var type = clone.currentType();
                  var value = clone.currentValue();

                  // Stop conditions
                  if (type === "identifier" ||
                      value === ";")
                  {
                     rowToUse = clone.$row;
                     break;
                  }

                  // Chomp keywords
                  if (type === "keyword") {
                     continue;
                  }

                  // Walk over parens
                  clone.bwdToMatchingToken();

               } while (clone.moveToPreviousToken());

            }

            // Otherwise, try walking over class inheritance
            else {
               tokenCursor.moveToPreviousToken();
               if (tokenCursor.bwdOverClassySpecifiers()) {
                  rowToUse = tokenCursor.$row;
               }
            }

            if (rowToUse >= 0) {
               this.setIndent(session, row, rowToUse, session.getTabString(),
                              function(oldIndent, newIndent) {
                                 return oldIndent === newIndent;
                              });
            }

         }
      }

      // Outdent for lines starting with a '>' if an associated matching
      // token can be found. This is intended for template contexts, e.g.
      //
      //     template <
      //         int RTYPE
      //     >
      //     ^
      //
      if ($outdentRightArrow &&
          /^\s*>/.test(line) &&
          !/^\s*>>/.test(line)) {

         var rowToUse = this.codeModel.getRowForMatchingEOLArrows(session, doc, row);
         if (rowToUse >= 0) {
            this.setIndent(session, row, rowToUse);
            return;
         }

         // TODO: Renable this block if we get better tokenization
         // (need to discover whether '<', '>' are operators or not)
         //
         // if (this.codeModel.$tokenUtils.$tokenizeUpToRow(row)) {
         //    var tokenCursor = new CppTokenCursor(this.codeModel.$tokens, row, 0);
         //    if (tokenCursor.bwdToMatchingArrow()) {
         //       this.setIndent(session, row, tokenCursor.$row);
         //    }
         // }

      }

      // Outdent for closing braces (to match the indentation of their
      // matched opening brace
      //
      // If the line on which the matching '{' was found is of
      // the form
      //
      //  foo) {
      //
      // then indent according to the location of the matching
      // '('
      //
      // This rule should apply to closing braces with semi-colons
      // or comments following as well.
      if ($outdentRightBrace && /^\s*\}/.test(line)) {

         var openBracketPos = session.findMatchingBracket({
            row: row,
            column: line.indexOf("}") + 1
         });

         if (openBracketPos !== null) {

            // If the open brace lies on its own line, match its indentation
            var openBracketLine =
                   doc.$lines[openBracketPos.row];

            if (/^\s*\{/.test(openBracketLine)) {
               this.setIndent(session, row, openBracketPos.row);
               return;
            }

            // Otherwise, try looking upwards to get an appropriate indentation
            var heuristicRow = this.codeModel.getRowForOpenBraceIndent(
               session,
               openBracketPos.row
            );

            if (heuristicRow >= 0) {
               this.setIndent(session, row, heuristicRow);
               return;
            }

         }

      }

      if ($outdentRightParen) {

         var closingParenMatch = /^\s*\)/.exec(line);
         if (closingParenMatch) {
            var openParenPos = session.findMatchingBracket({
               row: row,
               column: line.indexOf(")") + 1
            });
            if (openParenPos) {
               this.setIndent(session, row, openParenPos.row);
               return;
            }
         }
      }

      if ($outdentRightBracket) {

         var closingBracketMatch = /^\s*\]/.exec(line);
         if (closingBracketMatch) {
            var openBracketPos = session.findMatchingBracket({
               row: row,
               column: line.indexOf("]") + 1
            });
            if (openBracketPos) {
               this.setIndent(session, row, openBracketPos.row);
               return;
            }
         }
      }

      // If we just typed 'public:', 'private:' or 'protected:',
      // we should outdent if possible. Do so by looking for the
      // enclosing 'class' scope.
      if ($alignClassAccessModifiers &&
          /^\s*public\s*:\s*$|^\s*private\s*:\s*$|^\s*protected\s*:\s*$/.test(line)) {

         // Find the associated open bracket.
         var openBracePos = session.$findOpeningBracket(
            "}",
            {
               row: row,
               column: line.length
            },
            new RegExp(/paren\.keyword\.operator/)
         );

         if (openBracePos) {
            // If this open brace is already associated with a class or struct,
            // step over all of those rows.
            var heuristicRow =
                   this.codeModel.getRowForOpenBraceIndent(session, openBracePos.row);

            if (heuristicRow >= 0) {
               this.setIndent(session, row, heuristicRow);
               return;
            } else {
               this.setIndent(session, row, openBracePos.row);
               return;
            }
         }

      }

      // Similar lookback for 'case foo:'.
      if ($alignCase &&
          (/^\s*case.+:/.test(line) || /^\s*default\s*:/.test(line)))
      {

         // Find the associated open bracket.
         var openBracePos = session.$findOpeningBracket(
            "}",
            {
               row: row,
               column: /(\S)/.exec(line).index + 1
            }
         );

         if (openBracePos) {
            var heuristicRow =
                   this.codeModel.getRowForOpenBraceIndent(session, openBracePos.row);

            if (heuristicRow >= 0) {
               this.setIndent(session, row, heuristicRow);
               return;
            } else {
               this.setIndent(session, row, openBracePos.row);
               return;
            }
         }

      }

      // If we just inserted a '{' on a new line to begin a class definition,
      // try looking up for the associated class statement.
      // We want to look back over the following common indentation styles:
      //
      // (1) class Foo
      //     : public A,
      //       public B,
      //       public C
      //
      // and
      //
      // (2) class Foo
      //     : public A
      //     , public B
      //     , public C
      //
      // We also design the rules to 'work' for initialization lists, e.g.
      //
      //    Foo()
      //    : foo_(foo),
      //      bar_(bar),
      //      baz_(baz)
      if ($outdentLeftBrace && /^\s*\{/.test(line)) {

         // Don't outdent if the previous line ends with a semicolon
         if (!/;\s*$/.test(prevLine)) {

            if (this.codeModel.$tokenUtils.$tokenizeUpToRow(row)) {

               var tokenCursor = new CppTokenCursor(this.codeModel.$tokens);
               tokenCursor.$row = row,
               tokenCursor.$offset = 0;

               if (tokenCursor.moveToPreviousToken()) {
                  if (tokenCursor.currentValue() === "=") {
                     return;
                  }
               }
            }

            var scopeRow = this.codeModel.getRowForOpenBraceIndent(
               session,
               row
            );

            if (scopeRow >= 0) {

               this.setIndent(session, row, scopeRow);
               return;

            }

         }

      }

      // For lines intended for the preprocessor, trim off the indentation.
      if (/^\s*#/.test(line))
      {
         var oldIndent = this.$getIndent(line);
         doc.replace(
            new Range(row, 0, row, oldIndent.length),
            ""
         );
         return;
      }

   };

   this.$getIndent = function(line) {
      var match = line.match(/^(\s+)/);
      if (match) {
         return match[1];
      }
      return "";
   };

}).call(MatchingBraceOutdent.prototype);

exports.MatchingBraceOutdent = MatchingBraceOutdent;

exports.getOutdentColon = function() { return $outdentColon; };
exports.setOutdentColon = function(x) { $outdentColon = x; };

exports.getOutdentRightParen = function() { return $outdentRightParen; };
exports.setOutdentRightParen = function(x) { $outdentRightParen = x; };

exports.getOutdentLeftBrace = function() { return $outdentLeftBrace; };
exports.setOutdentLeftBrace = function(x) { $outdentLeftBrace = x; };

exports.getOutdentRightBrace = function() { return $outdentRightBrace; };
exports.setOutdentRightBrace = function(x) { $outdentRightBrace = x; };

exports.getOutdentRightBracket = function() { return $outdentRightBracket; };
exports.setOutdentRightBracket = function(x) { $outdentRightBracket = x; };

exports.getOutdentRightArrow = function() { return $outdentRightArrow; };
exports.setOutdentRightArrow = function(x) { $outdentRightArrow = x; };

exports.getAlignDots = function() { return $alignDots; };
exports.setAlignDots = function(x) { $alignDots = x; };

exports.getAlignEquals = function() { return $alignEquals; };
exports.setAlignEquals = function(x) { $alignEquals = x; };

exports.getAlignStreamIn = function() { return $alignStreamIn; };
exports.setAlignStreamIn = function(x) { $alignStreamIn = x; };

exports.getAlignStreamOut = function() { return $alignStreamOut; };
exports.setAlignStreamOut = function(x) { $alignStreamOut = x; };

exports.getAlignClassAccessModifiers = function() { return $alignClassAccessModifiers; };
exports.setAlignClassAccessModifiers = function(x) { $alignClassAccessModifiers = x; };

exports.getAlignCase = function() { return $alignCase; };
exports.setAlignCase = function(x) { $alignCase = x; };

});
<commit_msg>disable 'equals' alignment for now (doesn't work as intended)<commit_after>define("mode/c_cpp_matching_brace_outdent", function(require, exports, module) {

var Range = require("ace/range").Range;

var CppTokenCursor = require("mode/token_cursor").CppTokenCursor;
var MatchingBraceOutdent = function(codeModel) {
   this.codeModel = codeModel;
};

// Allow the user to control various levels of outdenting if desired
var $outdentColon              = true; // : (initializer list)
var $outdentRightParen         = true; // )
var $outdentLeftBrace          = true; // {
var $outdentRightBrace         = true; // }
var $outdentRightBracket       = true; // ]
var $outdentRightArrow         = true; // >
var $alignDots                 = true; // .
var $alignEquals               = true; // int x = 1,
                                       //     y = 2;
var $alignStreamIn             = true; // >>
var $alignStreamOut            = true; // <<
var $alignClassAccessModifiers = true; // public: etc.
var $alignCase                 = true; // case 'a':

(function() {

   // Set the indent of the line at 'row' to the indentation at
   // 'rowFrom'. This operation is only performed if the indentation
   // of the lines at 'rowTo' and 'rowFrom' match.
   //
   // 'predicate' is an (optional) function taking the old and new
   // indents, and returning true or false -- this is used to ensure
   // outdenting only occurs when explicitly desired.
   this.setIndent = function(session, rowTo, rowFrom, extraIndent, predicate) {

      var doc = session.getDocument();
      extraIndent = typeof extraIndent === "string" ?
         extraIndent :
         "";

      var line = doc.$lines[rowTo];
      var prevLine = doc.$lines[rowFrom];

      var oldIndent = this.$getIndent(line);
      var newIndent = this.$getIndent(prevLine);

      if (typeof predicate !== "function" || predicate(oldIndent, newIndent)) {
         doc.replace(
            new Range(rowTo, 0, rowTo, oldIndent.length),
            newIndent + extraIndent
         );
      }

   };

   this.checkOutdent = function(state, line, input) {

      if (state == "start") {

         // private: / public: / protected
         // also class initializer lists
         if (input === ":") {
            return true;
         }

         // outdenting for lines starting with 'closers' and 'openers'
         // also preproc lines
         if (/^\s*[#\{\}\>\]\)<.:]/.test(input))
            return true;

         // outdenting for '='
         if (input === "=")
            return true;

      }

      // check for nudging of '/' to the left (?)
      if (state == "comment") {

         if (input == "/") {
            return true;
         }

      }

      return false;

   };

   this.escapeRegExp = function(string) {
      return string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
   };

   this.alignStartToken = function(token, session, row, line, prevLine) {

      if (prevLine === null || line === null) return false;
      var regex = new RegExp("^\\s*" + this.escapeRegExp(token));
      if (regex.test(line)) {
         var index = prevLine.indexOf(token);
         if (index >= 0) {

            var doc = session.getDocument();
            var oldIndent = this.$getIndent(line);
            var newIndent = new Array(index + 1).join(" ");

            doc.replace(
               new Range(row, 0, row, oldIndent.length),
               newIndent
            );

            return true;
         }
      }
      return false;
   };

   this.alignEquals = function(session, row, line, prevLine) {

      if (prevLine === null || line === null) return false;
      var equalsIndex = line.indexOf("=");

      // Bail if there is more than one '=' on the line
      if (equalsIndex !== line.lastIndexOf("="))
         return false;

      var prevLineEqualsIndex = prevLine.indexOf("=");
      if (equalsIndex !== -1 && prevLineEqualsIndex !== -1 && /,\s*$/.test(prevLine))
      {
         var doc = session.getDocument();
         var oldIndent = this.$getIndent(line);
         if (oldIndent.length >= prevLineEqualsIndex)
            return false;

         var diff = prevLineEqualsIndex - equalsIndex;
         if (diff <= 0)
            return false;

         var newIndent = new Array(oldIndent.length + diff + 1).join(" ");

         doc.replace(
            new Range(row, 0, row, oldIndent.length),
            newIndent
         );

         return true;

      }

      return false;

   };

   this.autoOutdent = function(state, session, row) {

      var doc = session.doc;
      var line = doc.getLine(row);
      var prevLine = null;
      if (row > 0)
         prevLine = doc.getLine(row - 1);
      var indent = this.$getIndent(line);

      // Check for '<<', '.'alignment
      if ($alignStreamOut && this.alignStartToken("<<", session, row, line, prevLine))
         return;

      if ($alignStreamIn && this.alignStartToken(">>", session, row, line, prevLine))
         return;

      if ($alignDots && this.alignStartToken(".", session, row, line, prevLine))
         return;

      // if ($alignEquals && this.alignEquals(session, row, line, prevLine))
      //    return;

      // Outdent for a ':' places on its own line if it appears the
      // user is creating an initialization list for
      // a constructor, e.g.
      //
      //     SomeConstructor(int a,
      //                     int b)
      //         :
      //         ^
      //
      // We also perform a similar action for class inheritance, e.g.
      //
      //     class Foo
      //         :
      if ($outdentColon &&
          /^\s*:/.test(doc.getLine(row)) &&
          !/^\s*::/.test(doc.getLine(row))) {

         if (this.codeModel.$tokenUtils.$tokenizeUpToRow(row)) {

            var tokenCursor = new CppTokenCursor(this.codeModel.$tokens, row, 0);
            var rowToUse = -1;

            // First, handle constructors. Note that we need to first walk
            // over some keywords, e.g.
            //
            //     int foo(int a, int b) const noexcept()
            //         :
            //
            var clone = tokenCursor.cloneCursor();
            if (clone.peekBwd().currentValue() === ")" ||
                clone.peekBwd().currentType() === "keyword")
            {
               do {

                  var type = clone.currentType();
                  var value = clone.currentValue();

                  // Stop conditions
                  if (type === "identifier" ||
                      value === ";")
                  {
                     rowToUse = clone.$row;
                     break;
                  }

                  // Chomp keywords
                  if (type === "keyword") {
                     continue;
                  }

                  // Walk over parens
                  clone.bwdToMatchingToken();

               } while (clone.moveToPreviousToken());

            }

            // Otherwise, try walking over class inheritance
            else {
               tokenCursor.moveToPreviousToken();
               if (tokenCursor.bwdOverClassySpecifiers()) {
                  rowToUse = tokenCursor.$row;
               }
            }

            if (rowToUse >= 0) {
               this.setIndent(session, row, rowToUse, session.getTabString(),
                              function(oldIndent, newIndent) {
                                 return oldIndent === newIndent;
                              });
            }

         }
      }

      // Outdent for lines starting with a '>' if an associated matching
      // token can be found. This is intended for template contexts, e.g.
      //
      //     template <
      //         int RTYPE
      //     >
      //     ^
      //
      if ($outdentRightArrow &&
          /^\s*>/.test(line) &&
          !/^\s*>>/.test(line)) {

         var rowToUse = this.codeModel.getRowForMatchingEOLArrows(session, doc, row);
         if (rowToUse >= 0) {
            this.setIndent(session, row, rowToUse);
            return;
         }

         // TODO: Renable this block if we get better tokenization
         // (need to discover whether '<', '>' are operators or not)
         //
         // if (this.codeModel.$tokenUtils.$tokenizeUpToRow(row)) {
         //    var tokenCursor = new CppTokenCursor(this.codeModel.$tokens, row, 0);
         //    if (tokenCursor.bwdToMatchingArrow()) {
         //       this.setIndent(session, row, tokenCursor.$row);
         //    }
         // }

      }

      // Outdent for closing braces (to match the indentation of their
      // matched opening brace
      //
      // If the line on which the matching '{' was found is of
      // the form
      //
      //  foo) {
      //
      // then indent according to the location of the matching
      // '('
      //
      // This rule should apply to closing braces with semi-colons
      // or comments following as well.
      if ($outdentRightBrace && /^\s*\}/.test(line)) {

         var openBracketPos = session.findMatchingBracket({
            row: row,
            column: line.indexOf("}") + 1
         });

         if (openBracketPos !== null) {

            // If the open brace lies on its own line, match its indentation
            var openBracketLine =
                   doc.$lines[openBracketPos.row];

            if (/^\s*\{/.test(openBracketLine)) {
               this.setIndent(session, row, openBracketPos.row);
               return;
            }

            // Otherwise, try looking upwards to get an appropriate indentation
            var heuristicRow = this.codeModel.getRowForOpenBraceIndent(
               session,
               openBracketPos.row
            );

            if (heuristicRow >= 0) {
               this.setIndent(session, row, heuristicRow);
               return;
            }

         }

      }

      if ($outdentRightParen) {

         var closingParenMatch = /^\s*\)/.exec(line);
         if (closingParenMatch) {
            var openParenPos = session.findMatchingBracket({
               row: row,
               column: line.indexOf(")") + 1
            });
            if (openParenPos) {
               this.setIndent(session, row, openParenPos.row);
               return;
            }
         }
      }

      if ($outdentRightBracket) {

         var closingBracketMatch = /^\s*\]/.exec(line);
         if (closingBracketMatch) {
            var openBracketPos = session.findMatchingBracket({
               row: row,
               column: line.indexOf("]") + 1
            });
            if (openBracketPos) {
               this.setIndent(session, row, openBracketPos.row);
               return;
            }
         }
      }

      // If we just typed 'public:', 'private:' or 'protected:',
      // we should outdent if possible. Do so by looking for the
      // enclosing 'class' scope.
      if ($alignClassAccessModifiers &&
          /^\s*public\s*:\s*$|^\s*private\s*:\s*$|^\s*protected\s*:\s*$/.test(line)) {

         // Find the associated open bracket.
         var openBracePos = session.$findOpeningBracket(
            "}",
            {
               row: row,
               column: line.length
            },
            new RegExp(/paren\.keyword\.operator/)
         );

         if (openBracePos) {
            // If this open brace is already associated with a class or struct,
            // step over all of those rows.
            var heuristicRow =
                   this.codeModel.getRowForOpenBraceIndent(session, openBracePos.row);

            if (heuristicRow >= 0) {
               this.setIndent(session, row, heuristicRow);
               return;
            } else {
               this.setIndent(session, row, openBracePos.row);
               return;
            }
         }

      }

      // Similar lookback for 'case foo:'.
      if ($alignCase &&
          (/^\s*case.+:/.test(line) || /^\s*default\s*:/.test(line)))
      {

         // Find the associated open bracket.
         var openBracePos = session.$findOpeningBracket(
            "}",
            {
               row: row,
               column: /(\S)/.exec(line).index + 1
            }
         );

         if (openBracePos) {
            var heuristicRow =
                   this.codeModel.getRowForOpenBraceIndent(session, openBracePos.row);

            if (heuristicRow >= 0) {
               this.setIndent(session, row, heuristicRow);
               return;
            } else {
               this.setIndent(session, row, openBracePos.row);
               return;
            }
         }

      }

      // If we just inserted a '{' on a new line to begin a class definition,
      // try looking up for the associated class statement.
      // We want to look back over the following common indentation styles:
      //
      // (1) class Foo
      //     : public A,
      //       public B,
      //       public C
      //
      // and
      //
      // (2) class Foo
      //     : public A
      //     , public B
      //     , public C
      //
      // We also design the rules to 'work' for initialization lists, e.g.
      //
      //    Foo()
      //    : foo_(foo),
      //      bar_(bar),
      //      baz_(baz)
      if ($outdentLeftBrace && /^\s*\{/.test(line)) {

         // Don't outdent if the previous line ends with a semicolon
         if (!/;\s*$/.test(prevLine)) {

            if (this.codeModel.$tokenUtils.$tokenizeUpToRow(row)) {

               var tokenCursor = new CppTokenCursor(this.codeModel.$tokens);
               tokenCursor.$row = row,
               tokenCursor.$offset = 0;

               if (tokenCursor.moveToPreviousToken()) {
                  if (tokenCursor.currentValue() === "=") {
                     return;
                  }
               }
            }

            var scopeRow = this.codeModel.getRowForOpenBraceIndent(
               session,
               row
            );

            if (scopeRow >= 0) {

               this.setIndent(session, row, scopeRow);
               return;

            }

         }

      }

      // For lines intended for the preprocessor, trim off the indentation.
      if (/^\s*#/.test(line))
      {
         var oldIndent = this.$getIndent(line);
         doc.replace(
            new Range(row, 0, row, oldIndent.length),
            ""
         );
         return;
      }

   };

   this.$getIndent = function(line) {
      var match = line.match(/^(\s+)/);
      if (match) {
         return match[1];
      }
      return "";
   };

}).call(MatchingBraceOutdent.prototype);

exports.MatchingBraceOutdent = MatchingBraceOutdent;

exports.getOutdentColon = function() { return $outdentColon; };
exports.setOutdentColon = function(x) { $outdentColon = x; };

exports.getOutdentRightParen = function() { return $outdentRightParen; };
exports.setOutdentRightParen = function(x) { $outdentRightParen = x; };

exports.getOutdentLeftBrace = function() { return $outdentLeftBrace; };
exports.setOutdentLeftBrace = function(x) { $outdentLeftBrace = x; };

exports.getOutdentRightBrace = function() { return $outdentRightBrace; };
exports.setOutdentRightBrace = function(x) { $outdentRightBrace = x; };

exports.getOutdentRightBracket = function() { return $outdentRightBracket; };
exports.setOutdentRightBracket = function(x) { $outdentRightBracket = x; };

exports.getOutdentRightArrow = function() { return $outdentRightArrow; };
exports.setOutdentRightArrow = function(x) { $outdentRightArrow = x; };

exports.getAlignDots = function() { return $alignDots; };
exports.setAlignDots = function(x) { $alignDots = x; };

exports.getAlignEquals = function() { return $alignEquals; };
exports.setAlignEquals = function(x) { $alignEquals = x; };

exports.getAlignStreamIn = function() { return $alignStreamIn; };
exports.setAlignStreamIn = function(x) { $alignStreamIn = x; };

exports.getAlignStreamOut = function() { return $alignStreamOut; };
exports.setAlignStreamOut = function(x) { $alignStreamOut = x; };

exports.getAlignClassAccessModifiers = function() { return $alignClassAccessModifiers; };
exports.setAlignClassAccessModifiers = function(x) { $alignClassAccessModifiers = x; };

exports.getAlignCase = function() { return $alignCase; };
exports.setAlignCase = function(x) { $alignCase = x; };

});
<|endoftext|>


<commit_before>/*!
  Copyright (C) 2016 Google Inc., authors, and contributors <see AUTHORS file>
  Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
  Created By: ivan@reciprocitylabs.com
  Maintained By: ivan@reciprocitylabs.com
*/

(function (GGRC, can) {
  'use strict';

/**
   * A component that takes care of adding comments with attachments
   *
   */
  GGRC.Components('addComment', {
    tag: 'add-comment',
    template: can.view('/static/mustache/base_templates/add_comment.mustache'),
    scope: {
      attachments: new can.List(),
      parent_instance: null,
      instance: null,
      instance_attr: '@',
      source_mapping: null,
      source_mapping_source: '@',
      mapping: '@',
      deferred: '@',
      isSaving: false,  // is there a save operation currently in progress
      attributes: {},
      list: [],
      // the following are just for the case when we have no object to start with,
      changes: [],
      get_assignee_type: can.compute(function () {
        // TODO: We prioritize order V > A > R
        var types = {
          related_verifiers: 'verifier',
          related_assignees: 'assignee',
          related_requesters: 'requester'
        };
        var instance = this.attr('parent_instance');
        var user = GGRC.current_user;
        var user_type;

        if (!instance || !user) {
          return;
        }
        _.each(types, function (type, mapping) {
          var mappings = instance.get_mapping(mapping);
          if (!mappings.length) {
            return;
          }
          if (_.filter(mappings, function (mapping) {
            return mapping.instance.id === user.id;
          }).length) {
            type = can.capitalize(type);
            user_type = user_type ? (user_type + ',' + type) : type;
          }
        });
        return user_type;
      })
    },
    events: {
      init: function () {
        if (!this.scope.attr('source_mapping')) {
          this.scope.attr('source_mapping', GGRC.page_instance());
        }
        this.newInstance();
      },
      newInstance: function () {
        var instance = CMS.Models.Comment();
        instance._source_mapping = this.scope.attr('source_mapping');
        instance.attr('context', this.scope.attr('parent_instance.context'));
        this.scope.attr('instance', instance);
      },
      cleanPanel: function () {
        this.scope.attachments.replace([]);
        this.element.find('textarea').val('');
      },
      /**
       * The component's click event (happens when the user clicks add comment),
       * takes care of saving the comment with appended evidence.
       */
      '.btn-success click': function (el, ev) {
        var $textarea = this.element.find('.add-comment textarea');
        var description = $.trim($textarea.val());
        var attachments = this.scope.attachments;
        var source = this.scope.source_mapping;
        var instance = this.scope.instance;
        var data;
        var $sendNotification = this.element.find('[name=send_notification]');
        var sendNotification = $sendNotification[0].checked;

        if (!description.length && !attachments.length) {
          return;
        }
        data = {
          description: description,
          send_notification: sendNotification,
          context: source.context,
          assignee_type: this.scope.attr('get_assignee_type')
        };

        this.scope.attr('isSaving', true);

        instance.attr(data).save()
          .then(function () {
            return instance.constructor.resolve_deferred_bindings(instance);
          })
          .then(function () {
            this.newInstance();
            this.cleanPanel();
          }.bind(this))
          .always(function () {
            this.scope.attr('isSaving', false);
          }.bind(this));
      }
    }
  });
})(window.GGRC, window.can);
<commit_msg>Add creator assignee type<commit_after>/*!
  Copyright (C) 2016 Google Inc., authors, and contributors <see AUTHORS file>
  Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
  Created By: ivan@reciprocitylabs.com
  Maintained By: ivan@reciprocitylabs.com
*/

(function (GGRC, can) {
  'use strict';

/**
   * A component that takes care of adding comments with attachments
   *
   */
  GGRC.Components('addComment', {
    tag: 'add-comment',
    template: can.view('/static/mustache/base_templates/add_comment.mustache'),
    scope: {
      attachments: new can.List(),
      parent_instance: null,
      instance: null,
      instance_attr: '@',
      source_mapping: null,
      source_mapping_source: '@',
      mapping: '@',
      deferred: '@',
      isSaving: false,  // is there a save operation currently in progress
      attributes: {},
      list: [],
      // the following are just for the case when we have no object to start with,
      changes: [],
      get_assignee_type: can.compute(function () {
        // TODO: We prioritize order V > A > R
        var types = {
          related_creators: 'creator',
          related_verifiers: 'verifier',
          related_assignees: 'assignee',
          related_requesters: 'requester'
        };
        var instance = this.attr('parent_instance');
        var user = GGRC.current_user;
        var user_type;

        if (!instance || !user) {
          return;
        }
        _.each(types, function (type, mapping) {
          var mappings = instance.get_mapping(mapping);
          if (!mappings.length) {
            return;
          }
          if (_.filter(mappings, function (mapping) {
            return mapping.instance.id === user.id;
          }).length) {
            type = can.capitalize(type);
            user_type = user_type ? (user_type + ',' + type) : type;
          }
        });
        return user_type;
      })
    },
    events: {
      init: function () {
        if (!this.scope.attr('source_mapping')) {
          this.scope.attr('source_mapping', GGRC.page_instance());
        }
        this.newInstance();
      },
      newInstance: function () {
        var instance = CMS.Models.Comment();
        instance._source_mapping = this.scope.attr('source_mapping');
        instance.attr('context', this.scope.attr('parent_instance.context'));
        this.scope.attr('instance', instance);
      },
      cleanPanel: function () {
        this.scope.attachments.replace([]);
        this.element.find('textarea').val('');
      },
      /**
       * The component's click event (happens when the user clicks add comment),
       * takes care of saving the comment with appended evidence.
       */
      '.btn-success click': function (el, ev) {
        var $textarea = this.element.find('.add-comment textarea');
        var description = $.trim($textarea.val());
        var attachments = this.scope.attachments;
        var source = this.scope.source_mapping;
        var instance = this.scope.instance;
        var data;
        var $sendNotification = this.element.find('[name=send_notification]');
        var sendNotification = $sendNotification[0].checked;

        if (!description.length && !attachments.length) {
          return;
        }
        data = {
          description: description,
          send_notification: sendNotification,
          context: source.context,
          assignee_type: this.scope.attr('get_assignee_type')
        };

        this.scope.attr('isSaving', true);

        instance.attr(data).save()
          .then(function () {
            return instance.constructor.resolve_deferred_bindings(instance);
          })
          .then(function () {
            this.newInstance();
            this.cleanPanel();
          }.bind(this))
          .always(function () {
            this.scope.attr('isSaving', false);
          }.bind(this));
      }
    }
  });
})(window.GGRC, window.can);
<|endoftext|>


<commit_before>// usage: log('inside coolFunc', this, arguments);
// paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
window.log = function f(){ log.history = log.history || []; log.history.push(arguments); if(this.console) { var args = arguments, newarr; args.callee = args.callee.caller; newarr = [].slice.call(args); if (typeof console.log === 'object') log.apply.call(console.log, console, newarr); else console.log.apply(console, newarr);}};

// make it safe to use console.log always
(function(a){function b(){}for(var c="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","),d;!!(d=c.pop());){a[d]=a[d]||b;}})
(function(){try{console.log();return window.console;}catch(a){return (window.console={});}}());

// place any jQuery/helper plugins in here, instead of separate, slower script files.

/*
 * Form Collection
 */
(function($, Backbone, _){

	var MasterView = Backbone.View.extend({
		"tagName"	: "div",
		"className"	: "content",
		"icon" : '',
		"addlink" : _.template('<%= icon %> <%= label %>'),
		"legend" : _.template('<legend class="collection-heading"><%= label %> <%= counter %></legend>'),
		"counter" : 0,

		/*"events" : {
			"click a.add_form_collection_link" : "addForm",
		},*/

		"initialize": function () {

			this.render();

        },
        "render" : function() {

			var $this = this;

			var add_link = $(this.createAddLink()).on("click", function(e) { e.preventDefault(); $this.addForm($this, this); });

			this.$el.append(add_link);

			if(this.$el.find('fieldset:first').children().length > 0)
			{
				this.$el.find('fieldset:first').prepend($this.legend({"label" : $this.options.label, "counter" : ++$this.counter}));
			}

        	return this;
        },
        "createAddLink" : function(){
        	return this.addlink({"icon" : this.icon, "label" : ExposeTranslation.get('Add') + " " + this.options.label});
        },
        "addForm" : function($this, l) {

        	var prototype  = this.$el.attr('data-prototype');

		    var form = $(prototype.replace(/__name__/g, this.$el.children('.content').length));

		    form.find('fieldset:first').prepend(this.legend({"label" : this.options.label, "counter" : ++this.counter}));

		    var scripts = new Array();

		    if(typeof form[1] !== undefined)
		   	{
		    	scripts.push($(form[1]).html());
		   	}

		    var view = new FormCollectionView({"el" : form});

		    //$(l).before(view.render().el);

		    //$this.$el.prepend(r);

		    this.$el.prepend(view.render().el);

		    //$this.$el.find('.add_form_collection_link:last').before(view.render().el);

		    for(var i = 0; i < scripts.length; i++)
		    {
		    	$.globalEval(scripts[i]);
		    }

		    Loader.call();

		    return view;
        }
	});

	var FormCollectionView = Backbone.View.extend({

		"template" : _.template('<%= icon %> <%=label%>'),
		"icon" : ' ',

		"render" : function(){

			var $this = this;

			var template = this.template({"icon" : this.icon, "label" : ExposeTranslation.get('delete')});

			var tmpl = $(template).on("click", function(e){
				e.preventDefault();
				$this.destroy($this);
			});

			this.$el.prepend(tmpl);

			return this;
		},
		"destroy" : function($this) {

			$this.$el.remove();

			return this;
		}
	});

	$.fn.formCollection = function(options) {

		var view = new MasterView($.extend({"el" : this}, options));

		return view;
	};

})(window.jQuery, Backbone, _);<commit_msg>Updated FormCollection Plugin<commit_after>// usage: log('inside coolFunc', this, arguments);
// paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
window.log = function f(){ log.history = log.history || []; log.history.push(arguments); if(this.console) { var args = arguments, newarr; args.callee = args.callee.caller; newarr = [].slice.call(args); if (typeof console.log === 'object') log.apply.call(console.log, console, newarr); else console.log.apply(console, newarr);}};

// make it safe to use console.log always
(function(a){function b(){}for(var c="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","),d;!!(d=c.pop());){a[d]=a[d]||b;}})
(function(){try{console.log();return window.console;}catch(a){return (window.console={});}}());

// place any jQuery/helper plugins in here, instead of separate, slower script files.

/*
 * Form Collection
 */
(function($, Backbone, _){

	var MasterView = Backbone.View.extend({
		"tagName"	: "div",
		"className"	: "content",
		"icon" : '',
		"addlink" : _.template('<%= icon %> <%= label %>'),
		"legend" : _.template('<legend class="collection-heading"><h<%= heading %>><%= label %> <%= counter %></h<%= heading %>></legend>'),
		"counter" : 0,
		"heading" : 2,

		"initialize": function () {
			this.render();
        },
        "render" : function() {

			var $this = this,
				add_link = $(this.createAddLink()).on("click", function(e) { e.preventDefault(); $this.addForm($this, this); });

			this.$el.append(add_link);

			if(this.$el.find('fieldset:first').children().length > 0)
			{
				this.$el.find('fieldset:first').prepend($this.legend({"label" : $this.options.label, "counter" : ++$this.counter}));
			}

        	return this;
        },
        "createAddLink" : function(){
        	return this.addlink({"icon" : this.icon, "label" : ExposeTranslation.get('Add') + " " + this.options.label});
        },
        "addForm" : function($this, l) {

        	var prototype  = this.$el.attr('data-prototype'),
        		form = $(prototype.replace(/__name__/g, this.$el.children('.control-group').length)),
        		parents = this.$el.parents('.form-collection').length,
        		heading = this.heading + (parents === 2 ? 3 : parents),
        		scripts = new Array();

		    form.find('fieldset:first').prepend(this.legend({"heading" : heading, "label" : this.options.label, "counter" : ++this.counter}));

		    if(typeof form[1] !== undefined)
		   	{
		    	scripts.push($(form[1]).html());
		   	}

		    var view = new FormCollectionView({"el" : form}),
		    	el = view.render().el;

		    $(l).before(el);

		    var legend = $(el).find('.form-collection').siblings('legend'),
		    	head = $('<h' + (heading + 1) + ' />').html(legend.children().first().html());

		    legend.html(head);

		    for(var i = 0; i < scripts.length; i++)
		    {
		    	$.globalEval(scripts[i]);
		    }

		    Loader.call();

		    return view;
        }
	});

	var FormCollectionView = Backbone.View.extend({

		"template" : _.template('<%= icon %> <%=label%>'),
		"icon" : ' ',

		"render" : function(){

			var $this = this,
				template = this.template({"icon" : this.icon, "label" : ExposeTranslation.get('delete')}),
				tmpl = $(template).on("click", function(e){
							e.preventDefault();
							$this.destroy($this);
				});

			this.$el.prepend(tmpl);

			return this;
		},
		"destroy" : function($this) {

			$this.$el.remove();

			return this;
		}
	});

	$.fn.formCollection = function(options) {
		var view = new MasterView($.extend({"el" : this}, options));

		return view;
	};

})(window.jQuery, Backbone, _);<|endoftext|>


<commit_before>/*jshint globalstrict:true */
/*global angular:true */
/*global FileReader:false*/
/*

  ## Dashcontrol

  ### Parameters
  * save
  ** gist :: Allow saving to gist. Requires registering an oauth domain with Github
  ** elasticsearch :: Allow saving to a special Kibana index within Elasticsearch
  ** local :: Allow saving to local file
  * load
  ** gist :: Allow loading from gists
  ** elasticsearch :: Allow searching and loading of elasticsearch saved dashboards
  ** local :: Allow loading of dashboards from Elasticsearch
  * hide_control :: Upon save, hide this panel
  * elasticsearch_size :: show this many dashboards under the ES section in the load drop down
  * temp :: Allow saving of temp dashboards
  * ttl :: Enable setting ttl.
  * temp_ttl :: How long should temp dashboards persist

*/
'use strict';

angular.module('kibana.dashcontrol', [])
.controller('dashcontrol', function($scope, $http, timer, dashboard, alertSrv) {

  $scope.panelMeta = {
    status  : "Stable",
    description : "This panel allows for saving, loading, exporting and sharing dashboard schemas."
  };

  $scope.panel = $scope.panel || {};
  // Set and populate defaults
  var _d = {
    save : {
      gist: false,
      elasticsearch: true,
      local: true,
      'default': true
    },
    load : {
      gist: true,
      elasticsearch: true,
      local: true
    },
    hide_control: false,
    elasticsearch_size: 20,
    temp: true,
    ttl_enable: true,
    temp_ttl: '30d'
  };
  _.defaults($scope.panel,_d);

  // A hash of defaults for the dashboard object
  var _dash = {
    title: "",
    editable: true,
    rows: [],
    services: {}
  };

  $scope.init = function() {
    $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
    $scope.gist = {};
    $scope.elasticsearch = {};
  };

  $scope.set_default = function() {
    if(dashboard.set_default()) {
      alertSrv.set('Local Default Set',dashboard.current.title+' has been set as your local default','success',5000);
    } else {
      alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000);
    }
  };

  $scope.purge_default = function() {
    if(dashboard.purge_default()) {
      alertSrv.set('Local Default Clear','Your local default dashboard has been cleared','success',5000);
    } else {
      alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000);
    }
  };

  $scope.elasticsearch_save = function(type,ttl) {
    dashboard.elasticsearch_save(
      type,
      ($scope.elasticsearch.title || dashboard.current.title),
      ($scope.panel.ttl_enable ? ttl : false)
      ).then(
      function(result) {
      if(!_.isUndefined(result._id)) {
        alertSrv.set('Dashboard Saved','This dashboard has been saved to Elasticsearch as "' +
          result._id + '"','success',5000);
        if(type === 'temp') {
          $scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
        }
      } else {
        alertSrv.set('Save failed','Dashboard could not be saved to Elasticsearch','error',5000);
      }
    });
  };

  $scope.elasticsearch_delete = function(id) {
    dashboard.elasticsearch_delete(id).then(
      function(result) {
        if(!_.isUndefined(result)) {
          if(result.found) {
            alertSrv.set('Dashboard Deleted',id+' has been deleted','success',5000);
            // Find the deleted dashboard in the cached list and remove it
            var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0];
            $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete);
          } else {
            alertSrv.set('Dashboard Not Found','Could not find '+id+' in Elasticsearch','warning',5000);
          }
        } else {
          alertSrv.set('Dashboard Not Deleted','An error occurred deleting the dashboard','error',5000);
        }
      }
    );
  };

  $scope.elasticsearch_dblist = function(query) {
    dashboard.elasticsearch_list(query,$scope.panel.elasticsearch_size).then(
      function(result) {
      if(!_.isUndefined(result.hits)) {
        $scope.panel.error =  false;
        $scope.hits = result.hits.total;
        $scope.elasticsearch.dashboards = result.hits.hits;
      }
    });
  };

  $scope.save_gist = function() {
    dashboard.save_gist($scope.gist.title).then(
      function(link) {
      if(!_.isUndefined(link)) {
        $scope.gist.last = link;
        alertSrv.set('Gist saved','You will be able to access your exported dashboard file at '+
          ''+link+' in a moment','success');
      } else {
        alertSrv.set('Save failed','Gist could not be saved','error',5000);
      }
    });
  };

  $scope.gist_dblist = function(id) {
    dashboard.gist_list(id).then(
      function(files) {
      if(files && files.length > 0) {
        $scope.gist.files = files;
      } else {
        alertSrv.set('Gist Failed','Could not retrieve dashboard list from gist','error',5000);
      }
    });
  };
})
.directive('dashUpload', function(timer, dashboard, alertSrv){
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      function file_selected(evt) {
        var files = evt.target.files; // FileList object

        // files is a FileList of File objects. List some properties.
        var output = [];
        var readerOnload = function(theFile) {
          return function(e) {
            dashboard.dash_load(JSON.parse(e.target.result));
            scope.$apply();
          };
        };
        for (var i = 0, f; f = files[i]; i++) {
          var reader = new FileReader();
          reader.onload = (readerOnload)(f);
          reader.readAsText(f);
        }
      }

      // Check for the various File API support.
      if (window.File && window.FileReader && window.FileList && window.Blob) {
        // Something
        document.getElementById('dashupload').addEventListener('change', file_selected, false);
      } else {
        alertSrv.set('Oops','Sorry, the HTML5 File APIs are not fully supported in this browser.','error');
      }
    }
  };
}).filter('gistid', function() {
  var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
  return function(input, scope) {
    //return input+"boners"
    if(!(_.isUndefined(input))) {
      var output = input.match(gist_pattern);
      if(!_.isNull(output) && !_.isUndefined(output)) {
        return output[0].replace(/.*\//, '');
      }
    }
  };
});<commit_msg>spacing<commit_after>/*jshint globalstrict:true */
/*global angular:true */
/*global FileReader:false*/
/*

  ## Dashcontrol

  ### Parameters
  * save
  ** gist :: Allow saving to gist. Requires registering an oauth domain with Github
  ** elasticsearch :: Allow saving to a special Kibana index within Elasticsearch
  ** local :: Allow saving to local file
  * load
  ** gist :: Allow loading from gists
  ** elasticsearch :: Allow searching and loading of elasticsearch saved dashboards
  ** local :: Allow loading of dashboards from Elasticsearch
  * hide_control :: Upon save, hide this panel
  * elasticsearch_size :: show this many dashboards under the ES section in the load drop down
  * temp :: Allow saving of temp dashboards
  * ttl :: Enable setting ttl.
  * temp_ttl :: How long should temp dashboards persist

*/
'use strict';

angular.module('kibana.dashcontrol', [])
.controller('dashcontrol', function($scope, $http, timer, dashboard, alertSrv) {

  $scope.panelMeta = {
    status  : "Stable",
    description : "This panel allows for saving, loading, exporting and sharing dashboard schemas."
  };

  $scope.panel = $scope.panel || {};
  // Set and populate defaults
  var _d = {
    save : {
      gist: false,
      elasticsearch: true,
      local: true,
      'default': true
    },
    load : {
      gist: true,
      elasticsearch: true,
      local: true
    },
    hide_control: false,
    elasticsearch_size: 20,
    temp: true,
    ttl_enable: true,
    temp_ttl: '30d'
  };
  _.defaults($scope.panel,_d);

  // A hash of defaults for the dashboard object
  var _dash = {
    title: "",
    editable: true,
    rows: [],
    services: {}
  };

  $scope.init = function() {
    $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
    $scope.gist = {};
    $scope.elasticsearch = {};
  };

  $scope.set_default = function() {
    if(dashboard.set_default()) {
      alertSrv.set('Local Default Set',dashboard.current.title+' has been set as your local default','success',5000);
    } else {
      alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000);
    }
  };

  $scope.purge_default = function() {
    if(dashboard.purge_default()) {
      alertSrv.set('Local Default Clear','Your local default dashboard has been cleared','success',5000);
    } else {
      alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000);
    }
  };

  $scope.elasticsearch_save = function(type,ttl) {
    dashboard.elasticsearch_save(
      type,
      ($scope.elasticsearch.title || dashboard.current.title),
      ($scope.panel.ttl_enable ? ttl : false)
    ).then(
      function(result) {
      if(!_.isUndefined(result._id)) {
        alertSrv.set('Dashboard Saved','This dashboard has been saved to Elasticsearch as "' +
          result._id + '"','success',5000);
        if(type === 'temp') {
          $scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
        }
      } else {
        alertSrv.set('Save failed','Dashboard could not be saved to Elasticsearch','error',5000);
      }
    });
  };

  $scope.elasticsearch_delete = function(id) {
    dashboard.elasticsearch_delete(id).then(
      function(result) {
        if(!_.isUndefined(result)) {
          if(result.found) {
            alertSrv.set('Dashboard Deleted',id+' has been deleted','success',5000);
            // Find the deleted dashboard in the cached list and remove it
            var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0];
            $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete);
          } else {
            alertSrv.set('Dashboard Not Found','Could not find '+id+' in Elasticsearch','warning',5000);
          }
        } else {
          alertSrv.set('Dashboard Not Deleted','An error occurred deleting the dashboard','error',5000);
        }
      }
    );
  };

  $scope.elasticsearch_dblist = function(query) {
    dashboard.elasticsearch_list(query,$scope.panel.elasticsearch_size).then(
      function(result) {
      if(!_.isUndefined(result.hits)) {
        $scope.panel.error =  false;
        $scope.hits = result.hits.total;
        $scope.elasticsearch.dashboards = result.hits.hits;
      }
    });
  };

  $scope.save_gist = function() {
    dashboard.save_gist($scope.gist.title).then(
      function(link) {
      if(!_.isUndefined(link)) {
        $scope.gist.last = link;
        alertSrv.set('Gist saved','You will be able to access your exported dashboard file at '+
          ''+link+' in a moment','success');
      } else {
        alertSrv.set('Save failed','Gist could not be saved','error',5000);
      }
    });
  };

  $scope.gist_dblist = function(id) {
    dashboard.gist_list(id).then(
      function(files) {
      if(files && files.length > 0) {
        $scope.gist.files = files;
      } else {
        alertSrv.set('Gist Failed','Could not retrieve dashboard list from gist','error',5000);
      }
    });
  };
})
.directive('dashUpload', function(timer, dashboard, alertSrv){
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      function file_selected(evt) {
        var files = evt.target.files; // FileList object

        // files is a FileList of File objects. List some properties.
        var output = [];
        var readerOnload = function(theFile) {
          return function(e) {
            dashboard.dash_load(JSON.parse(e.target.result));
            scope.$apply();
          };
        };
        for (var i = 0, f; f = files[i]; i++) {
          var reader = new FileReader();
          reader.onload = (readerOnload)(f);
          reader.readAsText(f);
        }
      }

      // Check for the various File API support.
      if (window.File && window.FileReader && window.FileList && window.Blob) {
        // Something
        document.getElementById('dashupload').addEventListener('change', file_selected, false);
      } else {
        alertSrv.set('Oops','Sorry, the HTML5 File APIs are not fully supported in this browser.','error');
      }
    }
  };
}).filter('gistid', function() {
  var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
  return function(input, scope) {
    //return input+"boners"
    if(!(_.isUndefined(input))) {
      var output = input.match(gist_pattern);
      if(!_.isNull(output) && !_.isUndefined(output)) {
        return output[0].replace(/.*\//, '');
      }
    }
  };
});<|endoftext|>


<commit_before>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      productsICanEat = _(products).filter(function(x) {
        return (! x.containsNuts) && _(x.ingredients).all(function(ing) {
          return ing !== "mushrooms"
        });
      });

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {
    /* try chaining range() and reduce() */
    var sum = _.range(1000).reduce(function(total, x) {
      return (total ? total : 0) + ((x % 3 === 0 || x % 5 === 0) ? x : 0);
    });
    expect(233168).toBe(sum);
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
    _(products).chain()
      .map(function(prod) { return prod.ingredients })
      .flatten()
      .reduce(function(counts, ing) {
        counts[ing] = (counts[ing] || 0) + 1;
        return counts;
      }, ingredientCount);
    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */
  /*
   */
  it("should find the largest prime factor of a composite number", function () {
    // For this,
    // * find all the primes less than composite number
    // * Then, iterate through primes, highest to lowest
    //   * if composite % prime === 0, and composite / prime = prime
    isPrime = function(possiblePrime) {
      if (possiblePrime === 1 || possiblePrime === 2) {
        return true;
      } else if (possiblePrime % 2 === 0) {
        return false;
      }
      for (var i=3; i < possiblePrime; i+= 2) {
        if (possiblePrime % i === 0) {
          return false;
        }
      }
      return true;
    };
    expect(isPrime(1)).toBe(true);
    expect(isPrime(4)).toBe(false);
    expect(isPrime(5)).toBe(true);

    // durrr...use range
    var primesLessThanNum = function(composite) {
      return _.range(2,composite).filter(function(x) { return isPrime(x); });
    };
    expect(primesLessThanNum(6)).toEqual([2, 3, 5]);
    expect(primesLessThanNum(9)).toEqual([2, 3, 5, 7]);

    var largestPrimeFactor = function(composite) {
      return _(primesLessThanNum(composite)).chain()
        .filter(function(x) { return composite % x === 0})
        .max()
        .value();
    }
    expect(largestPrimeFactor(9)).toBe(3);
    expect(largestPrimeFactor(25)).toBe(5);
    expect(largestPrimeFactor(247)).toBe(19);
  });

  /*
  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  });*/

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {
    var isDivisibleByOneThroughTwenty = function(num) {
      for (var i=1; i <=20; i++) {
        if (num % i !== 0) {
          return false;
        }
      }
      return true;
    };
    var twentyFactorial = 1*2*3*4*5*6*7*8*9*10*11*12*12*13*14*15*16*17*18*19*20;
    expect(isDivisibleByOneThroughTwenty(10)).toBe(false);
    expect(isDivisibleByOneThroughTwenty(twentyFactorial)).toBe(true);

    var divRange20 = function () {
      var testNum = 1;
      while (! isDivisibleByOneThroughTwenty(testNum)) {
        //console.log(testNum);
        testNum++;
      }
      return testNum;
    };
    expect(divRange20()).toBe(232792560);
  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {
    var squareDiffs = function(nums) {
      var sumOfSquares = function(nums) {
        var total = 0;
        for (var i=0; i < nums.length; i++) {
          total += nums[i] * nums[i];
          // console.log("Sum of squares total: " + total);
        };
        return total;
      }
      expect(sumOfSquares([3,4])).toBe(25);
      expect(sumOfSquares([3,4,5])).toBe(50);

      var squareOfSums = function(nums) {
        var total = 0;
        for (var i=0; i < nums.length; i++) {
          total += nums[i];
          // console.log("Square of sums total: " + total);
        };
        return total * total;
      }
      expect(squareOfSums([3,4])).toBe(49);
      expect(squareOfSums([3,4,5])).toBe(144);

      return squareOfSums(nums) - sumOfSquares(nums);
    };

    expect(squareDiffs([3,4])).toBe(24);
  });

  it("should find the 10001st prime", function () {
    var tenThousandAndOnethPrime = function() {
      var primes = [2];
      console.log(isPrime(6));

    }
    expect(tenThousandAndOnethPrime()).toBe(104743);
  });
});
<commit_msg>finds the 10001st prime<commit_after>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      productsICanEat = _(products).filter(function(x) {
        return (! x.containsNuts) && _(x.ingredients).all(function(ing) {
          return ing !== "mushrooms"
        });
      });

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {
    /* try chaining range() and reduce() */
    var sum = _.range(1000).reduce(function(total, x) {
      return (total ? total : 0) + ((x % 3 === 0 || x % 5 === 0) ? x : 0);
    });
    expect(233168).toBe(sum);
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
    _(products).chain()
      .map(function(prod) { return prod.ingredients })
      .flatten()
      .reduce(function(counts, ing) {
        counts[ing] = (counts[ing] || 0) + 1;
        return counts;
      }, ingredientCount);
    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */
  /*
   */
  it("should find the largest prime factor of a composite number", function () {
    // For this,
    // * find all the primes less than composite number
    // * Then, iterate through primes, highest to lowest
    //   * if composite % prime === 0, and composite / prime = prime
    isPrime = function(possiblePrime) {
      if (possiblePrime === 1 || possiblePrime === 2) {
        return true;
      } else if (possiblePrime % 2 === 0) {
        return false;
      }
      for (var i=3; i < possiblePrime; i+= 2) {
        if (possiblePrime % i === 0) {
          return false;
        }
      }
      return true;
    };
    expect(isPrime(1)).toBe(true);
    expect(isPrime(4)).toBe(false);
    expect(isPrime(5)).toBe(true);

    // durrr...use range
    var primesLessThanNum = function(composite) {
      return _.range(2,composite).filter(function(x) { return isPrime(x); });
    };
    expect(primesLessThanNum(6)).toEqual([2, 3, 5]);
    expect(primesLessThanNum(9)).toEqual([2, 3, 5, 7]);

    var largestPrimeFactor = function(composite) {
      return _(primesLessThanNum(composite)).chain()
        .filter(function(x) { return composite % x === 0})
        .max()
        .value();
    }
    expect(largestPrimeFactor(9)).toBe(3);
    expect(largestPrimeFactor(25)).toBe(5);
    expect(largestPrimeFactor(247)).toBe(19);
  });

  /*
  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  });*/

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {
    var isDivisibleByOneThroughTwenty = function(num) {
      for (var i=1; i <=20; i++) {
        if (num % i !== 0) {
          return false;
        }
      }
      return true;
    };
    var twentyFactorial = 1*2*3*4*5*6*7*8*9*10*11*12*12*13*14*15*16*17*18*19*20;
    expect(isDivisibleByOneThroughTwenty(10)).toBe(false);
    expect(isDivisibleByOneThroughTwenty(twentyFactorial)).toBe(true);

    var divRange20 = function () {
      var testNum = 1;
      while (! isDivisibleByOneThroughTwenty(testNum)) {
        //console.log(testNum);
        testNum++;
      }
      return testNum;
    };
    expect(divRange20()).toBe(232792560);
  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {
    var squareDiffs = function(nums) {
      var sumOfSquares = function(nums) {
        var total = 0;
        for (var i=0; i < nums.length; i++) {
          total += nums[i] * nums[i];
          // console.log("Sum of squares total: " + total);
        };
        return total;
      }
      expect(sumOfSquares([3,4])).toBe(25);
      expect(sumOfSquares([3,4,5])).toBe(50);

      var squareOfSums = function(nums) {
        var total = 0;
        for (var i=0; i < nums.length; i++) {
          total += nums[i];
          // console.log("Square of sums total: " + total);
        };
        return total * total;
      }
      expect(squareOfSums([3,4])).toBe(49);
      expect(squareOfSums([3,4,5])).toBe(144);

      return squareOfSums(nums) - sumOfSquares(nums);
    };

    expect(squareDiffs([3,4])).toBe(24);
  });

  it("should find the 10001st prime", function () {
    var tenThousandAndOnethPrime = function() {
      var primes = [2];
      var potentialPrime = 3;
      while (primes.length < 10001) {
        if (isPrime(potentialPrime) ) {
          primes.push(potentialPrime);
        }
        potentialPrime += 2;
      }
      // console.log(primes[10000]);
      return primes[10000];
    }
    expect(tenThousandAndOnethPrime()).toBe(104743);
  });
});
<|endoftext|>


<commit_before>import generateMarkupAndState from "../server";

describe('generateMarkup', () => {

	it('generates markup for /ui/about', () => {
		return generateMarkupAndState("/ui/about", "")
			.then(({markup, state}) => {
				expect(markup).to.have.string("Welcome to Redouble!");
				expect(state).to.be.defined;
			});
	});

	it('generates markup for /ui/settings', () => {
		return generateMarkupAndState("/ui/settings", "")
			.then(({markup, state}) => {
				expect(markup).to.have.string(`<h3 class="settings-player-header"`);
				expect(state).to.be.defined;
			});
	});

	it('generates markup for /', () => {
		return generateMarkupAndState("/", "")
			.then(({markup, state}) => {
				expect(markup).to.have.string(`<div class="bridge-table"`);
				expect(state).to.be.defined;
			});
	});

});
<commit_msg>fix broken test<commit_after>import generateMarkupAndState from "../server";

describe('generateMarkup', () => {

	it('generates markup for /ui/about', () => {
		return generateMarkupAndState("/ui/about", "")
			.then(({markup, state}) => {
				expect(markup).to.have.string(">About Redouble</h3>");
				expect(state).to.be.defined;
			});
	});

	it('generates markup for /ui/settings', () => {
		return generateMarkupAndState("/ui/settings", "")
			.then(({markup, state}) => {
				expect(markup).to.have.string(`<h3 class="settings-player-header"`);
				expect(state).to.be.defined;
			});
	});

	it('generates markup for /', () => {
		return generateMarkupAndState("/", "")
			.then(({markup, state}) => {
				expect(markup).to.have.string(`<div class="bridge-table"`);
				expect(state).to.be.defined;
			});
	});

});
<|endoftext|>