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

var App = require('app');
var dateUtils = require('utils/date/date');

function computedOnSummaryState(state) {
  return Em.computed('summary.' + state, 'summary.' + state + '.count', 'summary.' + state + '.maintenanceCount', function () {
    var summary = Em.get(this, 'summary');
    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  });
}

App.AlertDefinition = DS.Model.extend({

  name: DS.attr('string'),
  label: DS.attr('string'),
  description: DS.attr('string'),
  service: DS.belongsTo('App.Service'),
  serviceName: DS.attr('string'),
  componentName: DS.attr('string'),
  enabled: DS.attr('boolean'),
  scope: DS.attr('string'),
  interval: DS.attr('number'),
  type: DS.attr('string'),
  groups: DS.hasMany('App.AlertGroup'),
  reporting: DS.hasMany('App.AlertReportDefinition'),
  parameters: DS.hasMany('App.AlertDefinitionParameter'),
  lastTriggered: DS.attr('number'),
  lastTriggeredRaw: DS.attr('number'),

  //relates only to SCRIPT-type alert definition
  location: DS.attr('string'),
  //relates only to AGGREGATE-type alert definition
  alertName: DS.attr('string'),
  //relates only to WEB and METRIC types of alert definition
  uri: DS.belongsTo('App.AlertMetricsUriDefinition'),
  //relates only METRIC-type alert definition
  jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  //relates only PORT-type alert definition
  defaultPort: DS.attr('number'),
  portUri: DS.attr('string'),

  /**
   * Raw data from AlertDefinition/source
   * used to format request content for updating alert definition
   * @type {Object}
   */
  rawSourceData: {},

  /**
   * Counts of alert grouped by their status
   * Format:
   *
   *   {
   *    "CRITICAL": {
   *      count: 1,
   *      maintenanceCount: 0
   *    },
   *    "OK": {
   *      count: 0,
   *      maintenanceCount: 1
   *    },
   *    "UNKNOWN": {
   *      count: 0,
   *      maintenanceCount: 0
   *    },
   *    "WARNING": {
   *      count: 1,
   *      maintenanceCount: 1
   *    }
   *   }
   *
   * @type {object}
   */
  summary: {},

  /**
   * Formatted timestamp for latest alert triggering for current alertDefinition
   * @type {string}
   */
  lastTriggeredFormatted: function () {
    return dateUtils.dateFormat(this.get('lastTriggered'));
  }.property('lastTriggered'),

  /**
   * Formatted timestamp with $.timeago
   * @type {string}
   */
  lastTriggeredAgoFormatted: function () {
    var lastTriggered = this.get('lastTriggeredRaw');
    return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
  }.property('lastTriggeredRaw'),

  lastTriggeredVerboseDisplay: function () {
    var lastTriggered = this.get('lastTriggered');
    return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
  }.property('lastTriggered'),

  /**
   * Formatted timestamp in format: for 4 days
   * @type {string}
   */
  lastTriggeredForFormatted: function () {
    var lastTriggered = this.get('lastTriggeredRaw');
    var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
    var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
    $.timeago.settings.strings.suffixAgo = null;
    $.timeago.settings.strings.prefixAgo = 'for';
    var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
    $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
    $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
    return triggeredFor;
  }.property('lastTriggeredRaw'),

  /**
   * Formatted displayName for componentName
   * @type {String}
   */
  componentNameFormatted: Em.computed.formatRole('componentName'),

  /**
   * Status generates from child-alerts
   * Format: OK(1)  WARN(2)  CRIT(1)  UNKN(1)
   * If single host: show: OK/WARNING/CRITICAL/UNKNOWN
   * If some there are no alerts with some state, this state isn't shown
   * If no OK/WARN/CRIT/UNKN state, then show PENDING
   * Order is equal to example
   * @type {string}
   */
  status: function () {
    var order = this.get('order'),
        summary = this.get('summary'),
        hostCnt = 0,
        self = this;
    order.forEach(function (state) {
      hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
    });
    if (hostCnt > 1) {
      // multiple hosts
      return order.map(function (state) {
        var shortState = self.get('shortState')[state];
        var result = '';
        result += summary[state].count ? '' + shortState + ' (' + summary[state].count + ')' : '';
        // add status with maintenance mode icon
        result += summary[state].maintenanceCount ?
        ' ' + shortState + ' (' + summary[state].maintenanceCount + ')' : '';
        return result;
      }).without('').join(' ');
    } else if (hostCnt === 1) {
      // single host, single status
      return order.map(function (state) {
        var shortState = self.get('shortState')[state];
        var result = '';
        result += summary[state].count ? '' + shortState + '' : '';
        // add status with maintenance mode icon
        result += summary[state].maintenanceCount ?
        ' ' + shortState + '' : '';
        return result;
      }).without('').join(' ');
    } else if (!hostCnt) {
      // none
      return 'NONE';
    }
    return '';
  }.property('summary'),

  latestText: function () {
    var order = this.get('order'), summary = this.get('summary'), text = '';
    order.forEach(function (state) {
      var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
      if (cnt > 0) {
        text = summary[state].latestText;
      }
    });
    return text;
  }.property('summary'),

  isAmbariService: Em.computed.equal('service._id', 'AMBARI'),

  isAmbariAgentComponent: Em.computed.equal('componentName', 'AMBARI_AGENT'),

  isHostAlertDefinition: Em.computed.and('isAmbariService', 'isAmbariAgentComponent'),

  typeIconClass: function () {
    var typeIcons = this.get('typeIcons'),
        type = this.get('type');
    return typeIcons[type];
  }.property('type'),

  /**
   * if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
   * instances with maintenance mode ON are ignored
   * @type {boolean}
   */
  isCriticalOrWarning: function () {
    return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
  }.property('summary'),

  /**
   * if this definition is in state: CRITICAL
   * @type {boolean}
   */
  isCritical: computedOnSummaryState('CRITICAL'),

  /**
   * if this definition is in state: WARNING
   * @type {boolean}
   */
  isWarning: computedOnSummaryState('WARNING'),

  /**
   * if this definition is in state: OK
   * @type {boolean}
   */
  isOK: computedOnSummaryState('OK'),

  /**
   * if this definition is in state: UNKNOWN
   * @type {boolean}
   */
  isUnknown: computedOnSummaryState('UNKNOWN'),

  /**
   * For alerts we will have processes which are not typical
   * cluster services - like Ambari-Server. This method unifies
   * cluster services and other services into a common display-name.
   * @see App.AlertInstance#serviceDisplayName()
   */
  serviceDisplayName: function () {
    var serviceName = this.get('service.displayName');
    if (!serviceName) {
      serviceName = this.get('serviceName');
      if (serviceName) {
        serviceName = serviceName.toCapital();
      }
    }
    return serviceName;
  }.property('serviceName', 'service.displayName'),

  /**
   * List of css-classes for alert types
   * @type {object}
   */
  typeIcons: {
    'METRIC': 'icon-bolt',
    'SCRIPT': 'icon-file-text',
    'WEB': 'icon-globe',
    'PORT': 'icon-signin',
    'AGGREGATE': 'icon-plus',
    'SERVER': 'icon-desktop',
    'RECOVERY': 'icon-desktop'
  },

  /**
   * Sort on load definitions by this severity order
   */
  severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
  order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],

  shortState: {
    'CRITICAL': 'CRIT',
    'WARNING': 'WARN',
    'OK': 'OK',
    'UNKNOWN': 'UNKWN',
    'PENDING': 'NONE'
  }
});

App.AlertDefinition.reopenClass({

  /**
   * Return function to sort list of AlertDefinitions by their status
   * It sorts according to severityOrder
   * @param {boolean} order true - DESC, false - ASC
   * @returns {Function}
   * @method getSortDefinitionsByStatus
   */
  getSortDefinitionsByStatus: function (order) {
    return function (a, b) {
      var aSummary = a.get('summary'),
        bSummary = b.get('summary'),
        stOrder = a.get('severityOrder'),
        ret = 0;
      for (var i = 0; i < stOrder.length; i++) {
        var aV = Em.isNone(aSummary[stOrder[i]]) ? 0 : aSummary[stOrder[i]].count + aSummary[stOrder[i]].maintenanceCount,
          bV = Em.isNone(bSummary[stOrder[i]]) ? 0 : bSummary[stOrder[i]].count + bSummary[stOrder[i]].maintenanceCount;
        ret = bV - aV;
        if (ret !== 0) {
          break;
        }
      }
      return order ? ret : -ret;
    };
  }

});

App.AlertDefinitionParameter = DS.Model.extend({
  name: DS.attr('string'),
  displayName: DS.attr('string'),
  units: DS.attr('string'),
  value: DS.attr('string'),
  description: DS.attr('string'),
  type: DS.attr('string'),
  threshold: DS.attr('string')
});

App.AlertReportDefinition = DS.Model.extend({
  type: DS.attr('string'),
  text: DS.attr('string'),
  value: DS.attr('number')
});

App.AlertMetricsSourceDefinition = DS.Model.extend({
  propertyList: [],
  value: DS.attr('string')
});

App.AlertMetricsUriDefinition = DS.Model.extend({
  http: DS.attr('string'),
  https: DS.attr('string'),
  httpsProperty: DS.attr('string'),
  httpsPropertyValue: DS.attr('string'),
  connectionTimeout: DS.attr('number')
});

App.AlertDefinition.FIXTURES = [];
App.AlertReportDefinition.FIXTURES = [];
App.AlertMetricsSourceDefinition.FIXTURES = [];
App.AlertMetricsUriDefinition.FIXTURES = [];
App.AlertDefinitionParameter.FIXTURES = [];
<commit_msg>AMBARI-15113. UI does not update alert state (alexantonenko)<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');
var dateUtils = require('utils/date/date');

function computedOnSummaryState(state) {
  return Em.computed('summary.' + state, 'summary.' + state + '.count', 'summary.' + state + '.maintenanceCount', function () {
    var summary = Em.get(this, 'summary');
    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  });
}

App.AlertDefinition = DS.Model.extend({

  name: DS.attr('string'),
  label: DS.attr('string'),
  description: DS.attr('string'),
  service: DS.belongsTo('App.Service'),
  serviceName: DS.attr('string'),
  componentName: DS.attr('string'),
  enabled: DS.attr('boolean'),
  scope: DS.attr('string'),
  interval: DS.attr('number'),
  type: DS.attr('string'),
  groups: DS.hasMany('App.AlertGroup'),
  reporting: DS.hasMany('App.AlertReportDefinition'),
  parameters: DS.hasMany('App.AlertDefinitionParameter'),
  lastTriggered: 0,
  lastTriggeredRaw: 0,

  //relates only to SCRIPT-type alert definition
  location: DS.attr('string'),
  //relates only to AGGREGATE-type alert definition
  alertName: DS.attr('string'),
  //relates only to WEB and METRIC types of alert definition
  uri: DS.belongsTo('App.AlertMetricsUriDefinition'),
  //relates only METRIC-type alert definition
  jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  //relates only PORT-type alert definition
  defaultPort: DS.attr('number'),
  portUri: DS.attr('string'),

  /**
   * Raw data from AlertDefinition/source
   * used to format request content for updating alert definition
   * @type {Object}
   */
  rawSourceData: {},

  /**
   * Counts of alert grouped by their status
   * Format:
   *
   *   {
   *    "CRITICAL": {
   *      count: 1,
   *      maintenanceCount: 0
   *    },
   *    "OK": {
   *      count: 0,
   *      maintenanceCount: 1
   *    },
   *    "UNKNOWN": {
   *      count: 0,
   *      maintenanceCount: 0
   *    },
   *    "WARNING": {
   *      count: 1,
   *      maintenanceCount: 1
   *    }
   *   }
   *
   * @type {object}
   */
  summary: {},

  /**
   * Formatted timestamp for latest alert triggering for current alertDefinition
   * @type {string}
   */
  lastTriggeredFormatted: function () {
    return dateUtils.dateFormat(this.get('lastTriggered'));
  }.property('lastTriggered'),

  /**
   * Formatted timestamp with $.timeago
   * @type {string}
   */
  lastTriggeredAgoFormatted: function () {
    var lastTriggered = this.get('lastTriggeredRaw');
    return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
  }.property('lastTriggeredRaw'),

  lastTriggeredVerboseDisplay: function () {
    var lastTriggered = this.get('lastTriggered');
    return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
  }.property('lastTriggered'),

  /**
   * Formatted timestamp in format: for 4 days
   * @type {string}
   */
  lastTriggeredForFormatted: function () {
    var lastTriggered = this.get('lastTriggeredRaw');
    var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
    var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
    $.timeago.settings.strings.suffixAgo = null;
    $.timeago.settings.strings.prefixAgo = 'for';
    var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
    $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
    $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
    return triggeredFor;
  }.property('lastTriggeredRaw'),

  /**
   * Formatted displayName for componentName
   * @type {String}
   */
  componentNameFormatted: Em.computed.formatRole('componentName'),

  /**
   * Status generates from child-alerts
   * Format: OK(1)  WARN(2)  CRIT(1)  UNKN(1)
   * If single host: show: OK/WARNING/CRITICAL/UNKNOWN
   * If some there are no alerts with some state, this state isn't shown
   * If no OK/WARN/CRIT/UNKN state, then show PENDING
   * Order is equal to example
   * @type {string}
   */
  status: function () {
    var order = this.get('order'),
        summary = this.get('summary'),
        hostCnt = 0,
        self = this;
    order.forEach(function (state) {
      hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
    });
    if (hostCnt > 1) {
      // multiple hosts
      return order.map(function (state) {
        var shortState = self.get('shortState')[state];
        var result = '';
        result += summary[state].count ? '' + shortState + ' (' + summary[state].count + ')' : '';
        // add status with maintenance mode icon
        result += summary[state].maintenanceCount ?
        ' ' + shortState + ' (' + summary[state].maintenanceCount + ')' : '';
        return result;
      }).without('').join(' ');
    } else if (hostCnt === 1) {
      // single host, single status
      return order.map(function (state) {
        var shortState = self.get('shortState')[state];
        var result = '';
        result += summary[state].count ? '' + shortState + '' : '';
        // add status with maintenance mode icon
        result += summary[state].maintenanceCount ?
        ' ' + shortState + '' : '';
        return result;
      }).without('').join(' ');
    } else if (!hostCnt) {
      // none
      return 'NONE';
    }
    return '';
  }.property('summary'),

  latestText: function () {
    var order = this.get('order'), summary = this.get('summary'), text = '';
    order.forEach(function (state) {
      var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
      if (cnt > 0) {
        text = summary[state].latestText;
      }
    });
    return text;
  }.property('summary'),

  isAmbariService: Em.computed.equal('service._id', 'AMBARI'),

  isAmbariAgentComponent: Em.computed.equal('componentName', 'AMBARI_AGENT'),

  isHostAlertDefinition: Em.computed.and('isAmbariService', 'isAmbariAgentComponent'),

  typeIconClass: function () {
    var typeIcons = this.get('typeIcons'),
        type = this.get('type');
    return typeIcons[type];
  }.property('type'),

  /**
   * if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
   * instances with maintenance mode ON are ignored
   * @type {boolean}
   */
  isCriticalOrWarning: function () {
    return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
  }.property('summary'),

  /**
   * if this definition is in state: CRITICAL
   * @type {boolean}
   */
  isCritical: computedOnSummaryState('CRITICAL'),

  /**
   * if this definition is in state: WARNING
   * @type {boolean}
   */
  isWarning: computedOnSummaryState('WARNING'),

  /**
   * if this definition is in state: OK
   * @type {boolean}
   */
  isOK: computedOnSummaryState('OK'),

  /**
   * if this definition is in state: UNKNOWN
   * @type {boolean}
   */
  isUnknown: computedOnSummaryState('UNKNOWN'),

  /**
   * For alerts we will have processes which are not typical
   * cluster services - like Ambari-Server. This method unifies
   * cluster services and other services into a common display-name.
   * @see App.AlertInstance#serviceDisplayName()
   */
  serviceDisplayName: function () {
    var serviceName = this.get('service.displayName');
    if (!serviceName) {
      serviceName = this.get('serviceName');
      if (serviceName) {
        serviceName = serviceName.toCapital();
      }
    }
    return serviceName;
  }.property('serviceName', 'service.displayName'),

  /**
   * List of css-classes for alert types
   * @type {object}
   */
  typeIcons: {
    'METRIC': 'icon-bolt',
    'SCRIPT': 'icon-file-text',
    'WEB': 'icon-globe',
    'PORT': 'icon-signin',
    'AGGREGATE': 'icon-plus',
    'SERVER': 'icon-desktop',
    'RECOVERY': 'icon-desktop'
  },

  /**
   * Sort on load definitions by this severity order
   */
  severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
  order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],

  shortState: {
    'CRITICAL': 'CRIT',
    'WARNING': 'WARN',
    'OK': 'OK',
    'UNKNOWN': 'UNKWN',
    'PENDING': 'NONE'
  }
});

App.AlertDefinition.reopenClass({

  /**
   * Return function to sort list of AlertDefinitions by their status
   * It sorts according to severityOrder
   * @param {boolean} order true - DESC, false - ASC
   * @returns {Function}
   * @method getSortDefinitionsByStatus
   */
  getSortDefinitionsByStatus: function (order) {
    return function (a, b) {
      var aSummary = a.get('summary'),
        bSummary = b.get('summary'),
        stOrder = a.get('severityOrder'),
        ret = 0;
      for (var i = 0; i < stOrder.length; i++) {
        var aV = Em.isNone(aSummary[stOrder[i]]) ? 0 : aSummary[stOrder[i]].count + aSummary[stOrder[i]].maintenanceCount,
          bV = Em.isNone(bSummary[stOrder[i]]) ? 0 : bSummary[stOrder[i]].count + bSummary[stOrder[i]].maintenanceCount;
        ret = bV - aV;
        if (ret !== 0) {
          break;
        }
      }
      return order ? ret : -ret;
    };
  }

});

App.AlertDefinitionParameter = DS.Model.extend({
  name: DS.attr('string'),
  displayName: DS.attr('string'),
  units: DS.attr('string'),
  value: DS.attr('string'),
  description: DS.attr('string'),
  type: DS.attr('string'),
  threshold: DS.attr('string')
});

App.AlertReportDefinition = DS.Model.extend({
  type: DS.attr('string'),
  text: DS.attr('string'),
  value: DS.attr('number')
});

App.AlertMetricsSourceDefinition = DS.Model.extend({
  propertyList: [],
  value: DS.attr('string')
});

App.AlertMetricsUriDefinition = DS.Model.extend({
  http: DS.attr('string'),
  https: DS.attr('string'),
  httpsProperty: DS.attr('string'),
  httpsPropertyValue: DS.attr('string'),
  connectionTimeout: DS.attr('number')
});

App.AlertDefinition.FIXTURES = [];
App.AlertReportDefinition.FIXTURES = [];
App.AlertMetricsSourceDefinition.FIXTURES = [];
App.AlertMetricsUriDefinition.FIXTURES = [];
App.AlertDefinitionParameter.FIXTURES = [];
<|endoftext|>


<commit_before>'use strict';
const OidcProvider = require('oidc-provider');
const cors = require('koa-cors');
const querystring = require('querystring');
const path = require('path');
const fs = require('fs');
const handlebars = require('handlebars');

exports.register = function (server, options, next) {
  const issuer = options.issuer || process.env.OIDC_BASE_URL || 'http://localhost:9000';

  const prefix = options.prefix ? `/${options.prefix}` : '/op';
  const provider = new OidcProvider(issuer, {
    adapter: options.adapter,
    findById: options.findUserById,
    routes: {
      authorization: `${prefix}/auth`,
      certificates: `${prefix}/certs`,
      check_session: `${prefix}/session/check`,
      end_session: `${prefix}/session/end`,
      introspection: `${prefix}/token/introspection`,
      registration: `${prefix}/reg`,
      revocation: `${prefix}/token/revocation`,
      token: `${prefix}/token`,
      userinfo: `${prefix}/me`,
    },
    acrValues: ['session', 'urn:mace:incommon:iap:bronze'],
    cookies: {
      long: { signed: true },
      short: { signed: true },
    },
    discovery: {
      service_documentation: '',
      version: '',
    },
    claims: {
      amr: null,
      address: ['address'],
      email: ['email', 'email_verified'],
      phone: ['phone_number', 'phone_number_verified'],
      app_metadata: ['app_metadata'],
      profile: ['birthdate', 'family_name', 'gender', 'name', 'given_name', 'locale', 'middle_name', 'name',
        'nickname', 'picture', 'preferred_username', 'profile', 'updated_at', 'website', 'zoneinfo'],
    },
    features: {
      devInteractions: false,
      discovery: true,
      claimsParameter: true,
      clientCredentials: true,
      encryption: true,
      introspection: true,
      registration: {
        initialAccessToken: options.initialAccessToken,
      },
      registrationManagement: false,
      request: true,
      requestUri: true,
      revocation: true,
      sessionManagement: true,
      backchannelLogout: false,
    },
    logoutSource: function renderLogoutSource(form) {
      // this => koa context;
      const layout = fs.readFileSync(path.join(__dirname, './templates/layout/layout.hbs'), 'utf8');
      const logout = fs.readFileSync(path.join(__dirname, './templates/end_session.hbs'), 'utf8');

      this.body = handlebars.compile(layout)({
        content: handlebars.compile(logout)({ form })
      });
    },
    subjectTypes: ['public', 'pairwise'],
    pairwiseSalt: 'da1c442b365b563dfc121f285a11eedee5bbff7110d55c88',
    interactionUrl: function interactionUrl(interaction) {
      // this => koa context;
      return `/interaction/${this.oidc.uuid}`;
    },
  });

  provider.initialize({
    keystore: options.keystores.certificates,
    integrity: options.keystores.integrity,
  })
    .then(() => {
      provider.app.use(cors());
      provider.app.keys = options.cookieKeys;
      provider.app.proxy = true;

      server.ext('onRequest', function(request, reply) {
        if (request.path.substring(0, prefix.length) === prefix) {
          provider.callback(request.raw.req, request.raw.res);
        } else {
          return reply.continue();
        }
      });

      server.views({
        engines: {
          hbs: handlebars
        },
        relativeTo: __dirname,
        path: 'templates',
        layout: true,
        layoutPath: './templates/layout',
      });

      server.route({
        method: 'GET',
        path: '/interaction/{grant}',
        handler: (request, reply) => {
          const cookie = provider.interactionDetails(request.raw.req);
          const client = provider.Client.find(cookie.params.client_id);

          if (cookie.interaction.error === 'login_required') {
            reply.view('login', {
              client,
              cookie,
              title: 'Log In',
              debug: querystring.stringify(cookie.params, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
              interaction: querystring.stringify(cookie.interaction, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
              forgotPasswordPath: `${issuer}/user/forgot-password?client_id=${cookie.params.client_id}&response_type=${cookie.params.response_type}&scope=${cookie.params.scope}&redirect_uri=${cookie.params.redirect_uri}&nonce=${cookie.params.nonce}`,
            });
          } else {
            reply.view('interaction', {
              client,
              cookie,
              title: 'Authorize',
              debug: querystring.stringify(cookie.params, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
              interaction: querystring.stringify(cookie.interaction, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
            });
          }
        },
        config: {
          state: {
            parse: false // hapi fails to parse oidc cookie...
          }
        }
      });

      server.route({
        method: 'POST',
        path: '/interaction/{grant}/confirm',
        handler: (request, reply) => {
          const result = { consent: {} };
          provider.interactionFinished(request.raw.req, request.raw.res, result);
        },
        config: {
          state: {
            parse: false
          }
        }
      });

      server.route({
        method: 'POST',
        path: '/interaction/{grant}/login',
        handler: (request, reply) => {
          options.authenticateUser(request.payload.login, request.payload.password)
            .then(account => {
              const result = {
                login: {
                  account: account.accountId,
                  acr: 'urn:mace:incommon:iap:bronze',
                  amr: ['pwd'],
                  remember: request.payload.remember,
                  ts: Math.floor(Date.now() / 1000),
                },
                consent: {}
              };
              provider.interactionFinished(request.raw.req, request.raw.res, result);
            })
            .catch(e => {
              const cookie = provider.interactionDetails(request.raw.req);
              const client = provider.Client.find(cookie.params.client_id);
              reply.view('login', {
                error: 'Invalid email password combination',
                client,
                cookie,
                title: 'Log In',
                debug: querystring.stringify(cookie.params, ',
', ' = ', {
                  encodeURIComponent: value => value,
                }),
                interaction: querystring.stringify(cookie.interaction, ',
', ' = ', {
                  encodeURIComponent: value => value,
                }),
              });

            });
        },
        config: {
          state: {
            parse: false
          }
        }
      });

      server.expose('provider', provider);

      next();
    })
    .catch(e => {
      console.error(e);
    });
};

exports.register.attributes = {
  name: 'open-id-connect',
  version: '1.0.0'
};
<commit_msg>Fixes #87 - Enable native url schemes<commit_after>'use strict';
const OidcProvider = require('oidc-provider');
const cors = require('koa-cors');
const querystring = require('querystring');
const path = require('path');
const fs = require('fs');
const handlebars = require('handlebars');

exports.register = function (server, options, next) {
  const issuer = options.issuer || process.env.OIDC_BASE_URL || 'http://localhost:9000';

  const prefix = options.prefix ? `/${options.prefix}` : '/op';
  const provider = new OidcProvider(issuer, {
    adapter: options.adapter,
    findById: options.findUserById,
    routes: {
      authorization: `${prefix}/auth`,
      certificates: `${prefix}/certs`,
      check_session: `${prefix}/session/check`,
      end_session: `${prefix}/session/end`,
      introspection: `${prefix}/token/introspection`,
      registration: `${prefix}/reg`,
      revocation: `${prefix}/token/revocation`,
      token: `${prefix}/token`,
      userinfo: `${prefix}/me`,
    },
    acrValues: ['session', 'urn:mace:incommon:iap:bronze'],
    cookies: {
      long: { signed: true },
      short: { signed: true },
    },
    discovery: {
      service_documentation: '',
      version: '',
    },
    claims: {
      amr: null,
      address: ['address'],
      email: ['email', 'email_verified'],
      phone: ['phone_number', 'phone_number_verified'],
      app_metadata: ['app_metadata'],
      profile: ['birthdate', 'family_name', 'gender', 'name', 'given_name', 'locale', 'middle_name', 'name',
        'nickname', 'picture', 'preferred_username', 'profile', 'updated_at', 'website', 'zoneinfo'],
    },
    features: {
      devInteractions: false,
      discovery: true,
      claimsParameter: true,
      clientCredentials: true,
      encryption: true,
      introspection: true,
      oauthNativeApps: true,
      registration: {
        initialAccessToken: options.initialAccessToken,
      },
      registrationManagement: false,
      request: true,
      requestUri: true,
      revocation: true,
      sessionManagement: true,
      backchannelLogout: false,
    },
    logoutSource: function renderLogoutSource(form) {
      // this => koa context;
      const layout = fs.readFileSync(path.join(__dirname, './templates/layout/layout.hbs'), 'utf8');
      const logout = fs.readFileSync(path.join(__dirname, './templates/end_session.hbs'), 'utf8');

      this.body = handlebars.compile(layout)({
        content: handlebars.compile(logout)({ form })
      });
    },
    subjectTypes: ['public', 'pairwise'],
    pairwiseSalt: 'da1c442b365b563dfc121f285a11eedee5bbff7110d55c88',
    interactionUrl: function interactionUrl(interaction) {
      // this => koa context;
      return `/interaction/${this.oidc.uuid}`;
    },
  });

  provider.initialize({
    keystore: options.keystores.certificates,
    integrity: options.keystores.integrity,
  })
    .then(() => {
      provider.app.use(cors());
      provider.app.keys = options.cookieKeys;
      provider.app.proxy = true;

      server.ext('onRequest', function(request, reply) {
        if (request.path.substring(0, prefix.length) === prefix) {
          provider.callback(request.raw.req, request.raw.res);
        } else {
          return reply.continue();
        }
      });

      server.views({
        engines: {
          hbs: handlebars
        },
        relativeTo: __dirname,
        path: 'templates',
        layout: true,
        layoutPath: './templates/layout',
      });

      server.route({
        method: 'GET',
        path: '/interaction/{grant}',
        handler: (request, reply) => {
          const cookie = provider.interactionDetails(request.raw.req);
          const client = provider.Client.find(cookie.params.client_id);

          if (cookie.interaction.error === 'login_required') {
            reply.view('login', {
              client,
              cookie,
              title: 'Log In',
              debug: querystring.stringify(cookie.params, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
              interaction: querystring.stringify(cookie.interaction, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
              forgotPasswordPath: `${issuer}/user/forgot-password?client_id=${cookie.params.client_id}&response_type=${cookie.params.response_type}&scope=${cookie.params.scope}&redirect_uri=${cookie.params.redirect_uri}&nonce=${cookie.params.nonce}`,
            });
          } else {
            reply.view('interaction', {
              client,
              cookie,
              title: 'Authorize',
              debug: querystring.stringify(cookie.params, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
              interaction: querystring.stringify(cookie.interaction, ',
', ' = ', {
                encodeURIComponent: value => value,
              }),
            });
          }
        },
        config: {
          state: {
            parse: false // hapi fails to parse oidc cookie...
          }
        }
      });

      server.route({
        method: 'POST',
        path: '/interaction/{grant}/confirm',
        handler: (request, reply) => {
          const result = { consent: {} };
          provider.interactionFinished(request.raw.req, request.raw.res, result);
        },
        config: {
          state: {
            parse: false
          }
        }
      });

      server.route({
        method: 'POST',
        path: '/interaction/{grant}/login',
        handler: (request, reply) => {
          options.authenticateUser(request.payload.login, request.payload.password)
            .then(account => {
              const result = {
                login: {
                  account: account.accountId,
                  acr: 'urn:mace:incommon:iap:bronze',
                  amr: ['pwd'],
                  remember: request.payload.remember,
                  ts: Math.floor(Date.now() / 1000),
                },
                consent: {}
              };
              provider.interactionFinished(request.raw.req, request.raw.res, result);
            })
            .catch(e => {
              const cookie = provider.interactionDetails(request.raw.req);
              const client = provider.Client.find(cookie.params.client_id);
              reply.view('login', {
                error: 'Invalid email password combination',
                client,
                cookie,
                title: 'Log In',
                debug: querystring.stringify(cookie.params, ',
', ' = ', {
                  encodeURIComponent: value => value,
                }),
                interaction: querystring.stringify(cookie.interaction, ',
', ' = ', {
                  encodeURIComponent: value => value,
                }),
              });

            });
        },
        config: {
          state: {
            parse: false
          }
        }
      });

      server.expose('provider', provider);

      next();
    })
    .catch(e => {
      console.error(e);
    });
};

exports.register.attributes = {
  name: 'open-id-connect',
  version: '1.0.0'
};
<|endoftext|>


<commit_before>
import Joker from '../common/joker';

export class PickJoker extends Joker {

  static get name(){ return 'pick'; }

  get modifiers() {
    return ['of'];
  }

  getValue() {
    let option = this.options.of;
    if(!option || !Array.isArray(option) || option.length === 0)
      throw new Error('No options added for the Joker, please use "of" modyfier');

    let value = this.randomiser.pickone(option);
    return value instanceof Joker ? value.value : value;
  }

}<commit_msg>Adding an array joker<commit_after>
import Joker from '../common/joker';

export class PickJoker extends Joker {

  static get name(){ return 'pick'; }

  get modifiers() {
    return ['of'];
  }

  getValue() {
    let option = this.options.of;
    if(!option || !Array.isArray(option) || option.length === 0)
      throw new Error('No options added for the Joker, please use "of" modyfier');

    let value = this.randomiser.pickone(option);
    return value instanceof Joker ? value.value : value;
  }

}

export class ArrayJoker extends Joker {

  static get name() { return 'array'; }

  get modifiers() {
    return ['count', 'of'];
  }

  getValue() {
    let option = this.options.of;
    let { count } = this.options;

    return Array(count instanceof Joker ? count.value : count)
      .fill()
      .map(() => option instanceof Joker ? option.value : option);
  }

}<|endoftext|>


<commit_before>var walker = require('./walker').astWalker();
var translate = require('./translate').translate;

function process(ast, context){
  ast.throws = [];

  return walker.walk(ast, {
    CallExpression: function(token, scope){
      var expr = token.callee;
      var args = token.arguments;

      this.walk(expr);
      this.walkEach(args);

      var fn = scope.resolve(expr);

      if (fn)
      {
        var verbose = context.console.enabled;

        if (fn.ref_)
          fn = fn.ref_;

        if (fn.type === 'FunctionExpression' || fn.type === 'FunctionDeclaration' || fn.type === 'ArrowFunctionExpression')
        {
          if (fn.run)
          {
            if (verbose)
              context.console.start('> ' + translate(token));

            fn.run.call(
              this,
              token,
              expr.type === 'Identifier' || expr.type === 'MemberExpression' ? scope.resolve(expr.object || expr.name) : null,
              args,
              scope
            );

            if (verbose)
              context.console.end();
          }
        }
        else
        {
          if (fn.type === 'CallExpression' && fn.call && fn.call.run)
          {
            if (verbose)
              context.console.start('> ' + translate(token));

            fn.call.run.call(
              this,
              token,
              fn.call,
              args,
              scope
            );

            if (verbose)
              context.console.end();
          }
        }
      }

      return this.SKIP;
    },
    ReturnStatement: function(token){
      var res = this.walk(token.argument);
      if (res && res.obj)
      {
        var callToken = this.top(2);
        callToken.ref_ = res.ref_ || res;

        if (callToken && callToken.type === 'CallExpression' && !callToken.obj)
          callToken.obj = res.obj;
      }
      return this.SKIP;
    },
    MemberExpression: function(token){
      if (token.ref_)
        return;

      var path = this.walk(token.object);

      if (path.ref_)
      {
        var obj = path.ref_.obj;
        if (obj && path.ref_.type === 'CallExpression')
          obj = obj.obj;
        token.ref_ = obj && obj[token.property.name];
      }
      return this.SKIP;
    },
    Identifier: function(token, scope){
      if (token.ref_)
        return;
      var name = token.name;
      if (scope.isGlobal(name) && name !== 'global') // TODO: make correct test for global
      {
        var ref = scope.get(name);
        if (ref)
          token.ref_ = ref.token;
      }
      else
      {
        var ref = scope.resolve(token);
        if (ref && ref.ref_)
          token.ref_ = ref.ref_;
      }
    },
    ThisExpression: function(token, scope){
      var ref = scope.resolve(token);
      if (ref && ref.ref_)
        token.ref_ = ref.ref_;
    },
    ObjectExpression: function(token, scope){
      var props = token.properties;
      var obj = {};

      for (var i = 0, prop; prop = props[i]; i++)
      {
        var key = prop.key.type === 'Literal' ? prop.key.value : prop.key.name;

        if (key === undefined)
          throw new Error('Unknown key type');

        obj[key] = scope.resolve(prop.value) || prop.value;
      }

      token.obj = obj;
    },
    AssignmentExpression: function(token, scope){
      var op = token.operator;
      var lvalue = token.left;
      var rvalue = token.right;

      if (op === '=')
      {
        if (lvalue.type === 'Identifier')
        {
          rvalue = this.walk(rvalue);
          scope.set(lvalue.name, rvalue);

          return this.SKIP;
        }
        if (lvalue.type === 'MemberExpression')
        {
          lvalue = this.walk(lvalue);
          rvalue = this.walk(rvalue);

          var dest = scope.resolve(lvalue.object);

          if (dest && dest.obj)
          {
            var key = lvalue.property.type === 'Literal' ? lvalue.property.value : lvalue.property.name;
            dest.obj[key] = scope.resolve(rvalue) || rvalue;
          }

          return this.SKIP;
        }
      }
    },
    ThrowStatement: function(token){
      ast.throws.push(token);
    }
  }, context);
}

module.exports.process = process;
<commit_msg>support computed object keys<commit_after>var walker = require('./walker').astWalker();
var translate = require('./translate').translate;

function process(ast, context){
  ast.throws = [];

  return walker.walk(ast, {
    CallExpression: function(token, scope){
      var expr = token.callee;
      var args = token.arguments;

      this.walk(expr);
      this.walkEach(args);

      var fn = scope.resolve(expr);

      if (fn)
      {
        var verbose = context.console.enabled;

        if (fn.ref_)
          fn = fn.ref_;

        if (fn.type === 'FunctionExpression' || fn.type === 'FunctionDeclaration' || fn.type === 'ArrowFunctionExpression')
        {
          if (fn.run)
          {
            if (verbose)
              context.console.start('> ' + translate(token));

            fn.run.call(
              this,
              token,
              expr.type === 'Identifier' || expr.type === 'MemberExpression' ? scope.resolve(expr.object || expr.name) : null,
              args,
              scope
            );

            if (verbose)
              context.console.end();
          }
        }
        else
        {
          if (fn.type === 'CallExpression' && fn.call && fn.call.run)
          {
            if (verbose)
              context.console.start('> ' + translate(token));

            fn.call.run.call(
              this,
              token,
              fn.call,
              args,
              scope
            );

            if (verbose)
              context.console.end();
          }
        }
      }

      return this.SKIP;
    },
    ReturnStatement: function(token){
      var res = this.walk(token.argument);
      if (res && res.obj)
      {
        var callToken = this.top(2);
        callToken.ref_ = res.ref_ || res;

        if (callToken && callToken.type === 'CallExpression' && !callToken.obj)
          callToken.obj = res.obj;
      }
      return this.SKIP;
    },
    MemberExpression: function(token){
      if (token.ref_)
        return;

      var path = this.walk(token.object);

      if (path.ref_)
      {
        var obj = path.ref_.obj;
        if (obj && path.ref_.type === 'CallExpression')
          obj = obj.obj;
        token.ref_ = obj && obj[token.property.name];
      }
      return this.SKIP;
    },
    Identifier: function(token, scope){
      if (token.ref_)
        return;
      var name = token.name;
      if (scope.isGlobal(name) && name !== 'global') // TODO: make correct test for global
      {
        var ref = scope.get(name);
        if (ref)
          token.ref_ = ref.token;
      }
      else
      {
        var ref = scope.resolve(token);
        if (ref && ref.ref_)
          token.ref_ = ref.ref_;
      }
    },
    ThisExpression: function(token, scope){
      var ref = scope.resolve(token);
      if (ref && ref.ref_)
        token.ref_ = ref.ref_;
    },
    ObjectExpression: function(token, scope){
      var props = token.properties;
      var obj = {};

      for (var i = 0, prop; prop = props[i]; i++)
      {
        var key;
        if (prop.computed)
        {
          var resolvedKey = scope.resolve(prop.key);

          if (!resolvedKey)
            continue;

          key = resolvedKey.type === 'Literal' ? resolvedKey.value : resolvedKey.name;
        }
        else
          key = prop.key.type === 'Literal' ? prop.key.value : prop.key.name;

        if (key === undefined)
          throw new Error('Unknown key type');

        obj[key] = scope.resolve(prop.value) || prop.value;
      }

      token.obj = obj;
    },
    AssignmentExpression: function(token, scope){
      var op = token.operator;
      var lvalue = token.left;
      var rvalue = token.right;

      if (op === '=')
      {
        if (lvalue.type === 'Identifier')
        {
          rvalue = this.walk(rvalue);
          scope.set(lvalue.name, rvalue);

          return this.SKIP;
        }
        if (lvalue.type === 'MemberExpression')
        {
          lvalue = this.walk(lvalue);
          rvalue = this.walk(rvalue);

          var dest = scope.resolve(lvalue.object);

          if (dest && dest.obj)
          {
            var key = lvalue.property.type === 'Literal' ? lvalue.property.value : lvalue.property.name;
            dest.obj[key] = scope.resolve(rvalue) || rvalue;
          }

          return this.SKIP;
        }
      }
    },
    ThrowStatement: function(token){
      ast.throws.push(token);
    }
  }, context);
}

module.exports.process = process;
<|endoftext|>


<commit_before>var analyser = require('./analyser'),
    Table = (String.red) ? '' : require('cli-table'),
    f = require('file'),
    fs = require('fs'),
    path = require('path'),
    util = require('util'),
    renderers = {},
    checkstyleRules = require("./rules");

function analyse(label, source) {
    return {
        filename: label,
        results: analyser.analyse(source)
    };
}

function run(filename) {
    return analyse(filename, fs.readFileSync(filename, "utf8"));
}

function jsonRenderer(results) {
    return JSON.stringify(results);
}

function applyRules(results) {
    var annotatedResults = results.map(function(file) {
        var checkedResults = file.results;
        checkstyleRules.forEach(function(rule) {
            checkedResults = rule.check(checkedResults);
        });
        return { filename: file.filename, results: checkedResults };
    });
    return annotatedResults;
}

function hasViolations(result) {
    return result.violations && result.violations.length > 0;
}

function violationsOnly(results) {
    var filtered = [],
        allResults = applyRules(results);
    //first strip out any non-violating results
    allResults.forEach(function (file) {
        file.results = file.results.filter(hasViolations);
    });
    //then strip out any files without results (no violations at all)
    return allResults.filter(function (file) { return file.results.length > 0; });
}

function cliTableRenderer(results) {
    var output = [];
    results.forEach(function(file) {
        output.push("jscheckstyle results - ".green + file.filename);
        var table = new Table({
            head: ["Line", "Function", "Length", "Args", "Complexity"],
            colWidths: [ 8, 40, 8, 6, 10 ]
        });
        file.results.forEach(function(fn) {
            table.push([fn.lineStart, fn.shortName, fn.lines, fn.ins, fn.complexity]);
        });
        output.push(table.toString());
    });
    return output.join("\n");
}

function htmlRenderer(results) {
    var i, comp, mi, pl;

    var d = {
        buffer: ["<!doctype html><title>jscheckstyle results</title>"],
        write : function(t) {
            if (t===0) {
                t = "0";
            }
            t = t || "";
            if (typeof t !== "string") {
                t = t.toString();
            }
            this.buffer.push(t);
        },
        toString: function() {
            return this.buffer.join('');
        }
    };

    function title(value) {
        d.write("
");
        d.write(value);
        d.write("
");
    }

    function table(header, rows) {
        d.write("

");
        d.write(header);
        d.write("

");
        d.write(rows);
        d.write("

");
    }

    function header() {
        return ["
"].concat(
            [
                "Line",
                "Function",
                "Lines",
                "Arguments",
                "Cyclomatic Complexity"
            ].map(
                function(column) { return "" + column + "	"; }
            )).concat(["
"]).join("");
    }

    function rows(results) {
        function redIf(test, value) {
            return test ? '' + value + '' : value;
        }

        return results.map(function(item) {
            return [ "
" ].concat(
                [ item.lineStart,
                  item.shortName,
                  redIf(item.lines > 30, item.lines),
                  redIf(item.ins > 5, item.ins),
                  redIf(item.complexity > 10, item.complexity)
                ].map(
                    function(column) { return "" + column + "	" ; }
                )).concat(["
"]).join("");
        }).join("\n");
    }

    results.forEach(function(item) {
        title(item.filename);
        table(
            header(),
            rows(item.results)
        );
    });
    d.write("");
    return d.toString();

}

function checkstyleRenderer(data) {
    var output = [ '<?xml version="1.0" encoding="utf-8"?>\n<checkstyle>' ],
        results = violationsOnly( Array.isArray(data) ? data : [ data ] );

    results.forEach(function(file) {
        output.push('<file name="' + file.filename + '">');
        file.results.forEach(function(result) {
            result.violations.forEach(function(violation) {
                output.push('<error line="' + result.lineStart + '" column="1" severity="error" message="' + violation.message + '" source="' + violation.source + '"/>');
            });
        });
        output.push('</file>');
    });

    output.push('</checkstyle>');
    return output.join('\n');

}

function register(renderer, values) {
    values.forEach(function(item) {
        renderers[item] = renderer;
    });
}

function addFile(file, files, ignores) {
    var isIgnored = false,
        i, ln;
    for (i = 0, ln = ignores.length; i < ln; i += 1) {
        if (file.match(new RegExp('^' + ignores[i]))) {
            isIgnored = true;
            break;
        }
    }
    if (!isIgnored) {
        files.push(file);
    }
}

function files(arg) {
    var stat = fs.statSync(arg),
        files = [],
        ignoreFile = path.join(process.cwd(), '.jscheckstyleignore'),
        ignores = [];

    if (path.existsSync(ignoreFile)) {
        var stream =fs.createReadStream(ignoreFile);
        ignores = fs.readFileSync(ignoreFile, 'utf-8').split('\n').filter(function (line) {
            return !!line;
        });
    }

    if (stat.isDirectory()) {
        f.walkSync(arg, function (base, dirs, names) {
            names.forEach(function (name) {
                if (name.match(/.js$/)) {
                    addFile(path.join(base, name), files, ignores);
                }
            });
        });
    } else {
        addFile(arg, files, ignores);
    }
    return files;
}

function end(results) {
    var errCount = 0;
    results = violationsOnly(results);
    results.forEach(function (result) {
        errCount += result.results.length;
    });

    function exit() {
        process.exit(errCount  > 0 ? 1: 0);
    }
    try {
        if (!process.stdout.flush()) {
            process.stdout.once('drain', exit);
        } else {
            exit();
        }
    } catch (e) {
        exit();
    }
}

register(checkstyleRenderer, ['--checkstyle','checkstyle']);
register(jsonRenderer, ['--json','json']);
register(htmlRenderer, ['--html','html']);
register(cliTableRenderer, ['--cli', 'table']);

exports.renderers = renderers;
exports.analyse = analyse;
exports.violationsOnly = violationsOnly;
exports.run = run;
exports.end = end;
exports.cli = function(arguments) {
    var renderer = '--cli',
        onlyViolations = false,
        results = [];

    arguments.forEach(function (arg) {
        if (renderers[arg]) {
            renderer = arg;
        } else if (arg === '--violations') {
            onlyViolations = true;
        } else {
            files(arg).forEach(function (file) {
                results.push(
                    run(file)
                );
            });
        }
    });

    if (onlyViolations && renderer !== '--checkstyle') {
        results = violationsOnly(results);
    }
    util.puts(renderers[renderer](results));
    end(results);
};
<commit_msg>[fix] path.existsSync was moved to fs.existsSync<commit_after>var analyser = require('./analyser'),
    Table = (String.red) ? '' : require('cli-table'),
    f = require('file'),
    fs = require('fs'),
    path = require('path'),
    util = require('util'),
    renderers = {},
    checkstyleRules = require("./rules");

function analyse(label, source) {
    return {
        filename: label,
        results: analyser.analyse(source)
    };
}

function run(filename) {
    return analyse(filename, fs.readFileSync(filename, "utf8"));
}

function jsonRenderer(results) {
    return JSON.stringify(results);
}

function applyRules(results) {
    var annotatedResults = results.map(function(file) {
        var checkedResults = file.results;
        checkstyleRules.forEach(function(rule) {
            checkedResults = rule.check(checkedResults);
        });
        return { filename: file.filename, results: checkedResults };
    });
    return annotatedResults;
}

function hasViolations(result) {
    return result.violations && result.violations.length > 0;
}

function violationsOnly(results) {
    var filtered = [],
        allResults = applyRules(results);
    //first strip out any non-violating results
    allResults.forEach(function (file) {
        file.results = file.results.filter(hasViolations);
    });
    //then strip out any files without results (no violations at all)
    return allResults.filter(function (file) { return file.results.length > 0; });
}

function cliTableRenderer(results) {
    var output = [];
    results.forEach(function(file) {
        output.push("jscheckstyle results - ".green + file.filename);
        var table = new Table({
            head: ["Line", "Function", "Length", "Args", "Complexity"],
            colWidths: [ 8, 40, 8, 6, 10 ]
        });
        file.results.forEach(function(fn) {
            table.push([fn.lineStart, fn.shortName, fn.lines, fn.ins, fn.complexity]);
        });
        output.push(table.toString());
    });
    return output.join("\n");
}

function htmlRenderer(results) {
    var i, comp, mi, pl;

    var d = {
        buffer: ["<!doctype html><title>jscheckstyle results</title>"],
        write : function(t) {
            if (t===0) {
                t = "0";
            }
            t = t || "";
            if (typeof t !== "string") {
                t = t.toString();
            }
            this.buffer.push(t);
        },
        toString: function() {
            return this.buffer.join('');
        }
    };

    function title(value) {
        d.write("
");
        d.write(value);
        d.write("
");
    }

    function table(header, rows) {
        d.write("

");
        d.write(header);
        d.write("

");
        d.write(rows);
        d.write("

");
    }

    function header() {
        return ["
"].concat(
            [
                "Line",
                "Function",
                "Lines",
                "Arguments",
                "Cyclomatic Complexity"
            ].map(
                function(column) { return "" + column + "	"; }
            )).concat(["
"]).join("");
    }

    function rows(results) {
        function redIf(test, value) {
            return test ? '' + value + '' : value;
        }

        return results.map(function(item) {
            return [ "
" ].concat(
                [ item.lineStart,
                  item.shortName,
                  redIf(item.lines > 30, item.lines),
                  redIf(item.ins > 5, item.ins),
                  redIf(item.complexity > 10, item.complexity)
                ].map(
                    function(column) { return "" + column + "	" ; }
                )).concat(["
"]).join("");
        }).join("\n");
    }

    results.forEach(function(item) {
        title(item.filename);
        table(
            header(),
            rows(item.results)
        );
    });
    d.write("");
    return d.toString();

}

function checkstyleRenderer(data) {
    var output = [ '<?xml version="1.0" encoding="utf-8"?>\n<checkstyle>' ],
        results = violationsOnly( Array.isArray(data) ? data : [ data ] );

    results.forEach(function(file) {
        output.push('<file name="' + file.filename + '">');
        file.results.forEach(function(result) {
            result.violations.forEach(function(violation) {
                output.push('<error line="' + result.lineStart + '" column="1" severity="error" message="' + violation.message + '" source="' + violation.source + '"/>');
            });
        });
        output.push('</file>');
    });

    output.push('</checkstyle>');
    return output.join('\n');

}

function register(renderer, values) {
    values.forEach(function(item) {
        renderers[item] = renderer;
    });
}

function addFile(file, files, ignores) {
    var isIgnored = false,
        i, ln;
    for (i = 0, ln = ignores.length; i < ln; i += 1) {
        if (file.match(new RegExp('^' + ignores[i]))) {
            isIgnored = true;
            break;
        }
    }
    if (!isIgnored) {
        files.push(file);
    }
}

function files(arg) {
    var stat = fs.statSync(arg),
        files = [],
        ignoreFile = path.join(process.cwd(), '.jscheckstyleignore'),
        ignores = [];

    if (fs.existsSync(ignoreFile)) {
        var stream =fs.createReadStream(ignoreFile);
        ignores = fs.readFileSync(ignoreFile, 'utf-8').split('\n').filter(function (line) {
            return !!line;
        });
    }

    if (stat.isDirectory()) {
        f.walkSync(arg, function (base, dirs, names) {
            names.forEach(function (name) {
                if (name.match(/.js$/)) {
                    addFile(path.join(base, name), files, ignores);
                }
            });
        });
    } else {
        addFile(arg, files, ignores);
    }
    return files;
}

function end(results) {
    var errCount = 0;
    results = violationsOnly(results);
    results.forEach(function (result) {
        errCount += result.results.length;
    });

    function exit() {
        process.exit(errCount  > 0 ? 1: 0);
    }
    try {
        if (!process.stdout.flush()) {
            process.stdout.once('drain', exit);
        } else {
            exit();
        }
    } catch (e) {
        exit();
    }
}

register(checkstyleRenderer, ['--checkstyle','checkstyle']);
register(jsonRenderer, ['--json','json']);
register(htmlRenderer, ['--html','html']);
register(cliTableRenderer, ['--cli', 'table']);

exports.renderers = renderers;
exports.analyse = analyse;
exports.violationsOnly = violationsOnly;
exports.run = run;
exports.end = end;
exports.cli = function(arguments) {
    var renderer = '--cli',
        onlyViolations = false,
        results = [];

    arguments.forEach(function (arg) {
        if (renderers[arg]) {
            renderer = arg;
        } else if (arg === '--violations') {
            onlyViolations = true;
        } else {
            files(arg).forEach(function (file) {
                results.push(
                    run(file)
                );
            });
        }
    });

    if (onlyViolations && renderer !== '--checkstyle') {
        results = violationsOnly(results);
    }
    util.puts(renderers[renderer](results));
    end(results);
};
<|endoftext|>


<commit_before>const Bluebird = require('bluebird');
const csv = require('csvtojson');
const fetch = require('node-fetch');
const find = require('array.prototype.find');
const get = require('lodash.get');
const moment = require('moment');

// Locale needs to be set to en, to be able to read month names in English
moment.locale('en');

const originalCsvURL = process.env.PROD_CSV;
const earliestDate = moment("2017-02-26 12:00");
const latestDate = moment("2017-05-13 12:00");

/*
  CSVs are a bit tricky ones to parse manually. Because of that,
  an external library will handle that for us.
*/
const csvToJsonAsync = content => new Promise((resolve, reject) => {
  var entries = [];
  csv({})
    .fromString(content)
    .on('json', (json) => { entries.push(json); })
    .on('done',(error)=>{
      error ? reject(error) : resolve(entries);
    });
});

/*
  HERE Maps Multi Reverse Geocode API requires HTTP POST content to follow a custom format
  See. https://developer.here.com/rest-apis/documentation/geocoder/topics/resource-multi-reverse-geocode.html
*/
const bodyForGeocodingRequest = entries => entries
  .map(entry => `id=${entry.index}&prox=${entry.latitude},${entry.longitude},50`)
  .join("\n");

/*
  Get district info for the location provided. The Multi Reverse Geocode API support only
  up to 100 locations; because of this, we'll find location only for the map markers.
  There shouldn't be more than 100 of those during the pilgrimage.
*/
const getPlacesAsync = entries => Bluebird.resolve(entries)
  .filter(entry => entry.marker)
  .then(filteredEntries => fetch(
    'https://reverse.geocoder.cit.api.here.com/6.2/multi-reversegeocode.json' +
    '?mode=retrieveAreas&maxresults=1&gen=9' +
    `&app_id=${process.env.HERE_APP_ID}&app_code=${process.env.HERE_APP_CODE}`,
    {
      method: 'POST',
      body: bodyForGeocodingRequest(filteredEntries),
      headers: { 'Content-Type': 'text/plain' }
    }))
  .then(res => res.json())
  .then(res => res.Response.Item);

/*
  The actual JSON generation
*/

// Enable advanced promise functions in this chain
Bluebird.resolve(true)
  // Fetch CSV content
  .then(() => fetch(originalCsvURL))
  .then(res => res.text())
  // Add header row to CSV (to ease parsing of it) and parse it
  .then(body => "date,image,latitude,longitude,shareUrl\r\n" + body)
  .then(csvToJsonAsync)
  // Parse interesting columns (including the IFTTT custom date format)
  .then(entries => entries.map(entry => ({
    moment: moment(entry.date, 'MMMM D, YYYY at hh:mmA'),
    latitude: entry.latitude,
    longitude: entry.longitude
  })))
  // Filter problematic entries away
  .then(entries => entries.filter(entry => entry.moment.isValid() &&
    entry.moment.isAfter(earliestDate) && entry.moment.isBefore(latestDate)))
  // Enrich content (eg. which entries need an actual marker)
  .then(entries => entries.map((current, index) => {
    const next = entries[index + 1];
    const isMarker = (index === 0 || !next || next.moment.isAfter(current.moment, 'day'));
    return {
      index: index,
      date: current.moment.format('dddd MMM Do [of] YYYY [at] H:mm'),
      latitude: current.latitude,
      longitude: current.longitude,
      marker: isMarker
    };
  }))
  // Add reverse geocoding data
  .then(entries => Bluebird.join(entries, getPlacesAsync(entries)))
  // Combine entries and place names
  .spread((entries, places) => {
    return entries.map(entry => {
      const place = find(places, item => item.ItemId === entry.index);
      entry.place = get(place, 'Result[0].Location.Address.Label', '');
      return entry;
    });
  })
  // Output the end result as nicely formatted JSON to stdout
  .then(entries => console.log(JSON.stringify(entries, null, 2)));
<commit_msg>Improve comments<commit_after>const Bluebird = require('bluebird');
const csv = require('csvtojson');
const fetch = require('node-fetch');
const find = require('array.prototype.find');
const get = require('lodash.get');
const moment = require('moment');

// Locale needs to be set to en, to be able to read month names in English
moment.locale('en');

const originalCsvURL = process.env.PROD_CSV;
const earliestDate = moment("2017-02-26 12:00");
const latestDate = moment("2017-05-13 12:00");

/*
  CSVs are a bit tricky ones to parse manually. Because of that,
  an external library will handle that for us.
*/
const csvToJsonAsync = content => new Promise((resolve, reject) => {
  var entries = [];
  csv({})
    .fromString(content)
    .on('json', (json) => { entries.push(json); })
    .on('done',(error)=>{
      error ? reject(error) : resolve(entries);
    });
});

/*
  HERE Maps Multi Reverse Geocode API requires HTTP POST content to follow a custom format
  See. https://developer.here.com/rest-apis/documentation/geocoder/topics/resource-multi-reverse-geocode.html
*/
const bodyForGeocodingRequest = entries => entries
  .map(entry => `id=${entry.index}&prox=${entry.latitude},${entry.longitude},50`)
  .join("\n");

/*
  Get district info for the location provided. The Multi Reverse Geocode API support only
  up to 100 locations; because of this, we'll find location only for the map markers.
  There shouldn't be more than 100 of those during the pilgrimage.
*/
const getPlacesAsync = entries => Bluebird.resolve(entries)
  .filter(entry => entry.marker)
  .then(filteredEntries => fetch(
    'https://reverse.geocoder.cit.api.here.com/6.2/multi-reversegeocode.json' +
    '?mode=retrieveAreas&maxresults=1&gen=9' +
    `&app_id=${process.env.HERE_APP_ID}&app_code=${process.env.HERE_APP_CODE}`,
    {
      method: 'POST',
      body: bodyForGeocodingRequest(filteredEntries),
      headers: { 'Content-Type': 'text/plain' }
    }))
  .then(res => res.json())
  .then(res => res.Response.Item);

/*
  The actual JSON generation
*/

// Enable advanced promise functions in this chain
Bluebird.resolve(true)
  // Fetch CSV content
  .then(() => fetch(originalCsvURL))
  .then(res => res.text())
  // Add header row to CSV (to ease parsing of it) and parse it
  .then(body => "date,image,latitude,longitude,shareUrl\r\n" + body)
  .then(csvToJsonAsync)
  // Parse interesting columns (including the IFTTT custom date format)
  .then(entries => entries.map(entry => ({
    moment: moment(entry.date, 'MMMM D, YYYY at hh:mmA'),
    latitude: entry.latitude,
    longitude: entry.longitude
  })))
  // Filter problematic and unwanted entries away
  .then(entries => entries.filter(entry => entry.moment.isValid() &&
    entry.moment.isAfter(earliestDate) && entry.moment.isBefore(latestDate)))
  // Enrich content (eg. which entries need an actual marker)
  .then(entries => entries.map((current, index) => {
    const next = entries[index + 1];
    const isMarker = (index === 0 || !next || next.moment.isAfter(current.moment, 'day'));
    return {
      index: index,
      date: current.moment.format('dddd MMM Do [of] YYYY [at] H:mm'),
      latitude: current.latitude,
      longitude: current.longitude,
      marker: isMarker
    };
  }))
  // Add reverse geocoding data
  .then(entries => Bluebird.join(entries, getPlacesAsync(entries)))
  // Combine entries and place names
  .spread((entries, places) => {
    return entries.map(entry => {
      const place = find(places, item => item.ItemId === entry.index);
      entry.place = get(place, 'Result[0].Location.Address.Label', '');
      return entry;
    });
  })
  // Output the end result as nicely formatted JSON to stdout
  .then(entries => console.log(JSON.stringify(entries, null, 2)));
<|endoftext|>


<commit_before>process.on('uncaughtException', function(err) {
  console.log(err.stack);
});

var fs = require('fs'), path = require('path'), cp = require('child_process'),
compileDebug = true,
ansi = require('ansi'), cursor = ansi(process.stdout),

S = require('string'),
ejs = require('ejs'),
_ = require('underscore'),
which = require('which'),
tv4 = require('tv4'), mustache = require('mustache'), beautify = {
  '.html' : require('js-beautify').html,
  '.ejs' : require('js-beautify').html
}, schemata = require('./schemata');
var dummyRenderer = function(s,d){
  return s;
}
var json2angular = {};
var templates ={

};
function renderTemplate (filename,data,renderer){
  renderer = renderer ||mustache.render;
  var source = templates[filename];
  var filepath = path.join(__dirname, '..', 'template', filename);
  if(!source){
    source = templates[filename] = fs.readFileSync(filepath, 'utf8');
  }
  data.filename=filepath;
  return renderer(source, data);
}

function createTemplate(appname, filename, view, renderer) {
  // Handle the Mustache view
  view = !view ? {} : view
  view.appname = appname

  var content = renderTemplate(filename,view, renderer);
  var ext = path.extname(filename);
  fs.writeFileSync(path.join(appname, filename), beautify[ext]?beautify[ext](content):content)
};

function createScaffold(appname) {

  // Create the app directory
  !fs.existsSync(appname) && fs.mkdirSync(appname);
  var projectPath = path.join(__dirname, appname);

  [ "modules", "modules/conversation", 'modules/conversation/partial', 'modules/conversation/controller','modules/conversation/controller/custom', 'modules/conversation/locale', 'gruntTasks', "components", 'constant', 'service', 'libs', 'compiled_modules', "less", "styles", "locale", "controllers", "partials", "scripts"].forEach(
      function(directory) {
        var appDirectory = path.join(appname, directory)
        !fs.existsSync(appDirectory) && fs.mkdirSync(appDirectory);
      }, this);

  var customGruntFile = path.join(appname, 'Gruntfile_custom.js')
  !fs.existsSync(customGruntFile) && createTemplate(appname, 'Gruntfile_custom.js');

  var packageJson = path.join(appname, 'package.json');
  createTemplate(appname, 'package.json.req');
  !fs.existsSync(packageJson) && fs.renameSync(packageJson + '.req', packageJson);

  var bowerJson = path.join(appname, 'bower.json');
  createTemplate(appname, 'bower.json.req');
  !fs.existsSync(bowerJson) && fs.renameSync(bowerJson + '.req', bowerJson);
};

function createContents(elements ,path){
  var contents = "";
  var count = 0;
  Object.keys(elements).sort().forEach(function(e){
    var myPath = path?path +"."+e : e;
    var element =  elements[e];
    if(element.type!= null && !element.components ){
      if(element.typeWrapper == 'array'){
        var pathPart = myPath+"[$index]";
        var typeWrapper = element.typeWrapper;
        contents += renderTemplate("fragment/"+typeWrapper+"-wrapper.html",{
          element:element,
          path: myPath,
          pathPart:pathPart,
          contents:
            renderTemplate("fragment/"+element.type+".html",{
              element:element,
              path: pathPart
            },_.template)
        },_.template);
      } else {
        contents +=
          renderTemplate("fragment/element.html",{
            element:element,
            path: myPath,
            contents:
              renderTemplate("fragment/"+element.type+".html",{
                element:element,
                path: myPath
              },_.template)
          },_.template)
      }
    } else if (element.components) {
      if(element.type == 'array'){
        var pathPart = myPath.replace(/\./g,'_');
        contents += renderTemplate("fragment/arrayOfElements.html",{
          element:element,
          path: myPath,
          pathPart:pathPart,
          contents:createContents(element.components.elements,pathPart)
        },_.template)
      } else {
        contents += renderTemplate("fragment/elements.html",{
          element:element,
          contents:createContents(element.components.elements,myPath)
        },_.template)
      }
    }

  });
  return contents;
}

var flattenTitles = function(flattenedTitles,element,path){
  path = path.replace(/\//g,"_")
  var title = element.title || element.ui.title;
  flattenedTitles.push({
    key:path,
    title:title
  })
  if(element.title){
    element.title=path;
  } else {
    element.ui.title=path;
  }
  var elements = element.components?element.components.elements:element.elements;
  if(elements){
    Object.keys(elements).forEach(function(e){
      var myPath = path +"."+e.toUpperCase();
      var element =  elements[e];
      flattenTitles(flattenedTitles,element,myPath);
    });
  }
  elements = element.components?element.components.actions:null;
  if(elements){
    Object.keys(elements).forEach(function(e){
      var myPath = path +"."+e.toUpperCase();
      var element =  elements[e];
      flattenTitles(flattenedTitles,element,myPath);
    });
  }
}

// An application is described by many states. Each state defines UI elements
// and provides actionables to expose other application states. This function
// drives the UI generation for a specifed state.
function createState(appname, stateName, description,states) {

  stateName = new S(stateName);

  var newPath = path.join(appname, 'modules', 'conversation', 'controller',"custom", description.friendly + '.js');
  if(!fs.existsSync(newPath)){
    createTemplate(appname, path.join('modules', 'conversation', 'controller', 'emptyController.js'), {
      actionableName:"",
      actionables:description
    },ejs.render);
    // Rename the actionable template to the actionable name
    var oldPath = path.join(appname, 'modules', 'conversation', 'controller', 'emptyController.js');
    fs.renameSync(oldPath, newPath);
  }

  var elements = description.elements;
  for ( var n in elements) {
    var element = elements[n];

    createTemplate(appname, path.join('modules', 'conversation', 'partial', 'actionable.html'), {
      actionableName:n,
      contents : element.components?createContents(element.components.elements,"data."+n):"",
      actionable:element,
      actionables:description

    },ejs.render);

    // Rename the actionable template to the actionable name
    var oldPath = path.join(appname, 'modules', 'conversation', 'partial', 'actionable.html');
    var newPath = path.join(appname, 'modules', 'conversation', 'partial', description.friendly + '.'+ n + '.html');
    fs.renameSync(oldPath, newPath);

    var newPath = path.join(appname, 'modules', 'conversation', 'controller',"custom", description.friendly + '.'+ n + '.js');
    if(!fs.existsSync(newPath)){
      createTemplate(appname, path.join('modules', 'conversation', 'controller', 'emptyController.js'), {
        actionableName:n,
        actionables:description
      },ejs.render);

      // Rename the actionable template to the actionable name
      var oldPath = path.join(appname, 'modules', 'conversation', 'controller', 'emptyController.js');
      fs.renameSync(oldPath, newPath);
    }
  }

  // Setup view for state partial
  createTemplate(appname, path.join('modules', 'conversation', 'partial', 'state.html'), {
      stateName:stateName.s,
      description:description
    },ejs.render);
  // Rename the partial using the state name
  var partialPath = path.join(appname, 'modules', 'conversation', 'partial');
  var oldPath = path.join(partialPath, 'state.html');
  var newPath = path.join(partialPath, description.friendly + '.html');
  fs.renameSync(oldPath, newPath);

  view = {
    statename : stateName.s.toLowerCase(),
    description:description,
    states:states
  };
  createTemplate(appname, path.join('modules', 'conversation', 'controller', 'controller.js'), view,ejs.render);
  // rename the controller
  var controllerPath = path.join(appname, 'modules', 'conversation', 'controller');
  oldPath = path.join(controllerPath, 'controller.js');
  newPath = path.join(controllerPath, description.friendly + '.js');

  fs.renameSync(oldPath, newPath);
}

// Parse an application spec, and drive UI generation
function createApp(appname, spec) {
  var states = spec.states;
  var flattenedTitles = [];
  for ( var name in states) {
    var description = states[name];
    flattenTitles(flattenedTitles,description,name.toUpperCase())
  }
  for ( var name in states) {
    var description = states[name];
    createState(appname, name, description,states);
  }
  var locale = process.env.LANG?process.env.LANG.replace(/\..*/,""):"en_US";
  createTemplate(appname, path.join('modules', 'conversation', 'locale', 'locale.js'), {
    title:spec.title,
    keys:flattenedTitles.sort(function(e1,e2){
      return e1.key.localeCompare(e2.key);
    }),
    locale:locale
  });
  var oldPath = path.join(appname, 'modules', 'conversation', 'locale', 'locale.js');
  var newPath = path.join(appname, 'modules', 'conversation', 'locale', locale+'.js');
  fs.renameSync(oldPath, newPath);

  createTemplate(appname, path.join('modules', 'conversation', 'conversation.js'), {
    states : states
  },ejs.render);

}

// This is the top level function for application generation. It drives other
// functions
// to create a scaffold and templates.
function createProject(spec) {
  var appname = new S(spec.name).camelize().s, isNew = !fs.existsSync(appname);

  createScaffold(appname);

  // First check if the app name exists in the filesystem
  if (isNew) {
    createTemplate(appname, 'README.md');
    createTemplate(appname, 'app.js');
    createTemplate(appname, 'main.ejs');
    createTemplate(appname, 'index.ejs');
  }

  var doStuff = function() {

    createTemplate(appname, path.join('constant', 'serverLocation.js'));
    createTemplate(appname, path.join('service', 'SocketService.js'));
    createTemplate(appname, path.join('service', 'RestService.js'));
    createTemplate(appname, 'Gruntfile.js');
    fs.readdirSync(path.join(__dirname, '../', 'template', 'gruntTasks')).forEach(function(file) {
      createTemplate(appname, path.join('gruntTasks', file),null,dummyRenderer);
    });

    if (isNew) {
    	fs.readdirSync(path.join(__dirname, '../', 'template', 'less')).forEach(function(file) {
    	    createTemplate(appname, path.join('less', file),null,dummyRenderer);
    	});
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'libs')).forEach(function(file) {
	      createTemplate(appname, path.join('libs', file),null,dummyRenderer);
	    });
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'scripts')).forEach(function(file) {
	    	if(file != 'custom'){
	    		createTemplate(appname, path.join('scripts', file),null,dummyRenderer);
	    	}
	    });
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'components')).forEach(function(folder) {
	  	  fs.mkdir(path.join(path.resolve(appname), 'components', folder), function(response){
			  	fs.readdirSync(path.join(__dirname, '../', 'template', 'components', folder)).forEach(function(file) {
			  	  /* BIG ASSUMPTION HERE */
			  	  if(file == 'custom'){
		          !fs.existsSync( path.join(appname,'components', folder, file)) &&
		          fs.mkdirSync(path.join(path.resolve(appname), 'components', folder, file));
		          fs.readdirSync(path.join(__dirname, '../', 'template', 'components', folder, file)).forEach(function(customFile) {
		            !fs.existsSync( path.join(appname,'components', folder, file, customFile)) &&
		            createTemplate(appname, path.join('components', folder, file, customFile), {}, ejs.render);
		          });
		        }else{
		          createTemplate(appname, path.join('components', folder, file), {}, ejs.render);
		        }
			  	});
		     });
	    });
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'partials')).forEach(function(folder) {
	    	  fs.mkdir(path.join(path.resolve(appname), 'partials', folder), function(response){
	  		  	fs.readdirSync(path.join(__dirname, '../', 'template', 'partials', folder)).forEach(function(file) {
	  		  	  /* BIG ASSUMPTION HERE */
	  		  	  if(file == 'custom'){
	  	          !fs.existsSync( path.join(appname,'partials', folder, file)) &&
	  	          fs.mkdirSync(path.join(path.resolve(appname), 'partials', folder, file));
	  	          fs.readdirSync(path.join(__dirname, '../', 'template', 'partials', folder, file)).forEach(function(customFile) {
	  	            !fs.existsSync( path.join(appname,'partials', folder, file, customFile)) &&
	  	            createTemplate(appname, path.join('partials', folder, file, customFile), {}, ejs.render);
	  	          });
	  	        }else{
	  	          createTemplate(appname, path.join('partials', folder, file), {}, ejs.render);
	  	        }
	  		  	});
	  	     });
	      });
    }

    createApp(appname, spec);

    exec('npm',['install'], path.resolve(appname),
      function (error) {
        if (error) {
          console.log('exec error: ' + error);
        } else {
          exec('npm',['test'], path.resolve(appname),
             function (error) {
            if (error) {
              console.log('exec error: ' + error);
            }
         });
       }
    });
  }

  //replace setup.sh
  exec("bower", ["install"],path.resolve(appname), function(error) {
    if (error) {
      console.log('exec error: ' + error);
    } else {
      exec("npm", ["install"],path.resolve(appname)+"/bower_components/sockjs-client/", function(error) {
        if (error) {
          console.log('exec error: ' + error);
        } else {
          exec("make", ["build"],path.resolve(appname)+"/bower_components/sockjs-client/", function(error) {
            if (error) {
              console.log('exec error: ' + error);
            } else {
              doStuff();
            }
          });
        }
      });
    }
  });
};

function exec (cmd,args,cwd, cb){
  var proc = cp.spawn(which.sync(cmd), args||[],{cwd:cwd||path.resolve(appname), stdio: 'inherit' });
  if(cb){
    proc.on("close",cb)
  }
  return proc;
}
//This function is the main driver that is executed by the `json2angular`
//binary.
json2angular.exec = function(spec) {

 // The JSON spec must be validated before any project scaffold or code is
 // generated
 var valid = tv4.validate(spec, schemata);
 if (!valid) {
   cursor.red();
   console.log(tv4.error);
   console.log(JSON.stringify(spec,null,2))
   cursor.reset();
   return;
 }
};

// This function is the main driver that is executed by the `json2angular`
// binary.
json2angular.exec = function(spec) {

  // The JSON spec must be validated before any project scaffold or code is
  // generated
  var valid = tv4.validate(spec, schemata);
  if (!valid) {
    cursor.red();
    console.log(tv4.error);
    console.log(JSON.stringify(spec,null,2))
    cursor.reset();
    return;
  }

  createProject(spec);
};

// Export functions for testing
json2angular.createState = createState;

module.exports = json2angular;
<commit_msg>grunt fix<commit_after>process.on('uncaughtException', function(err) {
  console.log(err.stack);
});

var fs = require('fs'), path = require('path'), cp = require('child_process'),
compileDebug = true,
ansi = require('ansi'), cursor = ansi(process.stdout),

S = require('string'),
ejs = require('ejs'),
_ = require('underscore'),
which = require('which'),
tv4 = require('tv4'), mustache = require('mustache'), beautify = {
  '.html' : require('js-beautify').html,
  '.ejs' : require('js-beautify').html
}, schemata = require('./schemata');
var dummyRenderer = function(s,d){
  return s;
}
var json2angular = {};
var templates ={

};
function renderTemplate (filename,data,renderer){
  renderer = renderer ||mustache.render;
  var source = templates[filename];
  var filepath = path.join(__dirname, '..', 'template', filename);
  if(!source){
    source = templates[filename] = fs.readFileSync(filepath, 'utf8');
  }
  data.filename=filepath;
  return renderer(source, data);
}

function createTemplate(appname, filename, view, renderer) {
  // Handle the Mustache view
  view = !view ? {} : view
  view.appname = appname

  var content = renderTemplate(filename,view, renderer);
  var ext = path.extname(filename);
  fs.writeFileSync(path.join(appname, filename), beautify[ext]?beautify[ext](content):content)
};

function createScaffold(appname) {

  // Create the app directory
  !fs.existsSync(appname) && fs.mkdirSync(appname);
  var projectPath = path.join(__dirname, appname);

  [ "modules", "modules/conversation", 'modules/conversation/partial', 'modules/conversation/controller','modules/conversation/controller/custom', 'modules/conversation/locale', 'gruntTasks', "components", 'constant', 'service', 'libs', 'compiled_modules', "less", "styles", "locale", "controllers", "partials", "scripts"].forEach(
      function(directory) {
        var appDirectory = path.join(appname, directory)
        !fs.existsSync(appDirectory) && fs.mkdirSync(appDirectory);
      }, this);

  var customGruntFile = path.join(appname, 'Gruntfile_custom.js')
  !fs.existsSync(customGruntFile) && createTemplate(appname, 'Gruntfile_custom.js');

  var packageJson = path.join(appname, 'package.json');
  createTemplate(appname, 'package.json.req');
  !fs.existsSync(packageJson) && fs.renameSync(packageJson + '.req', packageJson);

  var bowerJson = path.join(appname, 'bower.json');
  createTemplate(appname, 'bower.json.req');
  !fs.existsSync(bowerJson) && fs.renameSync(bowerJson + '.req', bowerJson);
};

function createContents(elements ,path){
  var contents = "";
  var count = 0;
  Object.keys(elements).sort().forEach(function(e){
    var myPath = path?path +"."+e : e;
    var element =  elements[e];
    if(element.type!= null && !element.components ){
      if(element.typeWrapper == 'array'){
        var pathPart = myPath+"[$index]";
        var typeWrapper = element.typeWrapper;
        contents += renderTemplate("fragment/"+typeWrapper+"-wrapper.html",{
          element:element,
          path: myPath,
          pathPart:pathPart,
          contents:
            renderTemplate("fragment/"+element.type+".html",{
              element:element,
              path: pathPart
            },_.template)
        },_.template);
      } else {
        contents +=
          renderTemplate("fragment/element.html",{
            element:element,
            path: myPath,
            contents:
              renderTemplate("fragment/"+element.type+".html",{
                element:element,
                path: myPath
              },_.template)
          },_.template)
      }
    } else if (element.components) {
      if(element.type == 'array'){
        var pathPart = myPath.replace(/\./g,'_');
        contents += renderTemplate("fragment/arrayOfElements.html",{
          element:element,
          path: myPath,
          pathPart:pathPart,
          contents:createContents(element.components.elements,pathPart)
        },_.template)
      } else {
        contents += renderTemplate("fragment/elements.html",{
          element:element,
          contents:createContents(element.components.elements,myPath)
        },_.template)
      }
    }

  });
  return contents;
}

var flattenTitles = function(flattenedTitles,element,path){
  path = path.replace(/\//g,"_")
  var title = element.title || element.ui.title;
  flattenedTitles.push({
    key:path,
    title:title
  })
  if(element.title){
    element.title=path;
  } else {
    element.ui.title=path;
  }
  var elements = element.components?element.components.elements:element.elements;
  if(elements){
    Object.keys(elements).forEach(function(e){
      var myPath = path +"."+e.toUpperCase();
      var element =  elements[e];
      flattenTitles(flattenedTitles,element,myPath);
    });
  }
  elements = element.components?element.components.actions:null;
  if(elements){
    Object.keys(elements).forEach(function(e){
      var myPath = path +"."+e.toUpperCase();
      var element =  elements[e];
      flattenTitles(flattenedTitles,element,myPath);
    });
  }
}

// An application is described by many states. Each state defines UI elements
// and provides actionables to expose other application states. This function
// drives the UI generation for a specifed state.
function createState(appname, stateName, description,states) {

  stateName = new S(stateName);

  var newPath = path.join(appname, 'modules', 'conversation', 'controller',"custom", description.friendly + '.js');
  if(!fs.existsSync(newPath)){
    createTemplate(appname, path.join('modules', 'conversation', 'controller', 'emptyController.js'), {
      actionableName:"",
      actionables:description
    },ejs.render);
    // Rename the actionable template to the actionable name
    var oldPath = path.join(appname, 'modules', 'conversation', 'controller', 'emptyController.js');
    fs.renameSync(oldPath, newPath);
  }

  var elements = description.elements;
  for ( var n in elements) {
    var element = elements[n];

    createTemplate(appname, path.join('modules', 'conversation', 'partial', 'actionable.html'), {
      actionableName:n,
      contents : element.components?createContents(element.components.elements,"data."+n):"",
      actionable:element,
      actionables:description

    },ejs.render);

    // Rename the actionable template to the actionable name
    var oldPath = path.join(appname, 'modules', 'conversation', 'partial', 'actionable.html');
    var newPath = path.join(appname, 'modules', 'conversation', 'partial', description.friendly + '.'+ n + '.html');
    fs.renameSync(oldPath, newPath);

    var newPath = path.join(appname, 'modules', 'conversation', 'controller',"custom", description.friendly + '.'+ n + '.js');
    if(!fs.existsSync(newPath)){
      createTemplate(appname, path.join('modules', 'conversation', 'controller', 'emptyController.js'), {
        actionableName:n,
        actionables:description
      },ejs.render);

      // Rename the actionable template to the actionable name
      var oldPath = path.join(appname, 'modules', 'conversation', 'controller', 'emptyController.js');
      fs.renameSync(oldPath, newPath);
    }
  }

  // Setup view for state partial
  createTemplate(appname, path.join('modules', 'conversation', 'partial', 'state.html'), {
      stateName:stateName.s,
      description:description
    },ejs.render);
  // Rename the partial using the state name
  var partialPath = path.join(appname, 'modules', 'conversation', 'partial');
  var oldPath = path.join(partialPath, 'state.html');
  var newPath = path.join(partialPath, description.friendly + '.html');
  fs.renameSync(oldPath, newPath);

  view = {
    statename : stateName.s.toLowerCase(),
    description:description,
    states:states
  };
  createTemplate(appname, path.join('modules', 'conversation', 'controller', 'controller.js'), view,ejs.render);
  // rename the controller
  var controllerPath = path.join(appname, 'modules', 'conversation', 'controller');
  oldPath = path.join(controllerPath, 'controller.js');
  newPath = path.join(controllerPath, description.friendly + '.js');

  fs.renameSync(oldPath, newPath);
}

// Parse an application spec, and drive UI generation
function createApp(appname, spec) {
  var states = spec.states;
  var flattenedTitles = [];
  for ( var name in states) {
    var description = states[name];
    flattenTitles(flattenedTitles,description,name.toUpperCase())
  }
  for ( var name in states) {
    var description = states[name];
    createState(appname, name, description,states);
  }
  var locale = process.env.LANG?process.env.LANG.replace(/\..*/,""):"en_US";
  createTemplate(appname, path.join('modules', 'conversation', 'locale', 'locale.js'), {
    title:spec.title,
    keys:flattenedTitles.sort(function(e1,e2){
      return e1.key.localeCompare(e2.key);
    }),
    locale:locale
  });
  var oldPath = path.join(appname, 'modules', 'conversation', 'locale', 'locale.js');
  var newPath = path.join(appname, 'modules', 'conversation', 'locale', locale+'.js');
  fs.renameSync(oldPath, newPath);

  createTemplate(appname, path.join('modules', 'conversation', 'conversation.js'), {
    states : states
  },ejs.render);

}

// This is the top level function for application generation. It drives other
// functions
// to create a scaffold and templates.
function createProject(spec) {
	console.log('spec');
	console.log(spec);
  var appname = new S(spec.name).camelize().s, isNew = !fs.existsSync(appname);

  createScaffold(appname);

  // First check if the app name exists in the filesystem
  if (isNew) {
    createTemplate(appname, 'README.md');
    createTemplate(appname, 'app.js');
    createTemplate(appname, 'main.ejs');
    createTemplate(appname, 'index.ejs');
  }

  var doStuff = function() {

    createTemplate(appname, path.join('constant', 'serverLocation.js'));
    createTemplate(appname, path.join('service', 'SocketService.js'));
    createTemplate(appname, path.join('service', 'RestService.js'));

    if (isNew) {
    	createTemplate(appname, 'Gruntfile.js');
        fs.readdirSync(path.join(__dirname, '../', 'template', 'gruntTasks')).forEach(function(file) {
          createTemplate(appname, path.join('gruntTasks', file),null,dummyRenderer);
        });
    	fs.readdirSync(path.join(__dirname, '../', 'template', 'less')).forEach(function(file) {
    	    createTemplate(appname, path.join('less', file),null,dummyRenderer);
    	});
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'libs')).forEach(function(file) {
	      createTemplate(appname, path.join('libs', file),null,dummyRenderer);
	    });
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'scripts')).forEach(function(file) {
	    	if(file != 'custom'){
	    		createTemplate(appname, path.join('scripts', file),null,dummyRenderer);
	    	}
	    });
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'components')).forEach(function(folder) {
	  	  fs.mkdir(path.join(path.resolve(appname), 'components', folder), function(response){
			  	fs.readdirSync(path.join(__dirname, '../', 'template', 'components', folder)).forEach(function(file) {
			  	  /* BIG ASSUMPTION HERE */
			  	  if(file == 'custom'){
		          !fs.existsSync( path.join(appname,'components', folder, file)) &&
		          fs.mkdirSync(path.join(path.resolve(appname), 'components', folder, file));
		          fs.readdirSync(path.join(__dirname, '../', 'template', 'components', folder, file)).forEach(function(customFile) {
		            !fs.existsSync( path.join(appname,'components', folder, file, customFile)) &&
		            createTemplate(appname, path.join('components', folder, file, customFile), {}, ejs.render);
		          });
		        }else{
		          createTemplate(appname, path.join('components', folder, file), {}, ejs.render);
		        }
			  	});
		     });
	    });
	    fs.readdirSync(path.join(__dirname, '../', 'template', 'partials')).forEach(function(folder) {
	    	  fs.mkdir(path.join(path.resolve(appname), 'partials', folder), function(response){
	  		  	fs.readdirSync(path.join(__dirname, '../', 'template', 'partials', folder)).forEach(function(file) {
	  		  	  /* BIG ASSUMPTION HERE */
	  		  	  if(file == 'custom'){
	  	          !fs.existsSync( path.join(appname,'partials', folder, file)) &&
	  	          fs.mkdirSync(path.join(path.resolve(appname), 'partials', folder, file));
	  	          fs.readdirSync(path.join(__dirname, '../', 'template', 'partials', folder, file)).forEach(function(customFile) {
	  	            !fs.existsSync( path.join(appname,'partials', folder, file, customFile)) &&
	  	            createTemplate(appname, path.join('partials', folder, file, customFile), {}, ejs.render);
	  	          });
	  	        }else{
	  	          createTemplate(appname, path.join('partials', folder, file), {}, ejs.render);
	  	        }
	  		  	});
	  	     });
	      });
    }

    createApp(appname, spec);

    exec('npm',['install'], path.resolve(appname),
      function (error) {
        if (error) {
          console.log('exec error: ' + error);
        } else {
          exec('npm',['test'], path.resolve(appname),
             function (error) {
            if (error) {
              console.log('exec error: ' + error);
            }
         });
       }
    });
  }

  //replace setup.sh
  exec("bower", ["install"],path.resolve(appname), function(error) {
    if (error) {
      console.log('exec error: ' + error);
    } else {
      exec("npm", ["install"],path.resolve(appname)+"/bower_components/sockjs-client/", function(error) {
        if (error) {
          console.log('exec error: ' + error);
        } else {
          exec("make", ["build"],path.resolve(appname)+"/bower_components/sockjs-client/", function(error) {
            if (error) {
              console.log('exec error: ' + error);
            } else {
              doStuff();
            }
          });
        }
      });
    }
  });
};

function exec (cmd,args,cwd, cb){
  var proc = cp.spawn(which.sync(cmd), args||[],{cwd:cwd||path.resolve(appname), stdio: 'inherit' });
  if(cb){
    proc.on("close",cb)
  }
  return proc;
}
//This function is the main driver that is executed by the `json2angular`
//binary.
json2angular.exec = function(spec) {

 // The JSON spec must be validated before any project scaffold or code is
 // generated
 var valid = tv4.validate(spec, schemata);
 if (!valid) {
   cursor.red();
   console.log(tv4.error);
   console.log(JSON.stringify(spec,null,2))
   cursor.reset();
   return;
 }
};

// This function is the main driver that is executed by the `json2angular`
// binary.
json2angular.exec = function(spec) {

  // The JSON spec must be validated before any project scaffold or code is
  // generated
  var valid = tv4.validate(spec, schemata);
  if (!valid) {
    cursor.red();
    console.log(tv4.error);
    console.log(JSON.stringify(spec,null,2))
    cursor.reset();
    return;
  }

  createProject(spec);
};

// Export functions for testing
json2angular.createState = createState;

module.exports = json2angular;
<|endoftext|>