<commit_before>'use strict';

angular.module('deckApp')
  .factory('loadBalancerService', function (searchService, settings, $q, Restangular, _) {

    var oortEndpoint = Restangular.withConfig(function (RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl(settings.oortUrl);
    });

    function loadLoadBalancersByApplicationName(applicationName) {
      return searchService.search('oort', {q: applicationName, type: 'loadBalancers', pageSize: 10000}).then(function(searchResults) {
        return _.filter(searchResults.results, { application: applicationName });
      });
    }

    function loadLoadBalancers(application, loadBalancersByApplicationName) {
        var loadBalancerNames = _.pluck(loadBalancersByApplicationName, 'loadBalancer'),
          loadBalancerPromises = [];

        application.accounts.forEach(function(account) {
          var accountClusters = application.clusters[account] || [];
          accountClusters.forEach(function(cluster) {
            loadBalancerNames.push(cluster.loadBalancers);
          });
        });

        loadBalancerNames = _.unique(_.flatten(loadBalancerNames));
        loadBalancerNames.forEach(function(loadBalancer) {
          var loadBalancerPromise = getLoadBalancer(loadBalancer);
          loadBalancerPromises.push(loadBalancerPromise);
        });

        return $q.all(loadBalancerPromises).then(_.flatten);
    }

    function updateHealthCounts(loadBalancer) {
      var instances = loadBalancer.instances;
      loadBalancer.healthCounts = {
        upCount: instances.filter(function (instance) {
          return instance.healthStatus === 'Healthy';
        }).length,
        downCount: instances.filter(function (instance) {
          return instance.healthStatus === 'Unhealthy';
        }).length,
        unknownCount: instances.filter(function (instance) {
          return instance.healthStatus === 'Unknown';
        }).length
      };
    }

    function getLoadBalancer(name) {
      var promise = oortEndpoint.one('aws').one('loadBalancers', name).get();
      return promise.then(function(loadBalancerRollup) {
        if (angular.isUndefined(loadBalancerRollup)) { return []; }
        var loadBalancers = [];
        loadBalancerRollup.accounts.forEach(function (account) {
          account.regions.forEach(function (region) {
            region.loadBalancers.forEach(function (loadBalancer) {
              loadBalancer.account = account.name;
              loadBalancers.push(loadBalancer);
            });
          });
        });
        return loadBalancers;
      });
    }

    function normalizeLoadBalancersWithServerGroups(application) {
      application.loadBalancers.forEach(function(loadBalancer) {
        var serverGroups = application.serverGroups.filter(function(serverGroup) {
          return serverGroupIsInLoadBalancer(serverGroup, loadBalancer);
        });
        loadBalancer.serverGroups = serverGroups;
        loadBalancer.instances = _(serverGroups).filter({isDisabled: false}).collect('instances').flatten().valueOf();
        updateHealthCounts(loadBalancer);
      });
    }

    function serverGroupIsInLoadBalancer(serverGroup, loadBalancer) {
      if (serverGroup.region !== loadBalancer.region || loadBalancer.serverGroups.indexOf(serverGroup.name) === -1) {
        return false;
      }
      return true;
    }

    function convertLoadBalancerForEditing(loadBalancer) {
      var toEdit = {
        editMode: true,
        region: loadBalancer.region,
        credentials: loadBalancer.account,
        listeners: [],
        name: loadBalancer.name,
        regionZones: loadBalancer.availabilityZones
      };

      if (loadBalancer.elb) {
        var elb = loadBalancer.elb;

        toEdit.securityGroups = elb.securityGroups;
        toEdit.vpcId = elb.vpcid;

        if (elb.listenerDescriptions) {
          toEdit.listeners = elb.listenerDescriptions.map(function (description) {
            var listener = description.listener;
            return {
              internalProtocol: listener.instanceProtocol,
              internalPort: listener.instancePort,
              externalProtocol: listener.protocol,
              externalPort: listener.loadBalancerPort
            };
          });
        }

        if (elb.healthCheck && elb.healthCheck.target) {
          var healthCheck = loadBalancer.elb.healthCheck.target;
          var protocolIndex = healthCheck.indexOf(':'),
            pathIndex = healthCheck.indexOf('/');

          if (protocolIndex !== -1 && pathIndex !== -1) {
            toEdit.healthCheckProtocol = healthCheck.substring(0, protocolIndex);
            toEdit.healthCheckPort = healthCheck.substring(protocolIndex + 1, pathIndex);
            toEdit.healthCheckPath = healthCheck.substring(pathIndex);
            if (!isNaN(toEdit.healthCheckPort)) {
              toEdit.healthCheckPort = Number(toEdit.healthCheckPort);
            }
          }
        }
      }
      return toEdit;
    }

    function constructNewLoadBalancerTemplate() {
      return {
        credentials: null,
        vpcId: null,
        healthCheckProtocol: 'HTTPS',
        healthCheckPort: 7001,
        healthCheckPath: '/health',
        regionZones: [],
        securityGroups: [],
        listeners: [
          {
            internalProtocol: 'HTTP',
            internalPort: 7001,
            externalProtocol: 'HTTP',
            externalPort: 80
          }
        ]
      };
    }

    return {
      loadLoadBalancers: loadLoadBalancers,
      loadLoadBalancersByApplicationName: loadLoadBalancersByApplicationName,
      normalizeLoadBalancersWithServerGroups: normalizeLoadBalancersWithServerGroups,
      serverGroupIsInLoadBalancer: serverGroupIsInLoadBalancer,
      convertLoadBalancerForEditing: convertLoadBalancerForEditing,
      constructNewLoadBalancerTemplate: constructNewLoadBalancerTemplate
    };

  });
<commit_msg>marry load balancers to server groups<commit_after>'use strict';

angular.module('deckApp')
  .factory('loadBalancerService', function (searchService, settings, $q, Restangular, _) {

    var oortEndpoint = Restangular.withConfig(function (RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl(settings.oortUrl);
    });

    function loadLoadBalancersByApplicationName(applicationName) {
      return searchService.search('oort', {q: applicationName, type: 'loadBalancers', pageSize: 10000}).then(function(searchResults) {
        return _.filter(searchResults.results, { application: applicationName });
      });
    }

    function loadLoadBalancers(application, loadBalancersByApplicationName) {
        var loadBalancerNames = _.pluck(loadBalancersByApplicationName, 'loadBalancer'),
          loadBalancerPromises = [];

        application.accounts.forEach(function(account) {
          var accountClusters = application.clusters[account] || [];
          accountClusters.forEach(function(cluster) {
            loadBalancerNames.push(cluster.loadBalancers);
          });
        });

        loadBalancerNames = _.unique(_.flatten(loadBalancerNames));
        loadBalancerNames.forEach(function(loadBalancer) {
          var loadBalancerPromise = getLoadBalancer(loadBalancer);
          loadBalancerPromises.push(loadBalancerPromise);
        });

        return $q.all(loadBalancerPromises).then(_.flatten);
    }

    function updateHealthCounts(loadBalancer) {
      var instances = loadBalancer.instances;
      loadBalancer.healthCounts = {
        upCount: instances.filter(function (instance) {
          return instance.healthStatus === 'Healthy';
        }).length,
        downCount: instances.filter(function (instance) {
          return instance.healthStatus === 'Unhealthy';
        }).length,
        unknownCount: instances.filter(function (instance) {
          return instance.healthStatus === 'Unknown';
        }).length
      };
    }

    function getLoadBalancer(name) {
      var promise = oortEndpoint.one('aws').one('loadBalancers', name).get();
      return promise.then(function(loadBalancerRollup) {
        if (angular.isUndefined(loadBalancerRollup)) { return []; }
        var loadBalancers = [];
        loadBalancerRollup.accounts.forEach(function (account) {
          account.regions.forEach(function (region) {
            region.loadBalancers.forEach(function (loadBalancer) {
              loadBalancer.account = account.name;
              loadBalancers.push(loadBalancer);
            });
          });
        });
        return loadBalancers;
      });
    }

    function normalizeLoadBalancersWithServerGroups(application) {
      application.loadBalancers.forEach(function(loadBalancer) {
        var serverGroups = application.serverGroups.filter(function(serverGroup) {
          return serverGroupIsInLoadBalancer(serverGroup, loadBalancer);
        });
        loadBalancer.serverGroups = serverGroups;
        loadBalancer.instances = _(serverGroups).filter({isDisabled: false}).collect('instances').flatten().valueOf();
        updateHealthCounts(loadBalancer);
      });
    }

    function serverGroupIsInLoadBalancer(serverGroup, loadBalancer) {
      return serverGroup.account === loadBalancer.account &&
        serverGroup.region === loadBalancer.region &&
        serverGroup.asg && serverGroup.asg.loadBalancerNames.indexOf(loadBalancer.name) !== -1;
    }

    function convertLoadBalancerForEditing(loadBalancer) {
      var toEdit = {
        editMode: true,
        region: loadBalancer.region,
        credentials: loadBalancer.account,
        listeners: [],
        name: loadBalancer.name,
        regionZones: loadBalancer.availabilityZones
      };

      if (loadBalancer.elb) {
        var elb = loadBalancer.elb;

        toEdit.securityGroups = elb.securityGroups;
        toEdit.vpcId = elb.vpcid;

        if (elb.listenerDescriptions) {
          toEdit.listeners = elb.listenerDescriptions.map(function (description) {
            var listener = description.listener;
            return {
              internalProtocol: listener.instanceProtocol,
              internalPort: listener.instancePort,
              externalProtocol: listener.protocol,
              externalPort: listener.loadBalancerPort
            };
          });
        }

        if (elb.healthCheck && elb.healthCheck.target) {
          var healthCheck = loadBalancer.elb.healthCheck.target;
          var protocolIndex = healthCheck.indexOf(':'),
            pathIndex = healthCheck.indexOf('/');

          if (protocolIndex !== -1 && pathIndex !== -1) {
            toEdit.healthCheckProtocol = healthCheck.substring(0, protocolIndex);
            toEdit.healthCheckPort = healthCheck.substring(protocolIndex + 1, pathIndex);
            toEdit.healthCheckPath = healthCheck.substring(pathIndex);
            if (!isNaN(toEdit.healthCheckPort)) {
              toEdit.healthCheckPort = Number(toEdit.healthCheckPort);
            }
          }
        }
      }
      return toEdit;
    }

    function constructNewLoadBalancerTemplate() {
      return {
        credentials: null,
        vpcId: null,
        healthCheckProtocol: 'HTTPS',
        healthCheckPort: 7001,
        healthCheckPath: '/health',
        regionZones: [],
        securityGroups: [],
        listeners: [
          {
            internalProtocol: 'HTTP',
            internalPort: 7001,
            externalProtocol: 'HTTP',
            externalPort: 80
          }
        ]
      };
    }

    return {
      loadLoadBalancers: loadLoadBalancers,
      loadLoadBalancersByApplicationName: loadLoadBalancersByApplicationName,
      normalizeLoadBalancersWithServerGroups: normalizeLoadBalancersWithServerGroups,
      serverGroupIsInLoadBalancer: serverGroupIsInLoadBalancer,
      convertLoadBalancerForEditing: convertLoadBalancerForEditing,
      constructNewLoadBalancerTemplate: constructNewLoadBalancerTemplate
    };

  });
<|endoftext|>


<commit_before>/**
  The `DS.DateTransform` class is used to serialize and deserialize
  date attributes on Ember Data record objects. This transform is used
  when `date` is passed as the type parameter to the
  [DS.attr](../../data#method_attr) function.

  ```javascript
  var attr = DS.attr;
  App.Score = DS.Model.extend({
    value: attr('number'),
    player: DS.belongsTo('player'),
    date: attr('date')
  });
  ```

  @class DateTransform
  @extends DS.Transform
  @namespace DS
 */
import Transform from "ember-data/transforms/base";

// Date.prototype.toISOString shim
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
var toISOString = Date.prototype.toISOString || function() {
  function pad(number) {
    if ( number < 10 ) {
      return '0' + number;
    }
    return number;
  }

  return this.getUTCFullYear() +
    '-' + pad(this.getUTCMonth() + 1) +
    '-' + pad(this.getUTCDate()) +
    'T' + pad(this.getUTCHours()) +
    ':' + pad(this.getUTCMinutes()) +
    ':' + pad(this.getUTCSeconds()) +
    '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) +
    'Z';
};

if (Ember.SHIM_ES5) {
  if (!Date.prototype.toISOString) {
    Date.prototype.toISOString = toISOString;
  }
}

export default Transform.extend({
  deserialize: function(serialized) {
    var type = typeof serialized;

    if (type === "string") {
      return new Date(Ember.Date.parse(serialized));
    } else if (type === "number") {
      return new Date(serialized);
    } else if (serialized === null || serialized === undefined) {
      // if the value is not present in the data,
      // return undefined, not null.
      return serialized;
    } else {
      return null;
    }
  },

  serialize: function(date) {
    if (date instanceof Date) {
      return toISOString.call(date);
    } else {
      return null;
    }
  }
});
<commit_msg>Update comment to make its intention clear Closes #2726<commit_after>/**
  The `DS.DateTransform` class is used to serialize and deserialize
  date attributes on Ember Data record objects. This transform is used
  when `date` is passed as the type parameter to the
  [DS.attr](../../data#method_attr) function.

  ```javascript
  var attr = DS.attr;
  App.Score = DS.Model.extend({
    value: attr('number'),
    player: DS.belongsTo('player'),
    date: attr('date')
  });
  ```

  @class DateTransform
  @extends DS.Transform
  @namespace DS
 */
import Transform from "ember-data/transforms/base";

// Date.prototype.toISOString shim
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
var toISOString = Date.prototype.toISOString || function() {
  function pad(number) {
    if ( number < 10 ) {
      return '0' + number;
    }
    return number;
  }

  return this.getUTCFullYear() +
    '-' + pad(this.getUTCMonth() + 1) +
    '-' + pad(this.getUTCDate()) +
    'T' + pad(this.getUTCHours()) +
    ':' + pad(this.getUTCMinutes()) +
    ':' + pad(this.getUTCSeconds()) +
    '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) +
    'Z';
};

if (Ember.SHIM_ES5) {
  if (!Date.prototype.toISOString) {
    Date.prototype.toISOString = toISOString;
  }
}

export default Transform.extend({
  deserialize: function(serialized) {
    var type = typeof serialized;

    if (type === "string") {
      return new Date(Ember.Date.parse(serialized));
    } else if (type === "number") {
      return new Date(serialized);
    } else if (serialized === null || serialized === undefined) {
      // if the value is null return null
      // if the value is not present in the data return undefined
      return serialized;
    } else {
      return null;
    }
  },

  serialize: function(date) {
    if (date instanceof Date) {
      return toISOString.call(date);
    } else {
      return null;
    }
  }
});
<|endoftext|>


<commit_before>import {request} from 'tocco-util/src/rest'

const IGNORED_FIELD_TYPES = [
  'ch.tocco.nice2.model.form.components.simple.DescriptionField'
]

const defaultFormTransformer = json => (json.form)

export function fetchForm(formName, transformer = defaultFormTransformer) {
  return request(`forms/${formName}`, undefined, undefined, undefined, undefined, [404])
    .then(resp => resp.body || {})
    .then(json => transformer(json))
}

export const columnDefinitionTransformer = json => {
  const {form} = json

  const tableType = 'ch.tocco.nice2.model.form.components.table.Table'
  const columns = form.children.find(child => child.type === tableType)
    .children.filter(column => column.displayType !== 'HIDDEN')

  const isDisplayableType = child => {
    return child.type !== 'ch.tocco.nice2.model.form.components.action.Action'
      && !child.name.startsWith('custom:')
  }

  return columns.map(c => ({
    label: c.label,
    values: c.children.filter(isDisplayableType).map(child => ({name: child.name, type: child.type}))
  }))
}

export const searchFormTransformer = json => {
  const {form} = json

  if (!form) {
    return []
  }

  const fields = form.children[0].children

  return fields
    .filter(f => f.displayType !== 'HIDDEN')
    .map(f => ({
      name: f.name,
      type: f.type,
      displayType: f.displayType,
      label: f.label,
      useLabel: f.useLabel
    }))
}

export const getFieldsOfColumnDefinition = columnDefinition => {
  let fields = []

  columnDefinition
    .filter(column => !column.values.some(field => IGNORED_FIELD_TYPES.includes(field.type)))
    .forEach(column => {
      fields = fields.concat(column.values.map(field => field.name))
      fields = fields.concat(column.values.map(field => field.name))
    })

  return fields
}
<commit_msg>fix(entity-list): Remove duplicate line (added accidentally)<commit_after>import {request} from 'tocco-util/src/rest'

const IGNORED_FIELD_TYPES = [
  'ch.tocco.nice2.model.form.components.simple.DescriptionField'
]

const defaultFormTransformer = json => (json.form)

export function fetchForm(formName, transformer = defaultFormTransformer) {
  return request(`forms/${formName}`, undefined, undefined, undefined, undefined, [404])
    .then(resp => resp.body || {})
    .then(json => transformer(json))
}

export const columnDefinitionTransformer = json => {
  const {form} = json

  const tableType = 'ch.tocco.nice2.model.form.components.table.Table'
  const columns = form.children.find(child => child.type === tableType)
    .children.filter(column => column.displayType !== 'HIDDEN')

  const isDisplayableType = child => {
    return child.type !== 'ch.tocco.nice2.model.form.components.action.Action'
      && !child.name.startsWith('custom:')
  }

  return columns.map(c => ({
    label: c.label,
    values: c.children.filter(isDisplayableType).map(child => ({name: child.name, type: child.type}))
  }))
}

export const searchFormTransformer = json => {
  const {form} = json

  if (!form) {
    return []
  }

  const fields = form.children[0].children

  return fields
    .filter(f => f.displayType !== 'HIDDEN')
    .map(f => ({
      name: f.name,
      type: f.type,
      displayType: f.displayType,
      label: f.label,
      useLabel: f.useLabel
    }))
}

export const getFieldsOfColumnDefinition = columnDefinition => {
  let fields = []

  columnDefinition
    .filter(column => !column.values.some(field => IGNORED_FIELD_TYPES.includes(field.type)))
    .forEach(column => {
      fields = fields.concat(column.values.map(field => field.name))
    })

  return fields
}
<|endoftext|>


<commit_before>module.exports = {
  extends: ['prettier/@typescript-eslint'],
  plugins: ['@typescript-eslint'],
  parser: '@typescript-eslint/parser',
  settings: {
    'import/resolver': {
      typescript: {
        directory: process.cwd(),
        extensions: ['.js', '.ts', '.json'],
      },
    },
    'import/extensions': ['.js', '.ts'],
  },
  rules: {
    'spaced-comment': [
      'error',
      'always',
      {
        line: {
          exceptions: ['-', '+'],
          markers: ['=', '!', '/'], // space here to support sprockets directives
        },
        block: {
          exceptions: ['-', '+'],
          markers: ['=', '!'], // space here to support sprockets directives
          balanced: true,
        },
      },
    ],
    strict: 'off', // conflicts with typescript
    // https://github.com/benmosher/eslint-plugin-import
    'import/extensions': [
      'error',
      'always',
      {
        js: 'never',
        ts: 'never',
      },
    ],
    'import/no-named-as-default-member': 'off', // conflicts with typescript
    'import/no-named-as-default': 'off', // conflicts with typescript
    // https://github.com/nzakas/eslint-plugin-typescript
    '@typescript-eslint/adjacent-overload-signatures': 'error',
    '@typescript-eslint/array-type': 'error',
    '@typescript-eslint/ban-types': 'error',
    camelcase: 'off',
    '@typescript-eslint/camelcase': 'error',
    '@typescript-eslint/class-name-casing': 'error',
    '@typescript-eslint/explicit-function-return-type': 'warn',
    '@typescript-eslint/explicit-member-accessibility': 'error',
    indent: 'off',
    '@typescript-eslint/generic-type-naming': [
      'error',
      '^([TUKV]|T[A-Z][a-zA-Z]+)$',
    ],
    '@typescript-eslint/indent': 'error',
    '@typescript-eslint/interface-name-prefix': 'error',
    '@typescript-eslint/member-delimiter-style': 'error',
    '@typescript-eslint/member-naming': 'off',
    '@typescript-eslint/member-ordering': 'error',
    '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
    'no-array-constructor': 'off',
    '@typescript-eslint/no-array-constructor': 'error',
    '@typescript-eslint/no-empty-interface': 'error',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/no-extraneous-class': 'error',
    '@typescript-eslint/no-for-in-array': 'error',
    '@typescript-eslint/no-inferrable-types': 'error',
    '@typescript-eslint/no-misused-new': 'error',
    '@typescript-eslint/no-namespace': 'error',
    '@typescript-eslint/no-non-null-assertion': 'error',
    '@typescript-eslint/no-object-literal-type-assertion': 'error',
    '@typescript-eslint/no-parameter-properties': 'error',
    '@typescript-eslint/no-require-imports': 'off',
    '@typescript-eslint/no-this-alias': 'error',
    '@typescript-eslint/no-triple-slash-reference': 'error',
    '@typescript-eslint/no-type-alias': [
      'error',
      {
        allowAliases: 'always',
        allowCallbacks: 'always',
        allowLiterals: 'in-unions-and-intersections',
        allowMappedTypes: 'always',
      },
    ],
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unnecessary-type-assertion': 'error',
    '@typescript-eslint/no-unused-vars': 'warn',
    '@typescript-eslint/no-use-before-define': 'error',
    '@typescript-eslint/no-useless-constructor': 'error',
    '@typescript-eslint/no-var-requires': 'error',
    '@typescript-eslint/prefer-interface': 'error',
    '@typescript-eslint/prefer-namespace-keyword': 'error',
    '@typescript-eslint/promise-function-async': 'off',
    '@typescript-eslint/type-annotation-spacing': 'error',
    '@typescript-eslint/restrict-plus-operands': 'error',
  },
};
<commit_msg>fix(typescript): remove extending prettier config<commit_after>module.exports = {
  plugins: ['@typescript-eslint'],
  parser: '@typescript-eslint/parser',
  settings: {
    'import/resolver': {
      typescript: {
        directory: process.cwd(),
        extensions: ['.js', '.ts', '.json'],
      },
    },
    'import/extensions': ['.js', '.ts'],
  },
  rules: {
    'spaced-comment': [
      'error',
      'always',
      {
        line: {
          exceptions: ['-', '+'],
          markers: ['=', '!', '/'], // space here to support sprockets directives
        },
        block: {
          exceptions: ['-', '+'],
          markers: ['=', '!'], // space here to support sprockets directives
          balanced: true,
        },
      },
    ],
    strict: 'off', // conflicts with typescript
    // https://github.com/benmosher/eslint-plugin-import
    'import/extensions': [
      'error',
      'always',
      {
        js: 'never',
        ts: 'never',
      },
    ],
    'import/no-named-as-default-member': 'off', // conflicts with typescript
    'import/no-named-as-default': 'off', // conflicts with typescript
    // https://github.com/nzakas/eslint-plugin-typescript
    '@typescript-eslint/adjacent-overload-signatures': 'error',
    '@typescript-eslint/array-type': 'error',
    '@typescript-eslint/ban-types': 'error',
    camelcase: 'off',
    '@typescript-eslint/camelcase': 'error',
    '@typescript-eslint/class-name-casing': 'error',
    '@typescript-eslint/explicit-function-return-type': 'warn',
    '@typescript-eslint/explicit-member-accessibility': 'error',
    '@typescript-eslint/generic-type-naming': [
      'error',
      '^([TUKV]|T[A-Z][a-zA-Z]+)$',
    ],
    '@typescript-eslint/indent': 'off',
    '@typescript-eslint/interface-name-prefix': 'error',
    '@typescript-eslint/member-delimiter-style': 'off',
    '@typescript-eslint/member-naming': 'off',
    '@typescript-eslint/member-ordering': 'error',
    '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
    'no-array-constructor': 'off',
    '@typescript-eslint/no-array-constructor': 'error',
    '@typescript-eslint/no-empty-interface': 'error',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/no-extraneous-class': 'error',
    '@typescript-eslint/no-for-in-array': 'error',
    '@typescript-eslint/no-inferrable-types': 'error',
    '@typescript-eslint/no-misused-new': 'error',
    '@typescript-eslint/no-namespace': 'error',
    '@typescript-eslint/no-non-null-assertion': 'error',
    '@typescript-eslint/no-object-literal-type-assertion': 'error',
    '@typescript-eslint/no-parameter-properties': 'error',
    '@typescript-eslint/no-require-imports': 'off',
    '@typescript-eslint/no-this-alias': 'error',
    '@typescript-eslint/no-triple-slash-reference': 'error',
    '@typescript-eslint/no-type-alias': [
      'error',
      {
        allowAliases: 'always',
        allowCallbacks: 'always',
        allowLiterals: 'in-unions-and-intersections',
        allowMappedTypes: 'always',
      },
    ],
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unnecessary-type-assertion': 'error',
    '@typescript-eslint/no-unused-vars': 'warn',
    '@typescript-eslint/no-use-before-define': 'error',
    '@typescript-eslint/no-useless-constructor': 'error',
    '@typescript-eslint/no-var-requires': 'error',
    '@typescript-eslint/prefer-interface': 'error',
    '@typescript-eslint/prefer-namespace-keyword': 'error',
    '@typescript-eslint/promise-function-async': 'off',
    '@typescript-eslint/type-annotation-spacing': 'off',
    '@typescript-eslint/restrict-plus-operands': 'error',
  },
};
<|endoftext|>


<commit_before>'use strict';

var summarymarkerPrototype = require('../modules/runs-summary/prototypes/summarymarker.js');
var summaryMarkerBuilder = require('../modules/runs-summary/services/functions/summarymarkerbuilder.js');
var createSummary = require('../modules/runs-summary/services/functions/createsummary.js');
var totalDistanceCounter = require('../modules/runs-summary/services/functions/totaldistancecounter.js');
var factory = require('../../lib/custom/utils/object/factory.js');

exports.calculate =
  function calculate(runData) {
    var runCoords = runData.features[0].geometry.coordinates; // The run which contains an array of laps which each have an array of coordinates
    var totalDistance = 0; // keeps track of total distance (km) for all laps = the runs total distance
    var kmMarkers = []; // Marker points used for map
    var kmMarker = 1000; // used below in reduceData() to mark kms

    // these are used for calculating our pauses
    // it tells us what kmMarker the pauses were in
    var lapStart = [];
    var lapEnd = [];

    // loops over every lap. Each lap which contains an array of objects
    // that has coordinates and time
    // This creates the data for our summaries
    // (it outputs total distance, total times including pauses)
    runCoords.forEach(function(data) {

      // We're resaving the data into a format suitable with geolib so
      // that we can run calculations for distance
      var mappedData;
      var startOfLap;
      var endOfLap;

      // output [[ { longitude: -0.220693, latitude: 51.459465 }, { time: Tue Jun 24 2014 13:46:23 GMT+0100 (BST) } ]]
      mappedData = mapData(data);

      // ----- get the start of each lap ------ //
      // allows us to calculate pauses
      startOfLap = mappedData[0];
      var startOfEachLap = function startOfEachLap(start, marker) {
        return {
          meters : kmMarker,
          data : startOfLap,
        };
      };
      lapStart.push(startOfEachLap(startOfLap, kmMarker));

      // Reduces the mapped data down to return a total distance for each lap
      // Then adds this to the total distance in the parent scope
      // which counts the total distance for the run
      var revisedTotalDistance = totalDistanceCounter(mappedData, totalDistance, kmMarker, kmMarkers);
      totalDistance = revisedTotalDistance;

      // console.log(JSON.stringify(kmMarkers, null, 2));

      // ----- Updates the km marker ----- //
      // with output from totalDistanceCounter()
      kmMarker = setKmMarker(totalDistance);
      function setKmMarker(totalDistance) {
        var km = totalDistance / 1000;
        var result = isInt(km) ? km + 1 : Math.ceil(km);
        return result * 1000;
      }
      // checking if number is int - if so we use Math.ceil()
      // to push the number up to the next integer
      function isInt(n) {
         return n % 1 === 0;
      }

      // ----- get the end of each lap ------ //
      // allows us to calculate pauses
      endOfLap = mappedData[mappedData.length -1];
      var endOfEachLap = function endOfEachLap(endOfLap, kmMarker) {
        return {
          meters : kmMarker,
          data : endOfLap,
          rest : true
        };
      };
      lapEnd.push(endOfEachLap(endOfLap, kmMarker));

      function mapData(data) {
       return data.map(function(currentValue, index, array) {
          var result = [];
          result.push(
              { longitude: currentValue[0], latitude: currentValue[1] },
              { time: currentValue[3] }
          );
          return result;
        });
      } // mapData

    }); // forEach

    // Factory used to create new km summaries
    var kmSummaryFactory = function(props) {
      return factory(summarymarkerPrototype, props);
    };

    // create summaries - with pauses
    var summaryList = summaryMarkerBuilder(kmMarkers, lapStart, lapEnd, kmSummaryFactory, totalDistance);
    // console.log(JSON.stringify(summaryList, null, 2));

    // create summary
    var summary = createSummary(summaryList, totalDistance);

    return summary;
  }; // calculate
<commit_msg>Updated runs summary service. Refactored<commit_after>'use strict';

var summarymarkerPrototype = require('../modules/runs-summary/prototypes/summarymarker.js');
var summaryMarkerBuilder = require('../modules/runs-summary/services/functions/summarymarkerbuilder.js');
var createSummary = require('../modules/runs-summary/services/functions/createsummary.js');
var totalDistanceCounter = require('../modules/runs-summary/services/functions/totaldistancecounter.js');
var factory = require('../../lib/custom/utils/object/factory.js');

var kmSummaryFactory;
var summaryList;
var summary;

// Used by calculate() to map data to a longitude and latitude
// format consistent with geolib
// output [[ { longitude: -0.220693, latitude: 51.459465 }, { time: Tue Jun 24 2014 13:46:23 GMT+0100 (BST) } ]]
var mapData = function mapData(data) {
  return data.map(function(currentValue, index, array) {
    var result = [];
    result.push(
        { longitude: currentValue[0], latitude: currentValue[1] },
        { time: currentValue[3] }
    );
    return result;
  });
}; // mapData

// record the start of each lap
var startOfEachLap = function startOfEachLap(startOfLap, kmMarker) {
  return {
    meters : kmMarker,
    data : startOfLap,
  };
}; // startOfEachLap

// increments the kmMarker
var setKmMarker = function setKmMarker(totalDistance) {
  // checking if number is int - if so we use Math.ceil()
  // to push the number up to the next integer
  var isInt = function isInt(n) {
     return n % 1 === 0;
  };
  var km = totalDistance / 1000;
  var result = isInt(km) ? km + 1 : Math.ceil(km);
  return result * 1000;
};

// records the end of lap
var endOfEachLap = function endOfEachLap(endOfLap, kmMarker) {
  return {
    meters : kmMarker,
    data : endOfLap,
    rest : true
  };
};

exports.calculate =
  function calculate(runData) {

    var run = {
      totalDistance : 0, // keeps track of total distance (km) for all laps = the runs total distance
      kmMarkers : [], // Marker points used for map
      lapStart : [], // these are used for calculating our pauses
      lapEnd : [] // it tells us what kmMarker the pauses were in
    };

    var kmMarker = 1000; // records count of kms as run is processed
    var mappedData;
    var startOfLap;
    var endOfLap;

    if(Array.isArray(runData.features)) {
      runData.features.forEach(function(feature) {
        var runCoords = feature.geometry.coordinates;

        // loops over every lap. Each lap which contains an array of objects
        // that has coordinates and time
        // This creates the data for our summaries
        // (it outputs total distance, total times including pauses)
        runCoords.forEach(function(data) {

          mappedData = mapData(data);

          // ----- get the start of each lap ----- //
          // allows us to calculate pauses
          startOfLap = mappedData[0];

          run.lapStart.push(startOfEachLap(startOfLap, kmMarker));

          // Reduces the mapped data down to return a total distance for each lap
          // Then adds this to the total distance in the parent scope
          // which counts the total distance for the run
          run.totalDistance = totalDistanceCounter(mappedData, run.totalDistance, kmMarker, run.kmMarkers);

          // ----- Updates the km marker ----- //
          // with output from totalDistanceCounter()
          kmMarker = setKmMarker(run.totalDistance);

          // ----- get the end of each lap ------ //
          // allows us to calculate pauses
          endOfLap = mappedData[mappedData.length -1];
          run.lapEnd.push(endOfEachLap(endOfLap, kmMarker));

        }); // runCoords.forEach

      }); //runData.features.forEach
    }

    // Factory used to create new km summaries
    kmSummaryFactory = function(props) {
      return factory(summarymarkerPrototype, props);
    };

    // create summaries - with pauses
    summaryList = summaryMarkerBuilder(run.kmMarkers, run.lapStart, run.lapEnd, kmSummaryFactory, run.totalDistance);

    // create summary
    summary = createSummary(summaryList, run.totalDistance);

    return summary;
  }; // calculate
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import { BrowserWindow, shell, ipcMain, dialog } from 'electron';
import windowStateKeeper from 'electron-window-state';
import helpers from './../../helpers/helpers';
import createMenu from './../menu/menu';
import initContextMenu from './../contextMenu/contextMenu';

const {
  isOSX, linkIsInternal, getCssToInject, shouldInjectCss, getAppIcon, nativeTabsSupported,
} = helpers;

const ZOOM_INTERVAL = 0.1;

function maybeHideWindow(window, event, fastQuit, tray) {
  if (isOSX() && !fastQuit) {
    // this is called when exiting from clicking the cross button on the window
    event.preventDefault();
    window.hide();
  } else if (!fastQuit && tray) {
    event.preventDefault();
    window.hide();
  }
  // will close the window on other platforms
}

function maybeInjectCss(browserWindow) {
  if (!shouldInjectCss()) {
    return;
  }

  const cssToInject = getCssToInject();

  const injectCss = () => {
    browserWindow.webContents.insertCSS(cssToInject);
  };

  browserWindow.webContents.on('did-finish-load', () => {
    // remove the injection of css the moment the page is loaded
    browserWindow.webContents.removeListener('did-get-response-details', injectCss);
  });

  // on every page navigation inject the css
  browserWindow.webContents.on('did-navigate', () => {
    // we have to inject the css in did-get-response-details to prevent the fouc
    // will run multiple times
    browserWindow.webContents.on('did-get-response-details', injectCss);
  });
}

/**
 *
 * @param {{}} inpOptions AppArgs from nativefier.json
 * @param {function} onAppQuit
 * @param {function} setDockBadge
 * @returns {electron.BrowserWindow}
 */
function createMainWindow(inpOptions, onAppQuit, setDockBadge) {
  const options = Object.assign({}, inpOptions);
  const mainWindowState = windowStateKeeper({
    defaultWidth: options.width || 1280,
    defaultHeight: options.height || 800,
  });

  const DEFAULT_WINDOW_OPTIONS = {
    // Convert dashes to spaces because on linux the app name is joined with dashes
    title: options.name,
    tabbingIdentifier: nativeTabsSupported() ? options.name : undefined,
    webPreferences: {
      javascript: true,
      plugins: true,
      // node globals causes problems with sites like messenger.com
      nodeIntegration: false,
      webSecurity: !options.insecure,
      preload: path.join(__dirname, 'static', 'preload.js'),
      zoomFactor: options.zoom,
    },
  };

  const mainWindow = new BrowserWindow(Object.assign({
    frame: !options.hideWindowFrame,
    width: mainWindowState.width,
    height: mainWindowState.height,
    minWidth: options.minWidth,
    minHeight: options.minHeight,
    maxWidth: options.maxWidth,
    maxHeight: options.maxHeight,
    x: options.x,
    y: options.y,
    autoHideMenuBar: !options.showMenuBar,
    // after webpack path here should reference `resources/app/`
    icon: getAppIcon(),
    // set to undefined and not false because explicitly setting to false will disable full screen
    fullscreen: options.fullScreen || undefined,
    // Whether the window should always stay on top of other windows. Default is false.
    alwaysOnTop: options.alwaysOnTop,
  }, DEFAULT_WINDOW_OPTIONS));

  mainWindowState.manage(mainWindow);

  // after first run, no longer force maximize to be true
  if (options.maximize) {
    mainWindow.maximize();
    options.maximize = undefined;
    fs.writeFileSync(path.join(__dirname, '..', 'nativefier.json'), JSON.stringify(options));
  }

  const withFocusedWindow = (block) => {
    const focusedWindow = BrowserWindow.getFocusedWindow();
    if (focusedWindow) { block(focusedWindow); }
  };

  const adjustWindowZoom = (window, adjustment) => {
    window.webContents.getZoomFactor((zoomFactor) => {
      window.webContents.setZoomFactor(zoomFactor + adjustment);
    });
  };

  const onZoomIn = () => {
    withFocusedWindow(focusedWindow => adjustWindowZoom(focusedWindow, ZOOM_INTERVAL));
  };

  const onZoomOut = () => {
    withFocusedWindow(focusedWindow => adjustWindowZoom(focusedWindow, -ZOOM_INTERVAL));
  };

  const onZoomReset = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.setZoomFactor(options.zoom);
    });
  };

  const clearAppData = () => {
    dialog.showMessageBox(mainWindow, {
      type: 'warning',
      buttons: ['Yes', 'Cancel'],
      defaultId: 1,
      title: 'Clear cache confirmation',
      message: 'This will clear all data (cookies, local storage etc) from this app. Are you sure you wish to proceed?',
    }, (response) => {
      if (response !== 0) {
        return;
      }
      const { session } = mainWindow.webContents;
      session.clearStorageData(() => {
        session.clearCache(() => {
          mainWindow.loadURL(options.targetUrl);
        });
      });
    });
  };

  const onGoBack = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.goBack();
    });
  };

  const onGoForward = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.goForward();
    });
  };

  const getCurrentUrl = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.getURL();
    });
  };

  let createNewWindow;

  const createNewTab = (url, foreground) => {
    withFocusedWindow((focusedWindow) => {
      const newTab = createNewWindow(url);
      focusedWindow.addTabbedWindow(newTab);
      if (!foreground) {
        focusedWindow.focus();
      }
      return newTab;
    });
    return undefined;
  };

  const onNewWindow = (event, urlToGo, _, disposition) => {
    event.preventDefault();
    if (nativeTabsSupported()) {
      if (disposition === 'background-tab') {
        createNewTab(urlToGo, false);
        return;
      } else if (disposition === 'foreground-tab') {
        createNewTab(urlToGo, true);
        return;
      }
    }
    if (!linkIsInternal(options.targetUrl, urlToGo, options.internalUrls)) {
      shell.openExternal(urlToGo);
      return;
    }
    // eslint-disable-next-line no-param-reassign
    event.guest = createNewWindow(urlToGo);
  };

  const sendParamsOnDidFinishLoad = (window) => {
    window.webContents.on('did-finish-load', () => {
      window.webContents.send('params', JSON.stringify(options));
    });
  };

  createNewWindow = (url) => {
    const window = new BrowserWindow(DEFAULT_WINDOW_OPTIONS);
    if (options.userAgent) {
      window.webContents.setUserAgent(options.userAgent);
    }
    maybeInjectCss(window);
    sendParamsOnDidFinishLoad(window);
    window.webContents.on('new-window', onNewWindow);
    window.loadURL(url);
    return window;
  };

  const menuOptions = {
    nativefierVersion: options.nativefierVersion,
    appQuit: onAppQuit,
    zoomIn: onZoomIn,
    zoomOut: onZoomOut,
    zoomReset: onZoomReset,
    zoomBuildTimeValue: options.zoom,
    goBack: onGoBack,
    goForward: onGoForward,
    getCurrentUrl,
    clearAppData,
    disableDevTools: options.disableDevTools,
  };

  createMenu(menuOptions);
  if (!options.disableContextMenu) {
    initContextMenu(createNewWindow, nativeTabsSupported() ? createNewTab : undefined);
  }

  if (options.userAgent) {
    mainWindow.webContents.setUserAgent(options.userAgent);
  }

  maybeInjectCss(mainWindow);
  sendParamsOnDidFinishLoad(mainWindow);

  if (options.counter) {
    mainWindow.on('page-title-updated', (e, title) => {
      const itemCountRegex = /[([{](\d*?)\+?[}\])]/;
      const match = itemCountRegex.exec(title);
      if (match) {
        setDockBadge(match[1], options.bounce);
      } else {
        setDockBadge('');
      }
    });
  } else {
    ipcMain.on('notification', () => {
      if (!isOSX() || mainWindow.isFocused()) {
        return;
      }
      setDockBadge('•', options.bounce);
    });
    mainWindow.on('focus', () => {
      setDockBadge('');
    });
  }

  mainWindow.webContents.on('new-window', onNewWindow);

  mainWindow.loadURL(options.targetUrl);

  mainWindow.on('new-tab', () => createNewTab(options.targetUrl, true));

  mainWindow.on('close', (event) => {
    if (mainWindow.isFullScreen()) {
      if (nativeTabsSupported()) {
        mainWindow.moveTabToNewWindow();
      }
      mainWindow.setFullScreen(false);
      mainWindow.once('leave-full-screen', maybeHideWindow.bind(this, mainWindow, event, options.fastQuit));
    }
    maybeHideWindow(mainWindow, event, options.fastQuit, options.tray);
  });

  return mainWindow;
}

export default createMainWindow;
<commit_msg>Fix Gmail complaining window creation was prevented by a popup blocker (PR #603)<commit_after>import fs from 'fs';
import path from 'path';
import { BrowserWindow, shell, ipcMain, dialog } from 'electron';
import windowStateKeeper from 'electron-window-state';
import helpers from './../../helpers/helpers';
import createMenu from './../menu/menu';
import initContextMenu from './../contextMenu/contextMenu';

const {
  isOSX, linkIsInternal, getCssToInject, shouldInjectCss, getAppIcon, nativeTabsSupported,
} = helpers;

const ZOOM_INTERVAL = 0.1;

function maybeHideWindow(window, event, fastQuit, tray) {
  if (isOSX() && !fastQuit) {
    // this is called when exiting from clicking the cross button on the window
    event.preventDefault();
    window.hide();
  } else if (!fastQuit && tray) {
    event.preventDefault();
    window.hide();
  }
  // will close the window on other platforms
}

function maybeInjectCss(browserWindow) {
  if (!shouldInjectCss()) {
    return;
  }

  const cssToInject = getCssToInject();

  const injectCss = () => {
    browserWindow.webContents.insertCSS(cssToInject);
  };

  browserWindow.webContents.on('did-finish-load', () => {
    // remove the injection of css the moment the page is loaded
    browserWindow.webContents.removeListener('did-get-response-details', injectCss);
  });

  // on every page navigation inject the css
  browserWindow.webContents.on('did-navigate', () => {
    // we have to inject the css in did-get-response-details to prevent the fouc
    // will run multiple times
    browserWindow.webContents.on('did-get-response-details', injectCss);
  });
}

/**
 *
 * @param {{}} inpOptions AppArgs from nativefier.json
 * @param {function} onAppQuit
 * @param {function} setDockBadge
 * @returns {electron.BrowserWindow}
 */
function createMainWindow(inpOptions, onAppQuit, setDockBadge) {
  const options = Object.assign({}, inpOptions);
  const mainWindowState = windowStateKeeper({
    defaultWidth: options.width || 1280,
    defaultHeight: options.height || 800,
  });

  const DEFAULT_WINDOW_OPTIONS = {
    // Convert dashes to spaces because on linux the app name is joined with dashes
    title: options.name,
    tabbingIdentifier: nativeTabsSupported() ? options.name : undefined,
    webPreferences: {
      javascript: true,
      plugins: true,
      // node globals causes problems with sites like messenger.com
      nodeIntegration: false,
      webSecurity: !options.insecure,
      preload: path.join(__dirname, 'static', 'preload.js'),
      zoomFactor: options.zoom,
    },
  };

  const mainWindow = new BrowserWindow(Object.assign({
    frame: !options.hideWindowFrame,
    width: mainWindowState.width,
    height: mainWindowState.height,
    minWidth: options.minWidth,
    minHeight: options.minHeight,
    maxWidth: options.maxWidth,
    maxHeight: options.maxHeight,
    x: options.x,
    y: options.y,
    autoHideMenuBar: !options.showMenuBar,
    // after webpack path here should reference `resources/app/`
    icon: getAppIcon(),
    // set to undefined and not false because explicitly setting to false will disable full screen
    fullscreen: options.fullScreen || undefined,
    // Whether the window should always stay on top of other windows. Default is false.
    alwaysOnTop: options.alwaysOnTop,
  }, DEFAULT_WINDOW_OPTIONS));

  mainWindowState.manage(mainWindow);

  // after first run, no longer force maximize to be true
  if (options.maximize) {
    mainWindow.maximize();
    options.maximize = undefined;
    fs.writeFileSync(path.join(__dirname, '..', 'nativefier.json'), JSON.stringify(options));
  }

  const withFocusedWindow = (block) => {
    const focusedWindow = BrowserWindow.getFocusedWindow();
    if (focusedWindow) { block(focusedWindow); }
  };

  const adjustWindowZoom = (window, adjustment) => {
    window.webContents.getZoomFactor((zoomFactor) => {
      window.webContents.setZoomFactor(zoomFactor + adjustment);
    });
  };

  const onZoomIn = () => {
    withFocusedWindow(focusedWindow => adjustWindowZoom(focusedWindow, ZOOM_INTERVAL));
  };

  const onZoomOut = () => {
    withFocusedWindow(focusedWindow => adjustWindowZoom(focusedWindow, -ZOOM_INTERVAL));
  };

  const onZoomReset = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.setZoomFactor(options.zoom);
    });
  };

  const clearAppData = () => {
    dialog.showMessageBox(mainWindow, {
      type: 'warning',
      buttons: ['Yes', 'Cancel'],
      defaultId: 1,
      title: 'Clear cache confirmation',
      message: 'This will clear all data (cookies, local storage etc) from this app. Are you sure you wish to proceed?',
    }, (response) => {
      if (response !== 0) {
        return;
      }
      const { session } = mainWindow.webContents;
      session.clearStorageData(() => {
        session.clearCache(() => {
          mainWindow.loadURL(options.targetUrl);
        });
      });
    });
  };

  const onGoBack = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.goBack();
    });
  };

  const onGoForward = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.goForward();
    });
  };

  const getCurrentUrl = () => {
    withFocusedWindow((focusedWindow) => {
      focusedWindow.webContents.getURL();
    });
  };

  let createNewWindow;

  const createNewTab = (url, foreground) => {
    withFocusedWindow((focusedWindow) => {
      const newTab = createNewWindow(url);
      focusedWindow.addTabbedWindow(newTab);
      if (!foreground) {
        focusedWindow.focus();
      }
      return newTab;
    });
    return undefined;
  };

  const onNewWindow = (event, urlToGo, _, disposition) => {
    event.preventDefault();
    if (nativeTabsSupported()) {
      if (disposition === 'background-tab') {
        createNewTab(urlToGo, false);
        return;
      } else if (disposition === 'foreground-tab') {
        createNewTab(urlToGo, true);
        return;
      }
    }
    if (!linkIsInternal(options.targetUrl, urlToGo, options.internalUrls)) {
      shell.openExternal(urlToGo);
      return;
    }
    // eslint-disable-next-line no-param-reassign
    event.newGuest = createNewWindow(urlToGo);
  };

  const sendParamsOnDidFinishLoad = (window) => {
    window.webContents.on('did-finish-load', () => {
      window.webContents.send('params', JSON.stringify(options));
    });
  };

  createNewWindow = (url) => {
    const window = new BrowserWindow(DEFAULT_WINDOW_OPTIONS);
    if (options.userAgent) {
      window.webContents.setUserAgent(options.userAgent);
    }
    maybeInjectCss(window);
    sendParamsOnDidFinishLoad(window);
    window.webContents.on('new-window', onNewWindow);
    window.loadURL(url);
    return window;
  };

  const menuOptions = {
    nativefierVersion: options.nativefierVersion,
    appQuit: onAppQuit,
    zoomIn: onZoomIn,
    zoomOut: onZoomOut,
    zoomReset: onZoomReset,
    zoomBuildTimeValue: options.zoom,
    goBack: onGoBack,
    goForward: onGoForward,
    getCurrentUrl,
    clearAppData,
    disableDevTools: options.disableDevTools,
  };

  createMenu(menuOptions);
  if (!options.disableContextMenu) {
    initContextMenu(createNewWindow, nativeTabsSupported() ? createNewTab : undefined);
  }

  if (options.userAgent) {
    mainWindow.webContents.setUserAgent(options.userAgent);
  }

  maybeInjectCss(mainWindow);
  sendParamsOnDidFinishLoad(mainWindow);

  if (options.counter) {
    mainWindow.on('page-title-updated', (e, title) => {
      const itemCountRegex = /[([{](\d*?)\+?[}\])]/;
      const match = itemCountRegex.exec(title);
      if (match) {
        setDockBadge(match[1], options.bounce);
      } else {
        setDockBadge('');
      }
    });
  } else {
    ipcMain.on('notification', () => {
      if (!isOSX() || mainWindow.isFocused()) {
        return;
      }
      setDockBadge('•', options.bounce);
    });
    mainWindow.on('focus', () => {
      setDockBadge('');
    });
  }

  mainWindow.webContents.on('new-window', onNewWindow);

  mainWindow.loadURL(options.targetUrl);

  mainWindow.on('new-tab', () => createNewTab(options.targetUrl, true));

  mainWindow.on('close', (event) => {
    if (mainWindow.isFullScreen()) {
      if (nativeTabsSupported()) {
        mainWindow.moveTabToNewWindow();
      }
      mainWindow.setFullScreen(false);
      mainWindow.once('leave-full-screen', maybeHideWindow.bind(this, mainWindow, event, options.fastQuit));
    }
    maybeHideWindow(mainWindow, event, options.fastQuit, options.tray);
  });

  return mainWindow;
}

export default createMainWindow;
<|endoftext|>


<commit_before>const Discord = require('discord.js');
const UserRecord = require('./UserRecord.js');
const SimpleMsg = require('./SimpleMessage.js');
const BST = require('./BST.js');
const LINE = require('@line/bot-sdk');
const fs = require('fs');

// imgur setup
const config = require('../config.json');
const request = require('request');

// LINE setup
const LINEclient = new LINE.Client({
  channelAccessToken: config.LINEchannelAccessToken
});

// Langex regex
const jpregex = /[\u3040-\u30FF]|[\uFF66-\uFF9D]|[\u4E00-\u9FAF]/;
const enregex = /[a-zA-Z]|[Ａ-ｖｘ-ｚ]/;

module.exports = class Server {
    constructor(guild) {
      this.guild = guild;
      this.hiddenChannels = [];
      this.users = {};
      this.deletedMessages = [];
      this.today = 0;
      this.watchedUsers = []; // surveillance
      this.newUsers = [];
      if (fs.existsSync(`./.${this.guild.id}_restore.json`)) {
        let json = JSON.parse(fs.readFileSync(`./.${this.guild.id}_restore.json`, 'utf8'));
        this.hiddenChannels = json['hiddenChannels'];
        this.today = json['today'];
        this.newUsers = json['newUsers'];
        for (var user in json['users']) {
          let uRec = json['users'][user]
          this.users[user] = new UserRecord(uRec['record'], uRec['thirty'],
            uRec['jp'], uRec['chans']); // TODO fix to new var names
        }
        for (var msg in json['deletedMessages']) {
          let dm = json['deletedMessages'][msg];
          this.deletedMessages.push(new SimpleMsg(dm.id, dm.del, dm.a, dm.atag, dm.aid, dm.apfp, dm.con, dm.acon, dm.ch, dm.chid, dm.time, dm.dur, dm.img));
        }
        this.watchedUsers = json['watchedUsers'];
        // for (var wu in json['watchedUsers']) {
          // Uncomment below for restoring them
          // let dms = json['watchedUsers'][wu];
          // for (var i in dms) {
          //   let dm = json['watchedUsers'][wu][i];
          //   this.watchedUsers[wu].push(new SimpleMsg(dm.id, dm.del, dm.a, dm.atag, dm.aid, dm.apfp, dm.con, dm.acon, dm.ch, dm.chid, dm.time, dm.dur, dm.img));
          // }
        //}
      }
    }

    hideChannel(channel) {
      if (this.hiddenChannels.includes(channel)) return;
      this.hiddenChannels.push(channel);
    }

    addMessage(message) {
      let author = message.author.id;
      let channel = message.channel.id;
      if (!this.users[author]) {
        this.users[author] = new UserRecord();
      }
      let userRec = this.users[author];
      userRec.add(message.content, channel, this.today);

      if (message.channel.id == '376574779316109313') this.checkLanEx(message); // Check language exchange.

      // Notify via LINE
      if (message.mentions.users.has(config.owner_ID) || message.mentions.roles.has('240647591770062848')) {
        this.guild.fetchMember(config.owner_ID)
          .then((member) => {
            if (member.presence.status != 'offline') return; // if I'm offline
            if (message.content.startsWith('t!')) return; // ignore tatsumaki
            const LINEmsg = [];
            LINEmsg.push({
              type: 'text',
              text: `${message.cleanContent}`
            });
            LINEmsg.push({
              type: 'text',
              text: `In #${message.channel.name} by ${message.author.username}`
            });
            LINEclient.pushMessage(config.LINEuserID, LINEmsg)
            .catch((err) => {
              throw new Error(err);
            });
          });
      }
    }

    checkLanEx(message) {
      var japanese = message.member.roles.has('196765998706196480');
      var jpCount = 0;
      var enCount = 0;
      var keepIgnoring = false;
      for (var l of message.content) {
        if (keepIgnoring) {
          if (l == '>') {
            keepIgnoring = false;
          } else {
            continue;
          }
        } else if (l == '<') {
          keepIgnoring = true;
          continue;
        }
        if (jpregex.test(l)) {
          jpCount++;
        } else if (enregex.test(l)) {
          enCount++;
        }
      }
      if ((japanese && jpCount > enCount) || (!japanese && enCount > jpCount)) {
        message.react('❌');
      }
    }

    addDeletedMessage(message) {
      let con = message.content;
      if (con.startsWith('.') || con.startsWith('t!') ||
        con.startsWith('!') || con.startsWith(':') ||
        con.startsWith('&') || con.startsWith(',')) return; // no bot messages
      var imageURL = '';
      if (message.attachments.size > 0) {
        imageURL = message.attachments.first().url;
        message.content += `\n{Attachment (expires soon): ${imageURL} }`;
      } else if (message.content.length < 3) {
        return;
      }
      let simple = new SimpleMsg(message);
      var arr;
      if (this.watchedUsers.includes(message.author.id)) {
        // arr = this.watchedUsers[message.author.id];
        if (imageURL != '') {
          // Use IMGUR
          var options = { method: 'POST',
            url: 'https://api.imgur.com/3/image',
            headers:
             {
               'cache-control': 'no-cache',
               authorization: `Bearer ${config.imgurAccessToken}`,
               'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' },
            formData: {image: imageURL, album: config.imgurAlbum } };
          request(options, function (error, response, body) {
            if (error) throw new Error(error);
            var ret = JSON.parse(body);
            simple.img =  ret.data.link;
          });
        }
        this.postLogs(simple);
      } else {
        arr = this.deletedMessages;
        // Move the next two outside of the brackets if you don't want to post.
        arr.push(simple);
        if (arr.length > 30) arr.shift();
      }
      if (message.mentions.members.size > 20) { // SPAM alert!
        let chan = this.guild.channels.get('366692441442615306'); // #mod_log
        if (chan == undefined) return;
        if (this.watchedUsers.includes(message.author.id)) {
          message.member.addRole(`259181555803619329`); // muted role
          chan.send(`**USER MUTED** ${message.author} has been muted. <@&240647591770062848> if this was a mistake, unmute them by removing the mute tag. If not, BAN THEM!`);
        } else {
          this.watchedUsers.push(message.author.id);
          chan.send(`**POSSIBLE SPAM ALERT** (deleting a message with 20+ mentions) by ${message.author} in ${message.channel} ! Automatically added to the watchlist`);
        }
      }
    }

    addEdits(oldMessage, newMessage) {
      if (this.watchedUsers.includes(oldMessage.author.id)) {
        let simple = new SimpleMsg(oldMessage);
        simple.del = false;
        simple.acon = newMessage.content;
        this.postLogs(simple);
        // Uncomment below for storing messages
        // this.watchedUsers[oldMessage.author.id].push(simple);
        // if (this.watchedUsers[oldMessage.author.id].length > 30) this.watchedUsers[oldMessage.author.id].shift();
      }
    }

    postLogs(msg) {
      let embed = new Discord.RichEmbed();
      let date = new Date(msg.time);
      embed.setAuthor(`${msg.atag} ID: ${msg.aid}` ,msg.apfp);
      if (msg.del) { // message was deleted
        embed.title = `Message Deleted after ${msg.dur} seconds`;
        embed.description = `${msg.con}`;
        embed.color = Number('0xDB3C3C');
      } else { // message was edited
        embed.title = `Message Edited after ${msg.dur} seconds`;
        embed.addField('Before:', `${msg.con}`, false);
        embed.addField('After:', `${msg.acon}`, false);
        embed.color = Number('0xff9933');
      }
      embed.setFooter(`#${msg.ch}`)
      embed.timestamp = date;
      if (msg.img) { // if != null
        embed.setImage(msg.img);
      }
      let chan = this.guild.channels.get('366692441442615306'); // #mod_log
      if (chan == undefined) return;
      chan.send({embed});
    }

    addNewUser(memberID) {
      if (this.newUsers.unshift(memberID) > 3) this.newUsers.pop();
    }

    save(backup = false) {
      // Store the actual date?
      if (backup) {
        var date = new Date().toLocaleDateString().replace(/\//g, '-');
        try {
          fs.writeFileSync(`./backups/${this.guild.id}_log-${date}.json`, JSON.stringify(this), 'utf8');
        } catch (e) {
          console.log(e);
        }
        console.log(`Backup has been created for ${this.guild.id}: ${date}`);
      } else {
        try {
          fs.writeFileSync(`./.${this.guild.id}_restore.json`, JSON.stringify(this), 'utf8');
        } catch (e) {
          console.log(e);
        }
        // console.log(`./.${this.guild.id}_restore.json has been updated`);
      }
    }
  }
<commit_msg>skip snowflake<commit_after>const Discord = require('discord.js');
const UserRecord = require('./UserRecord.js');
const SimpleMsg = require('./SimpleMessage.js');
const BST = require('./BST.js');
const LINE = require('@line/bot-sdk');
const fs = require('fs');

// imgur setup
const config = require('../config.json');
const request = require('request');

// LINE setup
const LINEclient = new LINE.Client({
  channelAccessToken: config.LINEchannelAccessToken
});

// Langex regex
const jpregex = /[\u3040-\u30FF]|[\uFF66-\uFF9D]|[\u4E00-\u9FAF]/;
const enregex = /[a-zA-Z]|[Ａ-ｖｘ-ｚ]/;

module.exports = class Server {
    constructor(guild) {
      this.guild = guild;
      this.hiddenChannels = [];
      this.users = {};
      this.deletedMessages = [];
      this.today = 0;
      this.watchedUsers = []; // surveillance
      this.newUsers = [];
      if (fs.existsSync(`./.${this.guild.id}_restore.json`)) {
        let json = JSON.parse(fs.readFileSync(`./.${this.guild.id}_restore.json`, 'utf8'));
        this.hiddenChannels = json['hiddenChannels'];
        this.today = json['today'];
        this.newUsers = json['newUsers'];
        for (var user in json['users']) {
          let uRec = json['users'][user]
          this.users[user] = new UserRecord(uRec['record'], uRec['thirty'],
            uRec['jp'], uRec['chans']); // TODO fix to new var names
        }
        for (var msg in json['deletedMessages']) {
          let dm = json['deletedMessages'][msg];
          this.deletedMessages.push(new SimpleMsg(dm.id, dm.del, dm.a, dm.atag, dm.aid, dm.apfp, dm.con, dm.acon, dm.ch, dm.chid, dm.time, dm.dur, dm.img));
        }
        this.watchedUsers = json['watchedUsers'];
        // for (var wu in json['watchedUsers']) {
          // Uncomment below for restoring them
          // let dms = json['watchedUsers'][wu];
          // for (var i in dms) {
          //   let dm = json['watchedUsers'][wu][i];
          //   this.watchedUsers[wu].push(new SimpleMsg(dm.id, dm.del, dm.a, dm.atag, dm.aid, dm.apfp, dm.con, dm.acon, dm.ch, dm.chid, dm.time, dm.dur, dm.img));
          // }
        //}
      }
    }

    hideChannel(channel) {
      if (this.hiddenChannels.includes(channel)) return;
      this.hiddenChannels.push(channel);
    }

    addMessage(message) {
      let author = message.author.id;
      let channel = message.channel.id;
      if (!this.users[author]) {
        this.users[author] = new UserRecord();
      }
      let userRec = this.users[author];
      userRec.add(message.content, channel, this.today);

      if (message.channel.id == '376574779316109313') this.checkLanEx(message); // Check language exchange.

      // Notify via LINE
      if (message.mentions.users.has(config.owner_ID) || message.mentions.roles.has('240647591770062848')) {
        this.guild.fetchMember(config.owner_ID)
          .then((member) => {
            if (member.presence.status != 'offline') return; // if I'm offline
            if (message.content.startsWith('t!')) return; // ignore tatsumaki
            const LINEmsg = [];
            LINEmsg.push({
              type: 'text',
              text: `${message.cleanContent}`
            });
            LINEmsg.push({
              type: 'text',
              text: `In #${message.channel.name} by ${message.author.username}`
            });
            LINEclient.pushMessage(config.LINEuserID, LINEmsg)
            .catch((err) => {
              throw new Error(err);
            });
          });
      }
    }

    checkLanEx(message) {
      var japanese = message.member.roles.has('196765998706196480');
      var jpCount = 0;
      var enCount = 0;
      var keepIgnoring = false;
      let content = message.content;
      for (var i = 0; i < content.length; i++) {
        let l = content[i];
        if (keepIgnoring) {
          if (l == '>') {
            keepIgnoring = false;
          } else {
            continue;
          }
        } else if (l == '<') {
          keepIgnoring = true;
          i += 18; // skip snowflake id
          continue;
        }
        if (jpregex.test(l)) {
          jpCount++;
        } else if (enregex.test(l)) {
          enCount++;
        }
      }
      if ((japanese && jpCount > enCount) || (!japanese && enCount > jpCount)) {
        message.react('❌');
      }
    }

    addDeletedMessage(message) {
      let con = message.content;
      if (con.startsWith('.') || con.startsWith('t!') ||
        con.startsWith('!') || con.startsWith(':') ||
        con.startsWith('&') || con.startsWith(',')) return; // no bot messages
      var imageURL = '';
      if (message.attachments.size > 0) {
        imageURL = message.attachments.first().url;
        message.content += `\n{Attachment (expires soon): ${imageURL} }`;
      } else if (message.content.length < 3) {
        return;
      }
      let simple = new SimpleMsg(message);
      var arr;
      if (this.watchedUsers.includes(message.author.id)) {
        // arr = this.watchedUsers[message.author.id];
        if (imageURL != '') {
          // Use IMGUR
          var options = { method: 'POST',
            url: 'https://api.imgur.com/3/image',
            headers:
             {
               'cache-control': 'no-cache',
               authorization: `Bearer ${config.imgurAccessToken}`,
               'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' },
            formData: {image: imageURL, album: config.imgurAlbum } };
          request(options, function (error, response, body) {
            if (error) throw new Error(error);
            var ret = JSON.parse(body);
            simple.img =  ret.data.link;
          });
        }
        this.postLogs(simple);
      } else {
        arr = this.deletedMessages;
        // Move the next two outside of the brackets if you don't want to post.
        arr.push(simple);
        if (arr.length > 30) arr.shift();
      }
      if (message.mentions.members.size > 20) { // SPAM alert!
        let chan = this.guild.channels.get('366692441442615306'); // #mod_log
        if (chan == undefined) return;
        if (this.watchedUsers.includes(message.author.id)) {
          message.member.addRole(`259181555803619329`); // muted role
          chan.send(`**USER MUTED** ${message.author} has been muted. <@&240647591770062848> if this was a mistake, unmute them by removing the mute tag. If not, BAN THEM!`);
        } else {
          this.watchedUsers.push(message.author.id);
          chan.send(`**POSSIBLE SPAM ALERT** (deleting a message with 20+ mentions) by ${message.author} in ${message.channel} ! Automatically added to the watchlist`);
        }
      }
    }

    addEdits(oldMessage, newMessage) {
      if (this.watchedUsers.includes(oldMessage.author.id)) {
        let simple = new SimpleMsg(oldMessage);
        simple.del = false;
        simple.acon = newMessage.content;
        this.postLogs(simple);
        // Uncomment below for storing messages
        // this.watchedUsers[oldMessage.author.id].push(simple);
        // if (this.watchedUsers[oldMessage.author.id].length > 30) this.watchedUsers[oldMessage.author.id].shift();
      }
    }

    postLogs(msg) {
      let embed = new Discord.RichEmbed();
      let date = new Date(msg.time);
      embed.setAuthor(`${msg.atag} ID: ${msg.aid}` ,msg.apfp);
      if (msg.del) { // message was deleted
        embed.title = `Message Deleted after ${msg.dur} seconds`;
        embed.description = `${msg.con}`;
        embed.color = Number('0xDB3C3C');
      } else { // message was edited
        embed.title = `Message Edited after ${msg.dur} seconds`;
        embed.addField('Before:', `${msg.con}`, false);
        embed.addField('After:', `${msg.acon}`, false);
        embed.color = Number('0xff9933');
      }
      embed.setFooter(`#${msg.ch}`)
      embed.timestamp = date;
      if (msg.img) { // if != null
        embed.setImage(msg.img);
      }
      let chan = this.guild.channels.get('366692441442615306'); // #mod_log
      if (chan == undefined) return;
      chan.send({embed});
    }

    addNewUser(memberID) {
      if (this.newUsers.unshift(memberID) > 3) this.newUsers.pop();
    }

    save(backup = false) {
      // Store the actual date?
      if (backup) {
        var date = new Date().toLocaleDateString().replace(/\//g, '-');
        try {
          fs.writeFileSync(`./backups/${this.guild.id}_log-${date}.json`, JSON.stringify(this), 'utf8');
        } catch (e) {
          console.log(e);
        }
        console.log(`Backup has been created for ${this.guild.id}: ${date}`);
      } else {
        try {
          fs.writeFileSync(`./.${this.guild.id}_restore.json`, JSON.stringify(this), 'utf8');
        } catch (e) {
          console.log(e);
        }
        // console.log(`./.${this.guild.id}_restore.json has been updated`);
      }
    }
  }
<|endoftext|>


<commit_before>
function TwiddlersCount() {
	this.baseUrl = '';
	this.spaceName = 'replanadu';
	this._init();
}

TwiddlersCount.prototype.go = function() {
	var tag = '@' + this.spaceName;
	this._search(this.title, tag);
};

TwiddlersCount.prototype._init = function() {
	this.title = $('#title').text();;
	this._setSpaceName();
}

TwiddlersCount.prototype._setSpaceName = function() {
	var domains = document.location.hostname.split('.');
	if (domains.length > 1) {
		this.spaceName = domains[0];
	}
}

TwiddlersCount.prototype.addButton = function(count) {
	var button = $("Twiddlers(" + count + ")");
	button.attr('href', '/replanadu#' + encodeURIComponent(this.title));
	$('#container').append(button);
}

TwiddlersCount.prototype._search = function(title, tag) {
	var context = this;
	var success = function(data, status, xhr) {
		console.log(data);
		context.addButton(data.length);
	};
	$.getJSON('/search.json?q=title:"' + encodeURIComponent(title) + '" tag:' + tag, success, this._ajaxError);
};

TwiddlersCount.prototype._ajaxError = function(xhr, err, exc) {
	console.log('Error');
};

$(document).ready(function () {
	new TwiddlersCount().go();
});
<commit_msg>'Clever' target switching<commit_after>
function TwiddlersCount() {
	this.baseUrl = '';
	this.spaceName = 'replanadu';
	this.targetURI = 'replanadu.html';
	this._init();
}

TwiddlersCount.prototype.go = function() {
	var tag = '@' + this.spaceName;
	this._search(this.title, tag);
};

TwiddlersCount.prototype._init = function() {
	this.title = $('#title').text();;
	this._setSpaceName();
}

TwiddlersCount.prototype._setSpaceName = function() {
	var domains = document.location.hostname.split('.');
	if (domains.length > 1) {
		this.spaceName = domains[0];
		this.targetURI = 'replanadu';
	}
}

TwiddlersCount.prototype.addButton = function(count) {
	var button = $("Twiddlers(" + count + ")");
	button.attr('href', '/' + this.targetURI + '#' + encodeURIComponent(this.title));
	$('#container').append(button);
}

TwiddlersCount.prototype._search = function(title, tag) {
	var context = this;
	var success = function(data, status, xhr) {
		console.log(data);
		context.addButton(data.length);
	};
	$.getJSON('/search.json?q=title:"' + encodeURIComponent(title) + '" tag:' + tag, success, this._ajaxError);
};

TwiddlersCount.prototype._ajaxError = function(xhr, err, exc) {
	console.log('Error');
};

$(document).ready(function () {
	new TwiddlersCount().go();
});
<|endoftext|>


<commit_before>/**
 * Yii validation module.
 *
 * This JavaScript module provides the validation methods for the built-in validators.
 *
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */

yii.validation = (function ($) {
    var pub = {
        isEmpty: function (value) {
            return value === null || value === undefined || value == [] || value === '';
        },

        addMessage: function (messages, message, value) {
            messages.push(message.replace(/\{value\}/g, value));
        },

        required: function (value, messages, options) {
            var valid = false;
            if (options.requiredValue === undefined) {
                var isString = typeof value == 'string' || value instanceof String;
                if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
                    valid = true;
                }
            } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
                valid = true;
            }

            if (!valid) {
                pub.addMessage(messages, options.message, value);
            }
        },

        boolean: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }
            var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
                || options.strict && (value === options.trueValue || value === options.falseValue);

            if (!valid) {
                pub.addMessage(messages, options.message, value);
            }
        },

        string: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (typeof value !== 'string') {
                pub.addMessage(messages, options.message, value);
                return;
            }

            if (options.min !== undefined && value.length < options.min) {
                pub.addMessage(messages, options.tooShort, value);
            }
            if (options.max !== undefined && value.length > options.max) {
                pub.addMessage(messages, options.tooLong, value);
            }
            if (options.is !== undefined && value.length != options.is) {
                pub.addMessage(messages, options.notEqual, value);
            }
        },

        globalFiles: function(files, messages, options) {
            if (options.message && !files) {
                pub.addMessage(messages, options.message);
            }

            if (!options.skipOnEmpty && files.length === 0) {
                pub.addMessage(messages, options.uploadRequired);
            } else if (files.length === 0) {
                return false;
            }

            if (options.maxFiles && options.maxFiles < files.length) {
                pub.addMessage(messages, options.tooMany);
            }

            return true;
        },

        singleFile: function(file, messages, options) {
            var index, ext;

            if (options.extensions && options.extensions.length > 0) {
                    index = file.name.lastIndexOf('.');

                    if (!~index) {
                        ext = '';
                    } else {
                        ext = file.name.substr(index + 1, file.name.length).toLowerCase();
                    }

                    if (!~options.extensions.indexOf(ext)) {
                        pub.addMessage(messages, options.wrongExtension.replace(/\{file\}/g, file.name));
                    }
                }

                if (options.mimeTypes && options.mimeTypes.length > 0) {
                    if (!~options.mimeTypes.indexOf(file.type)) {
                        pub.addMessage(messages, options.wrongMimeType.replace(/\{file\}/g, file.name));
                    }
                }

                if (options.maxSize && options.maxSize < file.size) {
                    pub.addMessage(messages, options.tooBig.replace(/\{file\}/g, file.name));
                }

                if (options.maxSize && options.minSize > file.size) {
                    pub.addMessage(messages, options.tooSmall.replace(/\{file\}/g, file.name));
                }
        },

        file: function (messages, options, attribute) {
            var files = $(attribute.input).get(0).files,
                self = this;

            if ( !self.globalFiles(files, messages, options) ) {
                return;
            }

            $.each(files, function (i, file) {
                self.singleFile(file, messages, options);
            });
        },

        image: function (messages, options, deferred, attribute) {
            var files = $(attribute.input).get(0).files,
                self = this;

            if ( !self.globalFiles(files, messages, options) ) {
                return;
            }

            $.each(files, function (i, file) {
                // Perform file validation
                self.singleFile(file, messages, options);

                // Skip image validation if FileReader API is not available
                if (typeof FileReader === "undefined") {
                    return;
                }

                var def = $.Deferred(),
                    fr = new FileReader(),
                    img = new Image();

                img.onload = function () {
                    if (options.minWidth && this.width < options.minWidth) {
                        pub.addMessage(messages, options.underWidth.replace(/\{file\}/g, file.name));
                    }

                    if (options.maxWidth && this.width > options.maxWidth) {
                        pub.addMessage(messages, options.overWidth.replace(/\{file\}/g, file.name));
                    }

                    if (options.minHeight && this.height < options.minHeight) {
                        pub.addMessage(messages, options.underHeight.replace(/\{file\}/g, file.name));
                    }

                    if (options.maxHeight && this.height > options.maxHeight) {
                        pub.addMessage(messages, options.overHeight.replace(/\{file\}/g, file.name));
                    }
                    def.resolve();
                };

                img.onerror = function () {
                    pub.addMessage(messages, options.notImage);
                    def.resolve();
                };

                fr.onload = function () {
                    img.src = fr.result;
                };

                // Resolve deferred if there was error while reading data
                fr.onerror = function () {
                    def.resolve();
                };

                fr.readAsDataURL(file);

                deferred.push(def);
            });

        },

        number: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (typeof value === 'string' && !value.match(options.pattern)) {
                pub.addMessage(messages, options.message, value);
                return;
            }

            if (options.min !== undefined && value < options.min) {
                pub.addMessage(messages, options.tooSmall, value);
            }
            if (options.max !== undefined && value > options.max) {
                pub.addMessage(messages, options.tooBig, value);
            }
        },

        range: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (!options.allowArray && $.isArray(value)) {
                pub.addMessage(messages, options.message, value);
                return;
            }

            var inArray = true;

            $.each($.isArray(value) ? value : [value], function(i, v) {
                if ($.inArray(v, options.range) == -1) {
                    inArray = false;
                    return false;
                } else {
                    return true;
                }
            });

            if (options.not === inArray) {
                pub.addMessage(messages, options.message, value);
            }
        },

        regularExpression: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
                pub.addMessage(messages, options.message, value);
            }
        },

        email: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            var valid = true;

            if (options.enableIDN) {
                var regexp = /^(.*<?)(.*)@(.*)(>?)$/,
                    matches = regexp.exec(value);
                if (matches === null) {
                    valid = false;
                } else {
                    value = matches[1] + punycode.toASCII(matches[2]) + '@' + punycode.toASCII(matches[3]) + matches[4];
                }
            }

            if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) {
                pub.addMessage(messages, options.message, value);
            }
        },

        url: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (options.defaultScheme && !value.match(/:\/\//)) {
                value = options.defaultScheme + '://' + value;
            }

            var valid = true;

            if (options.enableIDN) {
                var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/,
                    matches = regexp.exec(value);
                if (matches === null) {
                    valid = false;
                } else {
                    value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
                }
            }

            if (!valid || !value.match(options.pattern)) {
                pub.addMessage(messages, options.message, value);
            }
        },

        captcha: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            // CAPTCHA may be updated via AJAX and the updated hash is stored in body data
            var hash = $('body').data(options.hashKey);
            if (hash == null) {
                hash = options.hash;
            } else {
                hash = hash[options.caseSensitive ? 0 : 1];
            }
            var v = options.caseSensitive ? value : value.toLowerCase();
            for (var i = v.length - 1, h = 0; i >= 0; --i) {
                h += v.charCodeAt(i);
            }
            if (h != hash) {
                pub.addMessage(messages, options.message, value);
            }
        },

        compare: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            var compareValue, valid = true;
            if (options.compareAttribute === undefined) {
                compareValue = options.compareValue;
            } else {
                compareValue = $('#' + options.compareAttribute).val();
            }
            switch (options.operator) {
                case '==':
                    valid = value == compareValue;
                    break;
                case '===':
                    valid = value === compareValue;
                    break;
                case '!=':
                    valid = value != compareValue;
                    break;
                case '!==':
                    valid = value !== compareValue;
                    break;
                case '>':
                    valid = parseFloat(value) > parseFloat(compareValue);
                    break;
                case '>=':
                    valid = parseFloat(value) >= parseFloat(compareValue);
                    break;
                case '<':
                    valid = parseFloat(value) < parseFloat(compareValue);
                    break;
                case '<=':
                    valid = parseFloat(value) <= parseFloat(compareValue);
                    break;
                default:
                    valid = false;
                    break;
            }

            if (!valid) {
                pub.addMessage(messages, options.message, value);
            }
        }
    };
    return pub;
})(jQuery);
<commit_msg>Abort further validation if there are no files to validate<commit_after>/**
 * Yii validation module.
 *
 * This JavaScript module provides the validation methods for the built-in validators.
 *
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */

yii.validation = (function ($) {
    var pub = {
        isEmpty: function (value) {
            return value === null || value === undefined || value == [] || value === '';
        },

        addMessage: function (messages, message, value) {
            messages.push(message.replace(/\{value\}/g, value));
        },

        required: function (value, messages, options) {
            var valid = false;
            if (options.requiredValue === undefined) {
                var isString = typeof value == 'string' || value instanceof String;
                if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
                    valid = true;
                }
            } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
                valid = true;
            }

            if (!valid) {
                pub.addMessage(messages, options.message, value);
            }
        },

        boolean: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }
            var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
                || options.strict && (value === options.trueValue || value === options.falseValue);

            if (!valid) {
                pub.addMessage(messages, options.message, value);
            }
        },

        string: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (typeof value !== 'string') {
                pub.addMessage(messages, options.message, value);
                return;
            }

            if (options.min !== undefined && value.length < options.min) {
                pub.addMessage(messages, options.tooShort, value);
            }
            if (options.max !== undefined && value.length > options.max) {
                pub.addMessage(messages, options.tooLong, value);
            }
            if (options.is !== undefined && value.length != options.is) {
                pub.addMessage(messages, options.notEqual, value);
            }
        },

        globalFiles: function(files, messages, options) {
            if (options.message && !files) {
                pub.addMessage(messages, options.message);
            }

            if (files.length === 0) {
                if (!options.skipOnEmpty) {
                    pub.addMessage(messages, options.uploadRequired);
                }
                return false;
            }

            if (options.maxFiles && options.maxFiles < files.length) {
                pub.addMessage(messages, options.tooMany);
            }

            return true;
        },

        singleFile: function(file, messages, options) {
            var index, ext;

            if (options.extensions && options.extensions.length > 0) {
                    index = file.name.lastIndexOf('.');

                    if (!~index) {
                        ext = '';
                    } else {
                        ext = file.name.substr(index + 1, file.name.length).toLowerCase();
                    }

                    if (!~options.extensions.indexOf(ext)) {
                        pub.addMessage(messages, options.wrongExtension.replace(/\{file\}/g, file.name));
                    }
                }

                if (options.mimeTypes && options.mimeTypes.length > 0) {
                    if (!~options.mimeTypes.indexOf(file.type)) {
                        pub.addMessage(messages, options.wrongMimeType.replace(/\{file\}/g, file.name));
                    }
                }

                if (options.maxSize && options.maxSize < file.size) {
                    pub.addMessage(messages, options.tooBig.replace(/\{file\}/g, file.name));
                }

                if (options.maxSize && options.minSize > file.size) {
                    pub.addMessage(messages, options.tooSmall.replace(/\{file\}/g, file.name));
                }
        },

        file: function (messages, options, attribute) {
            var files = $(attribute.input).get(0).files,
                self = this;

            if ( !self.globalFiles(files, messages, options) ) {
                return;
            }

            $.each(files, function (i, file) {
                self.singleFile(file, messages, options);
            });
        },

        image: function (messages, options, deferred, attribute) {
            var files = $(attribute.input).get(0).files,
                self = this;

            if ( !self.globalFiles(files, messages, options) ) {
                return;
            }

            $.each(files, function (i, file) {
                // Perform file validation
                self.singleFile(file, messages, options);

                // Skip image validation if FileReader API is not available
                if (typeof FileReader === "undefined") {
                    return;
                }

                var def = $.Deferred(),
                    fr = new FileReader(),
                    img = new Image();

                img.onload = function () {
                    if (options.minWidth && this.width < options.minWidth) {
                        pub.addMessage(messages, options.underWidth.replace(/\{file\}/g, file.name));
                    }

                    if (options.maxWidth && this.width > options.maxWidth) {
                        pub.addMessage(messages, options.overWidth.replace(/\{file\}/g, file.name));
                    }

                    if (options.minHeight && this.height < options.minHeight) {
                        pub.addMessage(messages, options.underHeight.replace(/\{file\}/g, file.name));
                    }

                    if (options.maxHeight && this.height > options.maxHeight) {
                        pub.addMessage(messages, options.overHeight.replace(/\{file\}/g, file.name));
                    }
                    def.resolve();
                };

                img.onerror = function () {
                    pub.addMessage(messages, options.notImage);
                    def.resolve();
                };

                fr.onload = function () {
                    img.src = fr.result;
                };

                // Resolve deferred if there was error while reading data
                fr.onerror = function () {
                    def.resolve();
                };

                fr.readAsDataURL(file);

                deferred.push(def);
            });

        },

        number: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (typeof value === 'string' && !value.match(options.pattern)) {
                pub.addMessage(messages, options.message, value);
                return;
            }

            if (options.min !== undefined && value < options.min) {
                pub.addMessage(messages, options.tooSmall, value);
            }
            if (options.max !== undefined && value > options.max) {
                pub.addMessage(messages, options.tooBig, value);
            }
        },

        range: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (!options.allowArray && $.isArray(value)) {
                pub.addMessage(messages, options.message, value);
                return;
            }

            var inArray = true;

            $.each($.isArray(value) ? value : [value], function(i, v) {
                if ($.inArray(v, options.range) == -1) {
                    inArray = false;
                    return false;
                } else {
                    return true;
                }
            });

            if (options.not === inArray) {
                pub.addMessage(messages, options.message, value);
            }
        },

        regularExpression: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
                pub.addMessage(messages, options.message, value);
            }
        },

        email: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            var valid = true;

            if (options.enableIDN) {
                var regexp = /^(.*<?)(.*)@(.*)(>?)$/,
                    matches = regexp.exec(value);
                if (matches === null) {
                    valid = false;
                } else {
                    value = matches[1] + punycode.toASCII(matches[2]) + '@' + punycode.toASCII(matches[3]) + matches[4];
                }
            }

            if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) {
                pub.addMessage(messages, options.message, value);
            }
        },

        url: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            if (options.defaultScheme && !value.match(/:\/\//)) {
                value = options.defaultScheme + '://' + value;
            }

            var valid = true;

            if (options.enableIDN) {
                var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/,
                    matches = regexp.exec(value);
                if (matches === null) {
                    valid = false;
                } else {
                    value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
                }
            }

            if (!valid || !value.match(options.pattern)) {
                pub.addMessage(messages, options.message, value);
            }
        },

        captcha: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            // CAPTCHA may be updated via AJAX and the updated hash is stored in body data
            var hash = $('body').data(options.hashKey);
            if (hash == null) {
                hash = options.hash;
            } else {
                hash = hash[options.caseSensitive ? 0 : 1];
            }
            var v = options.caseSensitive ? value : value.toLowerCase();
            for (var i = v.length - 1, h = 0; i >= 0; --i) {
                h += v.charCodeAt(i);
            }
            if (h != hash) {
                pub.addMessage(messages, options.message, value);
            }
        },

        compare: function (value, messages, options) {
            if (options.skipOnEmpty && pub.isEmpty(value)) {
                return;
            }

            var compareValue, valid = true;
            if (options.compareAttribute === undefined) {
                compareValue = options.compareValue;
            } else {
                compareValue = $('#' + options.compareAttribute).val();
            }
            switch (options.operator) {
                case '==':
                    valid = value == compareValue;
                    break;
                case '===':
                    valid = value === compareValue;
                    break;
                case '!=':
                    valid = value != compareValue;
                    break;
                case '!==':
                    valid = value !== compareValue;
                    break;
                case '>':
                    valid = parseFloat(value) > parseFloat(compareValue);
                    break;
                case '>=':
                    valid = parseFloat(value) >= parseFloat(compareValue);
                    break;
                case '<':
                    valid = parseFloat(value) < parseFloat(compareValue);
                    break;
                case '<=':
                    valid = parseFloat(value) <= parseFloat(compareValue);
                    break;
                default:
                    valid = false;
                    break;
            }

            if (!valid) {
                pub.addMessage(messages, options.message, value);
            }
        }
    };
    return pub;
})(jQuery);
<|endoftext|>