<commit_before>/**
 * VALIDATORS
 *
 * Form validation directives go into this file.
 */

var webutil = require('../util/web'),
    Amount = ripple.Amount;

var module = angular.module('validators', []);

/**
 * Address validator
 */
module.directive('rpAddress', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        if (value) {
          var address = ripple.UInt160.from_json(value);

          if (!address.is_valid()) {
            ctrl.$setValidity('rpAddress', false);
            return;
          }
        }

        ctrl.$setValidity('rpAddress', true);
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpAddress', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Secret Account Key validator
 */
module.directive('rpMasterKey', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        if (!value || ripple.Seed.is_valid(""+value)) {
          ctrl.$setValidity('rpMasterKey', true);
          return value;
        } else {
          ctrl.$setValidity('rpMasterKey', false);
          return;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpMasterKey', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Address or contact validator
 *
 * Allows a valid address or a contact in our addressbook.
 */
// TODO merge rpDestination, rpAddress and rpNotMe.
module.directive('rpDestination', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var strippedValue=webutil.stripRippleAddress(value);
        var address = ripple.UInt160.from_json(strippedValue);

        if (address.is_valid() || (scope.userBlob && webutil.getContact(scope.userBlob.data.contacts,strippedValue))) {
          ctrl.$setValidity('rpDestination', true);
          return value;
        } else {
          ctrl.$setValidity('rpDestination', false);
          return;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpDestination', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

module.directive('rpNotMe', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var contact = webutil.getContact(scope.userBlob.data.contacts,value);

        if (value) {
          if ((contact && contact.address == scope.userBlob.data.account_id) || scope.userBlob.data.account_id == value) {
            ctrl.$setValidity('rpNotMe', false);
            return;
          }
        }

        ctrl.$setValidity('rpNotMe', true);
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpNotMe', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

module.directive('rpIssuer', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        if(!value){
          ctrl.$setValidity('rpIssuer', false);
          return;
        }

        var shortValue = value.slice(0, 3).toUpperCase();

        if ( (shortValue==="XRP") || webutil.findIssuer(scope.lines,shortValue))
        {
          ctrl.$setValidity('rpIssuer', true);
          return value;
        } else {
          ctrl.$setValidity('rpIssuer', false);
          return;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpIssuer', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Verify a form is the same as another.
 *
 * For example you could use this as a password repeat validator.
 *
 * @example
 *   <input name=password type=password>
 *   <input name=password2 type=password rp-same-as=password>
 */
module.directive('rpSameAs', [function() {
  return {
    require: 'ngModel',
    link: function(scope, el, attr, ctrl) {
      var pwdWidget = el.inheritedData('$formController')[attr.rpSameAs];

      ctrl.$parsers.unshift(function(value) {
        if (value === pwdWidget.$viewValue) {
          ctrl.$setValidity('rpSameAs', true);
          return value;
        }
        ctrl.$setValidity('rpSameAs', false);
      });

      pwdWidget.$parsers.unshift(function(value) {
        ctrl.$setValidity('rpSameAs', value === ctrl.$viewValue);
        return value;
      });
    }
  };
}]);

/**
 * Field uniqueness validator.
 *
 * @param {array=} rpUnique Array of strings which are disallowed values.
 * @param {string=} rpUniqueField If set, rpUnique will be interpreted as an
 *   array of objects and we compare the value with the field named
 *   rpUniqueField inside of those objects.
 * @param {string=} rpUniqueOrig You can set this to the original value to
 *   ensure this value is always allowed.
 *
 * @example
 *   <input ng-model="name" ng-unique="addressbook" ng-unique-field="name">
 */
module.directive('rpUnique', function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function ($scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var pool = $scope.$eval(attr.rpUnique) || [];

        if (attr.rpUniqueOrig && value === $scope.$eval(attr.rpUniqueOrig)) {
          // Original value is always allowed
          ctrl.$setValidity('rpUnique', true);
        } else if (attr.rpUniqueField) {
          for (var i = 0, l = pool.length; i < l; i++) {
            if (pool[i][attr.rpUniqueField] === value) {
              ctrl.$setValidity('rpUnique', false);
              return;
            }
          }
          ctrl.$setValidity('rpUnique', true);
        } else {
          ctrl.$setValidity('rpUnique', pool.indexOf(value) === -1);
        }
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      $scope.$watch(attr.rpUnique, function () {
        validator(ctrl.$viewValue);
      }, true);
    }
  };
});

/**
 * Password strength validator
 */
module.directive('rpStrongPassword', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(password) {
        var score = 0;
        var username = ""+scope.username;

        if (!password) {
          scope.strength = '';
          return password;
        }

        // password < 4
        if (password.length < 4 ) {
          ctrl.$setValidity('rpStrongPassword', false);
          scope.strength = 'weak';
          return;
        }

        // password == user name
        if (password.toLowerCase() == username.toLowerCase()) {
          ctrl.$setValidity('rpStrongPassword', false);
          scope.strength = 'weak';
          return;
        }

        checkRepetition = function (pLen, str) {
          var res = "";
          for (var i = 0; i < str.length; i++ ) {
            var repeated = true;

            for (var j = 0; j < pLen && (j+i+pLen) < str.length; j++) {
              repeated = repeated && (str.charAt(j+i) == str.charAt(j+i+pLen));
            }
            if (j<pLen) {
              repeated = false;
            }

            if (repeated) {
              i += pLen-1;
              repeated = false;
            } else {
              res += str.charAt(i);
            }
          }
          return res;
        };

        // password length
        score += password.length * 4;
        score += ( checkRepetition(1, password).length - password.length ) * 1;
        score += ( checkRepetition(2, password).length - password.length ) * 1;
        score += ( checkRepetition(3, password).length - password.length ) * 1;
        score += ( checkRepetition(4, password).length - password.length ) * 1;

        // password has 3 numbers
        if (password.match(/(.*[0-9].*[0-9].*[0-9])/)) {
          score += 5;
        }

        // password has 2 symbols
        if (password.match(/(.*[!,@,#,$,%,&,*,?,_,~].*[!,@,#,$,%,&,*,?,_,~])/)) {
          score += 5;
        }

        // password has Upper and Lower chars
        if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)){
          score += 10;
        }

        // password has number and chars
        if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/)) {
          score += 15;
        }

        //password has number and symbol
        if (password.match(/([!,@,#,$,%,&,*,?,_,~])/) && password.match(/([0-9])/)) {
          score += 15;
        }

        // password has char and symbol
        if (password.match(/([!,@,#,$,%,&,*,?,_,~])/) && password.match(/([a-zA-Z])/)) {
          score += 15;
        }

        // password is just a numbers or chars
        if (password.match(/^\w+$/) || password.match(/^\d+$/) ) {
          score -= 10;
        }

        // verifying 0 < score < 100
        if (score < 0) { score = 0; }
        if (score > 100) { score = 100; }

        if (score < 34) {
          ctrl.$setValidity('rpStrongPassword', false);
          scope.strength = 'weak';
          return;
        }

        ctrl.$setValidity('rpStrongPassword', true);

        if (score < 68) {
          scope.strength = 'medium';
          return password;
        }

        scope.strength = 'strong';
        return password;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpStrongPassword', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Maximum amount of money user can send
 */
module.directive('rpMaxAmount', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var input = Amount.from_human(+value);

        var currency = attr.rpMaxAmountCurrency ? attr.rpMaxAmountCurrency.slice(0, 3).toUpperCase() : 'XRP';

        // Check for XRP only
        if (currency != 'XRP') {
          ctrl.$setValidity('rpMaxAmount', true);
          return value;
        }

        if (input.is_valid()
            && scope.account.max_spend
            && scope.account.max_spend.to_number() > 1
            && scope.account.max_spend.compareTo(input) >= 0) {
          ctrl.$setValidity('rpMaxAmount', true);
          return value;
        } else {
          ctrl.$setValidity('rpMaxAmount', false);
          return value;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      scope.$watch('account.max_spend', function () {
        validator(ctrl.$viewValue);
      }, true);

      attr.$observe('rpMaxAmount', function() {
        validator(ctrl.$viewValue);
      });

      attr.$observe('rpMaxAmountCurrency', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});
<commit_msg>Fix rpMasterKey validator. Fixes #264<commit_after>/**
 * VALIDATORS
 *
 * Form validation directives go into this file.
 */

var webutil = require('../util/web'),
    Base58Utils = require('../util/base58'),
    Amount = ripple.Amount;

var module = angular.module('validators', []);

/**
 * Address validator
 */
module.directive('rpAddress', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        if (value) {
          var address = ripple.UInt160.from_json(value);

          if (!address.is_valid()) {
            ctrl.$setValidity('rpAddress', false);
            return;
          }
        }

        ctrl.$setValidity('rpAddress', true);
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpAddress', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Secret Account Key validator
 */
module.directive('rpMasterKey', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        if (value && !Base58Utils.decode_base_check(33, value)) {
          ctrl.$setValidity('rpMasterKey', false);
          return;
        }

        ctrl.$setValidity('rpMasterKey', true);
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpMasterKey', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Address or contact validator
 *
 * Allows a valid address or a contact in our addressbook.
 */
// TODO merge rpDestination, rpAddress and rpNotMe.
module.directive('rpDestination', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var strippedValue=webutil.stripRippleAddress(value);
        var address = ripple.UInt160.from_json(strippedValue);

        if (address.is_valid() || (scope.userBlob && webutil.getContact(scope.userBlob.data.contacts,strippedValue))) {
          ctrl.$setValidity('rpDestination', true);
          return value;
        } else {
          ctrl.$setValidity('rpDestination', false);
          return;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpDestination', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

module.directive('rpNotMe', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var contact = webutil.getContact(scope.userBlob.data.contacts,value);

        if (value) {
          if ((contact && contact.address == scope.userBlob.data.account_id) || scope.userBlob.data.account_id == value) {
            ctrl.$setValidity('rpNotMe', false);
            return;
          }
        }

        ctrl.$setValidity('rpNotMe', true);
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpNotMe', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

module.directive('rpIssuer', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        if(!value){
          ctrl.$setValidity('rpIssuer', false);
          return;
        }

        var shortValue = value.slice(0, 3).toUpperCase();

        if ( (shortValue==="XRP") || webutil.findIssuer(scope.lines,shortValue))
        {
          ctrl.$setValidity('rpIssuer', true);
          return value;
        } else {
          ctrl.$setValidity('rpIssuer', false);
          return;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpIssuer', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Verify a form is the same as another.
 *
 * For example you could use this as a password repeat validator.
 *
 * @example
 *   <input name=password type=password>
 *   <input name=password2 type=password rp-same-as=password>
 */
module.directive('rpSameAs', [function() {
  return {
    require: 'ngModel',
    link: function(scope, el, attr, ctrl) {
      var pwdWidget = el.inheritedData('$formController')[attr.rpSameAs];

      ctrl.$parsers.unshift(function(value) {
        if (value === pwdWidget.$viewValue) {
          ctrl.$setValidity('rpSameAs', true);
          return value;
        }
        ctrl.$setValidity('rpSameAs', false);
      });

      pwdWidget.$parsers.unshift(function(value) {
        ctrl.$setValidity('rpSameAs', value === ctrl.$viewValue);
        return value;
      });
    }
  };
}]);

/**
 * Field uniqueness validator.
 *
 * @param {array=} rpUnique Array of strings which are disallowed values.
 * @param {string=} rpUniqueField If set, rpUnique will be interpreted as an
 *   array of objects and we compare the value with the field named
 *   rpUniqueField inside of those objects.
 * @param {string=} rpUniqueOrig You can set this to the original value to
 *   ensure this value is always allowed.
 *
 * @example
 *   <input ng-model="name" ng-unique="addressbook" ng-unique-field="name">
 */
module.directive('rpUnique', function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function ($scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var pool = $scope.$eval(attr.rpUnique) || [];

        if (attr.rpUniqueOrig && value === $scope.$eval(attr.rpUniqueOrig)) {
          // Original value is always allowed
          ctrl.$setValidity('rpUnique', true);
        } else if (attr.rpUniqueField) {
          for (var i = 0, l = pool.length; i < l; i++) {
            if (pool[i][attr.rpUniqueField] === value) {
              ctrl.$setValidity('rpUnique', false);
              return;
            }
          }
          ctrl.$setValidity('rpUnique', true);
        } else {
          ctrl.$setValidity('rpUnique', pool.indexOf(value) === -1);
        }
        return value;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      $scope.$watch(attr.rpUnique, function () {
        validator(ctrl.$viewValue);
      }, true);
    }
  };
});

/**
 * Password strength validator
 */
module.directive('rpStrongPassword', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(password) {
        var score = 0;
        var username = ""+scope.username;

        if (!password) {
          scope.strength = '';
          return password;
        }

        // password < 4
        if (password.length < 4 ) {
          ctrl.$setValidity('rpStrongPassword', false);
          scope.strength = 'weak';
          return;
        }

        // password == user name
        if (password.toLowerCase() == username.toLowerCase()) {
          ctrl.$setValidity('rpStrongPassword', false);
          scope.strength = 'weak';
          return;
        }

        checkRepetition = function (pLen, str) {
          var res = "";
          for (var i = 0; i < str.length; i++ ) {
            var repeated = true;

            for (var j = 0; j < pLen && (j+i+pLen) < str.length; j++) {
              repeated = repeated && (str.charAt(j+i) == str.charAt(j+i+pLen));
            }
            if (j<pLen) {
              repeated = false;
            }

            if (repeated) {
              i += pLen-1;
              repeated = false;
            } else {
              res += str.charAt(i);
            }
          }
          return res;
        };

        // password length
        score += password.length * 4;
        score += ( checkRepetition(1, password).length - password.length ) * 1;
        score += ( checkRepetition(2, password).length - password.length ) * 1;
        score += ( checkRepetition(3, password).length - password.length ) * 1;
        score += ( checkRepetition(4, password).length - password.length ) * 1;

        // password has 3 numbers
        if (password.match(/(.*[0-9].*[0-9].*[0-9])/)) {
          score += 5;
        }

        // password has 2 symbols
        if (password.match(/(.*[!,@,#,$,%,&,*,?,_,~].*[!,@,#,$,%,&,*,?,_,~])/)) {
          score += 5;
        }

        // password has Upper and Lower chars
        if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)){
          score += 10;
        }

        // password has number and chars
        if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/)) {
          score += 15;
        }

        //password has number and symbol
        if (password.match(/([!,@,#,$,%,&,*,?,_,~])/) && password.match(/([0-9])/)) {
          score += 15;
        }

        // password has char and symbol
        if (password.match(/([!,@,#,$,%,&,*,?,_,~])/) && password.match(/([a-zA-Z])/)) {
          score += 15;
        }

        // password is just a numbers or chars
        if (password.match(/^\w+$/) || password.match(/^\d+$/) ) {
          score -= 10;
        }

        // verifying 0 < score < 100
        if (score < 0) { score = 0; }
        if (score > 100) { score = 100; }

        if (score < 34) {
          ctrl.$setValidity('rpStrongPassword', false);
          scope.strength = 'weak';
          return;
        }

        ctrl.$setValidity('rpStrongPassword', true);

        if (score < 68) {
          scope.strength = 'medium';
          return password;
        }

        scope.strength = 'strong';
        return password;
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('rpStrongPassword', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});

/**
 * Maximum amount of money user can send
 */
module.directive('rpMaxAmount', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var validator = function(value) {
        var input = Amount.from_human(+value);

        var currency = attr.rpMaxAmountCurrency ? attr.rpMaxAmountCurrency.slice(0, 3).toUpperCase() : 'XRP';

        // Check for XRP only
        if (currency != 'XRP') {
          ctrl.$setValidity('rpMaxAmount', true);
          return value;
        }

        if (input.is_valid()
            && scope.account.max_spend
            && scope.account.max_spend.to_number() > 1
            && scope.account.max_spend.compareTo(input) >= 0) {
          ctrl.$setValidity('rpMaxAmount', true);
          return value;
        } else {
          ctrl.$setValidity('rpMaxAmount', false);
          return value;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      scope.$watch('account.max_spend', function () {
        validator(ctrl.$viewValue);
      }, true);

      attr.$observe('rpMaxAmount', function() {
        validator(ctrl.$viewValue);
      });

      attr.$observe('rpMaxAmountCurrency', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});
<|endoftext|>


<commit_before>/**
 * Filename: 'search-filter.js'
 * Author: JMW <rabbitfighter@cryptolab.net>
 * App search filter
 */

const _filtered = ( item, type, term ) => {
	// If no type or term selected or type is ALL. show all
	if ( !type || !term || type === 'ALL' ) {
		return true
    }
    // Index is a special case where it's a number not a string...
    if ( type == 'Index') {
        return term === item.index.toString()
    }
    // If an item has the sspecified type, run regex test
  	if ( !item.hasOwnProperty( type ) ) {
  		return false
  	} else {
  		let regex = new RegExp( term, "gi" )
    	return regex.test( item[type] )
  	}
}

export default ( item, type, term ) => {
    return _filtered( item, type, term )
}

<commit_msg>Fixed indentation in search-filter.js<commit_after>/**
 * Filename: 'search-filter.js'
 * Author: JMW <rabbitfighter@cryptolab.net>
 * App search filter
 */

const _filtered = ( item, type, term ) => {
    // If no type or term selected or type is ALL. show all
    if ( !type || !term || type === 'ALL' ) {
        return true
    }
    // Index is a special case where it's a number not a string...
    if ( type == 'Index') {
        return term === item.index.toString()
    }
    // If an item has the sspecified type, run regex test
    if ( !item.hasOwnProperty( type ) ) {
        return false
    } else {
        let regex = new RegExp( term, "gi" )
        return regex.test( item[type] )
    }
}

export default ( item, type, term ) => {
    return _filtered( item, type, term )
}

<|endoftext|>


<commit_before>{
	"%s ago": "%s sedan",
	"%d unread message": {
		"one": "%d unread message",
		"other": "%d unread messages"
	},
	"Unread messages in %%s, %%s and one other": {
		"one": "Unread messages in %%s, %%s and one other",
		"other": "Unread messages in %%s, %%s and %d others"
	},
	"Unread messages in %s": "Unread messages in %s",
	"Unread messages in %s and %s": "Unread messages in %s and %s",
	"Unread messages from %s": "Unread messages from %s",
	"Unread messages from %s and %s": "Unread messages from %s and %s",
	"Unread messages from %%s, %%s and one other": {
		"one": "Unread messages from %%s, %%s and one other",
		"other": "Unread messages from %%s, %%s and %d others"
	}
}<commit_msg>Completed translation<commit_after>{
	"%s ago": "%s sedan",
	"%d unread message": {
		"one": "%d oläst meddelande",
		"other": "%d olästa meddelanden"
	},
	"Unread messages in %%s, %%s and one other": {
		"one": "olästa meddelanden i %%s, %%s och en till",
		"other": "olästa meddelanden i %%s, %%s och %d andra"
	},
	"Unread messages in %s": "olästa meddelanden i %s",
	"Unread messages in %s and %s": "olästa meddelanden i %s och %s",
	"Unread messages from %s": "olästa meddelanden från %s",
	"Unread messages from %s and %s": "olästa meddelanden från %s och %s",
	"Unread messages from %%s, %%s and one other": {
		"one": "olästa meddelanden från %%s, %%s och en till",
		"other": "oläst meddelanden från %%s, %%s och %d andra"
	}
}
<|endoftext|>


<commit_before>self.addEventListener('install', function (event) {
    event.waitUntil(caches.open('isonet').then(function (cache) {
        return cache.addAll(['./', 'assets/favicon.png', 'manifest.json', 'https://cdn.ampproject.org/v0.js']);
    }));
});
self.addEventListener('fetch', function (event) {
    event.respondWith(caches.match(event.request).then(function (response) {
        return response || fetch(event.request);
    }));
});<commit_msg>Icons now white<commit_after>self.addEventListener('install', function (event) {
    event.waitUntil(caches.open('isonet').then(function (cache) {
        return cache.addAll(['./', 'assets/icons/icon-192x192.png', 'assets/favicon.png', 'manifest.json', 'https://cdn.ampproject.org/v0.js']);
    }));
});
self.addEventListener('fetch', function (event) {
    event.respondWith(caches.match(event.request).then(function (response) {
        return response || fetch(event.request);
    }));
});<|endoftext|>


<commit_before>---
layout: null
---

var APP_PREFIX = 'alexdiliberto-cache-';
var VESION = 'v17';
var CACHE_NAME = APP_PREFIX + VESION
var urlsToCache = [];

// Cache posts
// Limits the number of posts that gets cached to 3
// Reads a piece of front-matter in each post that directs the second loop to the folder where the assets are held
// {% for post in site.posts limit:3 %}
//   urlsToCache.push("{{ post.url }}");
//   {% for asset in post.assets %}
//     {% for file in site.static_files %}
//       {% if file.path contains asset %}
//         urlsToCache.push("{{ file.path }}");
//       {% endif %}
//     {% endfor %}
//   {% endfor %}
// {% endfor %}

{% for post in site.posts limit:3 %}
  urlsToCache.push("{{ post.url }}");
{% endfor %}

// Cache pages
{% for page in site.html_pages %}
  {% unless page.url contains '/talks' %}
    urlsToCache.push("{{ page.url }}");
  {% endunless %}
{% endfor %}

// Cache assets
{% for file in site.static_files %}
  {% unless file.path contains '/talks' %}
    {% if file.path contains '/img' or file.extname == '.js' or file.extname == '.png' %}
      urlsToCache.push("{{ file.path }}")
    {% endif %}
  {% endunless %}
{% endfor %}

//console.log('urlsToCache', urlsToCache);

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME).then(function(cache) {
      return cache.addAll(urlsToCache);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.open(CACHE_NAME).then(function(cache) {
      return cache.match(event.request).then(function(response) {
        return response || fetch(event.request).then(function(response) {
          if (event.request.url.indexOf('chrome-extension') !== -1) {
            return response;
          }
          cache.put(event.request, response.clone());
          return response;
        });
      });
    }).catch(function() {
      return caches.match('/offline/');
    })
  );
});

self.addEventListener('activate', function(event) {
  var cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});
<commit_msg>:punch: sw cache version<commit_after>---
layout: null
---

var APP_PREFIX = 'alexdiliberto-cache-';
var VESION = 'v18';
var CACHE_NAME = APP_PREFIX + VESION
var urlsToCache = [];

// Cache posts
// Limits the number of posts that gets cached to 3
// Reads a piece of front-matter in each post that directs the second loop to the folder where the assets are held
// {% for post in site.posts limit:3 %}
//   urlsToCache.push("{{ post.url }}");
//   {% for asset in post.assets %}
//     {% for file in site.static_files %}
//       {% if file.path contains asset %}
//         urlsToCache.push("{{ file.path }}");
//       {% endif %}
//     {% endfor %}
//   {% endfor %}
// {% endfor %}

{% for post in site.posts limit:3 %}
  urlsToCache.push("{{ post.url }}");
{% endfor %}

// Cache pages
{% for page in site.html_pages %}
  {% unless page.url contains '/talks' %}
    urlsToCache.push("{{ page.url }}");
  {% endunless %}
{% endfor %}

// Cache assets
{% for file in site.static_files %}
  {% unless file.path contains '/talks' %}
    {% if file.path contains '/img' or file.extname == '.js' or file.extname == '.png' %}
      urlsToCache.push("{{ file.path }}")
    {% endif %}
  {% endunless %}
{% endfor %}

//console.log('urlsToCache', urlsToCache);

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME).then(function(cache) {
      return cache.addAll(urlsToCache);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.open(CACHE_NAME).then(function(cache) {
      return cache.match(event.request).then(function(response) {
        return response || fetch(event.request).then(function(response) {
          if (event.request.url.indexOf('chrome-extension') !== -1) {
            return response;
          }
          cache.put(event.request, response.clone());
          return response;
        });
      });
    }).catch(function() {
      return caches.match('/offline/');
    })
  );
});

self.addEventListener('activate', function(event) {
  var cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});
<|endoftext|>


<commit_before>'use strict';

var bowerBrowser = require('bower-browser');

module.exports = function (grunt) {

  grunt.registerMultiTask('bower-browser', 'Browser-based GUI manager of Bower', function () {
    var options = this.options({
      keepalive: true
    });
    var done = this.async();
    var app = bowerBrowser(options);
    if (!options.keepalive) {
      app.on('start', function () {
        done();
      });
    }
  });

};
<commit_msg>Update task description<commit_after>'use strict';

var bowerBrowser = require('bower-browser');

module.exports = function (grunt) {

  grunt.registerMultiTask('bower-browser', 'Run browser-based GUI manager of Bower ', function () {
    var options = this.options({
      keepalive: true
    });
    var done = this.async();
    var app = bowerBrowser(options);
    if (!options.keepalive) {
      app.on('start', function () {
        done();
      });
    }
  });

};
<|endoftext|>


<commit_before>---
layout: compress
# PWA service worker
---

self.importScripts('{{ "/assets/js/data/swcache.js" | relative_url }}');

const cacheName = 'chirpy-{{ "now" | date: "%Y%m%d.%H%M" }}';

function verifyDomain(url) {
  for (const domain of allowedDomains) {
    const regex = RegExp(`^http(s)?:\/\/${domain}\/`);
    if (regex.test(url)) {
      return true;
    }
  }

  return false;
}

function isExcluded(url) {
  for (const item of denyUrls) {
    if (url === item) {
      return true;
    }
  }
  return false;
}

self.addEventListener('install', e => {
  self.skipWaiting();
  e.waitUntil(
    caches.open(cacheName).then(cache => {
      return cache.addAll(resource);
    })
  );
});

self.addEventListener('fetch', e => {
  e.respondWith(
    caches.match(e.request).then(r => {
      /* console.log(`[sw] method: ${e.request.method}, fetching: ${e.request.url}`); */
      return r || fetch(e.request).then(response => {
        const url = e.request.url;

        if (e.request.method !== 'GET'
          || !verifyDomain(url)
          || isExcluded(url)) {
          return response;
        }

        return caches.open(cacheName).then(cache => {
          /* console.log('[sw] Caching new resource: ' + e.request.url); */
          cache.put(e.request, response.clone());
          return response;
        });

      });
    })
  );
});

self.addEventListener('activate', e => {
  e.waitUntil(
    caches.keys().then(keyList => {
          return Promise.all(
            keyList.map(key => {
              if(key !== cacheName) {
                return caches.delete(key);
              }
            })
          );
    })
  );
});
<commit_msg>Fix the response stream of service worker<commit_after>---
layout: compress
# PWA service worker
---

self.importScripts('{{ "/assets/js/data/swcache.js" | relative_url }}');

const cacheName = 'chirpy-{{ "now" | date: "%Y%m%d.%H%M" }}';

function verifyDomain(url) {
  for (const domain of allowedDomains) {
    const regex = RegExp(`^http(s)?:\/\/${domain}\/`);
    if (regex.test(url)) {
      return true;
    }
  }

  return false;
}

function isExcluded(url) {
  for (const item of denyUrls) {
    if (url === item) {
      return true;
    }
  }
  return false;
}

self.addEventListener('install', e => {
  self.skipWaiting();
  e.waitUntil(
    caches.open(cacheName).then(cache => {
      return cache.addAll(resource);
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        }

        return fetch(event.request)
          .then(response => {
            const url = event.request.url;

            if (event.request.method !== 'GET' ||
              !verifyDomain(url) ||
              isExcluded(url)) {
              return response;
            }

            /*
              see: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>
             */
            let responseToCache = response.clone();

            caches.open(cacheName)
              .then(cache => {
                /* console.log('[sw] Caching new resource: ' + event.request.url); */
                cache.put(event.request, responseToCache);
              });

            return response;
          });
      })
    );
});

self.addEventListener('activate', e => {
  e.waitUntil(
    caches.keys().then(keyList => {
          return Promise.all(
            keyList.map(key => {
              if(key !== cacheName) {
                return caches.delete(key);
              }
            })
          );
    })
  );
});
<|endoftext|>


<commit_before>/*
 * grunt-bower.js
 * https://github.com/stephenplusplus/bower-install
 *
 * Copyright (c) 2013 Stephen Sawchuk
 * Licensed under the MIT license.
 */

var grunt = require('grunt');
var wiredep = require('wiredep');

/**
 * Developers may still be using "component.json". That's fine, we can use that
 * just the same. But if they are, we'll let them know it's deprecated.
 *
 * @return {object} bower's .json configuration object
 */
var findBowerJSON = function () {

  var bowerJSON;

  ['bower.json', 'component.json'].forEach(function (configFile) {
    if (!bowerJSON && grunt.file.isFile(configFile)) {
      bowerJSON = grunt.file.readJSON(configFile);
    }
  });

  return bowerJSON;
};

/**
 * Try to use a `.bowerrc` file to find a custom directory. If it doesn't exist,
 * we're going with "bower_components".
 *
 * @ return {string} the path to the bower component directory
 */
var findBowerDirectory = function () {

  var directory;

  if (grunt.file.isFile('.bowerrc')) {
    directory = grunt.file.readJSON('.bowerrc').directory;
  }

  if (!directory) {
    ['bower_components', 'components'].forEach(function (dir) {
      if (!directory && grunt.file.isDir(dir)) {
        directory = dir;
      }
    });
  }

  if (!directory || !grunt.file.isDir(directory)) {
    console.log(
      'Cannot find where you keep your Bower packages.'
      + '\n'
      + '\nWe tried looking for a `.bowerrc` file, but couldn\'t find a custom'
      + '\n`directory` property defined. We then tried `bower_components`, but'
      + '\nit looks like that doesn\'t exist either. As a last resort, we tried'
      + '\nthe pre-1.0 `components` directory, but that also couldn\'t be found.'
      + '\n'
      + '\nUnfortunately, we can\'t proceed without knowing where the Bower'
      + '\npackages you have installed are.'
      + '\n'
    );

    grunt.fail.fatal('No Bower components found.');
  }

  return directory;
};

module.exports = function (grunt) {

  grunt.registerMultiTask('bower-install', 'Inject all components in your HTML file.', function () {

    this.requiresConfig(['bower-install', this.target, 'html']);

    wiredep({
      directory: findBowerDirectory(),
      bowerJson: findBowerJSON(),
      ignorePath: this.data.ignorePath,
      htmlFile: this.data.html,
      cssPattern: this.data.cssPattern,
      jsPattern: this.data.jsPattern
    });
  });
};
<commit_msg>add 'exclude' option<commit_after>/*
 * grunt-bower.js
 * https://github.com/stephenplusplus/bower-install
 *
 * Copyright (c) 2013 Stephen Sawchuk
 * Licensed under the MIT license.
 */

var grunt = require('grunt');
var wiredep = require('wiredep');

/**
 * Developers may still be using "component.json". That's fine, we can use that
 * just the same. But if they are, we'll let them know it's deprecated.
 *
 * @return {object} bower's .json configuration object
 */
var findBowerJSON = function () {

  var bowerJSON;

  ['bower.json', 'component.json'].forEach(function (configFile) {
    if (!bowerJSON && grunt.file.isFile(configFile)) {
      bowerJSON = grunt.file.readJSON(configFile);
    }
  });

  return bowerJSON;
};

/**
 * Try to use a `.bowerrc` file to find a custom directory. If it doesn't exist,
 * we're going with "bower_components".
 *
 * @ return {string} the path to the bower component directory
 */
var findBowerDirectory = function () {

  var directory;

  if (grunt.file.isFile('.bowerrc')) {
    directory = grunt.file.readJSON('.bowerrc').directory;
  }

  if (!directory) {
    ['bower_components', 'components'].forEach(function (dir) {
      if (!directory && grunt.file.isDir(dir)) {
        directory = dir;
      }
    });
  }

  if (!directory || !grunt.file.isDir(directory)) {
    console.log(
      'Cannot find where you keep your Bower packages.'
      + '\n'
      + '\nWe tried looking for a `.bowerrc` file, but couldn\'t find a custom'
      + '\n`directory` property defined. We then tried `bower_components`, but'
      + '\nit looks like that doesn\'t exist either. As a last resort, we tried'
      + '\nthe pre-1.0 `components` directory, but that also couldn\'t be found.'
      + '\n'
      + '\nUnfortunately, we can\'t proceed without knowing where the Bower'
      + '\npackages you have installed are.'
      + '\n'
    );

    grunt.fail.fatal('No Bower components found.');
  }

  return directory;
};

module.exports = function (grunt) {

  grunt.registerMultiTask('bower-install', 'Inject all components in your HTML file.', function () {

    this.requiresConfig(['bower-install', this.target, 'html']);

    wiredep({
      directory: findBowerDirectory(),
      bowerJson: findBowerJSON(),
      ignorePath: this.data.ignorePath,
      htmlFile: this.data.html,
      cssPattern: this.data.cssPattern,
      jsPattern: this.data.jsPattern,
      exclude: this.data.exclude
    });
  });
};
<|endoftext|>


<commit_before>(function () {
    var snippetUrl = "http://babylonjs-api.azurewebsites.net/api/snippet";
    var currentSnippetToken;
    var engine;
    var fpsLabel = document.getElementById("fpsLabel");
    var scripts;
    var zipCode;
    BABYLON.Engine.ShadersRepository = "/src/Shaders/";
    var loadScript = function (scriptURL, title) {
        var xhr = new XMLHttpRequest();

        xhr.open('GET', scriptURL, true);

        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    blockEditorChange = true;
                    jsEditor.setValue(xhr.responseText);
                    jsEditor.setPosition({ lineNumber: 0, column: 0 });
                    blockEditorChange = false;
                    compileAndRun();

                    document.getElementById("currentScript").innerHTML = title;

                    currentSnippetToken = null;
                }
            }
        };

        xhr.send(null);
    };

    compileAndRun = function (code) {
        try {

            if (!BABYLON.Engine.isSupported()) {
                showError("Your browser does not support WebGL");
                return;
            }

            if (engine) {
                engine.dispose();
                engine = null;
            }

            var canvas = document.getElementById("renderCanvas");
            engine = new BABYLON.Engine(canvas, true);
            engine.renderEvenInBackground = false;
            BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;

            engine.runRenderLoop(function () {
                if (engine.scenes.length === 0) {
                    return;
                }

                if (canvas.width !== canvas.clientWidth) {
                    engine.resize();
                }

                var scene = engine.scenes[0];

                if (scene.activeCamera || scene.activeCameras.length > 0) {
                    scene.render();
                }

                fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
            });

            var scene;
            if (code.indexOf("createScene") !== -1) { // createScene
                eval(code);
                scene = createScene();
                if (!scene) {
                    showError("createScene function must return a scene.");
                    return;
                }

                zipCode = code + "\r\n\r\nvar scene = createScene();";
            } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
                eval(code);
                scene = CreateScene();
                if (!scene) {
                    showError("CreateScene function must return a scene.");
                    return;
                }

                zipCode = code + "\r\n\r\nvar scene = CreateScene();";
            } else if (code.indexOf("createscene") !== -1) { // createscene
                eval(code);
                scene = createscene();
                if (!scene) {
                    showError("createscene function must return a scene.");
                    return;
                }

                zipCode = code + "\r\n\r\nvar scene = createscene();";
            } else { // Direct code
                scene = new BABYLON.Scene(engine);
                eval("runScript = function(scene, canvas) {" + code + "}");
                runScript(scene, canvas);

                zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
            }

        } catch (e) {
            showError(e.message);
        }
    };
    window.addEventListener("resize", function () {
        if (engine) {
            engine.resize();
        }
    });

    // UI

    var cleanHash = function () {
        var splits = decodeURIComponent(location.hash.substr(1)).split("#");

        if (splits.length > 2) {
            splits.splice(2, splits.length - 2);
        }

        location.hash = splits.join("#");
    }

    var checkHash = function () {
        if (location.hash) {
            cleanHash();

            try {
                var xmlHttp = new XMLHttpRequest();
                xmlHttp.onreadystatechange = function () {
                    if (xmlHttp.readyState === 4) {
                        if (xmlHttp.status === 200) {
                            var snippet = JSON.parse(xmlHttp.responseText);
                            compileAndRun(snippet.code.toString());

                            document.getElementById("refresh").addEventListener("click", function () {
                                compileAndRun(snippet.code.toString());
                            });
                        }
                    }
                }

                var hash = location.hash.substr(1);
                currentSnippetToken = hash.split("#")[0];

                xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
                xmlHttp.send();

                document.getElementById("link").href = "http://www.babylonjs-playground.com/#" + hash;
            } catch (e) {

            }
        }
    }

    checkHash();

})();<commit_msg>Support https<commit_after>(function () {
    var snippetUrl = "//babylonjs-api.azurewebsites.net/api/snippet";
    var currentSnippetToken;
    var engine;
    var fpsLabel = document.getElementById("fpsLabel");
    var scripts;
    var zipCode;
    BABYLON.Engine.ShadersRepository = "/src/Shaders/";
    var loadScript = function (scriptURL, title) {
        var xhr = new XMLHttpRequest();

        xhr.open('GET', scriptURL, true);

        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    blockEditorChange = true;
                    jsEditor.setValue(xhr.responseText);
                    jsEditor.setPosition({ lineNumber: 0, column: 0 });
                    blockEditorChange = false;
                    compileAndRun();

                    document.getElementById("currentScript").innerHTML = title;

                    currentSnippetToken = null;
                }
            }
        };

        xhr.send(null);
    };

    compileAndRun = function (code) {
        try {

            if (!BABYLON.Engine.isSupported()) {
                showError("Your browser does not support WebGL");
                return;
            }

            if (engine) {
                engine.dispose();
                engine = null;
            }

            var canvas = document.getElementById("renderCanvas");
            engine = new BABYLON.Engine(canvas, true);
            engine.renderEvenInBackground = false;
            BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;

            engine.runRenderLoop(function () {
                if (engine.scenes.length === 0) {
                    return;
                }

                if (canvas.width !== canvas.clientWidth) {
                    engine.resize();
                }

                var scene = engine.scenes[0];

                if (scene.activeCamera || scene.activeCameras.length > 0) {
                    scene.render();
                }

                fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
            });

            var scene;
            if (code.indexOf("createScene") !== -1) { // createScene
                eval(code);
                scene = createScene();
                if (!scene) {
                    showError("createScene function must return a scene.");
                    return;
                }

                zipCode = code + "\r\n\r\nvar scene = createScene();";
            } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
                eval(code);
                scene = CreateScene();
                if (!scene) {
                    showError("CreateScene function must return a scene.");
                    return;
                }

                zipCode = code + "\r\n\r\nvar scene = CreateScene();";
            } else if (code.indexOf("createscene") !== -1) { // createscene
                eval(code);
                scene = createscene();
                if (!scene) {
                    showError("createscene function must return a scene.");
                    return;
                }

                zipCode = code + "\r\n\r\nvar scene = createscene();";
            } else { // Direct code
                scene = new BABYLON.Scene(engine);
                eval("runScript = function(scene, canvas) {" + code + "}");
                runScript(scene, canvas);

                zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
            }

        } catch (e) {
            showError(e.message);
        }
    };
    window.addEventListener("resize", function () {
        if (engine) {
            engine.resize();
        }
    });

    // UI

    var cleanHash = function () {
        var splits = decodeURIComponent(location.hash.substr(1)).split("#");

        if (splits.length > 2) {
            splits.splice(2, splits.length - 2);
        }

        location.hash = splits.join("#");
    }

    var checkHash = function () {
        if (location.hash) {
            cleanHash();

            try {
                var xmlHttp = new XMLHttpRequest();
                xmlHttp.onreadystatechange = function () {
                    if (xmlHttp.readyState === 4) {
                        if (xmlHttp.status === 200) {
                            var snippet = JSON.parse(xmlHttp.responseText);
                            compileAndRun(snippet.code.toString());

                            document.getElementById("refresh").addEventListener("click", function () {
                                compileAndRun(snippet.code.toString());
                            });
                        }
                    }
                }

                var hash = location.hash.substr(1);
                currentSnippetToken = hash.split("#")[0];

                xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
                xmlHttp.send();

                document.getElementById("link").href = "//www.babylonjs-playground.com/#" + hash;
            } catch (e) {

            }
        }
    }

    checkHash();

})();<|endoftext|>


<commit_before>(function (window) {

// This monkey patch overrides Jasmine internal utility function responsible
// for comparing objects and drops support for diff builder, introduced in
// Jasmine 2.6. Brings back legacy object output, so reporter could work with it
// as before.

window.jasmine.matchersUtil = matchersUtilPatched(window.jasmine);

function matchersUtilPatched(j$) {
  var util = j$.matchersUtil;
  var oldEquals = util.equals;

  // Below Jasmine 2.6 there is no NullDiffBuilder class
  if (typeof j$.NullDiffBuilder === 'undefined') {
    return util;
  }

  var newEquals = function (a, b, customTesters, diffBuilder) {
    return oldEquals(a, b, customTesters, j$.NullDiffBuilder());
  };

  util.equals = newEquals;

  return util;
}

}(window));
<commit_msg>Update util-patch.js<commit_after>(function (window) {

// This monkey patch overrides Jasmine internal utility function responsible
// for comparing objects and drops support for diff builder, introduced in
// Jasmine 2.6. Brings back legacy object output, so reporter could work with it
// as before.

window.jasmine.matchersUtil = matchersUtilPatched(window.jasmine);

function matchersUtilPatched(j$) {
  var util = j$.matchersUtil;
  var oldEquals = util.equals.bind(util);

  // Below Jasmine 2.6 there is no NullDiffBuilder class
  if (typeof j$.NullDiffBuilder === 'undefined') {
    return util;
  }

  var newEquals = function (a, b, customTesters, diffBuilder) {
    return oldEquals(a, b, customTesters, j$.NullDiffBuilder());
  };

  util.equals = newEquals;

  return util;
}

}(window));
<|endoftext|>


<commit_before>var cacheName= "testCacheName";
var filesToCache = [
    //'/',
    //'index.html',
    //'styles/style.css',
    'img/circle.png',
    'img/triangle.png',
    'img/squiggle.png',
    'img/square.png'
];

self.addEventListener('install', function(e) {
    console.log('[ServiceWorker] Install');
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            console.log('[ServiceWorker] Caching app shell');
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('activate', function(e) {
    console.log('[ServiceWorker] Activate');
    e.waitUntil(
        caches.keys().then(function(keyList) {
            return Promise.all(keyList.map(function(key) {
                if (key !== cacheName) {
                    console.log('[ServiceWorker] Removing old cache', key);
                    return caches.delete(key);
                }
            }));
        })
    );
    return self.clients.claim();
});

self.addEventListener('fetch', function(e) {
    console.log('[ServiceWorker] Fetch', e.request.url);
    e.respondWith(
        caches.match(e.request).then(function(response) {
            return response || fetch(e.request);
        })
    );
});<commit_msg>added files to be cached by service worker, and service worker fetch from cache<commit_after>var cacheName= "testCacheName";
var filesToCache = [
    //'/',
    'index.html',
    'styles/style.css',
    'img/circle.png',
    'img/triangle.png',
    'img/squiggle.png',
    'img/square.png'
];

self.addEventListener('install', function(e) {
    console.log('[ServiceWorker] Install');
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            console.log('[ServiceWorker] Caching app shell');
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('activate', function(e) {
    console.log('[ServiceWorker] Activate');
    e.waitUntil(
        caches.keys().then(function(keyList) {
            return Promise.all(keyList.map(function(key) {
                if (key !== cacheName) {
                    console.log('[ServiceWorker] Removing old cache', key);
                    return caches.delete(key);
                }
            }));
        })
    );
    return self.clients.claim();
});

self.addEventListener('fetch', function(e) {
    console.log('[ServiceWorker] Fetch', e.request.url);
    e.respondWith(
        caches.match(e.request).then(function(response) {
            return response || fetch(e.request);
        })
    );
});<|endoftext|>


<commit_before>var cheerio = require('cheerio'),
    fs = require('fs'),
    path = require('path'),
    pagedown = require('pagedown');

var converter = new pagedown.Converter();

var idRegex = /[^\w]/g;

var setextHeader1Regex = /^(.+)[ \t]*\n=+[ \t]*\n+/gm;
var setextHeader2Regex = /^(.+)[ \t]*\n-+[ \t]*\n+/gm;

/*    /
    ^(\#{1,6})      // $1 = string of #'s
        [ \t]*
    (.+?)           // $2 = Header text
    [ \t]*
    \#*             // optional closing #'s (not counted)
    \n+
    /gm */
var atxHeaderRegex = /^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm;
var markdownHeaders = [
    '',
    "#",
    "##",
    "###",
    "####",
    "#####",
    "######"
];

var allHtmlHeaders = 'h1, h2, h3, h4, h5, h6';

var buildHeader = function(name, depth) {
    var header = '<h' + (depth) + '>' + name + '</h' + depth + '>';
    return header;
};

var appendTocElement = function(toc, link) {
    var element = cheerio.load('

');
    element('li')
        .addClass('docmd-toc-item')
        .append(link);
    toc.root().append(element.html());
};

var buildSimpleTocLink = function(name, anchorId) {
    return cheerio.load('')('a')
        .attr('href', '#' + anchorId)
        .addClass("docmd-toc-link")
        .text(name);
};

var adjustMarkdownHeaders = function(markdown, depth) {
    markdown = markdown.replace(atxHeaderRegex, function (wholeMatch, m1, m2) {
        var currentLevel = m1.length;
        var newLevel = depth + currentLevel - 1;
        if (newLevel > 6) {
            newLevel = 6;
        }
        return '\n' + markdownHeaders[newLevel] + m2 + '\n\n';
        }
    );

    markdown = markdown.replace(setextHeader1Regex, function(wholeMatch, m1) {
        return '\n' + markdownHeaders[depth] + m1 + '\n\n';
    });

    markdown = markdown.replace(setextHeader1Regex, function(wholeMatch, m1) {
        var newLevel = depth + 1;
        if (newLevel > 6) {
            newLevel = 6;
        }
        return '\n' + markdownHeaders[newLevel] + m1 + '\n\n';
    });
    return markdown;
};

var buildAndLinkHtml = function(options, properties, depth) {
    if (depth > 4) {
        //TODO determine if this is the correct threshold
        depth = 4;
    }
    var tocSections = cheerio.load('');
    var name,
        header,
        $,
        markdown;
    if (properties["name"]) {
        name = properties["name"];
        $ = cheerio.load(buildHeader(name, depth));
        markdown = markdownHeaders[depth] + name + '\n\n';
        header = $(allHtmlHeaders).first();
    } else if (properties["file"]) {
        var sectionFile = path.join(options['docDir'], properties["file"]);
        markdown = fs.readFileSync(sectionFile, {"encoding": "utf-8"});
        if (options['normalizeHeaders']) {
            markdown = adjustMarkdownHeaders(markdown, depth);
        }
        var markdownHtml = converter.makeHtml(markdown);
        $ = cheerio.load('');
        $.root().append(markdownHtml);
        header = $(allHtmlHeaders).first();
        name = header.text();
    } else  {
        grunt.fail.warn("A toc list contains an element that is neither a name nor a file");
    }
    var anchorId = properties["referenceId"];
    if (!anchorId) {
        anchorId = buildId(name);
    }
    header.attr('id', anchorId);
    appendTocElement(tocSections, buildSimpleTocLink(name, anchorId));

    if (properties["toc"]) {
        properties["toc"].forEach(function(section) {
            var sectionContent = buildAndLinkHtml(options, section, depth + 1);

            appendTocElement(tocSections, sectionContent["toc"]);
            $.root().append(sectionContent['main']);
            markdown = markdown + sectionContent['markdown'];
        });
    }

    var toc = cheerio.load('');
    var tocContents = cheerio.load('
');
    tocContents('ul').addClass('docmd-toc-list')
        .append(tocSections.html());
    toc.root().append(tocContents.html());

    return {
        "main": $.root().html(),
        "toc": toc.html(),
        "markdown": markdown
    };
};

var buildGuideLinks = function(guides) {
    var $ = cheerio.load('
');
    guides.forEach(function(guide) {
        var element = cheerio.load('');
        element('a')
            .addClass("all-guides-list-item list-group-item")
            .attr('href', guide.link + '.html')
            .text(guide.text);
        $('div').append(element.root().html())
    });
    return $.root().html();
};

var highlightCurrentGuide = function(guideLinksHtml, guideLink) {
    var $ = cheerio.load(guideLinksHtml);
    $('a').each(function() {
        var link = $(this);
        if (link.attr('href') === guideLink) {
            link.addClass('docmd-selected-guide');
        }
    });
    return $.root().html();
};

var applyIconStyle = function(fullHtml, properties) {
    var $ = cheerio.load(fullHtml);
    var icon = $('#main-icon');
    for (var style in properties) {
        icon.css(style, properties[style]);
    }
    return $.root().html();
};

var buildId = function(name) {
    return name.replace(idRegex, '');
};

module.exports = {
    buildAndLinkHtml: buildAndLinkHtml,
    buildGuideLinks: buildGuideLinks,
    highlightCurrentGuide: highlightCurrentGuide,
    applyIconStyle: applyIconStyle,
    buildId: buildId
};<commit_msg>Fixes the normalize header function. It now uses the correct regex to match the header2 headers in markdown, rather than using the header1 regex again.<commit_after>var cheerio = require('cheerio'),
    fs = require('fs'),
    path = require('path'),
    pagedown = require('pagedown');

var converter = new pagedown.Converter();

var idRegex = /[^\w]/g;

var setextHeader1Regex = /^(.+)[ \t]*\n=+[ \t]*\n+/gm;
var setextHeader2Regex = /^(.+)[ \t]*\n-+[ \t]*\n+/gm;

/*    /
    ^(\#{1,6})      // $1 = string of #'s
        [ \t]*
    (.+?)           // $2 = Header text
    [ \t]*
    \#*             // optional closing #'s (not counted)
    \n+
    /gm */
var atxHeaderRegex = /^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm;
var markdownHeaders = [
    '',
    "#",
    "##",
    "###",
    "####",
    "#####",
    "######"
];

var allHtmlHeaders = 'h1, h2, h3, h4, h5, h6';

var buildHeader = function(name, depth) {
    var header = '<h' + (depth) + '>' + name + '</h' + depth + '>';
    return header;
};

var appendTocElement = function(toc, link) {
    var element = cheerio.load('

');
    element('li')
        .addClass('docmd-toc-item')
        .append(link);
    toc.root().append(element.html());
};

var buildSimpleTocLink = function(name, anchorId) {
    return cheerio.load('')('a')
        .attr('href', '#' + anchorId)
        .addClass("docmd-toc-link")
        .text(name);
};

var adjustMarkdownHeaders = function(markdown, depth) {
    markdown = markdown.replace(atxHeaderRegex, function (wholeMatch, m1, m2) {
        var currentLevel = m1.length;
        var newLevel = depth + currentLevel - 1;
        if (newLevel > 6) {
            newLevel = 6;
        }
        return '\n' + markdownHeaders[newLevel] + m2 + '\n\n';
        }
    );

    markdown = markdown.replace(setextHeader1Regex, function(wholeMatch, m1) {
        return '\n' + markdownHeaders[depth] + m1 + '\n\n';
    });

    markdown = markdown.replace(setextHeader2Regex, function(wholeMatch, m1) {
        var newLevel = depth + 1;
        if (newLevel > 6) {
            newLevel = 6;
        }
        return '\n' + markdownHeaders[newLevel] + m1 + '\n\n';
    });
    return markdown;
};

var buildAndLinkHtml = function(options, properties, depth) {
    if (depth > 4) {
        //TODO determine if this is the correct threshold
        depth = 4;
    }
    var tocSections = cheerio.load('');
    var name,
        header,
        $,
        markdown;
    if (properties["name"]) {
        name = properties["name"];
        $ = cheerio.load(buildHeader(name, depth));
        markdown = markdownHeaders[depth] + name + '\n\n';
        header = $(allHtmlHeaders).first();
    } else if (properties["file"]) {
        var sectionFile = path.join(options['docDir'], properties["file"]);
        markdown = fs.readFileSync(sectionFile, {"encoding": "utf-8"});
        if (options['normalizeHeaders']) {
            markdown = adjustMarkdownHeaders(markdown, depth);
        }
        var markdownHtml = converter.makeHtml(markdown);
        $ = cheerio.load('');
        $.root().append(markdownHtml);
        header = $(allHtmlHeaders).first();
        name = header.text();
    } else  {
        grunt.fail.warn("A toc list contains an element that is neither a name nor a file");
    }
    var anchorId = properties["referenceId"];
    if (!anchorId) {
        anchorId = buildId(name);
    }
    header.attr('id', anchorId);
    appendTocElement(tocSections, buildSimpleTocLink(name, anchorId));

    if (properties["toc"]) {
        properties["toc"].forEach(function(section) {
            var sectionContent = buildAndLinkHtml(options, section, depth + 1);

            appendTocElement(tocSections, sectionContent["toc"]);
            $.root().append(sectionContent['main']);
            markdown = markdown + sectionContent['markdown'];
        });
    }

    var toc = cheerio.load('');
    var tocContents = cheerio.load('
');
    tocContents('ul').addClass('docmd-toc-list')
        .append(tocSections.html());
    toc.root().append(tocContents.html());

    return {
        "main": $.root().html(),
        "toc": toc.html(),
        "markdown": markdown
    };
};

var buildGuideLinks = function(guides) {
    var $ = cheerio.load('
');
    guides.forEach(function(guide) {
        var element = cheerio.load('');
        element('a')
            .addClass("all-guides-list-item list-group-item")
            .attr('href', guide.link + '.html')
            .text(guide.text);
        $('div').append(element.root().html())
    });
    return $.root().html();
};

var highlightCurrentGuide = function(guideLinksHtml, guideLink) {
    var $ = cheerio.load(guideLinksHtml);
    $('a').each(function() {
        var link = $(this);
        if (link.attr('href') === guideLink) {
            link.addClass('docmd-selected-guide');
        }
    });
    return $.root().html();
};

var applyIconStyle = function(fullHtml, properties) {
    var $ = cheerio.load(fullHtml);
    var icon = $('#main-icon');
    for (var style in properties) {
        icon.css(style, properties[style]);
    }
    return $.root().html();
};

var buildId = function(name) {
    return name.replace(idRegex, '');
};

module.exports = {
    buildAndLinkHtml: buildAndLinkHtml,
    buildGuideLinks: buildGuideLinks,
    highlightCurrentGuide: highlightCurrentGuide,
    applyIconStyle: applyIconStyle,
    buildId: buildId
};<|endoftext|>


<commit_before>/*
 * grunt-shared-config
 *
 * Use this task to create multiple config files for JS/JS-AMD, SCSS/SASS/LESS/stylus from one JSON/YAML.
 *
 * Copyright (c) 2013 Mathias Paumgarten
 * Licensed under the MIT license.
 */

"use strict";

var mout = require( "mout" );

module.exports = function( grunt ) {

	grunt.registerMultiTask( "shared_config", "Your task description goes here.", function() {

		// ===========
		// -- UTILS --
		// ===========

		function normalizeOutArray( value ) {
			return typeof value === "string" ? [ value ] : value;
		}

		function normalizeFormat( value ) {
			return mout.array.contains( varFormats, value ) ? value : varFormats[ 0 ];
		}

		function format( value, type ) {
			value = value.replace( /-/g, " " );

			switch ( type ) {
				case "underscore":
					return mout.string.underscore( value );
				case "uppercase":
					return value.toUpperCase().replace( / /g, "_" );
				case "dash":
					return mout.string.hyphenate( value );
				default:
					return mout.string.camelCase( value );
			}
		}

		function fileExists( filePath ) {
			if ( !grunt.file.exists( filePath ) ) {
				grunt.log.warn( "Source file (" + filePath + ") not found." );
				return false;
			}
			return true;
		}

		function readFile( filePath ) {
			// fetch JSON or YAML from file
			var fileType = filePath.split( "." ).pop().toLowerCase();
			var src;
			if ( fileType === 'yml' || fileType === 'yaml' ) {
				src = grunt.file.readYAML( filePath );
			} else {
				src = grunt.file.readJSON( filePath );
			}
			return src;
		}

		function isStringNumber( value ) {
			var units = [ "em", "px", "s", "in", "mm", "cm", "pt", "pc", "%" ];

			return units.reduce( function( previous, current ) {
				return previous || mout.string.endsWith( value, current );
			}, false );
		}

		function getStyleSafeValue( value ) {
			if ( ! isStringNumber( value ) && value[ 0 ] !== "#" ) {
				value = "\"" + value + "\"";
			}
			return value;
		}

		// ==============
		// -- SETTINGS --
		// ==============

		// default options
		var options = this.options( {
			amd: false,
			jsFormat: "uppercase",
			cssFormat: "dash",
			name: "config",
			useSassMaps: false,
			indention: "\t",
			mask: undefined,
			maskFile: undefined,
			maskAllowUnknownOnFirstLevel: false,
		} );

		// possible variable formats
		var varFormats = [ "underscore", "uppercase", "dash", "camelcase" ];

		// available file extensions
		var fileExtensions = {
			js: [ "js" ],
			css: [ "scss", "sass", "less", "styl" ]
		};

		// variable patterns
		var outputPattern = {
			scss:     "${{key}}: {{value}};\n",
			sass:     "${{key}}: {{value}}\n",
			less:     "@{{key}}: {{value}};\n",
			sassmaps: "{{key}}: {{value}},",
			styl:     "{{key}} = {{value}}\n",
			amd:      "define( function() {\n\n"+options.indention+"return {{{vars}}"+options.indention+"}\n\n} );\n",
			js:       "var {{name}} = {{vars}};\n"
		};

		// Normalize user input
		options.dest = normalizeOutArray( options.dest );
		options.jsFormat = normalizeFormat( options.jsFormat );
		options.cssFormat = normalizeFormat( options.cssFormat );

		// ================
		// -- GENERATORS --
		// ================

		// Generate Style files
		function generateStyle( data, type ) {
			var content = "";
			var pattern = outputPattern[ type ];

			function resolveNested( data, parentKey ) {
				var name, key;
				for ( key in data ) {
					name = parentKey ? format( parentKey + "-" + key, options.cssFormat ) : format( key, options.cssFormat );

					if ( mout.lang.isObject( data[ key ] ) ) {

						resolveNested( data[ key ], name );

					} else {

						var value = getStyleSafeValue( data[ key ] );

						content += pattern.replace( "{{key}}", name ).replace( "{{value}}", value );
					}
				}
			}

			resolveNested( data );

			return content;
		}

		// Generate JavaScript files
		function generateJS( data, type ) {
			var preparedData = prepareValues( data );
			var content = JSON.stringify( preparedData, null, options.indention );

			return outputPattern.js.replace( "{{name}}", options.name ).replace( "{{vars}}", content );
		}

		function generateAMD( data ) {
			var preparedData = prepareValues( data );
			var content = JSON.stringify( preparedData, null, options.indention );
			var pattern = mout.lang.deepClone( outputPattern.amd );

			content = content.substr( 1, content.length - 2 );
			content = indent( content, options.indention );

			return pattern.replace( "{{vars}}", content );
		}

		function generateSassMaps( data ) {
			var pattern = outputPattern["sassmaps"];

			function generateSassMapsRecursive( data ) {
				var key;
				var currentItem = "";
				var first = true;
				var sassMapStr;
				var currentValue;

				for ( key in data ) {

					if ( mout.lang.isObject( data[ key ] ) ) {
						currentValue = generateSassMapsRecursive( data[ key ] );
					} else {
						currentValue = getStyleSafeValue( data[ key ] );
					}

					currentItem = pattern.replace( "{{key}}", key ).replace( "{{value}}", currentValue );

					if ( first ) {
						sassMapStr = indent("\n" + currentItem, options.indention);
						first = false;
					} else {
						sassMapStr = sassMapStr + indent("\n" + currentItem, options.indention);
					}

					// remove last comma before closing map
					sassMapStr = sassMapStr.replace( ",\n" + options.indention + ")", "\n" + options.indention + ")" );
				}

				// the slice removes the last comma
				return "(" + sassMapStr.slice( 0, -1 ) + "\n)";
			}
			return "$" + options.name + ": " + generateSassMapsRecursive( data ).replace( /,\)/g , ")" ) + ";";

		}

		function prepareValues( data ) {
			var newData = {};

			function updateValues( object, newData ) {
				for ( var key in object ) {
					var value = object[ key ];

					if ( mout.lang.isObject( value ) ) {

						var newKey = format( key, options.jsFormat );

						newData[ newKey ] = {};
						updateValues( value, newData[ newKey ] );

						continue;

					} else if ( mout.string.endsWith( value, "%" ) ) {

						value = parseInt( value, 10 ) / 100;

					} else if ( isStringNumber( value ) ) {

						value = parseInt( value, 10 );

					}

					newData[ format( key, options.jsFormat ) ] = value;
				}
			}

			updateValues( data, newData );

			return newData;
		}

		function indent( content, indention ) {
			content = content.replace( /\n/g, "\n" + indention );

			while ( mout.string.endsWith( content, options.indention ) ) {
				content = content.substr( 0, content.length - 1 );
			}

			return content;
		}

		function maskObject( src, mask, allowUnknownOnFirstLevel ) {
			var result = {};

			// check for every key in src, if it should end up in the result
			for ( var key in src ) {
				// if this property is in the mask too, check that
				if ( mask.hasOwnProperty( key ) ) {
					// if this mask is an object, send it through maskObject again
					if ( typeof mask[ key ] === 'object' ) {
						// we allow to include unknown objects only on the root level
						// on every other level, you can just use "allowAll"
						result[ key ] = maskObject( src[ key ], mask[ key ], false );
					} else {
						switch ( mask[ key ] ) {
							case true:
								if ( typeof src[ key ] === 'object' ) {
									// this is the case, if we have an object in the src, but only true in the mask
									// in this case, we only allow one level of the src in the result
									var subResult = {};
									for ( var subKey in src[ key ] ) {
										//only add it to result if it's not an object
										if ( typeof src[ key ][ subKey ] !== 'object' ) {
											subResult[ subKey ] = src[ key ][ subKey ];
										}
									}
									result[ key ] = subResult;
								} else {
									result[ key ] = src[ key ];
								}
								break;
							case 'allowAll':
								result[ key ] = src[ key ];
								break;
						}
					}
				// otherwise we only include it, if other first level object should end up in the result
				} else if (allowUnknownOnFirstLevel) {
					result[ key ] = src[ key ];
				}
			}
			return result;
		}

		// ===================
		// -- SHARED CONFIG --
		// ===================

		this.files.forEach( function( file ) {

			var srcConfig = {};
			var destinationFiles = normalizeOutArray( file.dest );

			file.src.filter( fileExists ).map( function( filePath ) {

				var src = readFile( filePath );

				// mask
				var mask = null;
				// if maskFile is given, read it in
				if ( typeof options.maskFile !== "undefined" && fileExists( options.maskFile ) ) {
					mask = readFile( options.maskFile );
				}
				// if mask object is given, merge it with the mask from file if any
				if ( typeof options.mask !== "undefined" && mout.lang.isObject( options.mask )) {
					if ( mask !== null ) {
						mask = mout.object.deepMixIn( mask, options.mask );
					} else {
						mask = options.mask;
					}
				}
				// if this results in a mask, apply it
				if ( mask !== null ) {
					src = maskObject( src, mask, options.maskAllowUnknownOnFirstLevel );
					var a = 1;
					//src = removeEmptyObjects( src );
				}

				// add configuration vars to main config
				mout.object.deepMixIn( srcConfig, src );

			} );

			destinationFiles.map( function( filePath ) {

				var fileType = filePath.split( "." ).pop().toLowerCase();
				var output, generator;

				// search for the correct generator by filetype
				if ( fileType === "scss" && options.useSassMaps) {

					generator = generateSassMaps;

				} else if ( mout.array.contains( fileExtensions.css, fileType ) ) {

					generator = generateStyle;

				} else if ( mout.array.contains( fileExtensions.js, fileType ) ) {

					generator = options.amd ? generateAMD : generateJS;

				} else {
					grunt.log.warn( "Unknown filetype (" + fileType + ")." );
					return false;
				}

				// generate and save output
				output = generator.apply( null, [ srcConfig, fileType ] );
				grunt.file.write( filePath, output );

				grunt.log.ok( "File: " + filePath + " created." );
			} );

		} );

	} );

};
<commit_msg>dont proceed to generator if src is empty<commit_after>/*
 * grunt-shared-config
 *
 * Use this task to create multiple config files for JS/JS-AMD, SCSS/SASS/LESS/stylus from one JSON/YAML.
 *
 * Copyright (c) 2013 Mathias Paumgarten
 * Licensed under the MIT license.
 */

"use strict";

var mout = require( "mout" );

module.exports = function( grunt ) {

	grunt.registerMultiTask( "shared_config", "Your task description goes here.", function() {

		// ===========
		// -- UTILS --
		// ===========

		function normalizeOutArray( value ) {
			return typeof value === "string" ? [ value ] : value;
		}

		function normalizeFormat( value ) {
			return mout.array.contains( varFormats, value ) ? value : varFormats[ 0 ];
		}

		function format( value, type ) {
			value = value.replace( /-/g, " " );

			switch ( type ) {
				case "underscore":
					return mout.string.underscore( value );
				case "uppercase":
					return value.toUpperCase().replace( / /g, "_" );
				case "dash":
					return mout.string.hyphenate( value );
				default:
					return mout.string.camelCase( value );
			}
		}

		function fileExists( filePath ) {
			if ( !grunt.file.exists( filePath ) ) {
				grunt.log.warn( "Source file (" + filePath + ") not found." );
				return false;
			}
			return true;
		}

		function readFile( filePath ) {
			// fetch JSON or YAML from file
			var fileType = filePath.split( "." ).pop().toLowerCase();
			var src;
			if ( fileType === 'yml' || fileType === 'yaml' ) {
				src = grunt.file.readYAML( filePath );
			} else {
				src = grunt.file.readJSON( filePath );
			}
			return src;
		}

		function isStringNumber( value ) {
			var units = [ "em", "px", "s", "in", "mm", "cm", "pt", "pc", "%" ];

			return units.reduce( function( previous, current ) {
				return previous || mout.string.endsWith( value, current );
			}, false );
		}

		function getStyleSafeValue( value ) {
			if ( ! isStringNumber( value ) && value[ 0 ] !== "#" ) {
				value = "\"" + value + "\"";
			}
			return value;
		}

		// ==============
		// -- SETTINGS --
		// ==============

		// default options
		var options = this.options( {
			amd: false,
			jsFormat: "uppercase",
			cssFormat: "dash",
			name: "config",
			useSassMaps: false,
			indention: "\t",
			mask: undefined,
			maskFile: undefined,
			maskAllowUnknownOnFirstLevel: false,
		} );

		// possible variable formats
		var varFormats = [ "underscore", "uppercase", "dash", "camelcase" ];

		// available file extensions
		var fileExtensions = {
			js: [ "js" ],
			css: [ "scss", "sass", "less", "styl" ]
		};

		// variable patterns
		var outputPattern = {
			scss:     "${{key}}: {{value}};\n",
			sass:     "${{key}}: {{value}}\n",
			less:     "@{{key}}: {{value}};\n",
			sassmaps: "{{key}}: {{value}},",
			styl:     "{{key}} = {{value}}\n",
			amd:      "define( function() {\n\n"+options.indention+"return {{{vars}}"+options.indention+"}\n\n} );\n",
			js:       "var {{name}} = {{vars}};\n"
		};

		// Normalize user input
		options.dest = normalizeOutArray( options.dest );
		options.jsFormat = normalizeFormat( options.jsFormat );
		options.cssFormat = normalizeFormat( options.cssFormat );

		// ================
		// -- GENERATORS --
		// ================

		// Generate Style files
		function generateStyle( data, type ) {
			var content = "";
			var pattern = outputPattern[ type ];

			function resolveNested( data, parentKey ) {
				var name, key;
				for ( key in data ) {
					name = parentKey ? format( parentKey + "-" + key, options.cssFormat ) : format( key, options.cssFormat );

					if ( mout.lang.isObject( data[ key ] ) ) {

						resolveNested( data[ key ], name );

					} else {

						var value = getStyleSafeValue( data[ key ] );

						content += pattern.replace( "{{key}}", name ).replace( "{{value}}", value );
					}
				}
			}

			resolveNested( data );

			return content;
		}

		// Generate JavaScript files
		function generateJS( data, type ) {
			var preparedData = prepareValues( data );
			var content = JSON.stringify( preparedData, null, options.indention );

			return outputPattern.js.replace( "{{name}}", options.name ).replace( "{{vars}}", content );
		}

		function generateAMD( data ) {
			var preparedData = prepareValues( data );
			var content = JSON.stringify( preparedData, null, options.indention );
			var pattern = mout.lang.deepClone( outputPattern.amd );

			content = content.substr( 1, content.length - 2 );
			content = indent( content, options.indention );

			return pattern.replace( "{{vars}}", content );
		}

		function generateSassMaps( data ) {
			var pattern = outputPattern["sassmaps"];

			function generateSassMapsRecursive( data ) {
				var key;
				var currentItem = "";
				var first = true;
				var sassMapStr;
				var currentValue;

				for ( key in data ) {

					if ( mout.lang.isObject( data[ key ] ) ) {
						currentValue = generateSassMapsRecursive( data[ key ] );
					} else {
						currentValue = getStyleSafeValue( data[ key ] );
					}

					currentItem = pattern.replace( "{{key}}", key ).replace( "{{value}}", currentValue );

					if ( first ) {
						sassMapStr = indent("\n" + currentItem, options.indention);
						first = false;
					} else {
						sassMapStr = sassMapStr + indent("\n" + currentItem, options.indention);
					}

					// remove last comma before closing map
					sassMapStr = sassMapStr.replace( ",\n" + options.indention + ")", "\n" + options.indention + ")" );
				}

				// the slice removes the last comma
				return "(" + sassMapStr.slice( 0, -1 ) + "\n)";
			}
			return "$" + options.name + ": " + generateSassMapsRecursive( data ).replace( /,\)/g , ")" ) + ";";

		}

		function prepareValues( data ) {
			var newData = {};

			function updateValues( object, newData ) {
				for ( var key in object ) {
					var value = object[ key ];

					if ( mout.lang.isObject( value ) ) {

						var newKey = format( key, options.jsFormat );

						newData[ newKey ] = {};
						updateValues( value, newData[ newKey ] );

						continue;

					} else if ( mout.string.endsWith( value, "%" ) ) {

						value = parseInt( value, 10 ) / 100;

					} else if ( isStringNumber( value ) ) {

						value = parseInt( value, 10 );

					}

					newData[ format( key, options.jsFormat ) ] = value;
				}
			}

			updateValues( data, newData );

			return newData;
		}

		function indent( content, indention ) {
			content = content.replace( /\n/g, "\n" + indention );

			while ( mout.string.endsWith( content, options.indention ) ) {
				content = content.substr( 0, content.length - 1 );
			}

			return content;
		}

		function maskObject( src, mask, allowUnknownOnFirstLevel ) {
			var result = {};

			// check for every key in src, if it should end up in the result
			for ( var key in src ) {
				// if this property is in the mask too, check that
				if ( mask.hasOwnProperty( key ) ) {
					// if this mask is an object, send it through maskObject again
					if ( typeof mask[ key ] === 'object' ) {
						// we allow to include unknown objects only on the root level
						// on every other level, you can just use "allowAll"
						result[ key ] = maskObject( src[ key ], mask[ key ], false );
					} else {
						switch ( mask[ key ] ) {
							case true:
								if ( typeof src[ key ] === 'object' ) {
									// this is the case, if we have an object in the src, but only true in the mask
									// in this case, we only allow one level of the src in the result
									var subResult = {};
									for ( var subKey in src[ key ] ) {
										//only add it to result if it's not an object
										if ( typeof src[ key ][ subKey ] !== 'object' ) {
											subResult[ subKey ] = src[ key ][ subKey ];
										}
									}
									result[ key ] = subResult;
								} else {
									result[ key ] = src[ key ];
								}
								break;
							case 'allowAll':
								result[ key ] = src[ key ];
								break;
						}
					}
				// otherwise we only include it, if other first level object should end up in the result
				} else if (allowUnknownOnFirstLevel) {
					result[ key ] = src[ key ];
				}
			}
			return result;
		}

		// ===================
		// -- SHARED CONFIG --
		// ===================

		this.files.forEach( function( file ) {

			var srcConfig = {};
			var destinationFiles = normalizeOutArray( file.dest );

			file.src.filter( fileExists ).map( function( filePath ) {

				var src = readFile( filePath );

				// mask
				var mask = null;
				// if maskFile is given, read it in
				if ( typeof options.maskFile !== "undefined" && fileExists( options.maskFile ) ) {
					mask = readFile( options.maskFile );
				}
				// if mask object is given, merge it with the mask from file if any
				if ( typeof options.mask !== "undefined" && mout.lang.isObject( options.mask )) {
					if ( mask !== null ) {
						mask = mout.object.deepMixIn( mask, options.mask );
					} else {
						mask = options.mask;
					}
				}
				// if this results in a mask, apply it
				if ( mask !== null ) {
					src = maskObject( src, mask, options.maskAllowUnknownOnFirstLevel );
					var a = 1;
					//src = removeEmptyObjects( src );
				}

				// add configuration vars to main config
				mout.object.deepMixIn( srcConfig, src );

			} );

			if ( Object.keys( srcConfig ).length === 0 ) {
				grunt.log.warn( "Empty src results in no output" );
				return false;
			}

			destinationFiles.map( function( filePath ) {

				var fileType = filePath.split( "." ).pop().toLowerCase();
				var output, generator;

				// search for the correct generator by filetype
				if ( fileType === "scss" && options.useSassMaps) {

					generator = generateSassMaps;

				} else if ( mout.array.contains( fileExtensions.css, fileType ) ) {

					generator = generateStyle;

				} else if ( mout.array.contains( fileExtensions.js, fileType ) ) {

					generator = options.amd ? generateAMD : generateJS;

				} else {
					grunt.log.warn( "Unknown filetype (" + fileType + ")." );
					return false;
				}

				// generate and save output
				output = generator.apply( null, [ srcConfig, fileType ] );
				grunt.file.write( filePath, output );

				grunt.log.ok( "File: " + filePath + " created." );
			} );

		} );

	} );

};
<|endoftext|>


<commit_before>let base = require('./')

module.exports = {
  ...base,
  plugins: [...base.plugins, '@typescript-eslint'],
  overrides: [
    ...base.overrides,
    {
      files: ['*.ts', '*.tsx'],
      parser: '@typescript-eslint/parser',
      parserOptions: {
        tsconfigRootDir: process.cwd(),
        project: ['./tsconfig.json']
      },
      rules: {
        '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
        '@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
        '@typescript-eslint/no-unnecessary-type-assertion': 'error',
        '@typescript-eslint/adjacent-overload-signatures': 'error',
        '@typescript-eslint/no-confusing-void-expression': 'error',
        '@typescript-eslint/lines-between-class-members': [
          'error',
          'always',
          {
            exceptAfterSingleLine: true
          }
        ],
        '@typescript-eslint/space-before-function-paren': ['error', 'always'],
        '@typescript-eslint/prefer-namespace-keyword': 'error',
        '@typescript-eslint/no-unnecessary-condition': 'error',
        '@typescript-eslint/type-annotation-spacing': 'error',
        '@typescript-eslint/member-delimiter-style': [
          'error',
          {
            multiline: {
              delimiter: 'none'
            },
            singleline: {
              delimiter: 'semi'
            }
          }
        ],
        '@typescript-eslint/restrict-plus-operands': 'error',
        '@typescript-eslint/no-useless-constructor': 'error',
        '@typescript-eslint/prefer-optional-chain': 'error',
        '@typescript-eslint/no-dupe-class-members': 'error',
        '@typescript-eslint/no-use-before-define': [
          'error',
          {
            functions: false,
            classes: false,
            variables: false
          }
        ],
        '@typescript-eslint/object-curly-spacing': ['error', 'always'],
        '@typescript-eslint/no-empty-interface': 'error',
        '@typescript-eslint/unified-signatures': 'error',
        '@typescript-eslint/func-call-spacing': ['error', 'never'],
        '@typescript-eslint/no-invalid-this': 'error',
        '@typescript-eslint/no-for-in-array': 'error',
        '@typescript-eslint/no-var-requires': 'error',
        '@typescript-eslint/no-explicit-any': 'error',
        '@typescript-eslint/await-thenable': 'error',
        '@typescript-eslint/no-unused-vars': 'error',
        '@typescript-eslint/no-redeclare': 'error',
        '@typescript-eslint/dot-notation': [
          'error',
          {
            allowKeywords: true
          }
        ],
        '@typescript-eslint/no-unused-expressions': [
          'error',
          {
            allowShortCircuit: true,
            allowTernary: true,
            allowTaggedTemplates: true
          }
        ],
        '@typescript-eslint/array-type': 'error',

        'import/extensions': ['error', 'always', { ignorePackages: true }],

        'lines-between-class-members': 'off',
        'no-useless-constructor': 'off',
        'no-unused-expressions': 'off',
        'no-dupe-class-members': 'off',
        'no-use-before-define': 'off',
        'object-curly-spacing': 'off',
        'func-callspacing': 'off',
        'no-invalid-this': 'off',
        'no-unused-vars': 'off',
        'no-redeclare': 'off',
        'dot-notation': 'off'
      }
    },
    {
      files: '*.test.{ts,tsx}',
      rules: {
        '@typescript-eslint/no-unused-expressions': 'off',
        '@typescript-eslint/no-explicit-any': 'off'
      }
    },
    {
      files: '*.d.ts',
      rules: {
        'unicorn/custom-error-definition': 'off'
      }
    }
  ]
}
<commit_msg>Disable no-undef for TS<commit_after>let base = require('./')

module.exports = {
  ...base,
  plugins: [...base.plugins, '@typescript-eslint'],
  overrides: [
    ...base.overrides,
    {
      files: ['*.ts', '*.tsx'],
      parser: '@typescript-eslint/parser',
      parserOptions: {
        tsconfigRootDir: process.cwd(),
        project: ['./tsconfig.json']
      },
      rules: {
        '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
        '@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
        '@typescript-eslint/no-unnecessary-type-assertion': 'error',
        '@typescript-eslint/adjacent-overload-signatures': 'error',
        '@typescript-eslint/no-confusing-void-expression': 'error',
        '@typescript-eslint/lines-between-class-members': [
          'error',
          'always',
          {
            exceptAfterSingleLine: true
          }
        ],
        '@typescript-eslint/space-before-function-paren': ['error', 'always'],
        '@typescript-eslint/prefer-namespace-keyword': 'error',
        '@typescript-eslint/no-unnecessary-condition': 'error',
        '@typescript-eslint/type-annotation-spacing': 'error',
        '@typescript-eslint/member-delimiter-style': [
          'error',
          {
            multiline: {
              delimiter: 'none'
            },
            singleline: {
              delimiter: 'semi'
            }
          }
        ],
        '@typescript-eslint/restrict-plus-operands': 'error',
        '@typescript-eslint/no-useless-constructor': 'error',
        '@typescript-eslint/prefer-optional-chain': 'error',
        '@typescript-eslint/no-dupe-class-members': 'error',
        '@typescript-eslint/no-use-before-define': [
          'error',
          {
            functions: false,
            classes: false,
            variables: false
          }
        ],
        '@typescript-eslint/object-curly-spacing': ['error', 'always'],
        '@typescript-eslint/no-empty-interface': 'error',
        '@typescript-eslint/unified-signatures': 'error',
        '@typescript-eslint/func-call-spacing': ['error', 'never'],
        '@typescript-eslint/no-invalid-this': 'error',
        '@typescript-eslint/no-for-in-array': 'error',
        '@typescript-eslint/no-var-requires': 'error',
        '@typescript-eslint/no-explicit-any': 'error',
        '@typescript-eslint/await-thenable': 'error',
        '@typescript-eslint/no-unused-vars': 'error',
        '@typescript-eslint/no-redeclare': 'error',
        '@typescript-eslint/dot-notation': [
          'error',
          {
            allowKeywords: true
          }
        ],
        '@typescript-eslint/no-unused-expressions': [
          'error',
          {
            allowShortCircuit: true,
            allowTernary: true,
            allowTaggedTemplates: true
          }
        ],
        '@typescript-eslint/array-type': 'error',

        'import/extensions': ['error', 'always', { ignorePackages: true }],

        'lines-between-class-members': 'off',
        'no-useless-constructor': 'off',
        'no-unused-expressions': 'off',
        'no-dupe-class-members': 'off',
        'no-use-before-define': 'off',
        'object-curly-spacing': 'off',
        'func-callspacing': 'off',
        'no-invalid-this': 'off',
        'no-unused-vars': 'off',
        'no-redeclare': 'off',
        'dot-notation': 'off',
        'no-undef': 'off'
      }
    },
    {
      files: '*.test.{ts,tsx}',
      rules: {
        '@typescript-eslint/no-unused-expressions': 'off',
        '@typescript-eslint/no-explicit-any': 'off'
      }
    },
    {
      files: '*.d.ts',
      rules: {
        'unicorn/custom-error-definition': 'off'
      }
    }
  ]
}
<|endoftext|>