<commit_before>var Joi = require('joi')
var schemas = module.exports = {}
var swaggerVersion = Joi.string().valid('2.0').required()
var dataTypes = Joi.string().valid(['integer', 'number', 'string', 'boolean', 'array', 'file'])
var dataFormat = Joi.string().valid(['int32', 'int64', 'float', 'double', 'byte', 'date', 'date-time'])
var arrayOfStrings = Joi.array().items(Joi.string())
var reference = Joi.string()
// var collectionFormat = Joi.string().valid(['csv', 'ssv', 'tsv', 'pipes', 'multi'])

// reference: https://github.com/swagger-api/swagger-spec/blob/master/schemas/v2.0/schema.json

schemas.SimpleReference = Joi.object({
  $ref: reference
}).meta({
  className: 'SimpleReference'
})

schemas.Reference = Joi.object({
  $ref: reference,
  type: Joi.string(),
  items: Joi.object({
    $ref: reference.required()
  })
}).xor(['$ref', 'items']).meta({
  className: 'Reference'
})

schemas.ExternalDocs = Joi.object({
  description: Joi.string().required(),
  url: Joi.string().required()
}).meta({
  className: 'ExternalDocs'
})

schemas.Item = Joi.object({
  type: dataTypes.required(),
  format: dataFormat.optional(),
  items: Joi.any(),
  default: Joi.any().optional(),
  maximum: Joi.number().optional(),
  minimum: Joi.number().optional()
/*
 collectionFormat: collectionFormat.optional(),
 exclusiveMaximum: Joi.boolean().optional(),
 exclusiveMinimum: Joi.boolean().optional(),
 maxLength: Joi.number().integer().optional(),
 minLength: Joi.number().integer().optional(),
 pattern: Joi.string().optional(),
 maxItems: Joi.number().integer().optional(),
 minItems: Joi.number().integer().optional(),
 uniqueItems: Joi.boolean().optional(),
 multipleOf: Joi.number().optional(),
 enum: Joi.any().optional()
 */
}).meta({
  className: 'Items'
})

schemas.Property = Joi.object().keys({
  type: Joi.string().optional(),
  description: Joi.string().allow('').optional(),
  format: Joi.string().optional(),
  items: Joi.alternatives().try(schemas.SimpleReference, schemas.Item).optional(),
  default: Joi.any().optional(),
  enum: Joi.any().optional(),
  maximum: Joi.number().optional(),
  minimum: Joi.number().optional()
// schema: schemas.Reference.optional()
}).meta({
  className: 'Property'
})

schemas.Parameter = Joi.object({
  name: Joi.string().required(),
  in: Joi.string().valid(['query', 'header', 'path', 'formData', 'body']).required(),
  description: Joi.string().allow('').optional(),
  required: Joi.boolean().optional(),
  // if body
  schema: Joi.alternatives().when('in', {is: 'body', then: Joi.alternatives().try(schemas.Reference.required(), schemas.Property)}),
  // else
  type: Joi.alternatives().when('in', {is: 'body', otherwise: dataTypes.required()}),
  format: Joi.alternatives().when('in', {is: 'body', otherwise: dataFormat.optional()}),
  items: Joi.alternatives().when('type', {is: 'array', then: Joi.alternatives().try(schemas.SimpleReference, schemas.Item).required()}),
  collectionFormat: Joi.alternatives().when('in', {
    is: 'body',
    otherwise: Joi.string().valid(['csv', 'ssv', 'tsv', 'pipes', 'multi']).default('csv').optional()
  }),
  default: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.any().optional()}),
  maximum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().optional()}),
  exclusiveMaximum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.boolean().optional()}),
  minimum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().optional()}),
  exclusiveMinimum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.boolean().optional()}),
  maxLength: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  minLength: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  pattern: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.string().optional()}),
  maxItems: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  minItems: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  uniqueItems: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.boolean().optional()}),
  enum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.any().optional()}),
  multipleOf: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().optional()})
}).meta({
  className: 'Parameter'
})

schemas.Response = Joi.object({
  description: Joi.string().allow('').optional(),
  schema: Joi.alternatives().try(schemas.Reference, schemas.Property).optional(),
  // posible but will not be generated (yet)
  headers: Joi.any().optional(),
  examples: Joi.any().optional()
}).meta({
  className: 'Response'
})

schemas.Responses = Joi.object({
  default: schemas.Response.required() // optional in swagger ui
}).pattern(/^[0-9]{3}$/, schemas.Response).meta({
  className: 'Responses'
})

schemas.Operation = Joi.object({
  tags: arrayOfStrings.optional(),
  summary: Joi.string().optional(),
  description: Joi.string().allow('').optional(),
  externalDocs: schemas.ExternalDocs.optional(),
  operationId: Joi.string().optional(),
  consumes: arrayOfStrings.optional(),
  produces: arrayOfStrings.optional(),
  parameters: Joi.array().items(schemas.Parameter).optional(),
  responses: schemas.Responses.required(),
  schemes: arrayOfStrings.optional(),
  deprecated: Joi.boolean().optional(),
  security: Joi.any()
}).meta({
  className: 'Operation'
})

schemas.Path = Joi.object({
  get: schemas.Operation.optional(),
  put: schemas.Operation.optional(),
  post: schemas.Operation.optional(),
  delete: schemas.Operation.optional(),
  options: schemas.Operation.optional(),
  head: schemas.Operation.optional(),
  patch: schemas.Operation.optional(),
  parameters: Joi.array().items(schemas.Parameter).optional()
}).meta({
  className: 'Path'
})

schemas.Definition = Joi.object({
  title: Joi.string().optional(),
  description: Joi.string().allow('').optional(),
  type: dataTypes.optional(),
  required: Joi.array().items(Joi.string()),
  properties: Joi.object({}).pattern(/.*/, Joi.alternatives().try(schemas.Reference, schemas.Property)),
  default: Joi.any().optional(),
  items: Joi.alternatives().try(schemas.SimpleReference, schemas.Item).optional(),
  format: dataFormat.optional(),

  // For schema integration tests:
  allOf: Joi.array().items(schemas.Reference).optional()

/*
,anyOf: Joi.array().items(schemas.Reference).optional(),
oneOf: Joi.array().items(schemas.Reference).optional(),
multipleOf: Joi.number().optional(),
collectionFormat: collectionFormat.optional(),
maximum: Joi.number().optional(),
exclusiveMaximum: Joi.boolean().optional(),
minimum: Joi.number().optional(),
exclusiveMinimum: Joi.boolean().optional(),
maxLength: Joi.number().integer().optional(),
minLength: Joi.number().integer().optional(),
pattern: Joi.string().optional(),
maxItems: Joi.number().integer().optional(),
minItems: Joi.number().integer().optional(),
uniqueItems: Joi.boolean().optional(),
maxProperties: Joi.number().optional(),
minProperties: Joi.number().optional(),
enum: Joi.any().optional(),
externalDocs: schemas.ExternalDocs.optional(),
example: Joi.any().optional(),
readOnly: Joi.boolean().optional()
*/
}).meta({className: 'Definition'})

// Meta-Information
schemas.Contact = Joi.object({
  name: Joi.string().optional(),
  url: Joi.string().optional(),
  email: Joi.string().optional()
}).meta({
  className: 'Contact'
})

schemas.License = Joi.object({
  name: Joi.string().required(),
  url: Joi.string().optional()
}).meta({
  className: 'License'
})

schemas.Info = Joi.object({
  title: Joi.string().required(),
  description: Joi.string().allow('').optional(),
  termsOfService: Joi.string().optional(),
  contact: schemas.Contact.optional(),
  license: schemas.License.optional(),
  version: Joi.string().required()
}).meta({
  className: 'Info'
})

schemas.Tag = Joi.object({
  name: Joi.string().required(),
  description: Joi.string().allow('').optional(),
  externalDocs: schemas.ExternalDocs.optional()
}).meta({
  className: 'Tag'
})

// Root
schemas.Swagger = Joi.object({
  swagger: swaggerVersion.required(),
  info: schemas.Info.optional(),
  host: Joi.string().optional(),
  basePath: Joi.string().optional(),
  schemes: arrayOfStrings,
  consumes: arrayOfStrings,
  produces: arrayOfStrings,
  paths: Joi.object({}).pattern(/^\/.*/, schemas.Path),
  definitions: Joi.object({}).pattern(/.*/, schemas.Definition),
  // parameters: Joi.array().items(schemas.Parameter, schemas.Reference).optional()
  // responses: schemas.Responses,
  tags: Joi.array().items(schemas.Tag).optional(),
  externalDocs: schemas.ExternalDocs.optional()
}).meta({
  className: 'Swagger'
})

// Plugin options
schemas.TaggingOptions = Joi.object({
  mode: Joi.string().valid('path', 'tags'),
  pathLevel: Joi.number().integer().min(1).optional(),
  stripRequiredTags: Joi.boolean().optional()
})

schemas.PluginOptions = Joi.object({
  requiredTags: arrayOfStrings.optional(),
  produces: arrayOfStrings.optional(),
  consumes: arrayOfStrings.optional(),
  endpoint: Joi.string().optional(),
  routeTags: Joi.array().items(Joi.string()).optional(),
  stripPrefix: Joi.string().optional(),
  responseValidation: Joi.boolean().optional(),
  supportedMethods: Joi.array().items(Joi.string().valid(['get', 'put', 'post', 'delete', 'options', 'head', 'patch'])).optional(),
  tagging: schemas.TaggingOptions.optional(),
  cache: Joi.any().optional(),
  tags: Joi.alternatives().try(Joi.object().pattern(/.*/, Joi.string()), Joi.array().items(schemas.Tag)),
  info: schemas.Info,
  host: Joi.string().optional(),
  schemes: Joi.array().items(Joi.string().valid(['http', 'https', 'ws', 'wss'])).optional()
})

schemas.RoutesPluginOptions = Joi.object({
  produces: arrayOfStrings,
  responses: Joi.object().pattern(/^(default|[0-9]{3})$/, Joi.object({
    type: dataTypes.optional(),
    description: Joi.string().required(),
    schema: Joi.object().optional()
  }))
}).optional()
<commit_msg>Add validation of cors option<commit_after>var Joi = require('joi')
var schemas = module.exports = {}
var swaggerVersion = Joi.string().valid('2.0').required()
var dataTypes = Joi.string().valid(['integer', 'number', 'string', 'boolean', 'array', 'file'])
var dataFormat = Joi.string().valid(['int32', 'int64', 'float', 'double', 'byte', 'date', 'date-time'])
var arrayOfStrings = Joi.array().items(Joi.string())
var reference = Joi.string()
// var collectionFormat = Joi.string().valid(['csv', 'ssv', 'tsv', 'pipes', 'multi'])

// reference: https://github.com/swagger-api/swagger-spec/blob/master/schemas/v2.0/schema.json

schemas.SimpleReference = Joi.object({
  $ref: reference
}).meta({
  className: 'SimpleReference'
})

schemas.Reference = Joi.object({
  $ref: reference,
  type: Joi.string(),
  items: Joi.object({
    $ref: reference.required()
  })
}).xor(['$ref', 'items']).meta({
  className: 'Reference'
})

schemas.ExternalDocs = Joi.object({
  description: Joi.string().required(),
  url: Joi.string().required()
}).meta({
  className: 'ExternalDocs'
})

schemas.Item = Joi.object({
  type: dataTypes.required(),
  format: dataFormat.optional(),
  items: Joi.any(),
  default: Joi.any().optional(),
  maximum: Joi.number().optional(),
  minimum: Joi.number().optional()
/*
 collectionFormat: collectionFormat.optional(),
 exclusiveMaximum: Joi.boolean().optional(),
 exclusiveMinimum: Joi.boolean().optional(),
 maxLength: Joi.number().integer().optional(),
 minLength: Joi.number().integer().optional(),
 pattern: Joi.string().optional(),
 maxItems: Joi.number().integer().optional(),
 minItems: Joi.number().integer().optional(),
 uniqueItems: Joi.boolean().optional(),
 multipleOf: Joi.number().optional(),
 enum: Joi.any().optional()
 */
}).meta({
  className: 'Items'
})

schemas.Property = Joi.object().keys({
  type: Joi.string().optional(),
  description: Joi.string().allow('').optional(),
  format: Joi.string().optional(),
  items: Joi.alternatives().try(schemas.SimpleReference, schemas.Item).optional(),
  default: Joi.any().optional(),
  enum: Joi.any().optional(),
  maximum: Joi.number().optional(),
  minimum: Joi.number().optional()
// schema: schemas.Reference.optional()
}).meta({
  className: 'Property'
})

schemas.Parameter = Joi.object({
  name: Joi.string().required(),
  in: Joi.string().valid(['query', 'header', 'path', 'formData', 'body']).required(),
  description: Joi.string().allow('').optional(),
  required: Joi.boolean().optional(),
  // if body
  schema: Joi.alternatives().when('in', {is: 'body', then: Joi.alternatives().try(schemas.Reference.required(), schemas.Property)}),
  // else
  type: Joi.alternatives().when('in', {is: 'body', otherwise: dataTypes.required()}),
  format: Joi.alternatives().when('in', {is: 'body', otherwise: dataFormat.optional()}),
  items: Joi.alternatives().when('type', {is: 'array', then: Joi.alternatives().try(schemas.SimpleReference, schemas.Item).required()}),
  collectionFormat: Joi.alternatives().when('in', {
    is: 'body',
    otherwise: Joi.string().valid(['csv', 'ssv', 'tsv', 'pipes', 'multi']).default('csv').optional()
  }),
  default: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.any().optional()}),
  maximum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().optional()}),
  exclusiveMaximum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.boolean().optional()}),
  minimum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().optional()}),
  exclusiveMinimum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.boolean().optional()}),
  maxLength: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  minLength: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  pattern: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.string().optional()}),
  maxItems: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  minItems: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().integer().optional()}),
  uniqueItems: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.boolean().optional()}),
  enum: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.any().optional()}),
  multipleOf: Joi.alternatives().when('in', {is: 'body', otherwise: Joi.number().optional()})
}).meta({
  className: 'Parameter'
})

schemas.Response = Joi.object({
  description: Joi.string().allow('').optional(),
  schema: Joi.alternatives().try(schemas.Reference, schemas.Property).optional(),
  // posible but will not be generated (yet)
  headers: Joi.any().optional(),
  examples: Joi.any().optional()
}).meta({
  className: 'Response'
})

schemas.Responses = Joi.object({
  default: schemas.Response.required() // optional in swagger ui
}).pattern(/^[0-9]{3}$/, schemas.Response).meta({
  className: 'Responses'
})

schemas.Operation = Joi.object({
  tags: arrayOfStrings.optional(),
  summary: Joi.string().optional(),
  description: Joi.string().allow('').optional(),
  externalDocs: schemas.ExternalDocs.optional(),
  operationId: Joi.string().optional(),
  consumes: arrayOfStrings.optional(),
  produces: arrayOfStrings.optional(),
  parameters: Joi.array().items(schemas.Parameter).optional(),
  responses: schemas.Responses.required(),
  schemes: arrayOfStrings.optional(),
  deprecated: Joi.boolean().optional(),
  security: Joi.any()
}).meta({
  className: 'Operation'
})

schemas.Path = Joi.object({
  get: schemas.Operation.optional(),
  put: schemas.Operation.optional(),
  post: schemas.Operation.optional(),
  delete: schemas.Operation.optional(),
  options: schemas.Operation.optional(),
  head: schemas.Operation.optional(),
  patch: schemas.Operation.optional(),
  parameters: Joi.array().items(schemas.Parameter).optional()
}).meta({
  className: 'Path'
})

schemas.Definition = Joi.object({
  title: Joi.string().optional(),
  description: Joi.string().allow('').optional(),
  type: dataTypes.optional(),
  required: Joi.array().items(Joi.string()),
  properties: Joi.object({}).pattern(/.*/, Joi.alternatives().try(schemas.Reference, schemas.Property)),
  default: Joi.any().optional(),
  items: Joi.alternatives().try(schemas.SimpleReference, schemas.Item).optional(),
  format: dataFormat.optional(),

  // For schema integration tests:
  allOf: Joi.array().items(schemas.Reference).optional()

/*
,anyOf: Joi.array().items(schemas.Reference).optional(),
oneOf: Joi.array().items(schemas.Reference).optional(),
multipleOf: Joi.number().optional(),
collectionFormat: collectionFormat.optional(),
maximum: Joi.number().optional(),
exclusiveMaximum: Joi.boolean().optional(),
minimum: Joi.number().optional(),
exclusiveMinimum: Joi.boolean().optional(),
maxLength: Joi.number().integer().optional(),
minLength: Joi.number().integer().optional(),
pattern: Joi.string().optional(),
maxItems: Joi.number().integer().optional(),
minItems: Joi.number().integer().optional(),
uniqueItems: Joi.boolean().optional(),
maxProperties: Joi.number().optional(),
minProperties: Joi.number().optional(),
enum: Joi.any().optional(),
externalDocs: schemas.ExternalDocs.optional(),
example: Joi.any().optional(),
readOnly: Joi.boolean().optional()
*/
}).meta({className: 'Definition'})

// Meta-Information
schemas.Contact = Joi.object({
  name: Joi.string().optional(),
  url: Joi.string().optional(),
  email: Joi.string().optional()
}).meta({
  className: 'Contact'
})

schemas.License = Joi.object({
  name: Joi.string().required(),
  url: Joi.string().optional()
}).meta({
  className: 'License'
})

schemas.Info = Joi.object({
  title: Joi.string().required(),
  description: Joi.string().allow('').optional(),
  termsOfService: Joi.string().optional(),
  contact: schemas.Contact.optional(),
  license: schemas.License.optional(),
  version: Joi.string().required()
}).meta({
  className: 'Info'
})

schemas.Tag = Joi.object({
  name: Joi.string().required(),
  description: Joi.string().allow('').optional(),
  externalDocs: schemas.ExternalDocs.optional()
}).meta({
  className: 'Tag'
})

// Root
schemas.Swagger = Joi.object({
  swagger: swaggerVersion.required(),
  info: schemas.Info.optional(),
  host: Joi.string().optional(),
  basePath: Joi.string().optional(),
  schemes: arrayOfStrings,
  consumes: arrayOfStrings,
  produces: arrayOfStrings,
  paths: Joi.object({}).pattern(/^\/.*/, schemas.Path),
  definitions: Joi.object({}).pattern(/.*/, schemas.Definition),
  // parameters: Joi.array().items(schemas.Parameter, schemas.Reference).optional()
  // responses: schemas.Responses,
  tags: Joi.array().items(schemas.Tag).optional(),
  externalDocs: schemas.ExternalDocs.optional()
}).meta({
  className: 'Swagger'
})

// Plugin options
schemas.TaggingOptions = Joi.object({
  mode: Joi.string().valid('path', 'tags'),
  pathLevel: Joi.number().integer().min(1).optional(),
  stripRequiredTags: Joi.boolean().optional()
})

schemas.PluginOptions = Joi.object({
  requiredTags: arrayOfStrings.optional(),
  produces: arrayOfStrings.optional(),
  consumes: arrayOfStrings.optional(),
  endpoint: Joi.string().optional(),
  routeTags: Joi.array().items(Joi.string()).optional(),
  stripPrefix: Joi.string().optional(),
  responseValidation: Joi.boolean().optional(),
  supportedMethods: Joi.array().items(Joi.string().valid(['get', 'put', 'post', 'delete', 'options', 'head', 'patch'])).optional(),
  tagging: schemas.TaggingOptions.optional(),
  cache: Joi.any().optional(),
  tags: Joi.alternatives().try(Joi.object().pattern(/.*/, Joi.string()), Joi.array().items(schemas.Tag)),
  info: schemas.Info,
  host: Joi.string().optional(),
  schemes: Joi.array().items(Joi.string().valid(['http', 'https', 'ws', 'wss'])).optional(),
  cors: Joi.alternatives().try(Joi.boolean(), Joi.object({
    origin: arrayOfStrings.optional(),
    matchOrigin: Joi.boolean().optional(),
    isOriginExposed: Joi.boolean().optional(),
    maxAge: Joi.number().integer().optional(),
    headers: arrayOfStrings.optional(),
    additionalHeaders: arrayOfStrings.optional(),
    methods: arrayOfStrings.optional(),
    additionlMethods: arrayOfStrings.optional(),
    exposedHeaders: arrayOfStrings.optional(),
    additionalExposedHeaders: arrayOfStrings.optional(),
    credentials: Joi.boolean().optional(),
    override: Joi.boolean().optional()
  }).min(1))
})

schemas.RoutesPluginOptions = Joi.object({
  produces: arrayOfStrings,
  responses: Joi.object().pattern(/^(default|[0-9]{3})$/, Joi.object({
    type: dataTypes.optional(),
    description: Joi.string().required(),
    schema: Joi.object().optional()
  }))
}).optional()
<|endoftext|>


<commit_before>var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var InstallationSchema = new Schema(
    {
        name: String,
        placement: String,
        address: String,
        location: {lat: Number, lng: Number},
        contact: {
            name: String,
            email: String,
            phone: String,
            website: String
        },
        metadata: String,
        devices: [
            {
                name: String,
                placement: String,
                id: String,
                noOfAlarms: Number,
                updatedAt: {
                    date: {type: Date},
                    user: {type: String}
                },
                metadata: String,
                controls: [
                    {
                        id: String,
                        name: String,
                        publishInterval: Number,
                        isState: Boolean,
                        metadata: String,
                        ctrlType: String,
                        minValue: Number,
                        maxValue: Number,
                        minCritical: Number,
                        maxCritical: Number,
                        unit: {
                            symbol: String,
                            units: String,
                            precision: Number,
                            name: String
                        },
                        timers: [
                            {
                                name: String,
                                last_run: Date,
                                active: Boolean,
                                enabled: Boolean,
                                time: Date,
                                duration: Number,
                                days: Number
                            }
                        ]
                    }
                ],
                triggers: [
                    {
                        name: String,
                        enabled: Boolean,
                        notify: Boolean,
                        notifyLevel: String,
                        notifyText: String,
                        requests: [
                            {
                                name: String,
                                request_options: Schema.Types.Mixed
                            }
                        ],
                        trigger_type: { type: String, enum: ['lt', 'lte', 'gt', 'gte', 'eq'] },
                        threshold_value: String,
                        stream_id: String,
                        triggered_value: String,
                        triggered_time: Date,
                        trigger_pause: Number,
                        resolution: { type: String, enum: ['sec', 'min', 'hour', 'day'] },
                        metadata: String
                    }
                ]
            }
        ]
    }
);

module.exports = InstallationSchema;<commit_msg>Modelling timers<commit_after>var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var InstallationSchema = new Schema(
    {
        name: String,
        placement: String,
        address: String,
        location: {lat: Number, lng: Number},
        contact: {
            name: String,
            email: String,
            phone: String,
            website: String
        },
        metadata: String,
        devices: [
            {
                name: String,
                placement: String,
                id: String,
                noOfAlarms: Number,
                updatedAt: {
                    date: {type: Date},
                    user: {type: String}
                },
                metadata: String,
                controls: [
                    {
                        id: String,
                        name: String,
                        interval: Number,
                        isState: Boolean,
                        metadata: String,
                        ctrlType: String,
                        minValue: Number,
                        maxValue: Number,
                        minCritical: Number,
                        maxCritical: Number,
                        unit: {
                            symbol: String,
                            units: String,
                            precision: Number,
                            name: String
                        },
                        timers: [
                            {
                                name: String,
                                enabled: Boolean,
                                time: Date,
                                duration: Number,
                                days: Number
                            }
                        ]
                    }
                ],
                triggers: [
                    {
                        name: String,
                        enabled: Boolean,
                        notify: Boolean,
                        notifyLevel: String,
                        notifyText: String,
                        requests: [
                            {
                                name: String,
                                request_options: Schema.Types.Mixed
                            }
                        ],
                        trigger_type: { type: String, enum: ['lt', 'lte', 'gt', 'gte', 'eq'] },
                        threshold_value: String,
                        stream_id: String,
                        triggered_value: String,
                        triggered_time: Date,
                        trigger_pause: Number,
                        resolution: { type: String, enum: ['sec', 'min', 'hour', 'day'] },
                        metadata: String
                    }
                ]
            }
        ]
    }
);

module.exports = InstallationSchema;<|endoftext|>


<commit_before>'use strict';

/*
    Example of field definitions:

    fieldDefs = {
        field_name: {
            validator: function (inp) {
                return {
                    message: "This field is required"
                }
            },
            required: false
        }
    }

    invariantDefs = [
        function (data, selectedFields) {
            return {
                message: "bla bla",
                fields: ['field_name', 'field_name']
            }
        }
    ]
*/
var clone = require('./utils').clone;

var Schema = function (opts, fieldDefs) {
    if (typeof opts === 'string') {
        // Backward compatibility
        var schemaName = opts;
    } else {
        var schemaName = opts.schemaName;
    }

    // Check that we paased a schema name (used for debugging)
    if (typeof schemaName !== 'string') {
        throw {
            message: "You didn't pass a name to the schema",
            data: {
                schemaName: schemaName,
                fieldDefs: fieldDefs
            }
        }
    };

    this._name = schemaName;
    this._fields = {};
    this._invariants = [];
    this._validationConstraints = [];

    // Check if we are extending other schemas
    if (Array.isArray(opts.extends)) {
        // Left most overrides those to the right
        opts.extends.reverse();
        opts.extends.map(function (schema) {
            for (var key in schema._fields) {
                this._fields[key] = schema._fields[key];
            }
            for (var key in schema._invariants) {
                this._invariants[key] = schema._invariants[key];
            }
            for (var key in schema._validationConstraints) {
                this._validationConstraints[key] = schema._validationConstraints[key];
            }
        }.bind(this));
    }

    for (var key in fieldDefs) {
        this._fields[key] = fieldDefs[key];
    }

};

Schema.prototype.addInvariant = function (invariant) {
    // TODO: Check that it is valid
    this._invariants.push(invariant);
};

Schema.prototype.addValidationConstraint = function (constraint) {
    // TODO: Check that it is valid
    this._validationConstraints.push(constraint);
};

Schema.prototype._addFieldError = function (formErrors, propName, error) {
    if (typeof formErrors.fieldErrors === "undefined") {
        formErrors.fieldErrors = {};
    }
    formErrors.fieldErrors[propName] = error;
};

Schema.prototype._addInvariantError = function (formErrors, error) {
    if (typeof formErrors.invariantErrors === "undefined") {
        formErrors.invariantErrors = [];
    }
    formErrors.invariantErrors.push(error);
};

Schema.prototype._getSelectedFieldsList = function (selectedFields) {
    if (typeof selectedFields === "string") {
        selectedFields = [selectedFields];
    }

    if (typeof selectedFields === 'undefined') {
        selectedFields = []
        for (var key in this._fields) {
            selectedFields.push(key);
        }
    }
    return selectedFields;
}

Schema.prototype.validate = function (data, options) {
    var skipInvariants = false,
        selectedFields = undefined;

    if (options) {
        skipInvariants = options.skipInvariants || false;
        selectedFields = options.selectedFields;
    }

    // We are making the validation stateless to avoid contaminating schemas
    // that are now used as a way to define the object model
    var formErrors = {
        fieldErrors: undefined,
        invariantErrors: undefined
    };

    selectedFields = this._getSelectedFieldsList(selectedFields);

    // Validate selected fields
    for (var i in selectedFields) {
        var key = selectedFields[i];

        // Make sure we have a new options object...
        if (!options) {
            var newOptions = {};
        } else {
            var newOptions = clone(options);
        };

        // ...so we can add objectPath for easier debugging
        if (newOptions.objectPath) {
            newOptions.objectPath.push(key);
        } else {
            newOptions.objectPath = [key]
        }

        // Remove the selectedFields if passed because we don't want them to be sent to next validate function
        if (newOptions.selectedFields) {
            delete newOptions.selectedFields;
        }

        // console.log("[Schema] validating: " + newOptions.objectPath.join("."));

        try {

            // Check validation constraints
            var failedValidators = this._validationConstraints.filter(function (constraint) {
                return !constraint(data, key);
            });
            // Only validate if we pass all the validation constraints
            if (failedValidators.length === 0) {
                if (!this._fields[key].readOnly) {
                    var tmpError = this._fields[key].validate(data[key], newOptions, data);
                    tmpError && this._addFieldError(formErrors, key, tmpError);
                }
            }
        } catch (e) {
            console.error('[Schema] Field validation error for: ' + key);
            console.log(data && data[key]);
            throw e;
        }
    }

    if (!skipInvariants) {

        // Validate invariants
        for (var i = 0, imax = this._invariants.length; i < imax; i++) {
            try {
                var tmpError = this._invariants[i](data, selectedFields);
                tmpError && this._addInvariantError(formErrors, tmpError);
            } catch (e) {
                console.error('[Schema] Invariant validation error for: ' + key);
                console.log(data[key]);
                throw e;
            }
        }

    };

    // Return error object if any found, else return undefined
    if (typeof formErrors.fieldErrors === "undefined" && typeof formErrors.invariantErrors === "undefined") {
        return undefined;
    } else {
        return formErrors;
    };
};

Schema.prototype.transform = function (data, selectedFields, doNotRemoveReadOnly) {
    selectedFields = this._getSelectedFieldsList(selectedFields);
    var outp = {};
    for (var i in selectedFields) {
        var key = selectedFields[i];
        try {
            if (!this._fields[key].readOnly || doNotRemoveReadOnly) {
                outp[key] = this._fields[key].fromString(data[key], doNotRemoveReadOnly);
            }
        } catch (err) {
            // TODO: Error handling
            console.warn(err)
        }
    }
    return outp;
}

module.exports = Schema;
<commit_msg>Pass options to invariants and validation constraints<commit_after>'use strict';

/*
    Example of field definitions:

    fieldDefs = {
        field_name: {
            validator: function (inp) {
                return {
                    message: "This field is required"
                }
            },
            required: false
        }
    }

    invariantDefs = [
        function (data, selectedFields) {
            return {
                message: "bla bla",
                fields: ['field_name', 'field_name']
            }
        }
    ]
*/
var clone = require('./utils').clone;

var Schema = function (opts, fieldDefs) {
    if (typeof opts === 'string') {
        // Backward compatibility
        var schemaName = opts;
    } else {
        var schemaName = opts.schemaName;
    }

    // Check that we paased a schema name (used for debugging)
    if (typeof schemaName !== 'string') {
        throw {
            message: "You didn't pass a name to the schema",
            data: {
                schemaName: schemaName,
                fieldDefs: fieldDefs
            }
        }
    };

    this._name = schemaName;
    this._fields = {};
    this._invariants = [];
    this._validationConstraints = [];

    // Check if we are extending other schemas
    if (Array.isArray(opts.extends)) {
        // Left most overrides those to the right
        opts.extends.reverse();
        opts.extends.map(function (schema) {
            for (var key in schema._fields) {
                this._fields[key] = schema._fields[key];
            }
            for (var key in schema._invariants) {
                this._invariants[key] = schema._invariants[key];
            }
            for (var key in schema._validationConstraints) {
                this._validationConstraints[key] = schema._validationConstraints[key];
            }
        }.bind(this));
    }

    for (var key in fieldDefs) {
        this._fields[key] = fieldDefs[key];
    }

};

Schema.prototype.addInvariant = function (invariant) {
    // TODO: Check that it is valid
    this._invariants.push(invariant);
};

Schema.prototype.addValidationConstraint = function (constraint) {
    // TODO: Check that it is valid
    this._validationConstraints.push(constraint);
};

Schema.prototype._addFieldError = function (formErrors, propName, error) {
    if (typeof formErrors.fieldErrors === "undefined") {
        formErrors.fieldErrors = {};
    }
    formErrors.fieldErrors[propName] = error;
};

Schema.prototype._addInvariantError = function (formErrors, error) {
    if (typeof formErrors.invariantErrors === "undefined") {
        formErrors.invariantErrors = [];
    }
    formErrors.invariantErrors.push(error);
};

Schema.prototype._getSelectedFieldsList = function (selectedFields) {
    if (typeof selectedFields === "string") {
        selectedFields = [selectedFields];
    }

    if (typeof selectedFields === 'undefined') {
        selectedFields = []
        for (var key in this._fields) {
            selectedFields.push(key);
        }
    }
    return selectedFields;
}

Schema.prototype.validate = function (data, options) {
    var skipInvariants = false,
        selectedFields = undefined;

    if (options) {
        skipInvariants = options.skipInvariants || false;
        selectedFields = options.selectedFields;
    }

    // We are making the validation stateless to avoid contaminating schemas
    // that are now used as a way to define the object model
    var formErrors = {
        fieldErrors: undefined,
        invariantErrors: undefined
    };

    selectedFields = this._getSelectedFieldsList(selectedFields);

    // Validate selected fields
    for (var i in selectedFields) {
        var key = selectedFields[i];

        // Make sure we have a new options object...
        if (!options) {
            var newOptions = {};
        } else {
            var newOptions = clone(options);
        };

        // ...so we can add objectPath for easier debugging
        if (newOptions.objectPath) {
            newOptions.objectPath.push(key);
        } else {
            newOptions.objectPath = [key]
        }

        // Remove the selectedFields if passed because we don't want them to be sent to next validate function
        if (newOptions.selectedFields) {
            delete newOptions.selectedFields;
        }

        // console.log("[Schema] validating: " + newOptions.objectPath.join("."));

        try {

            // Check validation constraints
            var failedValidators = this._validationConstraints.filter(function (constraint) {
                return !constraint(data, key, options);
            });
            // Only validate if we pass all the validation constraints
            if (failedValidators.length === 0) {
                if (!this._fields[key].readOnly) {
                    var tmpError = this._fields[key].validate(data[key], newOptions, data);
                    tmpError && this._addFieldError(formErrors, key, tmpError);
                }
            }
        } catch (e) {
            console.error('[Schema] Field validation error for: ' + key);
            console.log(data && data[key]);
            throw e;
        }
    }

    if (!skipInvariants) {

        // Validate invariants
        for (var i = 0, imax = this._invariants.length; i < imax; i++) {
            try {
                var tmpError = this._invariants[i](data, selectedFields, options);
                tmpError && this._addInvariantError(formErrors, tmpError);
            } catch (e) {
                console.error('[Schema] Invariant validation error for: ' + key);
                console.log(data[key]);
                throw e;
            }
        }

    };

    // Return error object if any found, else return undefined
    if (typeof formErrors.fieldErrors === "undefined" && typeof formErrors.invariantErrors === "undefined") {
        return undefined;
    } else {
        return formErrors;
    };
};

Schema.prototype.transform = function (data, selectedFields, doNotRemoveReadOnly) {
    selectedFields = this._getSelectedFieldsList(selectedFields);
    var outp = {};
    for (var i in selectedFields) {
        var key = selectedFields[i];
        try {
            if (!this._fields[key].readOnly || doNotRemoveReadOnly) {
                outp[key] = this._fields[key].fromString(data[key], doNotRemoveReadOnly);
            }
        } catch (err) {
            // TODO: Error handling
            console.warn(err)
        }
    }
    return outp;
}

module.exports = Schema;
<|endoftext|>


<commit_before>var pinyin = require("pinyin");

console.log(pinyin("中心"));    // [ [ 'zhōng' ], [ 'xīn' ] ]
console.log(pinyin("中心", {
  heteronym: true               // 启用多音字模式
}));                            // [ [ 'zhōng', 'zhòng' ], [ 'xīn' ] ]
console.log(pinyin("中心", {
  heteronym: true,              // 启用多音字模式
  segment: true                 // 启用分词，以解决多音字问题。
}));                            // [ [ 'zhōng' ], [ 'xīn' ] ]
console.log(pinyin("中心", {
  style: pinyin.STYLE_INITIALS, // 设置拼音风格
  heteronym: true
}));                            // [ [ 'zh' ], [ 'x' ] ]<commit_msg>ignore segment function to continue error:  Segment need nodejieba, please run '$ npm install nodejieba'.  分词需要使用 nodejieba 模块，请运行 '$ npm install nodejieba' 并确保安装完成<commit_after>var pinyin = require("pinyin");

console.log(pinyin("中心"));    // [ [ 'zhōng' ], [ 'xīn' ] ]
console.log(pinyin("中心", {
  heteronym: true               // 启用多音字模式
}));                            // [ [ 'zhōng', 'zhòng' ], [ 'xīn' ] ]
console.log(pinyin("中心", {
  heteronym: true,              // 启用多音字模式
  // segment: true                 // 启用分词，以解决多音字问题。
}));                            // [ [ 'zhōng' ], [ 'xīn' ] ]
console.log(pinyin("中心", {
  style: pinyin.STYLE_INITIALS, // 设置拼音风格
  heteronym: true
}));                            // [ [ 'zh' ], [ 'x' ] ]<|endoftext|>


<commit_before>/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Registry = require('../../registry');
var Lib = require('../../lib');
var Color = require('../../components/color');
var basePlotLayoutAttributes = require('../layout_attributes');

var constants = require('./constants');
var layoutAttributes = require('./layout_attributes');
var handleTypeDefaults = require('./type_defaults');
var handleAxisDefaults = require('./axis_defaults');
var handleConstraintDefaults = require('./constraint_defaults');
var handlePositionDefaults = require('./position_defaults');
var axisIds = require('./axis_ids');

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
    var layoutKeys = Object.keys(layoutIn),
        xaListCartesian = [],
        yaListCartesian = [],
        xaListGl2d = [],
        yaListGl2d = [],
        xaCheater = {},
        xaNonCheater = {},
        outerTicks = {},
        noGrids = {},
        i;

    // look for axes in the data
    for(i = 0; i < fullData.length; i++) {
        var trace = fullData[i];
        var listX, listY;

        if(Registry.traceIs(trace, 'cartesian')) {
            listX = xaListCartesian;
            listY = yaListCartesian;
        }
        else if(Registry.traceIs(trace, 'gl2d')) {
            listX = xaListGl2d;
            listY = yaListGl2d;
        }
        else continue;

        var xaName = axisIds.id2name(trace.xaxis),
            yaName = axisIds.id2name(trace.yaxis);

        // Two things trigger axis visibility:
        // 1. is not carpet
        // 2. carpet that's not cheater
        if(!Registry.traceIs(trace, 'carpet') || (trace.type === 'carpet' && !trace._cheater)) {
            if(xaName) xaNonCheater[xaName] = 1;
        }

        // The above check for definitely-not-cheater is not adequate. This
        // second list tracks which axes *could* be a cheater so that the
        // full condition triggering hiding is:
        //   *could* be a cheater and *is not definitely visible*
        if(trace.type === 'carpet' && trace._cheater) {
            if(xaName) xaCheater[xaName] = 1;
        }

        // add axes implied by traces
        if(xaName && listX.indexOf(xaName) === -1) listX.push(xaName);
        if(yaName && listY.indexOf(yaName) === -1) listY.push(yaName);

        // check for default formatting tweaks
        if(Registry.traceIs(trace, '2dMap')) {
            outerTicks[xaName] = true;
            outerTicks[yaName] = true;
        }

        if(Registry.traceIs(trace, 'oriented')) {
            var positionAxis = trace.orientation === 'h' ? yaName : xaName;
            noGrids[positionAxis] = true;
        }
    }

    // N.B. Ignore orphan axes (i.e. axes that have no data attached to them)
    // if gl3d or geo is present on graph. This is retain backward compatible.
    //
    // TODO drop this in version 2.0
    var ignoreOrphan = (layoutOut._has('gl3d') || layoutOut._has('geo'));

    if(!ignoreOrphan) {
        for(i = 0; i < layoutKeys.length; i++) {
            var key = layoutKeys[i];

            // orphan layout axes are considered cartesian subplots

            if(xaListGl2d.indexOf(key) === -1 &&
                xaListCartesian.indexOf(key) === -1 &&
                    constants.xAxisMatch.test(key)) {
                xaListCartesian.push(key);
            }
            else if(yaListGl2d.indexOf(key) === -1 &&
                yaListCartesian.indexOf(key) === -1 &&
                    constants.yAxisMatch.test(key)) {
                yaListCartesian.push(key);
            }
        }
    }

    // make sure that plots with orphan cartesian axes
    // are considered 'cartesian'
    if(xaListCartesian.length && yaListCartesian.length) {
        Lib.pushUnique(layoutOut._basePlotModules, Registry.subplotsRegistry.cartesian);
    }

    function axSort(a, b) {
        var aNum = Number(a.substr(5) || 1),
            bNum = Number(b.substr(5) || 1);
        return aNum - bNum;
    }

    var xaList = xaListCartesian.concat(xaListGl2d).sort(axSort),
        yaList = yaListCartesian.concat(yaListGl2d).sort(axSort),
        axesList = xaList.concat(yaList);

    // plot_bgcolor only makes sense if there's a (2D) plot!
    // TODO: bgcolor for each subplot, to inherit from the main one
    var plot_bgcolor = Color.background;
    if(xaList.length && yaList.length) {
        plot_bgcolor = Lib.coerce(layoutIn, layoutOut, basePlotLayoutAttributes, 'plot_bgcolor');
    }

    var bgColor = Color.combine(plot_bgcolor, layoutOut.paper_bgcolor);

    var axName, axLetter, axLayoutIn, axLayoutOut;

    function coerce(attr, dflt) {
        return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
    }

    function getCounterAxes(axLetter) {
        var list = {x: yaList, y: xaList}[axLetter];
        return Lib.simpleMap(list, axisIds.name2id);
    }

    var counterAxes = {x: getCounterAxes('x'), y: getCounterAxes('y')};

    function getOverlayableAxes(axLetter, axName) {
        var list = {x: xaList, y: yaList}[axLetter];
        var out = [];

        for(var j = 0; j < list.length; j++) {
            var axName2 = list[j];

            if(axName2 !== axName && !(layoutIn[axName2] || {}).overlaying) {
                out.push(axisIds.name2id(axName2));
            }
        }

        return out;
    }

    // first pass creates the containers, determines types, and handles most of the settings
    for(i = 0; i < axesList.length; i++) {
        axName = axesList[i];

        if(!Lib.isPlainObject(layoutIn[axName])) {
            layoutIn[axName] = {};
        }

        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName] = {};

        handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, fullData, axName);

        axLetter = axName.charAt(0);
        var overlayableAxes = getOverlayableAxes(axLetter, axName);

        var defaultOptions = {
            letter: axLetter,
            font: layoutOut.font,
            outerTicks: outerTicks[axName],
            showGrid: !noGrids[axName],
            data: fullData,
            bgColor: bgColor,
            calendar: layoutOut.calendar,
            cheateronly: axLetter === 'x' && (xaCheater[axName] && !xaNonCheater[axName])
        };

        handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions, layoutOut);

        var showSpikes = coerce('showspikes');
        if(showSpikes) {
            coerce('spikecolor');
            coerce('spikethickness');
            coerce('spikedash');
            coerce('spikemode');
        }

        var positioningOptions = {
            letter: axLetter,
            counterAxes: counterAxes[axLetter],
            overlayableAxes: overlayableAxes
        };

        handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, positioningOptions);

        axLayoutOut._input = axLayoutIn;
    }

    // quick second pass for range slider and selector defaults
    var rangeSliderDefaults = Registry.getComponentMethod('rangeslider', 'handleDefaults'),
        rangeSelectorDefaults = Registry.getComponentMethod('rangeselector', 'handleDefaults');

    for(i = 0; i < xaList.length; i++) {
        axName = xaList[i];
        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName];

        rangeSliderDefaults(layoutIn, layoutOut, axName);

        if(axLayoutOut.type === 'date') {
            rangeSelectorDefaults(
                axLayoutIn,
                axLayoutOut,
                layoutOut,
                yaList,
                axLayoutOut.calendar
            );
        }

        coerce('fixedrange');
    }

    for(i = 0; i < yaList.length; i++) {
        axName = yaList[i];
        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName];

        var anchoredAxis = layoutOut[axisIds.id2name(axLayoutOut.anchor)];

        var fixedRangeDflt = (
            anchoredAxis &&
            anchoredAxis.rangeslider &&
            anchoredAxis.rangeslider.visible
        );

        coerce('fixedrange', fixedRangeDflt);
    }

    // Finally, handle scale constraints. We need to do this after all axes have
    // coerced both `type` (so we link only axes of the same type) and
    // `fixedrange` (so we can avoid linking from OR TO a fixed axis).

    // sets of axes linked by `scaleanchor` along with the scaleratios compounded
    // together, populated in handleConstraintDefaults
    layoutOut._axisConstraintGroups = [];
    var allAxisIds = counterAxes.x.concat(counterAxes.y);

    for(i = 0; i < axesList.length; i++) {
        axName = axesList[i];
        axLetter = axName.charAt(0);

        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName];

        handleConstraintDefaults(axLayoutIn, axLayoutOut, coerce, allAxisIds, layoutOut);
    }
};
<commit_msg>lint cartesian layout_defaults<commit_after>/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Registry = require('../../registry');
var Lib = require('../../lib');
var Color = require('../../components/color');
var basePlotLayoutAttributes = require('../layout_attributes');

var constants = require('./constants');
var layoutAttributes = require('./layout_attributes');
var handleTypeDefaults = require('./type_defaults');
var handleAxisDefaults = require('./axis_defaults');
var handleConstraintDefaults = require('./constraint_defaults');
var handlePositionDefaults = require('./position_defaults');
var axisIds = require('./axis_ids');

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
    var layoutKeys = Object.keys(layoutIn);
    var xaListCartesian = [];
    var yaListCartesian = [];
    var xaListGl2d = [];
    var yaListGl2d = [];
    var xaCheater = {};
    var xaNonCheater = {};
    var outerTicks = {};
    var noGrids = {};
    var i;

    // look for axes in the data
    for(i = 0; i < fullData.length; i++) {
        var trace = fullData[i];
        var listX, listY;

        if(Registry.traceIs(trace, 'cartesian')) {
            listX = xaListCartesian;
            listY = yaListCartesian;
        }
        else if(Registry.traceIs(trace, 'gl2d')) {
            listX = xaListGl2d;
            listY = yaListGl2d;
        }
        else continue;

        var xaName = axisIds.id2name(trace.xaxis);
        var yaName = axisIds.id2name(trace.yaxis);

        // Two things trigger axis visibility:
        // 1. is not carpet
        // 2. carpet that's not cheater
        if(!Registry.traceIs(trace, 'carpet') || (trace.type === 'carpet' && !trace._cheater)) {
            if(xaName) xaNonCheater[xaName] = 1;
        }

        // The above check for definitely-not-cheater is not adequate. This
        // second list tracks which axes *could* be a cheater so that the
        // full condition triggering hiding is:
        //   *could* be a cheater and *is not definitely visible*
        if(trace.type === 'carpet' && trace._cheater) {
            if(xaName) xaCheater[xaName] = 1;
        }

        // add axes implied by traces
        if(xaName && listX.indexOf(xaName) === -1) listX.push(xaName);
        if(yaName && listY.indexOf(yaName) === -1) listY.push(yaName);

        // check for default formatting tweaks
        if(Registry.traceIs(trace, '2dMap')) {
            outerTicks[xaName] = true;
            outerTicks[yaName] = true;
        }

        if(Registry.traceIs(trace, 'oriented')) {
            var positionAxis = trace.orientation === 'h' ? yaName : xaName;
            noGrids[positionAxis] = true;
        }
    }

    // N.B. Ignore orphan axes (i.e. axes that have no data attached to them)
    // if gl3d or geo is present on graph. This is retain backward compatible.
    //
    // TODO drop this in version 2.0
    var ignoreOrphan = (layoutOut._has('gl3d') || layoutOut._has('geo'));

    if(!ignoreOrphan) {
        for(i = 0; i < layoutKeys.length; i++) {
            var key = layoutKeys[i];

            // orphan layout axes are considered cartesian subplots

            if(xaListGl2d.indexOf(key) === -1 &&
                xaListCartesian.indexOf(key) === -1 &&
                    constants.xAxisMatch.test(key)) {
                xaListCartesian.push(key);
            }
            else if(yaListGl2d.indexOf(key) === -1 &&
                yaListCartesian.indexOf(key) === -1 &&
                    constants.yAxisMatch.test(key)) {
                yaListCartesian.push(key);
            }
        }
    }

    // make sure that plots with orphan cartesian axes
    // are considered 'cartesian'
    if(xaListCartesian.length && yaListCartesian.length) {
        Lib.pushUnique(layoutOut._basePlotModules, Registry.subplotsRegistry.cartesian);
    }

    function axSort(a, b) {
        var aNum = Number(a.substr(5) || 1);
        var bNum = Number(b.substr(5) || 1);
        return aNum - bNum;
    }

    var xaList = xaListCartesian.concat(xaListGl2d).sort(axSort);
    var yaList = yaListCartesian.concat(yaListGl2d).sort(axSort);
    var axesList = xaList.concat(yaList);

    // plot_bgcolor only makes sense if there's a (2D) plot!
    // TODO: bgcolor for each subplot, to inherit from the main one
    var plot_bgcolor = Color.background;
    if(xaList.length && yaList.length) {
        plot_bgcolor = Lib.coerce(layoutIn, layoutOut, basePlotLayoutAttributes, 'plot_bgcolor');
    }

    var bgColor = Color.combine(plot_bgcolor, layoutOut.paper_bgcolor);

    var axName, axLetter, axLayoutIn, axLayoutOut;

    function coerce(attr, dflt) {
        return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
    }

    function getCounterAxes(axLetter) {
        var list = {x: yaList, y: xaList}[axLetter];
        return Lib.simpleMap(list, axisIds.name2id);
    }

    var counterAxes = {x: getCounterAxes('x'), y: getCounterAxes('y')};

    function getOverlayableAxes(axLetter, axName) {
        var list = {x: xaList, y: yaList}[axLetter];
        var out = [];

        for(var j = 0; j < list.length; j++) {
            var axName2 = list[j];

            if(axName2 !== axName && !(layoutIn[axName2] || {}).overlaying) {
                out.push(axisIds.name2id(axName2));
            }
        }

        return out;
    }

    // first pass creates the containers, determines types, and handles most of the settings
    for(i = 0; i < axesList.length; i++) {
        axName = axesList[i];

        if(!Lib.isPlainObject(layoutIn[axName])) {
            layoutIn[axName] = {};
        }

        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName] = {};

        handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, fullData, axName);

        axLetter = axName.charAt(0);
        var overlayableAxes = getOverlayableAxes(axLetter, axName);

        var defaultOptions = {
            letter: axLetter,
            font: layoutOut.font,
            outerTicks: outerTicks[axName],
            showGrid: !noGrids[axName],
            data: fullData,
            bgColor: bgColor,
            calendar: layoutOut.calendar,
            cheateronly: axLetter === 'x' && (xaCheater[axName] && !xaNonCheater[axName])
        };

        handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions, layoutOut);

        var showSpikes = coerce('showspikes');
        if(showSpikes) {
            coerce('spikecolor');
            coerce('spikethickness');
            coerce('spikedash');
            coerce('spikemode');
        }

        var positioningOptions = {
            letter: axLetter,
            counterAxes: counterAxes[axLetter],
            overlayableAxes: overlayableAxes
        };

        handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, positioningOptions);

        axLayoutOut._input = axLayoutIn;
    }

    // quick second pass for range slider and selector defaults
    var rangeSliderDefaults = Registry.getComponentMethod('rangeslider', 'handleDefaults'),
        rangeSelectorDefaults = Registry.getComponentMethod('rangeselector', 'handleDefaults');

    for(i = 0; i < xaList.length; i++) {
        axName = xaList[i];
        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName];

        rangeSliderDefaults(layoutIn, layoutOut, axName);

        if(axLayoutOut.type === 'date') {
            rangeSelectorDefaults(
                axLayoutIn,
                axLayoutOut,
                layoutOut,
                yaList,
                axLayoutOut.calendar
            );
        }

        coerce('fixedrange');
    }

    for(i = 0; i < yaList.length; i++) {
        axName = yaList[i];
        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName];

        var anchoredAxis = layoutOut[axisIds.id2name(axLayoutOut.anchor)];

        var fixedRangeDflt = (
            anchoredAxis &&
            anchoredAxis.rangeslider &&
            anchoredAxis.rangeslider.visible
        );

        coerce('fixedrange', fixedRangeDflt);
    }

    // Finally, handle scale constraints. We need to do this after all axes have
    // coerced both `type` (so we link only axes of the same type) and
    // `fixedrange` (so we can avoid linking from OR TO a fixed axis).

    // sets of axes linked by `scaleanchor` along with the scaleratios compounded
    // together, populated in handleConstraintDefaults
    layoutOut._axisConstraintGroups = [];
    var allAxisIds = counterAxes.x.concat(counterAxes.y);

    for(i = 0; i < axesList.length; i++) {
        axName = axesList[i];
        axLetter = axName.charAt(0);

        axLayoutIn = layoutIn[axName];
        axLayoutOut = layoutOut[axName];

        handleConstraintDefaults(axLayoutIn, axLayoutOut, coerce, allAxisIds, layoutOut);
    }
};
<|endoftext|>


<commit_before>/* SDK Modules */
const _ = require('sdk/l10n').get;
const simplePrefs = require('sdk/simple-prefs');

/* Modules */
const logger = require('logger.js');

/* Constants */
//messages
const HIDE_SEARCH_MSG = 'hide_search';
const SEARCH_MSG = 'search';
//preferences
const SHOW_SEARCH_PREF = 'show_search';

/**
 * Initializes search by sending search options to the content scripts.
 */
exports.initSearch = function(worker) {
    //don't initialize search when it is hidden
    var searchVisibility = simplePrefs.prefs[SHOW_SEARCH_PREF];
    if(searchVisibility === 'never') {
        worker.port.emit(HIDE_SEARCH_MSG);
        return;
    }

    logger.log('Initializing search.');

    var options = {
        placeholder: getPlaceholder()
    };
    options[SHOW_SEARCH_PREF] = simplePrefs.prefs[SHOW_SEARCH_PREF];
    worker.port.emit(SEARCH_MSG, options);
}

/**
 * Returns appropriate search input placeholder.
 */
 function getPlaceholder() {
    return _('search_google');
 }
<commit_msg>Refactoring<commit_after>/* SDK Modules */
const _ = require('sdk/l10n').get;
const simplePrefs = require('sdk/simple-prefs');

/* Modules */
const logger = require('logger.js');

/* Constants */
//messages
const HIDE_SEARCH_MSG = 'hide_search';
const SEARCH_MSG = 'search';
//preferences
const SHOW_SEARCH_PREF = 'show_search';

/**
 * Initializes search by sending search options to the content scripts.
 */
exports.initSearch = function(worker) {
    //don't initialize search when it is hidden
    var searchVisibility = simplePrefs.prefs[SHOW_SEARCH_PREF];
    if(searchVisibility === 'never') {
        worker.port.emit(HIDE_SEARCH_MSG);
        return;
    }

    logger.log('Initializing search.');

    var options = {
        form: {
            action: getFormAction(),
            method: getFormMethod()
        }, input: {
            placeholder: getPlaceholder()
        }
    };
    options[SHOW_SEARCH_PREF] = simplePrefs.prefs[SHOW_SEARCH_PREF];
    worker.port.emit(SEARCH_MSG, options);
}

/**
 * Returns appropriate search input placeholder based on user preferences.
 */
 function getPlaceholder() {
    return _('search_google');
 }

 /**
  * Returns appropriate search form action based on user preferences.
  */
 function getFormAction() {
    return 'https://www.google.com/search';
 }

 /**
  * Returns appropriate search form method based on user preferences.
  */
 function getFormMethod() {
    return 'get';
 }
<|endoftext|>


<commit_before>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Lib = require('../../lib');
var Plots = require('../plots');
var Color = require('../../components/color');

var RangeSlider = require('../../components/rangeslider');
var RangeSelector = require('../../components/rangeselector');

var constants = require('./constants');
var layoutAttributes = require('./layout_attributes');
var handleAxisDefaults = require('./axis_defaults');
var handlePositionDefaults = require('./position_defaults');
var axisIds = require('./axis_ids');

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
    var layoutKeys = Object.keys(layoutIn),
        xaListCartesian = [],
        yaListCartesian = [],
        xaListGl2d = [],
        yaListGl2d = [],
        outerTicks = {},
        noGrids = {},
        i;

    // look for axes in the data
    for(i = 0; i < fullData.length; i++) {
        var trace = fullData[i];
        var listX, listY;

        if(Plots.traceIs(trace, 'cartesian')) {
            listX = xaListCartesian;
            listY = yaListCartesian;
        }
        else if(Plots.traceIs(trace, 'gl2d')) {
            listX = xaListGl2d;
            listY = yaListGl2d;
        }
        else continue;

        var xaName = axisIds.id2name(trace.xaxis),
            yaName = axisIds.id2name(trace.yaxis);

        // add axes implied by traces
        if(xaName && listX.indexOf(xaName) === -1) listX.push(xaName);
        if(yaName && listY.indexOf(yaName) === -1) listY.push(yaName);

        // check for default formatting tweaks
        if(Plots.traceIs(trace, '2dMap')) {
            outerTicks[xaName] = true;
            outerTicks[yaName] = true;
        }

        if(Plots.traceIs(trace, 'oriented')) {
            var positionAxis = trace.orientation === 'h' ? yaName : xaName;
            noGrids[positionAxis] = true;
        }
    }

    // N.B. Ignore orphan axes (i.e. axes that have no data attached to them)
    // if gl3d or geo is present on graph. This is retain backward compatible.
    //
    // TODO drop this in version 2.0
    var ignoreOrphan = (layoutOut._hasGL3D || layoutOut._hasGeo);

    if(!ignoreOrphan) {
        for(i = 0; i < layoutKeys.length; i++) {
            var key = layoutKeys[i];

            // orphan layout axes are considered cartesian subplots

            if(xaListGl2d.indexOf(key) === -1 &&
                xaListCartesian.indexOf(key) === -1 &&
                    constants.xAxisMatch.test(key)) {
                xaListCartesian.push(key);
            }
            else if(yaListGl2d.indexOf(key) === -1 &&
                yaListCartesian.indexOf(key) === -1 &&
                    constants.yAxisMatch.test(key)) {
                yaListCartesian.push(key);
            }
        }
    }

    // make sure that plots with orphan cartesian axes
    // are considered 'cartesian'
    if(xaListCartesian.length && yaListCartesian.length) {
        layoutOut._hasCartesian = true;
    }

    function axSort(a, b) {
        var aNum = Number(a.substr(5) || 1),
            bNum = Number(b.substr(5) || 1);
        return aNum - bNum;
    }

    var xaList = xaListCartesian.concat(xaListGl2d).sort(axSort),
        yaList = yaListCartesian.concat(yaListGl2d).sort(axSort),
        axesList = xaList.concat(yaList);

    // plot_bgcolor only makes sense if there's a (2D) plot!
    // TODO: bgcolor for each subplot, to inherit from the main one
    var plot_bgcolor = Color.background;
    if(xaList.length && yaList.length) {
        plot_bgcolor = Lib.coerce(layoutIn, layoutOut, Plots.layoutAttributes, 'plot_bgcolor');
    }

    var bgColor = Color.combine(plot_bgcolor, layoutOut.paper_bgcolor);

    axesList.forEach(function(axName) {
        var axLetter = axName.charAt(0),
            axLayoutIn = layoutIn[axName] || {},
            axLayoutOut = {},
            defaultOptions = {
                letter: axLetter,
                font: layoutOut.font,
                outerTicks: outerTicks[axName],
                showGrid: !noGrids[axName],
                name: axName,
                data: fullData,
                bgColor: bgColor
            },
            positioningOptions = {
                letter: axLetter,
                counterAxes: {x: yaList, y: xaList}[axLetter].map(axisIds.name2id),
                overlayableAxes: {x: xaList, y: yaList}[axLetter].filter(function(axName2) {
                    return axName2!==axName && !(layoutIn[axName2]||{}).overlaying;
                }).map(axisIds.name2id)
            };

        function coerce(attr, dflt) {
            return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
        }

        handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions);
        handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, positioningOptions);

        layoutOut[axName] = axLayoutOut;

        // so we don't have to repeat autotype unnecessarily,
        // copy an autotype back to layoutIn
        if(!layoutIn[axName] && axLayoutIn.type !== '-') {
            layoutIn[axName] = {type: axLayoutIn.type};
        }

    });

    // quick second pass for range slider and selector defaults
    axesList.forEach(function(axName) {
        var axLetter = axName.charAt(0),
            axLayoutIn = layoutIn[axName],
            axLayoutOut = layoutOut[axName],
            counterAxes = {x: yaList, y: xaList}[axLetter];

        RangeSlider.supplyLayoutDefaults(layoutIn, layoutOut, axName, counterAxes);

        if(axLetter === 'x' && axLayoutOut.type === 'date') {
            RangeSelector.supplyLayoutDefaults(axLayoutIn, axLayoutOut, layoutOut, counterAxes);
        }
    });
};
<commit_msg>make sure to add cartesian base plot module to orphan axis graphs:<commit_after>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Lib = require('../../lib');
var Plots = require('../plots');
var Color = require('../../components/color');

var RangeSlider = require('../../components/rangeslider');
var RangeSelector = require('../../components/rangeselector');

var constants = require('./constants');
var layoutAttributes = require('./layout_attributes');
var handleAxisDefaults = require('./axis_defaults');
var handlePositionDefaults = require('./position_defaults');
var axisIds = require('./axis_ids');

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
    var layoutKeys = Object.keys(layoutIn),
        xaListCartesian = [],
        yaListCartesian = [],
        xaListGl2d = [],
        yaListGl2d = [],
        outerTicks = {},
        noGrids = {},
        i;

    // look for axes in the data
    for(i = 0; i < fullData.length; i++) {
        var trace = fullData[i];
        var listX, listY;

        if(Plots.traceIs(trace, 'cartesian')) {
            listX = xaListCartesian;
            listY = yaListCartesian;
        }
        else if(Plots.traceIs(trace, 'gl2d')) {
            listX = xaListGl2d;
            listY = yaListGl2d;
        }
        else continue;

        var xaName = axisIds.id2name(trace.xaxis),
            yaName = axisIds.id2name(trace.yaxis);

        // add axes implied by traces
        if(xaName && listX.indexOf(xaName) === -1) listX.push(xaName);
        if(yaName && listY.indexOf(yaName) === -1) listY.push(yaName);

        // check for default formatting tweaks
        if(Plots.traceIs(trace, '2dMap')) {
            outerTicks[xaName] = true;
            outerTicks[yaName] = true;
        }

        if(Plots.traceIs(trace, 'oriented')) {
            var positionAxis = trace.orientation === 'h' ? yaName : xaName;
            noGrids[positionAxis] = true;
        }
    }

    // N.B. Ignore orphan axes (i.e. axes that have no data attached to them)
    // if gl3d or geo is present on graph. This is retain backward compatible.
    //
    // TODO drop this in version 2.0
    var ignoreOrphan = (layoutOut._hasGL3D || layoutOut._hasGeo);

    if(!ignoreOrphan) {
        for(i = 0; i < layoutKeys.length; i++) {
            var key = layoutKeys[i];

            // orphan layout axes are considered cartesian subplots

            if(xaListGl2d.indexOf(key) === -1 &&
                xaListCartesian.indexOf(key) === -1 &&
                    constants.xAxisMatch.test(key)) {
                xaListCartesian.push(key);
            }
            else if(yaListGl2d.indexOf(key) === -1 &&
                yaListCartesian.indexOf(key) === -1 &&
                    constants.yAxisMatch.test(key)) {
                yaListCartesian.push(key);
            }
        }
    }

    // make sure that plots with orphan cartesian axes
    // are considered 'cartesian'
    if(xaListCartesian.length && yaListCartesian.length) {
        Lib.fillUnique(layoutOut._basePlotModules, Plots.subplotsRegistry.cartesian);
    }

    function axSort(a, b) {
        var aNum = Number(a.substr(5) || 1),
            bNum = Number(b.substr(5) || 1);
        return aNum - bNum;
    }

    var xaList = xaListCartesian.concat(xaListGl2d).sort(axSort),
        yaList = yaListCartesian.concat(yaListGl2d).sort(axSort),
        axesList = xaList.concat(yaList);

    // plot_bgcolor only makes sense if there's a (2D) plot!
    // TODO: bgcolor for each subplot, to inherit from the main one
    var plot_bgcolor = Color.background;
    if(xaList.length && yaList.length) {
        plot_bgcolor = Lib.coerce(layoutIn, layoutOut, Plots.layoutAttributes, 'plot_bgcolor');
    }

    var bgColor = Color.combine(plot_bgcolor, layoutOut.paper_bgcolor);

    axesList.forEach(function(axName) {
        var axLetter = axName.charAt(0),
            axLayoutIn = layoutIn[axName] || {},
            axLayoutOut = {},
            defaultOptions = {
                letter: axLetter,
                font: layoutOut.font,
                outerTicks: outerTicks[axName],
                showGrid: !noGrids[axName],
                name: axName,
                data: fullData,
                bgColor: bgColor
            },
            positioningOptions = {
                letter: axLetter,
                counterAxes: {x: yaList, y: xaList}[axLetter].map(axisIds.name2id),
                overlayableAxes: {x: xaList, y: yaList}[axLetter].filter(function(axName2) {
                    return axName2!==axName && !(layoutIn[axName2]||{}).overlaying;
                }).map(axisIds.name2id)
            };

        function coerce(attr, dflt) {
            return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
        }

        handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions);
        handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, positioningOptions);

        layoutOut[axName] = axLayoutOut;

        // so we don't have to repeat autotype unnecessarily,
        // copy an autotype back to layoutIn
        if(!layoutIn[axName] && axLayoutIn.type !== '-') {
            layoutIn[axName] = {type: axLayoutIn.type};
        }

    });

    // quick second pass for range slider and selector defaults
    axesList.forEach(function(axName) {
        var axLetter = axName.charAt(0),
            axLayoutIn = layoutIn[axName],
            axLayoutOut = layoutOut[axName],
            counterAxes = {x: yaList, y: xaList}[axLetter];

        RangeSlider.supplyLayoutDefaults(layoutIn, layoutOut, axName, counterAxes);

        if(axLetter === 'x' && axLayoutOut.type === 'date') {
            RangeSelector.supplyLayoutDefaults(axLayoutIn, axLayoutOut, layoutOut, counterAxes);
        }
    });
};
<|endoftext|>


<commit_before>/*globals define*/
/*jshint node:true, browser:true*/

/**
 * Generated by PluginGenerator 1.7.0 from webgme on Thu May 12 2016 19:55:04 GMT-0500 (CDT).
 * A plugin that inherits from the PluginBase. To see source code documentation about available
 * properties and methods visit %host%/docs/source/PluginBase.html.
 */

define([
    'plugin/PluginConfig',
    'text!./metadata.json',
    'plugin/PluginBase',
    'common/util/ejs', // for ejs templates
    'common/util/xmljsonconverter', // used to save model as json
    'plugin/SimulateTES/SimulateTES/Templates/Templates',
    'plugin/SimulateTES/SimulateTES/SimulateTES.Parser',
    'plugin/SimulateTES/SimulateTES/SimulateTES.Plotter',
    'gridlabd/meta',
    'gridlabd/modelLoader',
    'gridlabd/renderer',
    'q'
], function (
    PluginConfig,
    pluginMetadata,
    PluginBase,
    ejs,
    Converter,
    TEMPLATES,
    Parser,
    Plotter,
    MetaTypes,
    loader,
    renderer,
    Q) {
    'use strict';

    pluginMetadata = JSON.parse(pluginMetadata);

    /**
     * Initializes a new instance of SimulateTES.
     * @class
     * @augments {PluginBase}
     * @classdesc This class represents the plugin SimulateTES.
     * @constructor
     */
    var SimulateTES = function () {
        // Call base class' constructor.
        PluginBase.call(this);
        this.pluginMetadata = pluginMetadata;
        this.metaTypes = MetaTypes;
    };

    /**
     * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
     * This is also available at the instance at this.pluginMetadata.
     * @type {object}
     */
    SimulateTES.metadata = pluginMetadata;

    // Prototypical inheritance from PluginBase.
    SimulateTES.prototype = Object.create(PluginBase.prototype);
    SimulateTES.prototype.constructor = SimulateTES;

    SimulateTES.prototype.notify = function(level, msg) {
	var self = this;
	var prefix = self.projectId + '::' + self.projectName + '::' + level + '::';
	if (level=='error')
	    self.logger.error(msg);
	else if (level=='debug')
	    self.logger.debug(msg);
	else if (level=='info')
	    self.logger.info(msg);
	else if (level=='warning')
	    self.logger.warn(msg);
	self.createMessage(self.activeNode, msg, level);
	self.sendNotification(prefix+msg);
    };

    /**
     * Main function for the plugin to execute. This will perform the execution.
     * Notes:
     * - Always log with the provided logger.[error,warning,info,debug].
     * - Do NOT put any user interaction logic UI, etc. inside this method.
     * - callback always has to be called even if error happened.
     *
     * @param {function(string, plugin.PluginResult)} callback - the result callback
     */
    SimulateTES.prototype.main = function (callback) {
        // Use self to access core, project, result, logger etc from PluginBase.
        // These are all instantiated at this point.
        var self = this,
        modelNode;

	self.result.success = false;

        if (typeof WebGMEGlobal !== 'undefined') {
	    var msg = 'You must run this plugin on the server!';
	    self.notify('error', msg);
	    callback(new Error(msg), self.result);
        }

	self.updateMETA(self.metaTypes);

	// What did the user select for our configuration?
	var currentConfig = self.getCurrentConfig();
	self.simulationTime = currentConfig.simulationTime;
	self.delayMean = currentConfig.delayMean;
	self.delayStdDev = currentConfig.delayStdDev;
	self.community1 = currentConfig.community1;
	self.community2 = currentConfig.community2;
	self.generator1 = currentConfig.generator1;
	self.generator2 = currentConfig.generator2;
	self.returnZip = currentConfig.returnZip;

        modelNode = self.activeNode;
	self.modelName = self.core.getAttribute(modelNode, 'name');
	self.fileName = self.modelName + '.glm';

	var path = require('path');
	var filendir = require('filendir');
	self.root_dir = path.join(process.cwd(),
				  'generated',
				  self.project.projectId,
				  self.branchName,
				  'models');

	return loader.loadModel(self.core, modelNode)
	    .then(function(powerModel) {
		self.powerModel = powerModel;
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		return self.renderModel();
	    })
	    .then(function() {
		return self.writeInputs();
	    })
	    .then(function() {
		return self.runSimulation();
	    })
	    .then(function() {
		return self.copyArtifacts();
	    })
	    .then(function() {
		return self.plotLogs();
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		self.result.success = true;
		self.notify('info', 'Simulation Complete.');
		callback(null, self.result);
	    })
	    .catch(function(err) {
		self.result.success = false;
		self.notify('error', err);
		callback(err, self.result);
	    });
    };

    SimulateTES.prototype.clean = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo",
	path = require('path'),
	cp = require('child_process');

	self.notify('info', 'Cleaning experiment artifacts and processes from system.');

	// clear out any previous inputs
	cp.execSync('rm -rf ' + basePath + '/input/*');
	// clear out any previous outputs
	cp.execSync('rm -rf ' + basePath + '/output/*');

	// need to kill docker container processes with sudo pkill
	cp.execSync('docker stop $(docker ps -a -q)');
    };

    SimulateTES.prototype.renderModel = function() {
	var self = this;
	self.fileData = renderer.renderGLM(self.powerModel, self.core, self.META);
    };

    SimulateTES.prototype.writeInputs = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/input/",
	inputFiles = {
	    "model.glm": self.fileData,
	    "Community1DemandController.config": JSON.stringify({ "Threshold": +self.community1 }, null, 2),
	    "Community2DemandController.config": JSON.stringify({ "Threshold": +self.community2 }, null, 2),
	    "Generator1PriceController.config": JSON.stringify({ "Threshold": +self.generator1 }, null, 2),
	    "Generator2PriceController.config": JSON.stringify({ "Threshold": +self.generator2 }, null, 2),
	    "script.xml": ejs.render(
		TEMPLATES['script.xml.ejs'],
		{
		    simEnd: self.simulationTime,
		    delayMean: self.delayMean,
		    delayStdDev: self.delayStdDev
		})
	},
	fs = require('fs'),
	path = require('path'),
	filendir = require('filendir');

	var fileNames = Object.keys(inputFiles);
	var tasks = fileNames.map((fileName) => {
	    var deferred = Q.defer();
	    var data = inputFiles[fileName];
	    filendir.writeFile(path.join(basePath, fileName), data, (err) => {
		if (err) {
		    deferred.reject('Couldnt write ' + fileName + ': ' + err);
		}
		else {
		    deferred.resolve();
		}
	    });
	    return deferred.promise;
	});

	return Q.all(tasks)
	    .then(function() {
		self.notify('info', 'Generated artifacts.');
	    });
    };

    SimulateTES.prototype.runSimulation = function() {
	var self = this;
	var path = require('path');
	var cp = require('child_process');

	self.notify('info', 'Starting Simulation');

	var deferred = Q.defer();

	var fname = path.join(self.root_dir, self.fileName);

	// start fed manager
	return self.startFederates()
	    .then(function() {
		return self.monitorContainers();
	    })
	    .then(function() {
		return self.killFederates();
	    });

	return deferred.promise;
    };

    SimulateTES.prototype.startFederates = function() {
	// run-cpp-feds.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var fedMgr = cp.spawn('bash', [], {cwd:basePath});
	fedMgr.stdout.on('data', function (data) {});
	fedMgr.stderr.on('data', function (error) {
	});
	fedMgr.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Started Federates.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('federates:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Starting Federates.');
	    fedMgr.stdin.write('./run-cpp-feds.sh\n');
	    fedMgr.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.monitorContainers = function() {
	var self = this;
	var cp = require('child_process');
	var deferred = Q.defer();

	var stdout = cp.execSync('docker ps');
	var regex = /(demo_c2wt_cpp_fedmgr_run_[\w+]*)/gi;
	var results = regex.exec(stdout);
	if (results) {
	    var dockerName = results[1];
	    self.notify('info', 'Waiting for simulation to complete when ' + dockerName + ' exits.');
	    stdout = cp.execSync('docker wait ' + dockerName);
	    self.notify('info', 'Docker federate exited with stdout: ' + stdout);
	}
	else {
	    self.notify('error', 'Couldnt find the federate docker container in docker ps!');
	}
    };

    SimulateTES.prototype.killFederates = function() {
	// kill-all.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var stopFeds = cp.spawn('bash', [], {cwd:basePath});
	stopFeds.stdout.on('data', function (data) {});
	stopFeds.stderr.on('data', function (error) {
	});
	stopFeds.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Killed all experiment feds.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('stopFeds:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Killing experiment feds.');
	    stopFeds.stdin.write('docker stop $(docker ps -a -q)\n');
	    stopFeds.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.copyArtifacts = function() {
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/output";

	self.notify('info', 'Copying output.');

	return new Promise(function(resolve, reject) {
	    var zlib = require('zlib'),
	    tar = require('tar'),
	    fstream = require('fstream'),
	    input = basePath;

	    var bufs = [];
	    var packer = tar.Pack()
		.on('error', function(e) { reject(e); });

	    var gzipper = zlib.Gzip()
		.on('error', function(e) { reject(e); })
		.on('data', function(d) { bufs.push(d); })
		.on('end', function() {
		    var buf = Buffer.concat(bufs);
		    self.blobClient.putFile('output.tar.gz',buf)
			.then(function (hash) {
			    self.result.addArtifact(hash);
			    resolve();
			})
			.catch(function(err) {
			    reject(err);
			})
			    .done();
		});

	    var reader = fstream.Reader({ 'path': input, 'type': 'Directory' })
		.on('error', function(e) { reject(e); });

	    reader
		.pipe(packer)
		.pipe(gzipper);
	})
	    .then(function() {
		self.notify('info', 'Created archive.');
	    });
    };

    SimulateTES.prototype.plotLogs = function() {
	var self = this;
	var path = require('path');
	var fs = requrie('fs');
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/output";
	var controllers = [
	    "Community1DemandController",
	    "Community2DemandController",
	    "Generator1PriceController",
	    "Generator2PriceController"
	];
	var tasks = controllers.map((controller) => {
	    var fileName = path.join(basePath, controller, controller + '.log');
	    var deferred = Q.defer();
	    // load the file
	    fs.readFile(fileName, (err, data) => {
		if (err) {
		    deferred.reject('Couldnt open ' + fileName + ': ' + err);
		    return;
		}
		var logData = Parser.getDataFromLog(data);
		var svg = Plotter.plotData(logData);
		var resultFileName = controller + '.svg';
		self.blobClient.putFile(resultFileName, svg.outerHTML)
		    .then((hash) => {
			self.result.addArtifact(hash);
			var resultUrl = '/rest/blob/download/' + hash + '/' + resultFileName;
			self.createMessage(self.activeNode, svg.outerHTML,'info');
			deferred.resolve();
		    });
		    .catch((err) => {
			deferred.reject('Couldnt add ' + resultFileName +' to blob');
		    });
	    });
	    // add to blob
	    // add to result
	    return deferred.promise;
	});
	return Q.all(tasks);
    };

    return SimulateTES;
});
<commit_msg>minor update for execution.<commit_after>/*globals define*/
/*jshint node:true, browser:true*/

/**
 * Generated by PluginGenerator 1.7.0 from webgme on Thu May 12 2016 19:55:04 GMT-0500 (CDT).
 * A plugin that inherits from the PluginBase. To see source code documentation about available
 * properties and methods visit %host%/docs/source/PluginBase.html.
 */

define([
    'plugin/PluginConfig',
    'text!./metadata.json',
    'plugin/PluginBase',
    'common/util/ejs', // for ejs templates
    'common/util/xmljsonconverter', // used to save model as json
    'plugin/SimulateTES/SimulateTES/Templates/Templates',
    'plugin/SimulateTES/SimulateTES/SimulateTES.Parser',
    'plugin/SimulateTES/SimulateTES/SimulateTES.Plotter',
    'gridlabd/meta',
    'gridlabd/modelLoader',
    'gridlabd/renderer',
    'q'
], function (
    PluginConfig,
    pluginMetadata,
    PluginBase,
    ejs,
    Converter,
    TEMPLATES,
    Parser,
    Plotter,
    MetaTypes,
    loader,
    renderer,
    Q) {
    'use strict';

    pluginMetadata = JSON.parse(pluginMetadata);

    /**
     * Initializes a new instance of SimulateTES.
     * @class
     * @augments {PluginBase}
     * @classdesc This class represents the plugin SimulateTES.
     * @constructor
     */
    var SimulateTES = function () {
        // Call base class' constructor.
        PluginBase.call(this);
        this.pluginMetadata = pluginMetadata;
        this.metaTypes = MetaTypes;
    };

    /**
     * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
     * This is also available at the instance at this.pluginMetadata.
     * @type {object}
     */
    SimulateTES.metadata = pluginMetadata;

    // Prototypical inheritance from PluginBase.
    SimulateTES.prototype = Object.create(PluginBase.prototype);
    SimulateTES.prototype.constructor = SimulateTES;

    SimulateTES.prototype.notify = function(level, msg) {
	var self = this;
	var prefix = self.projectId + '::' + self.projectName + '::' + level + '::';
	if (level=='error')
	    self.logger.error(msg);
	else if (level=='debug')
	    self.logger.debug(msg);
	else if (level=='info')
	    self.logger.info(msg);
	else if (level=='warning')
	    self.logger.warn(msg);
	self.createMessage(self.activeNode, msg, level);
	self.sendNotification(prefix+msg);
    };

    /**
     * Main function for the plugin to execute. This will perform the execution.
     * Notes:
     * - Always log with the provided logger.[error,warning,info,debug].
     * - Do NOT put any user interaction logic UI, etc. inside this method.
     * - callback always has to be called even if error happened.
     *
     * @param {function(string, plugin.PluginResult)} callback - the result callback
     */
    SimulateTES.prototype.main = function (callback) {
        // Use self to access core, project, result, logger etc from PluginBase.
        // These are all instantiated at this point.
        var self = this,
        modelNode;

	self.result.success = false;

        if (typeof WebGMEGlobal !== 'undefined') {
	    var msg = 'You must run this plugin on the server!';
	    self.notify('error', msg);
	    callback(new Error(msg), self.result);
        }

	self.updateMETA(self.metaTypes);

	// What did the user select for our configuration?
	var currentConfig = self.getCurrentConfig();
	self.simulationTime = currentConfig.simulationTime;
	self.delayMean = currentConfig.delayMean;
	self.delayStdDev = currentConfig.delayStdDev;
	self.community1 = currentConfig.community1;
	self.community2 = currentConfig.community2;
	self.generator1 = currentConfig.generator1;
	self.generator2 = currentConfig.generator2;
	self.returnZip = currentConfig.returnZip;

        modelNode = self.activeNode;
	self.modelName = self.core.getAttribute(modelNode, 'name');
	self.fileName = self.modelName + '.glm';

	var path = require('path');
	var filendir = require('filendir');
	self.root_dir = path.join(process.cwd(),
				  'generated',
				  self.project.projectId,
				  self.branchName,
				  'models');

	return loader.loadModel(self.core, modelNode)
	    .then(function(powerModel) {
		self.powerModel = powerModel;
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		return self.renderModel();
	    })
	    .then(function() {
		return self.writeInputs();
	    })
	    .then(function() {
		return self.runSimulation();
	    })
	    .then(function() {
		return self.copyArtifacts();
	    })
	    .then(function() {
		return self.plotLogs();
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		self.result.success = true;
		self.notify('info', 'Simulation Complete.');
		callback(null, self.result);
	    })
	    .catch(function(err) {
		self.result.success = false;
		self.notify('error', err);
		callback(err, self.result);
	    });
    };

    SimulateTES.prototype.clean = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo",
	path = require('path'),
	cp = require('child_process');

	self.notify('info', 'Cleaning experiment artifacts and processes from system.');

	// clear out any previous inputs
	cp.execSync('rm -rf ' + basePath + '/input/*');
	// clear out any previous outputs
	cp.execSync('rm -rf ' + basePath + '/output/*');

	// need to kill docker container processes with sudo pkill
	cp.execSync('docker stop $(docker ps -a -q)');
    };

    SimulateTES.prototype.renderModel = function() {
	var self = this;
	self.fileData = renderer.renderGLM(self.powerModel, self.core, self.META);
    };

    SimulateTES.prototype.writeInputs = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/input/",
	inputFiles = {
	    "model.glm": self.fileData,
	    "Community1DemandController.config": JSON.stringify({ "Threshold": +self.community1 }, null, 2),
	    "Community2DemandController.config": JSON.stringify({ "Threshold": +self.community2 }, null, 2),
	    "Generator1PriceController.config": JSON.stringify({ "Threshold": +self.generator1 }, null, 2),
	    "Generator2PriceController.config": JSON.stringify({ "Threshold": +self.generator2 }, null, 2),
	    "script.xml": ejs.render(
		TEMPLATES['script.xml.ejs'],
		{
		    simEnd: self.simulationTime,
		    delayMean: self.delayMean,
		    delayStdDev: self.delayStdDev
		})
	},
	fs = require('fs'),
	path = require('path'),
	filendir = require('filendir');

	var fileNames = Object.keys(inputFiles);
	var tasks = fileNames.map((fileName) => {
	    var deferred = Q.defer();
	    var data = inputFiles[fileName];
	    filendir.writeFile(path.join(basePath, fileName), data, (err) => {
		if (err) {
		    deferred.reject('Couldnt write ' + fileName + ': ' + err);
		}
		else {
		    deferred.resolve();
		}
	    });
	    return deferred.promise;
	});

	return Q.all(tasks)
	    .then(function() {
		self.notify('info', 'Generated artifacts.');
	    });
    };

    SimulateTES.prototype.runSimulation = function() {
	var self = this;
	var path = require('path');
	var cp = require('child_process');

	self.notify('info', 'Starting Simulation');

	var deferred = Q.defer();

	var fname = path.join(self.root_dir, self.fileName);

	// start fed manager
	return self.startFederates()
	    .then(function() {
		return self.monitorContainers();
	    })
	    .then(function() {
		return self.killFederates();
	    });

	return deferred.promise;
    };

    SimulateTES.prototype.startFederates = function() {
	// run-cpp-feds.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var fedMgr = cp.spawn('bash', [], {cwd:basePath});
	fedMgr.stdout.on('data', function (data) {});
	fedMgr.stderr.on('data', function (error) {
	});
	fedMgr.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Started Federates.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('federates:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Starting Federates.');
	    fedMgr.stdin.write('./run-cpp-feds.sh\n');
	    fedMgr.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.monitorContainers = function() {
	var self = this;
	var cp = require('child_process');
	var deferred = Q.defer();

	var stdout = cp.execSync('docker ps');
	var regex = /(demo_c2wt_cpp_fedmgr_run_[\w+]*)/gi;
	var results = regex.exec(stdout);
	if (results) {
	    var dockerName = results[1];
	    self.notify('info', 'Waiting for simulation to complete when ' + dockerName + ' exits.');
	    stdout = cp.execSync('docker wait ' + dockerName);
	    self.notify('info', 'Docker federate exited with stdout: ' + stdout);
	}
	else {
	    self.notify('error', 'Couldnt find the federate docker container in docker ps!');
	}
    };

    SimulateTES.prototype.killFederates = function() {
	// kill-all.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var stopFeds = cp.spawn('bash', [], {cwd:basePath});
	stopFeds.stdout.on('data', function (data) {});
	stopFeds.stderr.on('data', function (error) {
	});
	stopFeds.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Killed all experiment feds.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('stopFeds:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Killing experiment feds.');
	    stopFeds.stdin.write('docker stop $(docker ps -a -q)\n');
	    stopFeds.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.copyArtifacts = function() {
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/output";

	self.notify('info', 'Copying output.');

	return new Promise(function(resolve, reject) {
	    var zlib = require('zlib'),
	    tar = require('tar'),
	    fstream = require('fstream'),
	    input = basePath;

	    var bufs = [];
	    var packer = tar.Pack()
		.on('error', function(e) { reject(e); });

	    var gzipper = zlib.Gzip()
		.on('error', function(e) { reject(e); })
		.on('data', function(d) { bufs.push(d); })
		.on('end', function() {
		    var buf = Buffer.concat(bufs);
		    self.blobClient.putFile('output.tar.gz',buf)
			.then(function (hash) {
			    self.result.addArtifact(hash);
			    resolve();
			})
			.catch(function(err) {
			    reject(err);
			})
			    .done();
		});

	    var reader = fstream.Reader({ 'path': input, 'type': 'Directory' })
		.on('error', function(e) { reject(e); });

	    reader
		.pipe(packer)
		.pipe(gzipper);
	})
	    .then(function() {
		self.notify('info', 'Created archive.');
	    });
    };

    SimulateTES.prototype.plotLogs = function() {
	var self = this;
	var path = require('path');
	var fs = requrie('fs');
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/output";
	var controllers = [
	    "Community1DemandController",
	    "Community2DemandController",
	    "Generator1PriceController",
	    "Generator2PriceController"
	];
	var tasks = controllers.map((controller) => {
	    var fileName = path.join(basePath, controller, controller + '.log');
	    var deferred = Q.defer();
	    // load the file
	    fs.readFile(fileName, (err, data) => {
		if (err) {
		    deferred.reject('Couldnt open ' + fileName + ': ' + err);
		    return;
		}
		var logData = Parser.getDataFromLog(data);
		var svg = Plotter.plotData(logData);
		var resultFileName = controller + '.svg';
		self.blobClient.putFile(resultFileName, svg.outerHTML)
		    .then((hash) => {
			self.result.addArtifact(hash);
			var resultUrl = '/rest/blob/download/' + hash + '/' + resultFileName;
			self.createMessage(self.activeNode, svg.outerHTML,'info');
			deferred.resolve();
		    })
		    .catch((err) => {
			deferred.reject('Couldnt add ' + resultFileName +' to blob');
		    });
	    });
	    // add to blob
	    // add to result
	    return deferred.promise;
	});
	return Q.all(tasks);
    };

    return SimulateTES;
});
<|endoftext|>