<commit_before>
    // Initial Setup
    // -------------

    /**
     * The one global object for F.
     * @namespace F
     */
    var F = {};

    /**
     * The previous value of the `F` variable, so that it can be
     * restored later on, if `noConflict` is used.
     * @type {F}
     */
    var previousF = F;

    /**
     * Current version of the library.
     * Must be keept in sync with `package.json` and `bower.json`.
     * @type {String}
     */
    F.VERSION = '::VERSION_NUMBER::';

    /**
     * Set framework to debug mode. Disabled by default
     * @type {Boolean}
     */
    F.DEBUG = false;

    /**
     * Runs F.js in *noConflict* mode, returning the `F` variable
     * to its previous owner.
     * @return {F} a reference to this F object
     */
    F.noConflict = function() {
        F = previousF;
        return this;
    };

    // Patch Object
    Object.getOwnPropertyDescriptors = function (obj) {
        var descriptors = {};
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                descriptors[prop] = Object.getOwnPropertyDescriptor(obj, prop);
            }
        }
        return descriptors;
    };

    // Util
    // ---

    // Composes objects by combining them into a new one
    // TODO: Object.assign only exists in ES6 and library is for ES5 so fix this.
    F.compose = Object.assign;

    /**
     * Helper function to correctly set up the prototype chain for subclasses.
     * Similar to `goog.inherits`, but uses a hash of prototype properties and
     * class properties to be extended.
     *
     * Taken from Backbone.js of Jeremy Ashkenas
     * @see https://github.com/jashkenas/backbone/blob/master/backbone.js#L1839
     * @see https://gist.github.com/juandopazo/1367191
     *
     * @param  {Object} protoProps - the instance properties for the *Class*
     * @param  {Object} staticProps - the static properties for the *Class*
     * @return {Function} - a new constructor function
     */
    F.extend = function(protoProps, staticProps) {
        var parent = this;
        var child;

        // The constructor function for the new subclass is either defined by you
        // (the "constructor" property in your `extend` definition), or defaulted
        // by us to simply call the parent constructor.
        if (!protoProps.hasOwnProperty('constructor')) {
            Object.defineProperty(protoProps, 'constructor', {
                value: function () {
                    // Default call to superclass as in maxmin classes
                    parent.apply(this, arguments);
                },
                writable: true,
                configurable: true,
                enumerable: false
            });
        }

        child = protoProps.constructor;
        // Add static properties to the constructor function, if supplied.
        Object.assign(child, parent, staticProps);

        // Set the prototype chain to inherit from `parent`, without calling
        // `parent`'s constructor function and add the prototype properties.
        child.prototype = Object.create(parent.prototype, Object.getOwnPropertyDescriptors(protoProps));
        child.prototype.constructor = child;

        // Set a convenience property in case the parent's prototype is needed
        // later.
        child.__super__ = parent.prototype;

        return child;
    };

    /**
     * Performs event delegation setting.
     * @param  {HTMLElement} element the element we want to delegate events for
     * @param  {string} event    the type of event we want to delegate
     * @param  {string} selector a css selector
     * @param  {Function} handler  the handler function
     * @param  {Object} context  the context under which the handler fn
     *                           will be called
     * @param {boolean} useCapture indicates that events of this type will be
     *                           dispatched to the registered listener before
     *                           being dispatched to any EventTarget beneath
     *                           it in the DOM tree
     * @return {void}
     */
    F.delegateEvent = function(element, event, selector, handler, context, useCapture) {

        var listener =  function(e){
            if (typeof selector === "undefined" || selector === null) {
                return handler.call(context || null, e);
            } else if (e.target && e.target.matches(selector)) {
                // console.log('event: ' + eventName + ', selector: ' + selector + ', handler: ' + handler + ', matches: ' + e.target.matches(selector));
                return handler.call(context || null, e);
            }
        };

        useCapture = useCapture || false;
        element.addEventListener(event, listener, useCapture);
    };

    /**
     * Performs event delegation unsetting.
     * @param  {HTMLElement} element the element we want to undelegate events for
     * @param  {string} event    the type of event we want to undelegate
     * @param  {string} selector a css selector
     * @param  {Function} handler  the handler function
     * @param  {Object} context  the context under which the handler fn
     *                           will be called
     * @param {boolean} useCapture indicates that events of this type will be
     *                             dispatched to the registered listener before
     *                             being dispatched to any EventTarget beneath
     *                             it in the DOM tree
     * @return {void}
     */
    F.undelegateEvent = function(element, event, selector, handler, context, useCapture) {

        var listener = function(e) {
            if (typeof selector === "undefined" || selector === null) {
                return handler.call(context || null, e);
            } else if (e.target && e.target.matches(selector)) {
                // console.log('event: ' + eventName + ', selector: ' + selector + ', handler: ' + handler + ', matches: ' + e.target.matches(selector));
                return handler.call(context || null, e);
            }
        };
        useCapture = useCapture || false;

        element.removeEventListener(event, listener, useCapture);
    };

    // Assert
    // ---

    /**
     * Assert that a given condition is satisfied, immediately raising an
     * error when its not.
     * @param {boolean} condition - the condition to be checked for truthness
     * @param {String} message - the message to be contained in the raised error
     * @return {void}
     */
    F.assert = function(condition, message) {
        if (typeof condition !== 'boolean') {
            throw new Error('condition must be boolean');
        }

        if (message && typeof message !== 'string') {
            throw new Error('message must be a string');
        }

        message = message ? ": " + message : "";

        if (!condition) {
            throw new Error("Assertion error" + message);
        }
    };

    /**
     * Do nothing.
     * @return {void}
     */
    F.noop = function(){

    }

    F.isArray = function(variable) {
        if( Object.prototype.toString.call( variable ) === '[object Array]' ) {
           return true;
        }

        return false;
    }
<commit_msg>Polyfill Object.assign since we targe ES5<commit_after>
    // Initial Setup
    // -------------

    /**
     * The one global object for F.
     * @namespace F
     */
    var F = {};

    /**
     * The previous value of the `F` variable, so that it can be
     * restored later on, if `noConflict` is used.
     * @type {F}
     */
    var previousF = F;

    /**
     * Current version of the library.
     * Must be keept in sync with `package.json` and `bower.json`.
     * @type {String}
     */
    F.VERSION = '::VERSION_NUMBER::';

    /**
     * Set framework to debug mode. Disabled by default
     * @type {Boolean}
     */
    F.DEBUG = false;

    /**
     * Runs F.js in *noConflict* mode, returning the `F` variable
     * to its previous owner.
     * @return {F} a reference to this F object
     */
    F.noConflict = function() {
        F = previousF;
        return this;
    };

    // Patch Object
    Object.getOwnPropertyDescriptors = function (obj) {
        var descriptors = {};
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                descriptors[prop] = Object.getOwnPropertyDescriptor(obj, prop);
            }
        }
        return descriptors;
    };

    // Polyfill Object.assign
    // taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
    if (typeof Object.assign != 'function') {
        Object.assign = function(target, varArgs) { // .length of function is 2
            'use strict';
            if (target == null) { // TypeError if undefined or null
                throw new TypeError('Cannot convert undefined or null to object');
            }

            var to = Object(target);

            for (var index = 1; index < arguments.length; index++) {
                var nextSource = arguments[index];

                if (nextSource != null) { // Skip over if undefined or null
                    for (var nextKey in nextSource) {
                        // Avoid bugs when hasOwnProperty is shadowed
                        if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
                            to[nextKey] = nextSource[nextKey];
                        }
                    }
                }
            }
            return to;
        };
    }

    // Util
    // ---

    // Composes objects by combining them into a new one
    F.compose = Object.assign;

    /**
     * Helper function to correctly set up the prototype chain for subclasses.
     * Similar to `goog.inherits`, but uses a hash of prototype properties and
     * class properties to be extended.
     *
     * Taken from Backbone.js of Jeremy Ashkenas
     * @see https://github.com/jashkenas/backbone/blob/master/backbone.js#L1839
     * @see https://gist.github.com/juandopazo/1367191
     *
     * @param  {Object} protoProps - the instance properties for the *Class*
     * @param  {Object} staticProps - the static properties for the *Class*
     * @return {Function} - a new constructor function
     */
    F.extend = function(protoProps, staticProps) {
        var parent = this;
        var child;

        // The constructor function for the new subclass is either defined by you
        // (the "constructor" property in your `extend` definition), or defaulted
        // by us to simply call the parent constructor.
        if (!protoProps.hasOwnProperty('constructor')) {
            Object.defineProperty(protoProps, 'constructor', {
                value: function () {
                    // Default call to superclass as in maxmin classes
                    parent.apply(this, arguments);
                },
                writable: true,
                configurable: true,
                enumerable: false
            });
        }

        child = protoProps.constructor;
        // Add static properties to the constructor function, if supplied.
        Object.assign(child, parent, staticProps);

        // Set the prototype chain to inherit from `parent`, without calling
        // `parent`'s constructor function and add the prototype properties.
        child.prototype = Object.create(parent.prototype, Object.getOwnPropertyDescriptors(protoProps));
        child.prototype.constructor = child;

        // Set a convenience property in case the parent's prototype is needed
        // later.
        child.__super__ = parent.prototype;

        return child;
    };

    /**
     * Performs event delegation setting.
     * @param  {HTMLElement} element the element we want to delegate events for
     * @param  {string} event    the type of event we want to delegate
     * @param  {string} selector a css selector
     * @param  {Function} handler  the handler function
     * @param  {Object} context  the context under which the handler fn
     *                           will be called
     * @param {boolean} useCapture indicates that events of this type will be
     *                           dispatched to the registered listener before
     *                           being dispatched to any EventTarget beneath
     *                           it in the DOM tree
     * @return {void}
     */
    F.delegateEvent = function(element, event, selector, handler, context, useCapture) {

        var listener =  function(e){
            if (typeof selector === "undefined" || selector === null) {
                return handler.call(context || null, e);
            } else if (e.target && e.target.matches(selector)) {
                // console.log('event: ' + eventName + ', selector: ' + selector + ', handler: ' + handler + ', matches: ' + e.target.matches(selector));
                return handler.call(context || null, e);
            }
        };

        useCapture = useCapture || false;
        element.addEventListener(event, listener, useCapture);
    };

    /**
     * Performs event delegation unsetting.
     * @param  {HTMLElement} element the element we want to undelegate events for
     * @param  {string} event    the type of event we want to undelegate
     * @param  {string} selector a css selector
     * @param  {Function} handler  the handler function
     * @param  {Object} context  the context under which the handler fn
     *                           will be called
     * @param {boolean} useCapture indicates that events of this type will be
     *                             dispatched to the registered listener before
     *                             being dispatched to any EventTarget beneath
     *                             it in the DOM tree
     * @return {void}
     */
    F.undelegateEvent = function(element, event, selector, handler, context, useCapture) {

        var listener = function(e) {
            if (typeof selector === "undefined" || selector === null) {
                return handler.call(context || null, e);
            } else if (e.target && e.target.matches(selector)) {
                // console.log('event: ' + eventName + ', selector: ' + selector + ', handler: ' + handler + ', matches: ' + e.target.matches(selector));
                return handler.call(context || null, e);
            }
        };
        useCapture = useCapture || false;

        element.removeEventListener(event, listener, useCapture);
    };

    // Assert
    // ---

    /**
     * Assert that a given condition is satisfied, immediately raising an
     * error when its not.
     * @param {boolean} condition - the condition to be checked for truthness
     * @param {String} message - the message to be contained in the raised error
     * @return {void}
     */
    F.assert = function(condition, message) {
        if (typeof condition !== 'boolean') {
            throw new Error('condition must be boolean');
        }

        if (message && typeof message !== 'string') {
            throw new Error('message must be a string');
        }

        message = message ? ": " + message : "";

        if (!condition) {
            throw new Error("Assertion error" + message);
        }
    };

    /**
     * Do nothing.
     * @return {void}
     */
    F.noop = function(){

    }

    F.isArray = function(variable) {
        if( Object.prototype.toString.call( variable ) === '[object Array]' ) {
           return true;
        }

        return false;
    }
<|endoftext|>


<commit_before>var Monkey = (function (config) {
  'use strict';

  if (!config) console.error('Error: no config');

  config.linesDelimiter = config.linesDelimiter || '\n';

  //TODO (S.Panfilov) return errors for out of range
  // if (config._maxLineKey > linesCount) {
  //   console.error('Error: line number too big');
  //   return;
  // }
  //
  // if (config._minLineKey <= 0) {
  //   console.error('Error: line number too lower than 0');
  //   return;
  // }

  var isBefore = !!config.before;
  var isAfter = !!config.after;

  var _p = {
    override: function (cb) {
      var object = config.obj;
      var method = config.method;
      object[method] = cb(object[method]);
      console.log(1);
    },
    getLineNumber: function (key) {
      key = key.trim();
      var commaIndex = key.indexOf(',');
      if (commaIndex === -1) return key;
      return +key.substr(0, key.indexOf(','));
    },
    getColumnNumber: function (key) {
      key = key.trim();
      var commaIndex = key.indexOf(',');
      if (commaIndex === -1) return 0;
      return +key.substr(key.indexOf(',') + 1);
    },
    sortNumberArr: function (arr) {
      var numberSort = function (a, b) {
        return this.getLineNumber(a) > this.getLineNumber(b)
      };

      return arr.sort(numberSort);
    },
    getStrArr: function (fn, linesDelimiter) {
      var fnArr = fn.toString().split(linesDelimiter);
      //TODO (S.Panfilov) check this for one-liner
      // Remove first line: "function (a) {"
      fnArr.splice(0, 1);
      // Remove last line: "}"
      fnArr.splice(fnArr.length - 1, 1);
      return fnArr;
    },
    makeFn: function (fnArr, originalFn, linesDelimiter) {
      var fnName = this.getFnName(originalFn);
      var fnStr = fnArr.join(linesDelimiter);
      var fnArgs = this.getParamNames(originalFn);

      //this is for named function
      if (fnName) fnStr = 'return function ' + fnName + ' () {' + fnStr + '};';
      //TODO (S.Panfilov) CurWorkPoint fnStr is invalid
      return new Function(fnArgs, fnStr);
    },
    modifyBody: function (fnArr, bodyConfig) {
      if (bodyConfig.positions)  fnArr = this.modifyAtPositions(fnArr, bodyConfig.positions);
      if (bodyConfig.regexps)  fnArr = this.modifyAtRegexp(fnArr, bodyConfig.regexps);
      return fnArr;
    },
    injectLine: function (arr, position, val) {
      var line = this.getLineNumber(position);
      var column = this.getColumnNumber(position);

      if (column > arr[line].length) column = arr.length;

      if (column > 0) {
        arr.splice(line, 0, val);
      } else {
        arr[line] = arr[line].slice(0, column) + val + arr[line].slice(column);
      }

      return arr;
    },
    modifyAtPositions: function (fnArr, positions) {
      var positionsKeys = this.sortNumberArr(Object.keys(positions));

      for (var i = positionsKeys.length - 1; i >= 0; i--) {
        var positionKey = positionsKeys[i];
        var positionVal = positions[positionsKeys];
        //TODO (S.Panfilov) cur work point
        this.injectLine(fnArr, positionKey, positionVal);
      }

      return fnArr;
    },
    wrapRegex: function (str) {

      //TODO (S.Panfilov) this woudn't work cause of '/g', '/i', etc. Should make new RegExp perhaps
      var isWrapped = (str.indexOf('/') === 0 && str.lastIndexOf('/'));

      return (isWrapped) ? str : ('/' + str + '/');
    },
    modifyAtRegexp: function (fnArr, regexpObj, linesDelimiter) {
      var fnStr = fnArr.join(linesDelimiter);

      for (var regex in regexpObj) {
        if (regexpObj.hasOwnProperty(regex)) {
          var fnOrStr = regexpObj[regex];
          if (typeof fnOrStr === 'function') {
            //(asd.toString()).search(/\)\n/g)
            var match;
            var matchesArr = [];
            while ((match = regex.exec(fnStr)) != null) {
              matchesArr.push(match.index);
            }

            for (var i = 0; i < matchesArr.length; i++) {
              var _match = matchesArr[i];
              var positions = [{}];
              positions[0][_match] = fnOrStr;
              fnStr = (this.modifyAtPositions(this.getStrArr(fnStr), positions)).join(linesDelimiter);
            }

          } else { //string
            fnStr.replace(this.wrapRegex(regex), fnOrStr);
          }
        }
      }

      return this.getStrArr(fnArr, config.linesDelimiter);

    },
    getFnName: function (fn) {
      if (fn.name) return fn.name;

      var regexp = /^function\s+([\w\$]+)\s*\(/;
      var nameArr = regexp.exec(fn.toString());
      return (nameArr) ? nameArr[1] : null;
    },
    getParamNames: function (fn) {
      var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
      var ARGUMENT_NAMES = /([^\s,]+)/g;

      var fnStr = fn.toString().replace(STRIP_COMMENTS, '');
      var result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);

      return result || [];
    }
  };

  var exports = {
    config: config,
    originalFn: null,
    modifiedFn: null,
    linesDelimiter: config.linesDelimiter,
    before: config.before,
    after: config.after,
    isLazy: false,
    punch: function () {
      //TODO (S.Panfilov) refactor work with override

      this.originalFn = this.config.obj[this.config.method];

      if (this.config.body) {
        this.modifiedFn = this.config.obj[this.config.method];
        var fnArr = _p.getStrArr(this.modifiedFn, this.linesDelimiter);
        _p.modifyBody(fnArr, config.body);
        this.modifiedFn = _p.makeFn(fnArr, this.originalFn, this.linesDelimiter);
      }

      var fn = (this.modifiedFn) ? this.modifiedFn : this.originalFn;

      //TODO (S.Panfilov) cur work point

      if (!this.before && !this.after) {
        this.config.obj[this.config.method] = this.fn;
      } else {
        var self = this;
        this.config.obj[this.config.method] = function () {

          if (isBefore) self.before(arguments);

          var returnValue = self.fn(arguments);

          if (isAfter) self.after(arguments);

          return returnValue;
        }
      }

      // _p.override(function (original) {
      //   exports.original = original;
      //   return function () {
      //     if (isBefore) this.before.apply(this, arguments);
      //     if (config.body) {
      //       var fnArr = _p.modifyBody(config.body);
      //       this.modifiedFnBody = fnArr.join(this.linesDelimiter);
      //       original = _p.makeFn(fnArr, this.linesDelimiter)
      //     }
      //     var returnValue = original.apply(this, arguments);
      //     if (isAfter) this.after.apply(this, arguments);
      //
      //     return returnValue;
      //   }
      // });

      return this;
    },
    restore: function () {
      config.obj[config.method] = this.original;
      this.isModified = false;
      return this;
    },
    clear: function (isClearOrigin) {
      //TODO (S.Panfilov) clear monkey object, but stay patched
      //Perhaps should save optional possibility to restore after clear
      return this;
    }
  };

  if (!exports.isLazy) return exports.punch();

  return exports;
});

//Support of node.js
if (typeof module === 'object' && module.exports) module.exports = Monkey;

//Roadmap:
//TODO (S.Panfilov) Add support for one-liners
//TODO (S.Panfilov) Add support for functions as well as strings in body params
//TODO (S.Panfilov) add "punch": ability to patch func agaig after restore was called
//TODO (S.Panfilov) Add "Lazy" option (do not patch immediately)
//TODO (S.Panfilov) Add ability to patch several methods at once

// var myMonkey = new Monkey({
//   obj: patchTarget,
//   method: ['sum', 'min'], //patch one (string) or several methods (array of str)
//   linesDelimiter: '\n',
//   before: doItBefore,
//   after: doItAfter,
//   body: {
//     regexps: {
//       '/\)\n/g': addSemiQuoteFn, // add ';' after each ')'
//       '/\{/g': ' ' // add space before each'{'
//     },
//     positions: {
//       1: '// injection to line one',
//       5: '// injection to line five',
//       2: lineTwoInjectionFunc,
//       '6,10': '// Injection to line 6 column 10',
//       '2,3': lineTwoColumnThreeInjectionFunc
//     }
//   }
// });

// ...
// myMonkey.restore();
// ...<commit_msg>Fixes<commit_after>var Monkey = (function (config) {
  'use strict';

  if (!config) console.error('Error: no config');

  config.linesDelimiter = config.linesDelimiter || '\n';

  //TODO (S.Panfilov) return errors for out of range
  // if (config._maxLineKey > linesCount) {
  //   console.error('Error: line number too big');
  //   return;
  // }
  //
  // if (config._minLineKey <= 0) {
  //   console.error('Error: line number too lower than 0');
  //   return;
  // }

  var isBefore = !!config.before;
  var isAfter = !!config.after;

  var _p = {
    override: function (cb) {
      var object = config.obj;
      var method = config.method;
      object[method] = cb(object[method]);
      console.log(1);
    },
    getLineNumber: function (key) {
      key = key.trim();
      var commaIndex = key.indexOf(',');
      if (commaIndex === -1) return key;
      return +key.substr(0, key.indexOf(','));
    },
    getColumnNumber: function (key) {
      key = key.trim();
      var commaIndex = key.indexOf(',');
      if (commaIndex === -1) return 0;
      return +key.substr(key.indexOf(',') + 1);
    },
    sortNumberArr: function (arr) {
      var numberSort = function (a, b) {
        return this.getLineNumber(a) > this.getLineNumber(b)
      };

      return arr.sort(numberSort);
    },
    getStrArr: function (fn, linesDelimiter) {
      var fnArr = fn.toString().split(linesDelimiter);
      //TODO (S.Panfilov) check this for one-liner
      // Remove first line: "function (a) {"
      fnArr.splice(0, 1);
      // Remove last line: "}"
      fnArr.splice(fnArr.length - 1, 1);
      return fnArr;
    },
    makeFn: function (fnArr, originalFn, linesDelimiter, isEval) {
      var fnName = this.getFnName(originalFn);
      var fnStr = fnArr.join(linesDelimiter);
      var fnArgs = this.getParamNames(originalFn);
      var result;

      if (!isEval) {
        //this is for named function
        if (fnName) fnStr = 'return function ' + fnName + ' () {' + fnStr + '};';

        result = new Function(fnArgs, fnStr);
      } else {
        //TODO (S.Panfilov) debug this branch
        //TODO (S.Panfilov) what about comma at the end?
        result = eval('function ' + fnName + '(' + fnArgs.toString + ') {' + fnStr + '}');
      }
      return result;
    },
    modifyBody: function (fnArr, bodyConfig) {
      if (bodyConfig.positions)  fnArr = this.modifyAtPositions(fnArr, bodyConfig.positions);
      if (bodyConfig.regexps)  fnArr = this.modifyAtRegexp(fnArr, bodyConfig.regexps);
      return fnArr;
    },
    injectLine: function (arr, position, val) {
      var line = this.getLineNumber(position);
      var column = this.getColumnNumber(position);

      if (column > arr[line].length) column = arr.length;

      if (column > 0) {
        arr.splice(line, 0, val);
      } else {
        arr[line] = arr[line].slice(0, column) + val + arr[line].slice(column);
      }

      return arr;
    },
    modifyAtPositions: function (fnArr, positions) {
      var positionsKeys = this.sortNumberArr(Object.keys(positions));

      for (var i = positionsKeys.length - 1; i >= 0; i--) {
        var positionKey = positionsKeys[i];
        var positionVal = positions[positionsKeys];
        //TODO (S.Panfilov) cur work point
        this.injectLine(fnArr, positionKey, positionVal);
      }

      return fnArr;
    },
    wrapRegex: function (str) {

      //TODO (S.Panfilov) this woudn't work cause of '/g', '/i', etc. Should make new RegExp perhaps
      var isWrapped = (str.indexOf('/') === 0 && str.lastIndexOf('/'));

      return (isWrapped) ? str : ('/' + str + '/');
    },
    modifyAtRegexp: function (fnArr, regexpObj, linesDelimiter) {
      var fnStr = fnArr.join(linesDelimiter);

      for (var regex in regexpObj) {
        if (regexpObj.hasOwnProperty(regex)) {
          var fnOrStr = regexpObj[regex];
          if (typeof fnOrStr === 'function') {
            //(asd.toString()).search(/\)\n/g)
            var match;
            var matchesArr = [];
            while ((match = regex.exec(fnStr)) != null) {
              matchesArr.push(match.index);
            }

            for (var i = 0; i < matchesArr.length; i++) {
              var _match = matchesArr[i];
              var positions = [{}];
              positions[0][_match] = fnOrStr;
              fnStr = (this.modifyAtPositions(this.getStrArr(fnStr), positions)).join(linesDelimiter);
            }

          } else { //string
            fnStr.replace(this.wrapRegex(regex), fnOrStr);
          }
        }
      }

      return this.getStrArr(fnArr, config.linesDelimiter);

    },
    getFnName: function (fn) {
      if (fn.name) return fn.name;

      var regexp = /^function\s+([\w\$]+)\s*\(/;
      var nameArr = regexp.exec(fn.toString());
      return (nameArr) ? nameArr[1] : null;
    },
    getParamNames: function (fn) {
      var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
      var ARGUMENT_NAMES = /([^\s,]+)/g;

      var fnStr = fn.toString().replace(STRIP_COMMENTS, '');
      var result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);

      return result || [];
    }
  };

  var exports = {
    config: config,
    originalFn: null,
    modifiedFn: null,
    linesDelimiter: config.linesDelimiter,
    before: config.before,
    after: config.after,
    isLazy: false,
    punch: function () {
      //TODO (S.Panfilov) refactor work with override

      this.originalFn = this.config.obj[this.config.method];

      if (this.config.body) {
        this.modifiedFn = this.config.obj[this.config.method];
        var fnArr = _p.getStrArr(this.modifiedFn, this.linesDelimiter);
        _p.modifyBody(fnArr, config.body);
        this.modifiedFn = _p.makeFn(fnArr, this.originalFn, this.linesDelimiter);
      }

      if (!this.before && !this.after) {
        this.config.obj[this.config.method] = this.modifiedFn || this.originalFn;
      } else {
        var self = this;
        this.config.obj[this.config.method] = function () {

          if (isBefore) self.before(arguments);

          var returnValue = (self.modifiedFn) ? self.modifiedFn(arguments) : self.originalFn(arguments);

          if (isAfter) self.after(arguments);

          return returnValue;
        }
      }

      // _p.override(function (original) {
      //   exports.original = original;
      //   return function () {
      //     if (isBefore) this.before.apply(this, arguments);
      //     if (config.body) {
      //       var fnArr = _p.modifyBody(config.body);
      //       this.modifiedFnBody = fnArr.join(this.linesDelimiter);
      //       original = _p.makeFn(fnArr, this.linesDelimiter)
      //     }
      //     var returnValue = original.apply(this, arguments);
      //     if (isAfter) this.after.apply(this, arguments);
      //
      //     return returnValue;
      //   }
      // });

      return this;
    },
    restore: function () {
      config.obj[config.method] = this.original;
      this.isModified = false;
      return this;
    },
    clear: function (isClearOrigin) {
      //TODO (S.Panfilov) clear monkey object, but stay patched
      //Perhaps should save optional possibility to restore after clear
      return this;
    }
  };

  if (!exports.isLazy) return exports.punch();

  return exports;
});

//Support of node.js
if (typeof module === 'object' && module.exports) module.exports = Monkey;

//Roadmap:
//TODO (S.Panfilov) Add support for one-liners
//TODO (S.Panfilov) Add support for functions as well as strings in body params
//TODO (S.Panfilov) add "punch": ability to patch func agaig after restore was called
//TODO (S.Panfilov) Add "Lazy" option (do not patch immediately)
//TODO (S.Panfilov) Add ability to patch several methods at once/
//TODO (S.Panfilov) Add ability to use eval instead of new Func

// var myMonkey = new Monkey({
//   obj: patchTarget,
//   method: ['sum', 'min'], //patch one (string) or several methods (array of str)
//   linesDelimiter: '\n',
//   before: doItBefore,
//   after: doItAfter,
//   body: {
//     isEval: false, //option to ue eval instead of new Function
//     regexps: {
//       '/\)\n/g': addSemiQuoteFn, // add ';' after each ')'
//       '/\{/g': ' ' // add space before each'{'
//     },
//     positions: {
//       1: '// injection to line one',
//       5: '// injection to line five',
//       2: lineTwoInjectionFunc,
//       '6,10': '// Injection to line 6 column 10',
//       '2,3': lineTwoColumnThreeInjectionFunc
//     }
//   }
// });

// ...
// myMonkey.restore();
// ...<|endoftext|>


<commit_before>'use strict';

module.exports = function (grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        concat: {
            options: {
                separator: "\n\n"
            },
            dist: {
                src: ['js/bootstrap.js', 'js/owl.carousel.js', 'js/jquery.magnific-popup.js', 'js/gmap3.js', 'js/custom.js'],
                dest: 'js/all.js'
            }
        },

        uglify: {
            main: {
                files: {
                    'js/all.min.js' : ['js/all.js'],
                }
            }
        },

/*
        sass: {
            dist: {
                options: {
                    outputStyle: 'compressed'
                },
                files: {
                    'css/main-unprefixed.css' : '_scss/main.scss'
                }
            }
        },
*/

        sass: {
            options: {
                sourceMap: true,
                relativeAssets: false,
                outputStyle: 'expanded',
                sassDir: '_scss',
                cssDir: '_site/css'
            },
            build: {
                files: [{
                    expand: false,
                    cwd: '_scss/',
                    src: ['**/*.{scss,sass}'],
                    dest: '_site/css',
                    ext: '.css'
                },
                {
                    expand: true,
                    cwd: '_scss/',
                    src: ['**/*.{scss,sass}'],
                    dest: 'css',
                    ext: '.css'
                }]
            }
        },

        autoprefixer: {
            main: {
                src: "css/main-unprefixed.css",
                dest: "css/main.css"
            }
        },

        shell : {
            jekyllServe : {
                command : 'jekyll serve'
            },

            jekyllBuild : {
                command : 'jekyll build'
            }
        },

        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'svg',
                    src: ['*.svg'],
                    dest: 'svg/min'
                }]
            }
        },

        svgstore: {
            options: {
                prefix : 'icon-',
                svg: {
                    style: 'display: none;'
                },
                cleanup: ['fill', 'style']
            },
            default: {
                files: {
                    '_includes/svg-defs.svg': ['svg/*.svg']
                }
            }
        },

        watch: {
            stylesheets: {
                files: ['_scss/**/*.scss'],
                tasks: ['sass', 'autoprefixer', 'shell:jekyllBuild']
            },
            scripts: {
                files: ['js/**/*.js'],
                tasks: ['concat', 'uglify', 'shell:jekyllBuild']
            },
            site: {
                files: ['**/*.html', '_layouts/*.html', '_posts/**/*.markdown', '_includes/*.html', '_config.yml', 'js/**/*.js', '_data/*.yml'],
                tasks: ['shell:jekyllBuild']
            },
            svgIcons: {
                files: ['svg/*.svg'],
                tasks: ['svgmin', 'svgstore', 'shell:jekyllBuild']
            },
            options: {
                spawn : false,
                livereload: true
            }
        }
    });

    require("load-grunt-tasks")(grunt);

    // Define the tasks
    grunt.registerTask('serve', ['sass','shell:jekyllServe']);
    grunt.registerTask('default', ['watch']);
}<commit_msg>expand false<commit_after>'use strict';

module.exports = function (grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        concat: {
            options: {
                separator: "\n\n"
            },
            dist: {
                src: ['js/bootstrap.js', 'js/owl.carousel.js', 'js/jquery.magnific-popup.js', 'js/gmap3.js', 'js/custom.js'],
                dest: 'js/all.js'
            }
        },

        uglify: {
            main: {
                files: {
                    'js/all.min.js' : ['js/all.js'],
                }
            }
        },

/*
        sass: {
            dist: {
                options: {
                    outputStyle: 'compressed'
                },
                files: {
                    'css/main-unprefixed.css' : '_scss/main.scss'
                }
            }
        },
*/

        sass: {
            options: {
                sourceMap: true,
                relativeAssets: false,
                outputStyle: 'expanded',
                sassDir: '_scss',
                cssDir: '_site/css'
            },
            build: {
                files: [{
                    expand: false,
                    cwd: '_scss/',
                    src: ['**/*.{scss,sass}'],
                    dest: '_site/css',
                    ext: '.css'
                },
                {
                    expand: false,
                    cwd: '_scss/',
                    src: ['**/*.{scss,sass}'],
                    dest: 'css',
                    ext: '.css'
                }]
            }
        },

        autoprefixer: {
            main: {
                src: "css/main-unprefixed.css",
                dest: "css/main.css"
            }
        },

        shell : {
            jekyllServe : {
                command : 'jekyll serve'
            },

            jekyllBuild : {
                command : 'jekyll build'
            }
        },

        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'svg',
                    src: ['*.svg'],
                    dest: 'svg/min'
                }]
            }
        },

        svgstore: {
            options: {
                prefix : 'icon-',
                svg: {
                    style: 'display: none;'
                },
                cleanup: ['fill', 'style']
            },
            default: {
                files: {
                    '_includes/svg-defs.svg': ['svg/*.svg']
                }
            }
        },

        watch: {
            stylesheets: {
                files: ['_scss/**/*.scss'],
                tasks: ['sass', 'autoprefixer', 'shell:jekyllBuild']
            },
            scripts: {
                files: ['js/**/*.js'],
                tasks: ['concat', 'uglify', 'shell:jekyllBuild']
            },
            site: {
                files: ['**/*.html', '_layouts/*.html', '_posts/**/*.markdown', '_includes/*.html', '_config.yml', 'js/**/*.js', '_data/*.yml'],
                tasks: ['shell:jekyllBuild']
            },
            svgIcons: {
                files: ['svg/*.svg'],
                tasks: ['svgmin', 'svgstore', 'shell:jekyllBuild']
            },
            options: {
                spawn : false,
                livereload: true
            }
        }
    });

    require("load-grunt-tasks")(grunt);

    // Define the tasks
    grunt.registerTask('serve', ['sass','shell:jekyllServe']);
    grunt.registerTask('default', ['watch']);
}<|endoftext|>


<commit_before>(function (root, factory) {
    if (typeof exports === 'object') {
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        root.f = factory();
    }
})(this, function () {
	var lambdaRegex = /^(\((.*)\)|([^\(\),.]*))?[\s]*=>[\s]*(.+)/;
	var expanderRegex = /^(\!?)([^\(\).]+)(\(\))?$/;
	function f(x) { return function() { return x; } };
	f.x = function(expression) {
		var match = expanderRegex.exec(expression);
		var isNegated = match[1];
		var propertyName = match[2];
		var isMethod = match[3];
		if(isNegated)
			return isMethod ? function(obj) { return !obj[propertyName](); } : function(obj) { return !obj[propertyName]; };
		else
			return isMethod ? function(obj) { return obj[propertyName](); } : function(obj) { return obj[propertyName]; };
	}
	f.n = function() {
		var args = arguments;
		if(args.length) args[args.length - 1] = "return " + args[args.length - 1];
		return Function.apply({}, args);
	}
	f.y = function(expression){
		var match = lambdaRegex.exec(expression);
		if (!match) throw new Error('Error in lambda syntax : ' + expression);
		var argsString = match[2] || match[3];
		var body = match[4];
		var args = argsString.split(',').map(f.x('trim()'));
		return f.n.apply(f, args.concat(body));
	}
	return f;
});<commit_msg>Better implementation of f.x<commit_after>(function (root, factory) {
    if (typeof exports === 'object') {
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        root.f = factory();
    }
})(this, function () {
	function f(x) { return function() { return x; } };
	f.x = function(expression) {
		var fnExpr = expression[0] === '!' ? expression.replace('!', '!o.') : 'o.' + expression;
		return f.n('o', fnExpr);
	}
	f.n = function() {
		var args = arguments;
		if(args.length) args[args.length - 1] = "return " + args[args.length - 1];
		return Function.apply({}, args);
	}
	var lambdaRegex = /^(\((.*)\)|([^\(\),.]*))?[\s]*=>[\s]*(.+)/;
	f.y = function(expression){
		var match = lambdaRegex.exec(expression);
		if (!match) throw new Error('Error in lambda syntax : ' + expression);
		var argsString = match[2] || match[3];
		var body = match[4];
		var args = argsString.split(',').map(f.x('trim()'));
		return f.n.apply(f, args.concat(body));
	}
	return f;
});<|endoftext|>


<commit_before>/**
 *  Copyright 2016 ReSys OÜ
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'core-js/fn/object/assign';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import Item from './components/Item';
import FlexiForm from './containers/FlexiForm';
import {createStore} from 'stores';
import {componentCreator} from './utils/componentCreator';
import {connectToAnswer} from './utils/formUtils';

require('styles/app.scss');

// TODO add support for callbacks
// TODO custom componentCreator
function renderFlexiForm(element,config) {
  if (typeof config === 'string') {
    config = {
      url: config
    };
  }

  var delegateComponentCreator = componentCreator;
  if (config.componentCreator) {
    delegateComponentCreator = item => config.componentCreator(item,componentCreator);
    delete config.componentCreator;
  }

  var store = createStore({config});

  ReactDOM.render(<Provider store={store}><FlexiForm componentCreator={delegateComponentCreator}/></Provider>, element);
}

export {
  renderFlexiForm,
  Item,
  connectToAnswer,
  React
};
<commit_msg>Fix custom component creator function reference<commit_after>/**
 *  Copyright 2016 ReSys OÜ
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'core-js/fn/object/assign';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import Item from './components/Item';
import FlexiForm from './containers/FlexiForm';
import {createStore} from 'stores';
import {componentCreator} from './utils/componentCreator';
import {connectToAnswer} from './utils/formUtils';

require('styles/app.scss');

// TODO add support for callbacks
// TODO custom componentCreator
function renderFlexiForm(element,config) {
  if (typeof config === 'string') {
    config = {
      url: config
    };
  }

  var delegateComponentCreator = componentCreator;
  if (config.componentCreator) {
    const customComponentCreator = config.componentCreator;
    delegateComponentCreator = item => customComponentCreator(item,componentCreator);
    delete config.componentCreator;
  }

  var store = createStore({config});

  ReactDOM.render(<Provider store={store}><FlexiForm componentCreator={delegateComponentCreator}/></Provider>, element);
}

export {
  renderFlexiForm,
  Item,
  connectToAnswer,
  React
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.export',
  name: 'GoogleApiCredentials',
  properties: [
    {
      class: 'String',
      name: 'clientId',
    },
    {
      class: 'String',
      name: 'projectId',
    },
    {
      class: 'String',
      name: 'authUri',
    },
    {
      class: 'String',
      name: 'tokenUri',
    },
    {
      class: 'String',
      name: 'authProviderCertUrl',
    },
    {
      class: 'String',
      name: 'clientSecret',
    },
    {
      class: 'StringArray',
      name: 'redirectUris',
    },
    {
      class: 'StringArray',
      name: 'javascriptOrigins',
    },
    {
      class: 'Int',
      name: 'port',
      visibility: 'RO'
    },
    {
      class: 'String',
      name: 'tokensFolderPath'
    }
  ]
});<commit_msg>Adding documentation<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.export',
  name: 'GoogleApiCredentials',
  properties: [
    {
      class: 'String',
      name: 'clientId',
    },
    {
      class: 'String',
      name: 'projectId',
    },
    {
      class: 'String',
      name: 'authUri',
    },
    {
      class: 'String',
      name: 'tokenUri',
    },
    {
      class: 'String',
      name: 'authProviderCertUrl',
    },
    {
      class: 'String',
      name: 'clientSecret',
    },
    {
      class: 'StringArray',
      name: 'redirectUris',
    },
    {
      class: 'StringArray',
      name: 'javascriptOrigins',
    },
    {
      class: 'Int',
      name: 'port',
      hidden: true,
      documentation: 'Port server uses for communication with authorization service'
    },
    {
      class: 'String',
      name: 'tokensFolderPath'
    }
  ]
});<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {
  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    mochaTest: {
      src: [
        'test/**/*.js',
        '!test/browser/*.js'
      ],
      options: {
        reporter: 'spec'
      }
    },

    column_lint: {
      files: {
        src: ['./lib/**/*.js']
      }
    },

    jshint: {
      src: ['Gruntfile.js', './lib/**/*.js'],
      options: {
        jshintrc: './jshintrc.js'
      }
    },

    shell: {
      build: {
        command: './node_modules/.bin/browserify -s Logger ' +
          '-e ./lib/LoggerFactory.js -o ./dist/logger.js'
      }
    },

    lintspaces: {
      javascript: {
        src: ['./lib/**/*.js'],
        options: {
          // TODO: Reference editorconfig
          indentation: 'spaces',
          spaces: 2,
          newline: true,
          trailingspaces: true,
          ignores: ['js-comments']
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-mocha-test');
  grunt.loadNpmTasks('grunt-lintspaces');
  grunt.loadNpmTasks('grunt-column-lint');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('format', ['lintspaces', 'jshint', 'column_lint']);
  grunt.registerTask('test', ['format', 'mochaTest']);
  grunt.registerTask('build', ['test', 'shell:build']);
  grunt.registerTask('default', ['format']);
};
<commit_msg>Change bundle name<commit_after>'use strict';

module.exports = function(grunt) {
  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    mochaTest: {
      src: [
        'test/**/*.js',
        '!test/browser/*.js'
      ],
      options: {
        reporter: 'spec'
      }
    },

    column_lint: {
      files: {
        src: ['./lib/**/*.js']
      }
    },

    jshint: {
      src: ['Gruntfile.js', './lib/**/*.js'],
      options: {
        jshintrc: './jshintrc.js'
      }
    },

    shell: {
      build: {
        command: './node_modules/.bin/browserify -s jslog ' +
          '-e ./lib/LoggerFactory.js -o ./dist/jslog.js'
      }
    },

    lintspaces: {
      javascript: {
        src: ['./lib/**/*.js'],
        options: {
          // TODO: Reference editorconfig
          indentation: 'spaces',
          spaces: 2,
          newline: true,
          trailingspaces: true,
          ignores: ['js-comments']
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-mocha-test');
  grunt.loadNpmTasks('grunt-lintspaces');
  grunt.loadNpmTasks('grunt-column-lint');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('format', ['lintspaces', 'jshint', 'column_lint']);
  grunt.registerTask('test', ['format', 'mochaTest']);
  grunt.registerTask('build', ['test', 'shell:build']);
  grunt.registerTask('default', ['format']);
};
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

// This is the main application configuration file.  It is a Grunt
// configuration file, which you can learn more about here:
// https://github.com/cowboy/grunt/blob/master/docs/configuring.md

module.exports = function(grunt) {
  var helper = require('./tasks/helper').init(grunt),
  _ = grunt.util._,
  path = require('path');

  var couch_config = function () {

    var default_couch_config = {
      fauxton: {
        db: 'http://localhost:5984/fauxton',
        app: './couchapp.js',
        options: {
          okay_if_missing: true
        }
      }
    };

    var settings_couch_config = helper.readSettingsFile().couch_config;
    return settings_couch_config || default_couch_config;
  }();

  var cleanableAddons =  function () {
    var theListToClean = [];
    helper.processAddons(function(addon){
      // Only clean addons that are included from a local dir
      if (addon.path){
        theListToClean.push("app/addons/" + addon.name);
      }
    });

    return theListToClean;
  }();

  var cleanable = function(){
    // Whitelist files and directories to be cleaned
    // You'll always want to clean these two directories
    // Now find the external addons you have and add them for cleaning up
    return _.union(["dist/", "app/load_addons.js"], cleanableAddons);
  }();

  var assets = function(){
    // Base assets
    var theAssets = {
      less:{
        paths: ["assets/less"],
        files: {
          "dist/debug/css/fauxton.css": "assets/less/fauxton.less"
        }
      },
      img: ["assets/img/**"]
    };
    helper.processAddons(function(addon){
      // Less files from addons
      var root = addon.path || "app/addons/" + addon.name;
      var lessPath = root + "/assets/less";
      if(path.existsSync(lessPath)){
        // .less files exist for this addon
        theAssets.less.paths.push(lessPath);
        theAssets.less.files["dist/debug/css/" + addon.name + ".css"] =
          lessPath + "/" + addon.name + ".less";
      }
      // Images
      root = addon.path || "app/addons/" + addon.name;
      var imgPath = root + "/assets/img";
      if(path.existsSync(imgPath)){
        theAssets.img.push(imgPath + "/**");
      }
    });
    return theAssets;
  }();

  var templateSettings = function(){
    var defaultSettings = {
     "development": {
        "src": "assets/index.underscore",
        "dest": "dist/debug/index.html",
        "variables": {
          "requirejs": "/assets/js/libs/require.js",
          "css": "./css/index.css",
          "base": null
        }
      },
      "release": {
        "src": "assets/index.underscore",
        "dest": "dist/debug/index.html",
        "variables": {
          "requirejs": "./js/require.js",
          "css": "./css/index.css",
          "base": null
        }
      }
    };

    var settings = helper.readSettingsFile();
    return settings.template || defaultSettings;
  }();

  grunt.initConfig({

    // The clean task ensures all files are removed from the dist/ directory so
    // that no files linger from previous builds.
    clean: {
      release:  cleanable,
      watch: cleanableAddons
    },

    // The lint task will run the build configuration and the application
    // JavaScript through JSHint and report any errors.  You can change the
    // options for this task, by reading this:
    // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md
    lint: {
      files: [
        "build/config.js", "app/**/*.js"
      ]
    },

    less: {
      compile: {
        options: {
          paths: assets.less.paths
        },
        files: assets.less.files
      }
    },

    // The jshint option for scripturl is set to lax, because the anchor
    // override inside main.js needs to test for them so as to not accidentally
    // route. Settings expr true so we can do `migtBeNullObject && mightBeNullObject.coolFunction()`
    jshint: {
      all: ['app/**/*.js', 'Gruntfile.js', "test/core/*.js"],
      options: {
        scripturl: true,
        evil: true,
        expr: true
      }
    },

    // The jst task compiles all application templates into JavaScript
    // functions with the underscore.js template function from 1.2.4.  You can
    // change the namespace and the template options, by reading this:
    // https://github.com/gruntjs/grunt-contrib/blob/master/docs/jst.md
    //
    // The concat task depends on this file to exist, so if you decide to
    // remove this, ensure concat is updated accordingly.
    jst: {
      compile: {
        options: {
          processContent: function(src) {
            return src.replace(/<!--[\s\S]*?-->/gm, '');
          }
        },
        files: {
          "dist/debug/templates.js": [
            "app/templates/**/*.html",
            "app/addons/**/templates/**/*.html"
          ]
        }
      }
    },

    template: templateSettings,

    // The concatenate task is used here to merge the almond require/define
    // shim and the templates into the application code.  It's named
    // dist/debug/require.js, because we want to only load one script file in
    // index.html.
    concat: {
      requirejs: {
        src: [ "assets/js/libs/require.js", "dist/debug/templates.js", "dist/debug/require.js"],
        dest: "dist/debug/js/require.js"
      },

      index_css: {
        src: ["dist/debug/css/*.css", 'assets/css/*.css'],
        dest: 'dist/debug/css/index.css'
      },

      test_config_js: {
        src: ["dist/debug/templates.js", "test/test.config.js"],
        dest: 'test/test.config.js'
      },
    },

    cssmin: {
      compress: {
        files: {
          "dist/release/css/index.css": [
            "dist/debug/css/index.css", 'assets/css/*.css',
            "app/addons/**/assets/css/*.css"
          ]
        },
        options: {
          report: 'min'
        }
      }
    },

    uglify: {
      release: {
        files: {
          "dist/release/js/require.js": [
            "dist/debug/js/require.js"
          ]
        }
      }
    },

    // Runs a proxy server for easier development, no need to keep deploying to couchdb
    couchserver: {
      dist: './dist/debug/',
      port: 8000,
      proxy: {
        target: {
          host: 'localhost',
          port: 5984,
          https: false
        },
        // This sets the Host header in the proxy so that you can use external
        // CouchDB instances and not have the Host set to 'localhost'
        changeOrigin: true
      }
    },

    watch: {
      js: {
        files: helper.watchFiles(['.js'], ["./app/**/*.js", '!./app/load_addons.js',"./assets/**/*.js", "./test/**/*.js"]),
        tasks: ['watchRun'],
      },
      style: {
        files: helper.watchFiles(['.less','.css'],["./app/**/*.css","./app/**/*.less","./assets/**/*.css", "./assets/**/*.less"]),
        tasks: ['clean:watch', 'dependencies','less', 'concat:index_css'],
      },
      html: {
        // the index.html is added in as a dummy file incase there is no
        // html dependancies this will break. So we need one include pattern
        files: helper.watchFiles(['.html'], ['./index.html']),
        tasks: ['clean:watch', 'dependencies']
      },
      options: {
        nospawn: true,
        debounceDelay: 500
      }
    },

    requirejs: {
      compile: {
        options: {
          baseUrl: 'app',
          // Include the main configuration file.
          mainConfigFile: "app/config.js",

          // Output file.
          out: "dist/debug/require.js",

          // Root application module.
          name: "config",

          // Do not wrap everything in an IIFE.
          wrap: false,
          optimize: "none",
          findNestedDependencies: true
        }
      }
    },

    // Copy build artifacts and library code into the distribution
    // see - http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
    copy: {
      couchdb: {
        files: [
          // this gets built in the template task
          {src: "dist/release/index.html", dest: "../../share/www/fauxton/index.html"},
          {src: ["**"], dest: "../../share/www/fauxton/js/", cwd:'dist/release/js/',  expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/img/", cwd:'dist/release/img/', expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/css/", cwd:"dist/release/css/", expand: true}
        ]
      },
      couchdebug: {
        files: [
          // this gets built in the template task
          {src: "dist/debug/index.html", dest: "../../share/www/fauxton/index.html"},
          {src: ["**"], dest: "../../share/www/fauxton/js/", cwd:'dist/debug/js/',  expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/img/", cwd:'dist/debug/img/', expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/css/", cwd:"dist/debug/css/", expand: true}
        ]
      },
      ace: {
        files: [
          {src: "assets/js/libs/ace/worker-json.js", dest: "dist/release/js/ace/worker-json.js"},
          {src: "assets/js/libs/ace/mode-json.js", dest: "dist/release/js/ace/mode-json.js"},
          {src: "assets/js/libs/ace/theme-crimson_editor.js", dest: "dist/release/js/ace/theme-crimson_editor.js"},
          {src: "assets/js/libs/ace/mode-javascript.js", dest: "dist/release/js/ace/mode-javascript.js"},
          {src: "assets/js/libs/ace/worker-javascript.js", dest: "dist/release/js/ace/worker-javascript.js"},
        ]
      },

      dist:{
        files:[
          {src: "dist/debug/index.html", dest: "dist/release/index.html"},
          {src: assets.img, dest: "dist/release/img/", flatten: true, expand: true}
        ]
      },
      debug:{
        files:[
          {src: assets.img, dest: "dist/debug/img/", flatten: true, expand: true}
        ]
      }
    },

    get_deps: {
      "default": {
        src: "settings.json"
      }
    },

    gen_load_addons: {
      "default": {
        src: "settings.json"
      }
    },
    gen_initialize: templateSettings,
    /*gen_initialize: {
      "default": {
        src: "settings.json"
      }
    },*/

    mkcouchdb: couch_config,
    rmcouchdb: couch_config,
    couchapp: couch_config,

    mochaSetup: {
      default: {
        files: { src: helper.watchFiles(['[Ss]pec.js'], ['./test/core/**/*[Ss]pec.js', './app/**/*[Ss]pec.js'])},
        template: 'test/test.config.underscore',
        config: './app/config.js'
      }
    },

    mocha_phantomjs: {
      all: ['test/runner.html']
    }

  });

  // on watch events configure jshint:all to only run on changed file
  grunt.event.on('watch', function(action, filepath) {
    if (!!filepath.match(/.js$/) && filepath.indexOf('test.config.js') === -1) {
      grunt.config(['jshint', 'all'], filepath);
    }

    if (!!filepath.match(/[Ss]pec.js$/)) {
      //grunt.task.run(['mochaSetup','jst', 'concat:test_config_js', 'mocha_phantomjs']);
    }
  });

  /*
   * Load Grunt plugins
   */
  // Load fauxton specific tasks
  grunt.loadTasks('tasks');
  // Load the couchapp task
  grunt.loadNpmTasks('grunt-couchapp');
  // Load the copy task
  grunt.loadNpmTasks('grunt-contrib-watch');
  // Load the exec task
  grunt.loadNpmTasks('grunt-exec');
  // Load Require.js task
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  // Load Copy task
  grunt.loadNpmTasks('grunt-contrib-copy');
  // Load Clean task
  grunt.loadNpmTasks('grunt-contrib-clean');
  // Load jshint task
  grunt.loadNpmTasks('grunt-contrib-jshint');
  // Load jst task
  grunt.loadNpmTasks('grunt-contrib-jst');
  // Load less task
  grunt.loadNpmTasks('grunt-contrib-less');
  // Load concat task
  grunt.loadNpmTasks('grunt-contrib-concat');
  // Load UglifyJS task
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // Load CSSMin task
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-mocha-phantomjs');

  /*
   * Default task
   */
  // defult task - install minified app to local CouchDB
  grunt.registerTask('default', 'couchdb');

  /*
   * Transformation tasks
   */
  // clean out previous build artefactsa and lint
  grunt.registerTask('lint', ['clean', 'jshint']);
  grunt.registerTask('test', ['lint', 'mochaSetup','jst', 'concat:test_config_js', 'mocha_phantomjs']);
  // Fetch dependencies (from git or local dir), lint them and make load_addons
  grunt.registerTask('dependencies', ['get_deps', 'gen_load_addons:default']);
  // build templates, js and css
  grunt.registerTask('build', ['less', 'concat:index_css', 'jst', 'requirejs', 'concat:requirejs', 'template:release']);
  // minify code and css, ready for release.
  grunt.registerTask('minify', ['uglify', 'cssmin:compress']);

  /*
   * Build the app in either dev, debug, or release mode
   */
  // dev server
  grunt.registerTask('dev', ['debugDev', 'couchserver']);
  // build a debug release
  grunt.registerTask('debug', ['lint', 'dependencies', "gen_initialize:development", 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
  grunt.registerTask('debugDev', ['clean', 'dependencies', "gen_initialize:development",'jshint','less', 'concat:index_css', 'template:development', 'copy:debug']);

  grunt.registerTask('watchRun', ['clean:watch', 'dependencies', 'jshint']);
  // build a release
  grunt.registerTask('release', ['clean' ,'dependencies', "gen_initialize:release", 'jshint', 'build', 'minify', 'copy:dist', 'copy:ace']);

  /*
   * Install into CouchDB in either debug, release, or couchapp mode
   */
  // make a development install that is server by mochiweb under _utils
  grunt.registerTask('couchdebug', ['debug', 'copy:couchdebug']);
  // make a minimized install that is server by mochiweb under _utils
  grunt.registerTask('couchdb', ['release', 'copy:couchdb']);
  // make an install that can be deployed as a couchapp
  grunt.registerTask('couchapp_setup', ['release']);
  // install fauxton as couchapp
  grunt.registerTask('couchapp_install', ['rmcouchdb:fauxton', 'mkcouchdb:fauxton', 'couchapp:fauxton']);
  // setup and install fauxton as couchapp
  grunt.registerTask('couchapp_deploy', ['couchapp_setup', 'couchapp_install']);
};
<commit_msg>made couchserver configurable via settings.json<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

// This is the main application configuration file.  It is a Grunt
// configuration file, which you can learn more about here:
// https://github.com/cowboy/grunt/blob/master/docs/configuring.md

module.exports = function(grunt) {
  var helper = require('./tasks/helper').init(grunt),
  _ = grunt.util._,
  path = require('path');

  var couch_config = function () {

    var default_couch_config = {
      fauxton: {
        db: 'http://localhost:5984/fauxton',
        app: './couchapp.js',
        options: {
          okay_if_missing: true
        }
      }
    };

    var settings_couch_config = helper.readSettingsFile().couch_config;
    return settings_couch_config || default_couch_config;
  }();

  var cleanableAddons =  function () {
    var theListToClean = [];
    helper.processAddons(function(addon){
      // Only clean addons that are included from a local dir
      if (addon.path){
        theListToClean.push("app/addons/" + addon.name);
      }
    });

    return theListToClean;
  }();

  var cleanable = function(){
    // Whitelist files and directories to be cleaned
    // You'll always want to clean these two directories
    // Now find the external addons you have and add them for cleaning up
    return _.union(["dist/", "app/load_addons.js"], cleanableAddons);
  }();

  var assets = function(){
    // Base assets
    var theAssets = {
      less:{
        paths: ["assets/less"],
        files: {
          "dist/debug/css/fauxton.css": "assets/less/fauxton.less"
        }
      },
      img: ["assets/img/**"]
    };
    helper.processAddons(function(addon){
      // Less files from addons
      var root = addon.path || "app/addons/" + addon.name;
      var lessPath = root + "/assets/less";
      if(path.existsSync(lessPath)){
        // .less files exist for this addon
        theAssets.less.paths.push(lessPath);
        theAssets.less.files["dist/debug/css/" + addon.name + ".css"] =
          lessPath + "/" + addon.name + ".less";
      }
      // Images
      root = addon.path || "app/addons/" + addon.name;
      var imgPath = root + "/assets/img";
      if(path.existsSync(imgPath)){
        theAssets.img.push(imgPath + "/**");
      }
    });
    return theAssets;
  }();

  var templateSettings = function(){
    var defaultSettings = {
     "development": {
        "src": "assets/index.underscore",
        "dest": "dist/debug/index.html",
        "variables": {
          "requirejs": "/assets/js/libs/require.js",
          "css": "./css/index.css",
          "base": null
        }
      },
      "release": {
        "src": "assets/index.underscore",
        "dest": "dist/debug/index.html",
        "variables": {
          "requirejs": "./js/require.js",
          "css": "./css/index.css",
          "base": null
        }
      }
    };

    var settings = helper.readSettingsFile();
    return settings.template || defaultSettings;
  }();

  var couchserver_config  = function () {
    // add a "couchserver" key to settings.json with JSON that matches the
    // keys and values below (plus your customizations) to have Fauxton work
    // against a remote CouchDB-compatible server.
    var defaults = {
      dist: './dist/debug/',
      port: 8000,
      proxy: {
        target: {
          host: 'localhost',
          port: 5984,
          https: false
        },
        // This sets the Host header in the proxy so that you can use external
        // CouchDB instances and not have the Host set to 'localhost'
        changeOrigin: true
      }
    };

    return helper.readSettingsFile().couchserver || defaults;
  }();

  grunt.initConfig({

    // The clean task ensures all files are removed from the dist/ directory so
    // that no files linger from previous builds.
    clean: {
      release:  cleanable,
      watch: cleanableAddons
    },

    // The lint task will run the build configuration and the application
    // JavaScript through JSHint and report any errors.  You can change the
    // options for this task, by reading this:
    // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md
    lint: {
      files: [
        "build/config.js", "app/**/*.js"
      ]
    },

    less: {
      compile: {
        options: {
          paths: assets.less.paths
        },
        files: assets.less.files
      }
    },

    // The jshint option for scripturl is set to lax, because the anchor
    // override inside main.js needs to test for them so as to not accidentally
    // route. Settings expr true so we can do `migtBeNullObject && mightBeNullObject.coolFunction()`
    jshint: {
      all: ['app/**/*.js', 'Gruntfile.js', "test/core/*.js"],
      options: {
        scripturl: true,
        evil: true,
        expr: true
      }
    },

    // The jst task compiles all application templates into JavaScript
    // functions with the underscore.js template function from 1.2.4.  You can
    // change the namespace and the template options, by reading this:
    // https://github.com/gruntjs/grunt-contrib/blob/master/docs/jst.md
    //
    // The concat task depends on this file to exist, so if you decide to
    // remove this, ensure concat is updated accordingly.
    jst: {
      compile: {
        options: {
          processContent: function(src) {
            return src.replace(/<!--[\s\S]*?-->/gm, '');
          }
        },
        files: {
          "dist/debug/templates.js": [
            "app/templates/**/*.html",
            "app/addons/**/templates/**/*.html"
          ]
        }
      }
    },

    template: templateSettings,

    // The concatenate task is used here to merge the almond require/define
    // shim and the templates into the application code.  It's named
    // dist/debug/require.js, because we want to only load one script file in
    // index.html.
    concat: {
      requirejs: {
        src: [ "assets/js/libs/require.js", "dist/debug/templates.js", "dist/debug/require.js"],
        dest: "dist/debug/js/require.js"
      },

      index_css: {
        src: ["dist/debug/css/*.css", 'assets/css/*.css'],
        dest: 'dist/debug/css/index.css'
      },

      test_config_js: {
        src: ["dist/debug/templates.js", "test/test.config.js"],
        dest: 'test/test.config.js'
      },
    },

    cssmin: {
      compress: {
        files: {
          "dist/release/css/index.css": [
            "dist/debug/css/index.css", 'assets/css/*.css',
            "app/addons/**/assets/css/*.css"
          ]
        },
        options: {
          report: 'min'
        }
      }
    },

    uglify: {
      release: {
        files: {
          "dist/release/js/require.js": [
            "dist/debug/js/require.js"
          ]
        }
      }
    },

    // Runs a proxy server for easier development, no need to keep deploying to couchdb
    couchserver: couchserver_config,

    watch: {
      js: {
        files: helper.watchFiles(['.js'], ["./app/**/*.js", '!./app/load_addons.js',"./assets/**/*.js", "./test/**/*.js"]),
        tasks: ['watchRun'],
      },
      style: {
        files: helper.watchFiles(['.less','.css'],["./app/**/*.css","./app/**/*.less","./assets/**/*.css", "./assets/**/*.less"]),
        tasks: ['clean:watch', 'dependencies','less', 'concat:index_css'],
      },
      html: {
        // the index.html is added in as a dummy file incase there is no
        // html dependancies this will break. So we need one include pattern
        files: helper.watchFiles(['.html'], ['./index.html']),
        tasks: ['clean:watch', 'dependencies']
      },
      options: {
        nospawn: true,
        debounceDelay: 500
      }
    },

    requirejs: {
      compile: {
        options: {
          baseUrl: 'app',
          // Include the main configuration file.
          mainConfigFile: "app/config.js",

          // Output file.
          out: "dist/debug/require.js",

          // Root application module.
          name: "config",

          // Do not wrap everything in an IIFE.
          wrap: false,
          optimize: "none",
          findNestedDependencies: true
        }
      }
    },

    // Copy build artifacts and library code into the distribution
    // see - http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
    copy: {
      couchdb: {
        files: [
          // this gets built in the template task
          {src: "dist/release/index.html", dest: "../../share/www/fauxton/index.html"},
          {src: ["**"], dest: "../../share/www/fauxton/js/", cwd:'dist/release/js/',  expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/img/", cwd:'dist/release/img/', expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/css/", cwd:"dist/release/css/", expand: true}
        ]
      },
      couchdebug: {
        files: [
          // this gets built in the template task
          {src: "dist/debug/index.html", dest: "../../share/www/fauxton/index.html"},
          {src: ["**"], dest: "../../share/www/fauxton/js/", cwd:'dist/debug/js/',  expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/img/", cwd:'dist/debug/img/', expand: true},
          {src: ["**"], dest: "../../share/www/fauxton/css/", cwd:"dist/debug/css/", expand: true}
        ]
      },
      ace: {
        files: [
          {src: "assets/js/libs/ace/worker-json.js", dest: "dist/release/js/ace/worker-json.js"},
          {src: "assets/js/libs/ace/mode-json.js", dest: "dist/release/js/ace/mode-json.js"},
          {src: "assets/js/libs/ace/theme-crimson_editor.js", dest: "dist/release/js/ace/theme-crimson_editor.js"},
          {src: "assets/js/libs/ace/mode-javascript.js", dest: "dist/release/js/ace/mode-javascript.js"},
          {src: "assets/js/libs/ace/worker-javascript.js", dest: "dist/release/js/ace/worker-javascript.js"},
        ]
      },

      dist:{
        files:[
          {src: "dist/debug/index.html", dest: "dist/release/index.html"},
          {src: assets.img, dest: "dist/release/img/", flatten: true, expand: true}
        ]
      },
      debug:{
        files:[
          {src: assets.img, dest: "dist/debug/img/", flatten: true, expand: true}
        ]
      }
    },

    get_deps: {
      "default": {
        src: "settings.json"
      }
    },

    gen_load_addons: {
      "default": {
        src: "settings.json"
      }
    },
    gen_initialize: templateSettings,
    /*gen_initialize: {
      "default": {
        src: "settings.json"
      }
    },*/

    mkcouchdb: couch_config,
    rmcouchdb: couch_config,
    couchapp: couch_config,

    mochaSetup: {
      default: {
        files: { src: helper.watchFiles(['[Ss]pec.js'], ['./test/core/**/*[Ss]pec.js', './app/**/*[Ss]pec.js'])},
        template: 'test/test.config.underscore',
        config: './app/config.js'
      }
    },

    mocha_phantomjs: {
      all: ['test/runner.html']
    }

  });

  // on watch events configure jshint:all to only run on changed file
  grunt.event.on('watch', function(action, filepath) {
    if (!!filepath.match(/.js$/) && filepath.indexOf('test.config.js') === -1) {
      grunt.config(['jshint', 'all'], filepath);
    }

    if (!!filepath.match(/[Ss]pec.js$/)) {
      //grunt.task.run(['mochaSetup','jst', 'concat:test_config_js', 'mocha_phantomjs']);
    }
  });

  /*
   * Load Grunt plugins
   */
  // Load fauxton specific tasks
  grunt.loadTasks('tasks');
  // Load the couchapp task
  grunt.loadNpmTasks('grunt-couchapp');
  // Load the copy task
  grunt.loadNpmTasks('grunt-contrib-watch');
  // Load the exec task
  grunt.loadNpmTasks('grunt-exec');
  // Load Require.js task
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  // Load Copy task
  grunt.loadNpmTasks('grunt-contrib-copy');
  // Load Clean task
  grunt.loadNpmTasks('grunt-contrib-clean');
  // Load jshint task
  grunt.loadNpmTasks('grunt-contrib-jshint');
  // Load jst task
  grunt.loadNpmTasks('grunt-contrib-jst');
  // Load less task
  grunt.loadNpmTasks('grunt-contrib-less');
  // Load concat task
  grunt.loadNpmTasks('grunt-contrib-concat');
  // Load UglifyJS task
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // Load CSSMin task
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-mocha-phantomjs');

  /*
   * Default task
   */
  // defult task - install minified app to local CouchDB
  grunt.registerTask('default', 'couchdb');

  /*
   * Transformation tasks
   */
  // clean out previous build artefactsa and lint
  grunt.registerTask('lint', ['clean', 'jshint']);
  grunt.registerTask('test', ['lint', 'mochaSetup','jst', 'concat:test_config_js', 'mocha_phantomjs']);
  // Fetch dependencies (from git or local dir), lint them and make load_addons
  grunt.registerTask('dependencies', ['get_deps', 'gen_load_addons:default']);
  // build templates, js and css
  grunt.registerTask('build', ['less', 'concat:index_css', 'jst', 'requirejs', 'concat:requirejs', 'template:release']);
  // minify code and css, ready for release.
  grunt.registerTask('minify', ['uglify', 'cssmin:compress']);

  /*
   * Build the app in either dev, debug, or release mode
   */
  // dev server
  grunt.registerTask('dev', ['debugDev', 'couchserver']);
  // build a debug release
  grunt.registerTask('debug', ['lint', 'dependencies', "gen_initialize:development", 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
  grunt.registerTask('debugDev', ['clean', 'dependencies', "gen_initialize:development",'jshint','less', 'concat:index_css', 'template:development', 'copy:debug']);

  grunt.registerTask('watchRun', ['clean:watch', 'dependencies', 'jshint']);
  // build a release
  grunt.registerTask('release', ['clean' ,'dependencies', "gen_initialize:release", 'jshint', 'build', 'minify', 'copy:dist', 'copy:ace']);

  /*
   * Install into CouchDB in either debug, release, or couchapp mode
   */
  // make a development install that is server by mochiweb under _utils
  grunt.registerTask('couchdebug', ['debug', 'copy:couchdebug']);
  // make a minimized install that is server by mochiweb under _utils
  grunt.registerTask('couchdb', ['release', 'copy:couchdb']);
  // make an install that can be deployed as a couchapp
  grunt.registerTask('couchapp_setup', ['release']);
  // install fauxton as couchapp
  grunt.registerTask('couchapp_install', ['rmcouchdb:fauxton', 'mkcouchdb:fauxton', 'couchapp:fauxton']);
  // setup and install fauxton as couchapp
  grunt.registerTask('couchapp_deploy', ['couchapp_setup', 'couchapp_install']);
};
<|endoftext|>


<commit_before>import { readFile } from 'fs'
import { createServer } from 'http'
import { resolve } from 'path'

import mime from 'mime'
import opener from 'opener'

export default function serve (options = {}) {
  if (Array.isArray(options) || typeof options === 'string') {
    options = { contentBase: options }
  }
  options.contentBase = Array.isArray(options.contentBase) ? options.contentBase : [options.contentBase]
  options.host = options.host || 'localhost'
  options.port = options.port || 10001

  mime.default_type = 'text/plain'

  createServer(function (request, response) {
    // Remove querystring
    const urlPath = request.url.split('?')[0]

    readFileFromContentBase(options.contentBase, urlPath, function (error, content, filePath) {
      if (!error)  {
        return found(response, filePath, content)
      }
      if (error.code !== 'ENOENT') {
        response.writeHead(500)
        response.end('500 Internal Server Error' +
          '\n\n' + filePath +
          '\n\n' + Object.keys(error).map(function (k) { return error[k]; }).join('\n') +
          '\n\n(rollup-plugin-serve)', 'utf-8')
        return
      }
      if (request.url === '/favicon.ico') {
        filePath = resolve(__dirname, '../dist/favicon.ico')
        readFile(filePath, function (error, content) {
          if (error) {
            notFound(response, filePath)
          } else {
            found(response, filePath, content)
          }
        })
      } else if (options.historyApiFallback) {
        filePath = resolve(options.contentBase, 'index.html')
        readFile(filePath, function (error, content) {
          if (error) {
            notFound(response, filePath)
          } else {
            found(response, filePath, content)
          }
        })
      } else {
        notFound(response, filePath)
      }
    })
  }).listen(options.port)

  var running = options.verbose === false

  return {
    name: 'serve',
    ongenerate () {
      if (!running) {
        running = true

        // Log which url to visit
        const url = 'http://' + options.host + ':' + options.port
        options.contentBase.forEach(base => {
          console.log(green(url) + ' -> ' + resolve(base))
        })

        // Open browser
        if (options.open) {
          opener(url)
        }
      }
    }
  }
}

function readFileFromContentBase (contentBase, urlPath, callback) {
  let filePath = resolve(contentBase[0] || '.', '.' + urlPath)

  // Load index.html in directories
  if (urlPath.endsWith('/')) {
    filePath = resolve(filePath, 'index.html')
  }

  readFile(filePath, (error, content) => {
    if (error && contentBase.length > 1) {
      // Try to read from next contentBase
      readFileFromContentBase(contentBase.slice(1), urlPath, callback)
    } else {
      // We know enough
      callback(error, content, filePath)
    }
  })
}

function notFound (response, filePath) {
  response.writeHead(404)
  response.end('404 Not Found' +
    '\n\n' + filePath +
    '\n\n(rollup-plugin-serve)', 'utf-8')
}

function found (response, filePath, content) {
  response.writeHead(200, { 'Content-Type': mime.lookup(filePath) })
  response.end(content, 'utf-8')
}

function green (text) {
  return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m'
}
<commit_msg>#3 Possible fix for historyApiFallback<commit_after>import { readFile } from 'fs'
import { createServer } from 'http'
import { resolve } from 'path'

import mime from 'mime'
import opener from 'opener'

export default function serve (options = {}) {
  if (Array.isArray(options) || typeof options === 'string') {
    options = { contentBase: options }
  }
  options.contentBase = Array.isArray(options.contentBase) ? options.contentBase : [options.contentBase]
  options.host = options.host || 'localhost'
  options.port = options.port || 10001

  mime.default_type = 'text/plain'

  createServer(function (request, response) {
    // Remove querystring
    const urlPath = request.url.split('?')[0]

    readFileFromContentBase(options.contentBase, urlPath, function (error, content, filePath) {
      if (!error)  {
        return found(response, filePath, content)
      }
      if (error.code !== 'ENOENT') {
        response.writeHead(500)
        response.end('500 Internal Server Error' +
          '\n\n' + filePath +
          '\n\n' + Object.keys(error).map(function (k) { return error[k]; }).join('\n') +
          '\n\n(rollup-plugin-serve)', 'utf-8')
        return
      }
      if (request.url === '/favicon.ico') {
        filePath = resolve(__dirname, '../dist/favicon.ico')
        readFile(filePath, function (error, content) {
          if (error) {
            notFound(response, filePath)
          } else {
            found(response, filePath, content)
          }
        })
      } else if (options.historyApiFallback) {
        readFileFromContentBase(options.contentBase, 'index.html', function (error, content, filePath) {
          if (error) {
            notFound(response, filePath)
          } else {
            found(response, filePath, content)
          }
        })
      } else {
        notFound(response, filePath)
      }
    })
  }).listen(options.port)

  var running = options.verbose === false

  return {
    name: 'serve',
    ongenerate () {
      if (!running) {
        running = true

        // Log which url to visit
        const url = 'http://' + options.host + ':' + options.port
        options.contentBase.forEach(base => {
          console.log(green(url) + ' -> ' + resolve(base))
        })

        // Open browser
        if (options.open) {
          opener(url)
        }
      }
    }
  }
}

function readFileFromContentBase (contentBase, urlPath, callback) {
  let filePath = resolve(contentBase[0] || '.', '.' + urlPath)

  // Load index.html in directories
  if (urlPath.endsWith('/')) {
    filePath = resolve(filePath, 'index.html')
  }

  readFile(filePath, (error, content) => {
    if (error && contentBase.length > 1) {
      // Try to read from next contentBase
      readFileFromContentBase(contentBase.slice(1), urlPath, callback)
    } else {
      // We know enough
      callback(error, content, filePath)
    }
  })
}

function notFound (response, filePath) {
  response.writeHead(404)
  response.end('404 Not Found' +
    '\n\n' + filePath +
    '\n\n(rollup-plugin-serve)', 'utf-8')
}

function found (response, filePath, content) {
  response.writeHead(200, { 'Content-Type': mime.lookup(filePath) })
  response.end(content, 'utf-8')
}

function green (text) {
  return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m'
}
<|endoftext|>


<commit_before>module.exports = function(grunt) {

    grunt.initConfig({
        sync: {
            custom: {
                files: [{
                    cwd     : 'src/main/resources',
                    src     : ['**/*'],
                    dest    : 'target/sqlfiddle',
                    flatten : false,
                    expand  : true
                }]
            }
        },
        less: {
            production: {
                files: {
                    "target/sqlfiddle/ui/sqlfiddle/www/css/fiddle.css": "src/main/resources/ui/sqlfiddle/www/css/fiddle.less",
                    "target/sqlfiddle/ui/sqlfiddle/www/css/fiddle_responsive.css": "src/main/resources/ui/sqlfiddle/www/css/fiddle_responsive.less",
                    "target/sqlfiddle/ui/sqlfiddle/www/css/fiddle_bootstrap_overrides.css": "src/main/resources/ui/sqlfiddle/www/css/fiddle_bootstrap_overrides.less"
                }
            }
        },
        requirejs: {
            minifyJS: {
                options: {
                    baseUrl: "target/sqlfiddle/ui/sqlfiddle/www/javascript",
                    mainConfigFile: "target/sqlfiddle/ui/sqlfiddle/www/javascript/main.js",
                    include: ["almond", "main"],
                    optimize: "uglify2",
                    generateSourceMaps: true,
                    preserveLicenseComments: false,
                    out: "target/sqlfiddle/ui/sqlfiddle/www/javascript/main_min.js"
                }
            },
            minifyMainCSS: {
                options: {
                    optimizeCss: 'standard',
                    cssIn: 'target/sqlfiddle/ui/sqlfiddle/www/css/styles.css',
                    out: 'target/sqlfiddle/ui/sqlfiddle/www/css/styles_min.css'
                }
            },
            minifyPrintCSS: {
                options: {
                    optimizeCss: 'standard',
                    cssIn: 'target/sqlfiddle/ui/sqlfiddle/www/css/print.css',
                    out: 'target/sqlfiddle/ui/sqlfiddle/www/css/print_min.css'
                }
            }
        },
        watch: {
            copy: {
                files: ['src/main/resources/ui/**/*.js','src/main/resources/script/*.js','src/main/resources/**/*.groovy', 'src/main/resources/ui/**/*.html', 'src/main/resources/conf/*.json', 'src/main/resources/ui/**/*.less', 'src/main/resources/ui/**/*.css'],
                tasks: [ 'sync', 'less', 'requirejs' ]
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-sync');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-contrib-less');

    grunt.registerTask('default', ['sync', 'less', 'requirejs', 'watch']);

};
<commit_msg>Tuning gruntfile to only run the tasks appropriate to the changed file, rather than everything each time<commit_after>module.exports = function(grunt) {

    grunt.initConfig({
        sync: {
            custom: {
                files: [{
                    cwd     : 'src/main/resources',
                    src     : ['**/*'],
                    dest    : 'target/sqlfiddle',
                    flatten : false,
                    expand  : true
                }]
            }
        },
        less: {
            production: {
                files: {
                    "target/sqlfiddle/ui/sqlfiddle/www/css/fiddle.css": "src/main/resources/ui/sqlfiddle/www/css/fiddle.less",
                    "target/sqlfiddle/ui/sqlfiddle/www/css/fiddle_responsive.css": "src/main/resources/ui/sqlfiddle/www/css/fiddle_responsive.less",
                    "target/sqlfiddle/ui/sqlfiddle/www/css/fiddle_bootstrap_overrides.css": "src/main/resources/ui/sqlfiddle/www/css/fiddle_bootstrap_overrides.less"
                }
            }
        },
        requirejs: {
            minifyJS: {
                options: {
                    baseUrl: "target/sqlfiddle/ui/sqlfiddle/www/javascript",
                    mainConfigFile: "target/sqlfiddle/ui/sqlfiddle/www/javascript/main.js",
                    include: ["almond", "main"],
                    optimize: "uglify2",
                    generateSourceMaps: true,
                    preserveLicenseComments: false,
                    out: "target/sqlfiddle/ui/sqlfiddle/www/javascript/main_min.js"
                }
            },
            minifyMainCSS: {
                options: {
                    optimizeCss: 'standard',
                    cssIn: 'target/sqlfiddle/ui/sqlfiddle/www/css/styles.css',
                    out: 'target/sqlfiddle/ui/sqlfiddle/www/css/styles_min.css'
                }
            },
            minifyPrintCSS: {
                options: {
                    optimizeCss: 'standard',
                    cssIn: 'target/sqlfiddle/ui/sqlfiddle/www/css/print.css',
                    out: 'target/sqlfiddle/ui/sqlfiddle/www/css/print_min.css'
                }
            }
        },
        watch: {
            copyUIJS: {
                files: ['src/main/resources/ui/**/*.js'],
                tasks: [ 'sync', 'requirejs:minifyJS' ]
            },
            copyLESS: {
                files: ['src/main/resources/ui/**/*.less', 'src/main/resources/ui/**/*.css'],
                tasks: [ 'sync', 'less', 'requirejs:minifyMainCSS', 'requirejs:minifyPrintCSS' ]
            },
            copyIDM: {
                files: ['src/main/resources/script/*.js','src/main/resources/**/*.groovy', 'src/main/resources/ui/**/*.html', 'src/main/resources/conf/*.json'],
                tasks: [ 'sync' ]
            }

        }
    });

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-sync');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-contrib-less');

    grunt.registerTask('default', ['sync', 'less', 'requirejs', 'watch']);

};
<|endoftext|>