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

var __ = require('underscore');
var util = require('util');
var async = require('async');

var utils = require('../../../util/utils');
var $ = utils.getLocaleString;

function VMImage(cli, serviceClients, resourceGroupName, params) {
  this.cli = cli;
  this.serviceClients = serviceClients;
  this.resourceGroupName = resourceGroupName;
  this.params = params;
}

__.extend(VMImage.prototype, {
  getVMImagePublisherList: function (location, _) {
    var publishers;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine and/or extension image publishers (Location: "%s")'), location));
    try {
      publishers = this.serviceClients.computeManagementClient.virtualMachineImages.listPublishers(location, _);
    } finally {
      progress.end();
    }

    return publishers;
  },

  getVMImageOffersList: function (location, publisherName, _) {
    var offers;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine image offers (Publisher: "%s" Location:"%s")'), publisherName, location));
    try {
      offers = this.serviceClients.computeManagementClient.virtualMachineImages.listOffers(location, publisherName, _);
    } finally {
      progress.end();
    }

    offers.map(function(sku){
      sku.publisher = publisherName;
      return sku;
    });

    return offers;
  },

  getVMImageSkusList: function (location, publisherName, offer, _) {
    var skus;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine image skus (Publisher:"%s" Offer:"%s" Location:"%s")'), publisherName, offer, location));
    try {
      skus = this.serviceClients.computeManagementClient.virtualMachineImages.listSkus(location, publisherName, offer, _);
    } finally {
      progress.end();
    }

    skus.map(function(sku){
      sku.publisher = publisherName;
      sku.offer = offer;
      return sku;
    });

    return skus;
  },

  getVMImageListForSku: function (location, publisherName, offer, skus, _) {
    var images;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine images (Publisher:"%s" Offer:"%s" Sku: "%s" Location:"%s")'), publisherName, offer, skus, location));
    try {
      images = this.serviceClients.computeManagementClient.virtualMachineImages.list(location, publisherName, offer, skus, _);
    } finally {
      progress.end();
    }

    return images;
  },

  getVMImageList: function (imageFilter, _) {
    if (!imageFilter.location) {
      imageFilter.location = this.cli.interaction.prompt($('Enter location: '), _);
    }

    if (imageFilter.publishername && imageFilter.offer && imageFilter.skus) {
      return this._getVMImageListForPublisherOfferAndSkus(imageFilter, _);
    }

    if (imageFilter.publishername && imageFilter.offer) {
      return this._getVMImageListForPublisherAndOffer(imageFilter, _);
    }

    if (imageFilter.publishername) {
      return this._getVMImageListForPublisher(imageFilter, _);
    }
  },

  _getVMImageListForPublisherOfferAndSkus: function (imageFilter, _) {
    var that = this;

    var images = that.getVMImageListForSku(imageFilter.location, imageFilter.publishername, imageFilter.offer, imageFilter.skus, _);
    var imageQueries = [];
    images.forEach(function (image) {
      imageQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineImages.get(
          imageFilter.location,
          imageFilter.publishername,
          imageFilter.offer,
          imageFilter.skus,
          image.name,
          function(error, imgResult) {
            imgResult = error ? { osDiskImage: {}, dataDiskImages: [] } : imgResult;
            image.publisher = imageFilter.publishername;
            image.offer = imageFilter.offer;
            image.skus = imageFilter.skus;
            image.urn = image.publisher + ':' +image.offer + ':' + image.skus + ':' + image.name;
            image.operatingSystem = imgResult.osDiskImage.operatingSystem;
            image.dataDiskImages = imgResult.dataDiskImages;
            image.purchasePlan = imgResult.purchasePlan;
            return callBack(null, image);
          });
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  _getVMImageListForPublisherAndOffer: function (imageFilter, _) {
    var that = this;
    var imageQueries;

    var skusCollection = that.getVMImageSkusList(imageFilter.location, imageFilter.publishername, imageFilter.offer, _);
    imageQueries = [];
    skusCollection.forEach( function(skus) {
      imageQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineImages.list(
          imageFilter.location,
          imageFilter.publishername,
          imageFilter.offer,
          skus.name,
          function(error, vmImages) {
            vmImages = error ? [] : vmImages;
            vmImages.skus = skus.name;
            skus.vmImages = vmImages;
            return callBack(error, vmImages);
          });
      });
    });

    async.parallel(imageQueries, _);

    // Flatten the collection
    imageQueries = [];
    skusCollection.forEach( function(skus) {
      skus.vmImages.forEach( function (image) {
        imageQueries.push(function(callBack) {
          that.serviceClients.computeManagementClient.virtualMachineImages.get(
            imageFilter.location,
            imageFilter.publishername,
            imageFilter.offer,
            skus.vmImages.skus,
            image.name,
            function(error, imgResult) {
              imgResult = error ? { osDiskImage: {}, dataDiskImages: [] } : imgResult;
              image.publisher = imageFilter.publishername;
              image.offer = imageFilter.offer;
              image.skus = skus.vmImages.skus;
              image.urn = image.publisher + ':' +image.offer + ':' + image.skus + ':' + image.name;
              image.operatingSystem = imgResult.osDiskImage.operatingSystem;
              image.dataDiskImages = imgResult.dataDiskImages;
              image.purchasePlan = imgResult.purchasePlan;
              return callBack(null, image);
            });
        });
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  _getVMImageListForPublisher: function (imageFilter, _) {
    var that = this;
    var imageQueries;

    var offers = that.getVMImageOffersList(imageFilter.location, imageFilter.publishername, _);
    var skuQueries = [];
    offers.forEach(function(offer) {
      skuQueries.push(function(callBack) {
        offer = offer;
        that.serviceClients.computeManagementClient.virtualMachineImages.listSkus(
          imageFilter.location,
          imageFilter.publishername,
          offer.name,
          function (error, skus) {
            skus = error ? [] : skus;
            skus.offer = offer.name;
            offer.skus = skus;
            return callBack(error, skus);
          });
      });
    });

    var skusCollections = async.parallel(skuQueries, _);
    imageQueries = [];
    skusCollections.forEach(function(skusCollection) {
      skusCollection.forEach(function(skus) {
        imageQueries.push(function(callBack) {
          skus = skus;
          that.serviceClients.computeManagementClient.virtualMachineImages.list(
            imageFilter.location,
            imageFilter.publishername,
            skusCollection.offer,
            skus.name,
            function(error, vmImages) {
              vmImages = error ? [] : vmImages;
              vmImages.skus = skus.name;
              skus.vmImages = vmImages;
              return callBack(error, vmImages);
            });
        });
      });
    });

    async.parallel(imageQueries, _);
    imageQueries = [];
    // Flatten the collection
    skusCollections.forEach (function (skusCollection) {
      skusCollection.forEach(function (skus) {
        skus.vmImages.forEach(function (image) {
          imageQueries.push(function(callBack) {
            that.serviceClients.computeManagementClient.virtualMachineImages.get(
              imageFilter.location,
              imageFilter.publishername,
              skusCollection.offer,
              skus.name,
              image.name,
              function(error, imgResult) {
                imgResult = error ? { osDiskImage: {}, dataDiskImages: [] } : imgResult;
                image.publisher = imageFilter.publishername;
                image.offer = skusCollection.offer;
                image.skus = skus.name;
                image.urn = image.publisher + ':' +image.offer + ':' + image.skus + ':' + image.name;
                image.operatingSystem = imgResult.osDiskImage.operatingSystem;
                image.dataDiskImages = imgResult.dataDiskImages;
                image.purchasePlan = imgResult.purchasePlan;
                return callBack(null, image);
              });
          });
        });
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  getVMImageDetails: function (imageFilter, _) {
    var that = this;
    var imageQueries = [];
    imageQueries.push(function(callBack) {
      that.serviceClients.computeManagementClient.virtualMachineImages.get(imageFilter.location, imageFilter.publishername, imageFilter.offer, imageFilter.skus, imageFilter.version, function(error, imgResult) {
        if (error) {
          callBack(error);
          return;
        }

        imgResult = error ? {} : imgResult;
        return callBack(null, imgResult);
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  getVMExtensionImageList: function (location, publisher, typeName, _) {
    if (!location) {
      location = this.cli.interaction.prompt($('Enter location: '), _);
    }

    if (publisher && typeName) {
      return this.getVMExtensionImageVersionList(location, publisher, typeName, _);
    }
    else if (publisher && !typeName) {
      return this._getExtImageListForPublisher(location, publisher, _);
    }
    else if (!publisher && typeName) {
      publisher = this.cli.interaction.prompt($('Enter publisher name: '), _);
      return this.getVMExtensionImageVersionList(location, publisher, typeName, _);
    }
    else {
      return this._getExtImageListForLocation(location, _);
    }
  },

  _getExtImageListForLocation: function (location, _) {
    var that = this;
    var publishers = this.serviceClients.computeManagementClient.virtualMachineImages.listPublishers(location, _);
    var typeQueries = [];
    publishers.forEach(function(publisherItem) {
      typeQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineExtensionImages.listTypes(
          location,
          publisherItem.name,
          function (error, types) {
            types = error ? [] : types;
            types.publisher = publisherItem.name;
            types.location = location;
            return callBack(error, types);
          });
      });
    });

    var typeCollections = async.parallel(typeQueries, _);

    imageQueries = [];
    typeCollections.forEach(function(typeCollection) {
      typeCollection.forEach(function(typeItem) {
        imageQueries.push(function(callBack) {
          that.serviceClients.computeManagementClient.virtualMachineExtensionImages.listVersions(
            typeCollection.location,
            typeCollection.publisher,
            typeItem.name,
            function(error, verItems) {
              verItems = error ? [] : verItems;
              verItems.publisher = typeCollection.publisher;
              verItems.location = typeCollection.location;
              verItems.typeName = typeItem.name;
              return callBack(error, verItems);
            });
        });
      });
    });

    var verCollections = async.parallel(imageQueries, _);

    var imgResult = [];
    verCollections.forEach(function(verCol) {
      if (verCol) {
        verCol.forEach(function(verItem) {
          imgResult.push({
            publisher: verCol.publisher,
            location: verCol.location,
            typeName: verCol.typeName,
            name: verItem.name
          });
        });
      }
    });

    return imgResult;
  },

  _getExtImageListForPublisher: function (location, publisher, _) {
    var that = this;
    var typeNames = that.getVMExtensionImageTypeList(location, publisher, _);
    var verQueries = [];
    typeNames.forEach(function(typeItem) {
      verQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineExtensionImages.listVersions(
          location,
          publisher,
          typeItem.name,
          function (error, item) {
            item = error ? [] : item;
            item.publisher = publisher;
            item.location = location;
            item.typeName = typeItem.name;
            return callBack(error, item);
          });
      });
    });

    var verCollections = async.parallel(verQueries, _);

    var imgResult = [];
    verCollections.forEach(function(verCol) {
      if (verCol) {
        verCol.forEach(function(resourceItem) {
          imgResult.push({
            publisher: verCol.publisher,
            location: verCol.location,
            typeName: verCol.typeName,
            name: resourceItem.name
          });
        });
      }
    });

    return imgResult;
  },

  getVMExtensionImageTypeList: function (location, publisherName, _) {
    var extTypes;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine extension image types (Publisher: "%s" Location:"%s")'), publisherName, location));
    try {
      extTypes = this.serviceClients.computeManagementClient.virtualMachineExtensionImages.listTypes(
        location,
        publisherName,
        _);
    } finally {
      progress.end();
    }

    extTypes.map(function(item){
      item.publisher = publisherName;
      return item;
    });

    return extTypes;
  },

  getVMExtensionImageVersionList: function (location, publisherName, typeName, _) {
    var extVersions = [];
    var resultList = null;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine extension image verions (Publisher: "%s" Type:"%s" Location:"%s")'), publisherName, typeName, location));

    try {
      resultList = this.serviceClients.computeManagementClient.virtualMachineExtensionImages.listVersions(
        location,
        publisherName,
        typeName,
        _);
    } finally {
      progress.end();
    }

    resultList.forEach(function (versionItem) {
      extVersions.push(versionItem);
    });

    extVersions.map(function(item){
      item.publisher = publisherName;
      item.typeName = typeName;
      return item;
    });

    return extVersions;
  },

  getVMExtensionImage: function (location, publisherName, typeName, version, _) {
    var extImage = null;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine extension images (Publisher: "%s" Type:"%s" Version:"%s" Location:"%s")'), publisherName, typeName, version, location));
    try {
      extImage = this.serviceClients.computeManagementClient.virtualMachineExtensionImages.get(
        location,
        publisherName,
        typeName,
        version,
        _);
    } finally {
      progress.end();
    }

    return extImage;
  }

});

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

var __ = require('underscore');
var util = require('util');
var async = require('async');

var utils = require('../../../util/utils');
var $ = utils.getLocaleString;

function VMImage(cli, serviceClients, resourceGroupName, params) {
  this.cli = cli;
  this.serviceClients = serviceClients;
  this.resourceGroupName = resourceGroupName;
  this.params = params;
}

__.extend(VMImage.prototype, {
  getVMImagePublisherList: function (location, _) {
    var publishers;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine and/or extension image publishers (Location: "%s")'), location));
    try {
      publishers = this.serviceClients.computeManagementClient.virtualMachineImages.listPublishers(location, _);
    } finally {
      progress.end();
    }

    return publishers;
  },

  getVMImageOffersList: function (location, publisherName, _) {
    var offers;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine image offers (Publisher: "%s" Location:"%s")'), publisherName, location));
    try {
      offers = this.serviceClients.computeManagementClient.virtualMachineImages.listOffers(location, publisherName, _);
    } finally {
      progress.end();
    }

    offers.map(function(sku){
      sku.publisher = publisherName;
      return sku;
    });

    return offers;
  },

  getVMImageSkusList: function (location, publisherName, offer, _) {
    var skus;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine image skus (Publisher:"%s" Offer:"%s" Location:"%s")'), publisherName, offer, location));
    try {
      skus = this.serviceClients.computeManagementClient.virtualMachineImages.listSkus(location, publisherName, offer, _);
    } finally {
      progress.end();
    }

    skus.map(function(sku){
      sku.publisher = publisherName;
      sku.offer = offer;
      return sku;
    });

    return skus;
  },

  getVMImageListForSku: function (location, publisherName, offer, skus, _) {
    var images;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine images (Publisher:"%s" Offer:"%s" Sku: "%s" Location:"%s")'), publisherName, offer, skus, location));
    try {
      images = this.serviceClients.computeManagementClient.virtualMachineImages.list(location, publisherName, offer, skus, _);
    } finally {
      progress.end();
    }

    return images;
  },

  getVMImageList: function (imageFilter, _) {
    if (!imageFilter.location) {
      imageFilter.location = this.cli.interaction.prompt($('Enter location: '), _);
    }

    if (imageFilter.publishername && imageFilter.offer && imageFilter.skus) {
      return this._getVMImageListForPublisherOfferAndSkus(imageFilter, _);
    }

    if (imageFilter.publishername && imageFilter.offer) {
      return this._getVMImageListForPublisherAndOffer(imageFilter, _);
    }

    if (imageFilter.publishername) {
      return this._getVMImageListForPublisher(imageFilter, _);
    }
  },

  _getVMImageListForPublisherOfferAndSkus: function (imageFilter, _) {
    var that = this;

    var images = that.getVMImageListForSku(imageFilter.location, imageFilter.publishername, imageFilter.offer, imageFilter.skus, _);
    var imageQueries = [];
    images.forEach(function (image) {
      imageQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineImages.get(
          imageFilter.location,
          imageFilter.publishername,
          imageFilter.offer,
          imageFilter.skus,
          image.name,
          function(error, imgResult) {
            imgResult = error ? { osDiskImage: {}, dataDiskImages: [] } : imgResult;
            image.publisher = imageFilter.publishername;
            image.offer = imageFilter.offer;
            image.skus = imageFilter.skus;
            image.urn = image.publisher + ':' +image.offer + ':' + image.skus + ':' + image.name;
            image.operatingSystem = imgResult.osDiskImage.operatingSystem;
            image.dataDiskImages = imgResult.dataDiskImages;
            image.purchasePlan = imgResult.purchasePlan;
            return callBack(null, image);
          });
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  _getVMImageListForPublisherAndOffer: function (imageFilter, _) {
    var that = this;
    var imageQueries;

    var skusCollection = that.getVMImageSkusList(imageFilter.location, imageFilter.publishername, imageFilter.offer, _);
    imageQueries = [];
    skusCollection.forEach( function(skus) {
      imageQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineImages.list(
          imageFilter.location,
          imageFilter.publishername,
          imageFilter.offer,
          skus.name,
          function(error, vmImages) {
            vmImages = error ? [] : vmImages;
            vmImages.skus = skus.name;
            skus.vmImages = vmImages;
            return callBack(error, vmImages);
          });
      });
    });

    async.parallel(imageQueries, _);

    // Flatten the collection
    imageQueries = [];
    skusCollection.forEach( function(skus) {
      skus.vmImages.forEach( function (image) {
        imageQueries.push(function(callBack) {
          that.serviceClients.computeManagementClient.virtualMachineImages.get(
            imageFilter.location,
            imageFilter.publishername,
            imageFilter.offer,
            skus.vmImages.skus,
            image.name,
            function(error, imgResult) {
              imgResult = error ? { osDiskImage: {}, dataDiskImages: [] } : imgResult;
              image.publisher = imageFilter.publishername;
              image.offer = imageFilter.offer;
              image.skus = skus.vmImages.skus;
              image.urn = image.publisher + ':' +image.offer + ':' + image.skus + ':' + image.name;
              image.operatingSystem = imgResult.osDiskImage.operatingSystem;
              image.dataDiskImages = imgResult.dataDiskImages;
              image.purchasePlan = imgResult.purchasePlan;
              return callBack(null, image);
            });
        });
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  _getVMImageListForPublisher: function (imageFilter, _) {
    var that = this;
    var imageQueries;

    var offers = that.getVMImageOffersList(imageFilter.location, imageFilter.publishername, _);
    var skuQueries = [];
    offers.forEach(function(offer) {
      skuQueries.push(function(callBack) {
        offer = offer;
        that.serviceClients.computeManagementClient.virtualMachineImages.listSkus(
          imageFilter.location,
          imageFilter.publishername,
          offer.name,
          function (error, skus) {
            skus = error ? [] : skus;
            skus.offer = offer.name;
            offer.skus = skus;
            return callBack(error, skus);
          });
      });
    });

    var skusCollections = async.parallel(skuQueries, _);
    imageQueries = [];
    skusCollections.forEach(function(skusCollection) {
      skusCollection.forEach(function(skus) {
        imageQueries.push(function(callBack) {
          skus = skus;
          that.serviceClients.computeManagementClient.virtualMachineImages.list(
            imageFilter.location,
            imageFilter.publishername,
            skusCollection.offer,
            skus.name,
            function(error, vmImages) {
              vmImages = error ? [] : vmImages;
              vmImages.skus = skus.name;
              skus.vmImages = vmImages;
              return callBack(error, vmImages);
            });
        });
      });
    });

    async.parallel(imageQueries, _);
    imageQueries = [];
    // Flatten the collection
    skusCollections.forEach (function (skusCollection) {
      skusCollection.forEach(function (skus) {
        skus.vmImages.forEach(function (image) {
          imageQueries.push(function(callBack) {
            that.serviceClients.computeManagementClient.virtualMachineImages.get(
              imageFilter.location,
              imageFilter.publishername,
              skusCollection.offer,
              skus.name,
              image.name,
              function(error, imgResult) {
                imgResult = error ? { osDiskImage: {}, dataDiskImages: [] } : imgResult;
                image.publisher = imageFilter.publishername;
                image.offer = skusCollection.offer;
                image.skus = skus.name;
                image.urn = image.publisher + ':' +image.offer + ':' + image.skus + ':' + image.name;
                image.operatingSystem = imgResult.osDiskImage.operatingSystem;
                image.dataDiskImages = imgResult.dataDiskImages;
                image.purchasePlan = imgResult.purchasePlan;
                return callBack(null, image);
              });
          });
        });
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  getVMImageDetails: function (imageFilter, _) {
    var that = this;
    var imageQueries = [];
    imageQueries.push(function(callBack) {
      that.serviceClients.computeManagementClient.virtualMachineImages.get(imageFilter.location, imageFilter.publishername, imageFilter.offer, imageFilter.skus, imageFilter.version, function(error, imgResult) {
        if (error) {
          callBack(error);
          return;
        }

        imgResult = error ? {} : imgResult;
        return callBack(null, imgResult);
      });
    });

    var imageCollection = async.parallel(imageQueries, _);
    return imageCollection;
  },

  getVMExtensionImageList: function (location, publisher, typeName, _) {
    if (!location) {
      location = this.cli.interaction.prompt($('Enter location: '), _);
    }

    if (publisher && typeName) {
      return this.getVMExtensionImageVersionList(location, publisher, typeName, _);
    }
    else if (publisher && !typeName) {
      return this._getExtImageListForPublisher(location, publisher, _);
    }
    else if (!publisher && typeName) {
      publisher = this.cli.interaction.prompt($('Enter publisher name: '), _);
      return this.getVMExtensionImageVersionList(location, publisher, typeName, _);
    }
    else {
      return this._getExtImageListForLocation(location, _);
    }
  },

  _getExtImageListForLocation: function (location, _) {
    var that = this;
    var publishers = this.serviceClients.computeManagementClient.virtualMachineImages.listPublishers(location, _);
    var typeQueries = [];
    publishers.forEach(function(publisherItem) {
      typeQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineExtensionImages.listTypes(
          location,
          publisherItem.name,
          function (error, types) {
            types = error ? [] : types;
            types.publisher = publisherItem.name;
            types.location = location;
            return callBack(error, types);
          });
      });
    });

    var typeCollections = async.parallel(typeQueries, _);

    imageQueries = [];
    typeCollections.forEach(function(typeCollection) {
      typeCollection.forEach(function(typeItem) {
        imageQueries.push(function(callBack) {
          that.serviceClients.computeManagementClient.virtualMachineExtensionImages.listVersions(
            typeCollection.location,
            typeCollection.publisher,
            typeItem.name,
            function(error, verItems) {
              verItems = error ? [] : verItems;
              verItems.publisher = typeCollection.publisher;
              verItems.location = typeCollection.location;
              verItems.typeName = typeItem.name;
              return callBack(error, verItems);
            });
        });
      });
    });

    var verCollections = async.parallel(imageQueries, _);

    var imgResult = [];
    verCollections.forEach(function(verCol) {
      if (verCol) {
        verCol.forEach(function(verItem) {
          imgResult.push({
            publisher: verCol.publisher,
            location: verCol.location,
            typeName: verCol.typeName,
            name: verItem.name
          });
        });
      }
    });

    return imgResult;
  },

  _getExtImageListForPublisher: function (location, publisher, _) {
    var that = this;
    var typeNames = that.getVMExtensionImageTypeList(location, publisher, _);
    var verQueries = [];
    typeNames.forEach(function(typeItem) {
      verQueries.push(function(callBack) {
        that.serviceClients.computeManagementClient.virtualMachineExtensionImages.listVersions(
          location,
          publisher,
          typeItem.name,
          function (error, item) {
            item = error ? [] : item;
            item.publisher = publisher;
            item.location = location;
            item.typeName = typeItem.name;
            return callBack(error, item);
          });
      });
    });

    var verCollections = async.parallel(verQueries, _);

    var imgResult = [];
    verCollections.forEach(function(verCol) {
      if (verCol) {
        verCol.forEach(function(resourceItem) {
          imgResult.push({
            publisher: verCol.publisher,
            location: verCol.location,
            typeName: verCol.typeName,
            name: resourceItem.name
          });
        });
      }
    });

    return imgResult;
  },

  getVMExtensionImageTypeList: function (location, publisherName, _) {
    var extTypes;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine extension image types (Publisher: "%s" Location:"%s")'), publisherName, location));
    try {
      extTypes = this.serviceClients.computeManagementClient.virtualMachineExtensionImages.listTypes(
        location,
        publisherName,
        _);
    } finally {
      progress.end();
    }

    extTypes.map(function(item){
      item.publisher = publisherName;
      return item;
    });

    return extTypes;
  },

  getVMExtensionImageVersionList: function (location, publisherName, typeName, _) {
    var extVersions = [];
    var resultList = null;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine extension image versions (Publisher: "%s" Type:"%s" Location:"%s")'), publisherName, typeName, location));

    try {
      resultList = this.serviceClients.computeManagementClient.virtualMachineExtensionImages.listVersions(
        location,
        publisherName,
        typeName,
        _);
    } finally {
      progress.end();
    }

    resultList.forEach(function (versionItem) {
      extVersions.push(versionItem);
    });

    extVersions.map(function(item){
      item.publisher = publisherName;
      item.typeName = typeName;
      return item;
    });

    return extVersions;
  },

  getVMExtensionImage: function (location, publisherName, typeName, version, _) {
    var extImage = null;
    var progress = this.cli.interaction.progress(util.format($('Getting virtual machine extension images (Publisher: "%s" Type:"%s" Version:"%s" Location:"%s")'), publisherName, typeName, version, location));
    try {
      extImage = this.serviceClients.computeManagementClient.virtualMachineExtensionImages.get(
        location,
        publisherName,
        typeName,
        version,
        _);
    } finally {
      progress.end();
    }

    return extImage;
  }

});

module.exports = VMImage;
<|endoftext|>


<commit_before>// A package for running jobs synchronized across multiple processes
SyncedCron = {
  _entries: {},
  running: false,
  options: {
    //Log job run details to console
    log: true,

    logger: null,

    //Name of collection to use for synchronisation and logging
    collectionName: 'cronHistory',

    //Default to using localTime
    utc: false,

    //TTL in seconds for history records in collection to expire
    //NOTE: Unset to remove expiry but ensure you remove the index from
    //mongo by hand
    collectionTTL: 172800
  },
  config: function(opts) {
    this.options = _.extend({}, this.options, opts);
  }
}

Later = Npm.require('later');

/*
  Logger factory function. Takes a prefix string and options object
  and uses an injected `logger` if provided, else falls back to
  Meteor's `Log` package.

  Will send a log object to the injected logger, on the following form:

    message: String
    level: String (info, warn, error, debug)
    tag: 'SyncedCron'
*/
function createLogger(prefix) {
  check(prefix, String);

  // Return noop if logging is disabled.
  if(SyncedCron.options.log === false) {
    return function() {};
  }

  return function(level, message) {
    check(level, Match.OneOf('info', 'error', 'warn', 'debug'));
    check(message, String);

    var logger = SyncedCron.options && SyncedCron.options.logger;

    if(logger && _.isFunction(logger)) {

      logger({
        level: level,
        message: message,
        tag: prefix
      });

    } else {
      Log[level]({ message: prefix + ': ' + message });
    }
  }
}

var log;

Meteor.startup(function() {
  var options = SyncedCron.options;

  log = createLogger('SyncedCron');

  ['info', 'warn', 'error', 'debug'].forEach(function(level) {
    log[level] = _.partial(log, level);
  });

  // Don't allow TTL less than 5 minutes so we don't break synchronization
  var minTTL = 300;

  // Use UTC or localtime for evaluating schedules
  if (options.utc)
    Later.date.UTC();
  else
    Later.date.localTime();

  // collection holding the job history records
  SyncedCron._collection = new Mongo.Collection(options.collectionName);
  SyncedCron._collection._ensureIndex({intendedAt: 1, name: 1}, {unique: true});

  if (options.collectionTTL) {
    if (options.collectionTTL > minTTL)
      SyncedCron._collection._ensureIndex({startedAt: 1 },
        { expireAfterSeconds: options.collectionTTL } );
    else
      log.warn('Not going to use a TTL that is shorter than:' + minTTL);
  }
});

var scheduleEntry = function(entry) {
  var schedule = entry.schedule(Later.parse);
  entry._timer =
    SyncedCron._laterSetInterval(SyncedCron._entryWrapper(entry), schedule);

  log.info('Scheduled "' + entry.name + '" next run @'
    + Later.schedule(schedule).next(1));
}

// add a scheduled job
// SyncedCron.add({
//   name: String, //*required* unique name of the job
//   schedule: function(laterParser) {},//*required* when to run the job
//   job: function() {}, //*required* the code to run
// });
SyncedCron.add = function(entry) {
  check(entry.name, String);
  check(entry.schedule, Function);
  check(entry.job, Function);
  check(entry.persist, Match.Optional(Boolean));

  if (entry.persist === undefined) {
    entry.persist = true;
  }

  // check
  if (!this._entries[entry.name]) {
    this._entries[entry.name] = entry;

    // If cron is already running, start directly.
    if (this.running) {
      scheduleEntry(entry);
    }
  }
}

// Start processing added jobs
SyncedCron.start = function() {
  var self = this;

  Meteor.startup(function() {
    // Schedule each job with later.js
    _.each(self._entries, function(entry) {
      scheduleEntry(entry);
    });
    self.running = true;
  });
}

// Return the next scheduled date of the first matching entry or undefined
SyncedCron.nextScheduledAtDate = function(jobName) {
  var entry = this._entries[jobName];

  if (entry)
    return Later.schedule(entry.schedule(Later.parse)).next(1);
}

// Remove and stop the entry referenced by jobName
SyncedCron.remove = function(jobName) {
  var entry = this._entries[jobName];

  if (entry) {
    if (entry._timer)
      entry._timer.clear();

    delete this._entries[jobName];
    log.info('Removed "' + entry.name + '"');
  }
}

// Pause processing, but do not remove jobs so that the start method will
// restart existing jobs
SyncedCron.pause = function() {
  if (this.running) {
    _.each(this._entries, function(entry) {
      entry._timer.clear();
    });
    this.running = false;
  }
}

// Stop processing and remove ALL jobs
SyncedCron.stop = function() {
  _.each(this._entries, function(entry, name) {
    SyncedCron.remove(name);
  });
  this.running = false;
}

// The meat of our logic. Checks if the specified has already run. If not,
// records that it's running the job, runs it, and records the output
SyncedCron._entryWrapper = function(entry) {
  var self = this;

  return function(intendedAt) {
    intendedAt = new Date(intendedAt.getTime());
    intendedAt.setMilliseconds(0);

    var jobHistory;

    if (entry.persist) {
      jobHistory = {
        intendedAt: intendedAt,
        name: entry.name,
        startedAt: new Date()
      };

      // If we have a dup key error, another instance has already tried to run
      // this job.
      try {
        jobHistory._id = self._collection.insert(jobHistory);
      } catch(e) {
        // http://www.mongodb.org/about/contributors/error-codes/
        // 11000 == duplicate key error
        if (e.name === 'MongoError' && e.code === 11000) {
          log.info('Not running "' + entry.name + '" again.');
          return;
        }

        throw e;
      };
    }

    // run and record the job
    try {
      log.info('Starting "' + entry.name + '".');
      var output = entry.job(intendedAt,entry.name); // <- Run the actual job

      log.info('Finished "' + entry.name + '".');
      if(entry.persist) {
        self._collection.update({_id: jobHistory._id}, {
          $set: {
            finishedAt: new Date(),
            result: output
          }
        });
      }
    } catch(e) {
      log.info('Exception "' + entry.name +'" ' + ((e && e.stack) ? e.stack : e));
      if(entry.persist) {
        self._collection.update({_id: jobHistory._id}, {
          $set: {
            finishedAt: new Date(),
            error: (e && e.stack) ? e.stack : e
          }
        });
      }
    }
  };
}

// for tests
SyncedCron._reset = function() {
  this._entries = {};
  this._collection.remove({});
  this.running = false;
}

// ---------------------------------------------------------------------------
// The following two functions are lifted from the later.js package, however
// I've made the following changes:
// - Use Meteor.setTimeout and Meteor.clearTimeout
// - Added an 'intendedAt' parameter to the callback fn that specifies the precise
//   time the callback function *should* be run (so we can co-ordinate jobs)
//   between multiple, potentially laggy and unsynced machines

// From: https://github.com/bunkat/later/blob/master/src/core/setinterval.js
SyncedCron._laterSetInterval = function(fn, sched) {

  var t = SyncedCron._laterSetTimeout(scheduleTimeout, sched),
      done = false;

  /**
  * Executes the specified function and then sets the timeout for the next
  * interval.
  */
  function scheduleTimeout(intendedAt) {
    if(!done) {
      try {
        fn(intendedAt);
      } catch(e) {
        log.info('Exception running scheduled job ' + ((e && e.stack) ? e.stack : e));
      }

      t = SyncedCron._laterSetTimeout(scheduleTimeout, sched);
    }
  }

  return {

    /**
    * Clears the timeout.
    */
    clear: function() {
      done = true;
      t.clear();
    }

  };

};

// From: https://github.com/bunkat/later/blob/master/src/core/settimeout.js
SyncedCron._laterSetTimeout = function(fn, sched) {

  var s = Later.schedule(sched), t;
  scheduleTimeout();

  /**
  * Schedules the timeout to occur. If the next occurrence is greater than the
  * max supported delay (2147483647 ms) than we delay for that amount before
  * attempting to schedule the timeout again.
  */
  function scheduleTimeout() {
    var now = Date.now(),
        next = s.next(2, now);

    // don't schedlue another occurence if no more exist synced-cron#41
    if (! next[0])
      return;

    var diff = next[0].getTime() - now,
        intendedAt = next[0];

    // minimum time to fire is one second, use next occurrence instead
    if(diff < 1000) {
      diff = next[1].getTime() - now;
      intendedAt = next[1];
    }

    if(diff < 2147483647) {
      t = Meteor.setTimeout(function() { fn(intendedAt); }, diff);
    }
    else {
      t = Meteor.setTimeout(scheduleTimeout, 2147483647);
    }
  }

  return {

    /**
    * Clears the timeout.
    */
    clear: function() {
      Meteor.clearTimeout(t);
    }

  };

};
// ---------------------------------------------------------------------------
<commit_msg>Fix error handling for Meteor 1.7.<commit_after>// A package for running jobs synchronized across multiple processes
SyncedCron = {
  _entries: {},
  running: false,
  options: {
    //Log job run details to console
    log: true,

    logger: null,

    //Name of collection to use for synchronisation and logging
    collectionName: 'cronHistory',

    //Default to using localTime
    utc: false,

    //TTL in seconds for history records in collection to expire
    //NOTE: Unset to remove expiry but ensure you remove the index from
    //mongo by hand
    collectionTTL: 172800
  },
  config: function(opts) {
    this.options = _.extend({}, this.options, opts);
  }
}

Later = Npm.require('later');

/*
  Logger factory function. Takes a prefix string and options object
  and uses an injected `logger` if provided, else falls back to
  Meteor's `Log` package.

  Will send a log object to the injected logger, on the following form:

    message: String
    level: String (info, warn, error, debug)
    tag: 'SyncedCron'
*/
function createLogger(prefix) {
  check(prefix, String);

  // Return noop if logging is disabled.
  if(SyncedCron.options.log === false) {
    return function() {};
  }

  return function(level, message) {
    check(level, Match.OneOf('info', 'error', 'warn', 'debug'));
    check(message, String);

    var logger = SyncedCron.options && SyncedCron.options.logger;

    if(logger && _.isFunction(logger)) {

      logger({
        level: level,
        message: message,
        tag: prefix
      });

    } else {
      Log[level]({ message: prefix + ': ' + message });
    }
  }
}

var log;

Meteor.startup(function() {
  var options = SyncedCron.options;

  log = createLogger('SyncedCron');

  ['info', 'warn', 'error', 'debug'].forEach(function(level) {
    log[level] = _.partial(log, level);
  });

  // Don't allow TTL less than 5 minutes so we don't break synchronization
  var minTTL = 300;

  // Use UTC or localtime for evaluating schedules
  if (options.utc)
    Later.date.UTC();
  else
    Later.date.localTime();

  // collection holding the job history records
  SyncedCron._collection = new Mongo.Collection(options.collectionName);
  SyncedCron._collection._ensureIndex({intendedAt: 1, name: 1}, {unique: true});

  if (options.collectionTTL) {
    if (options.collectionTTL > minTTL)
      SyncedCron._collection._ensureIndex({startedAt: 1 },
        { expireAfterSeconds: options.collectionTTL } );
    else
      log.warn('Not going to use a TTL that is shorter than:' + minTTL);
  }
});

var scheduleEntry = function(entry) {
  var schedule = entry.schedule(Later.parse);
  entry._timer =
    SyncedCron._laterSetInterval(SyncedCron._entryWrapper(entry), schedule);

  log.info('Scheduled "' + entry.name + '" next run @'
    + Later.schedule(schedule).next(1));
}

// add a scheduled job
// SyncedCron.add({
//   name: String, //*required* unique name of the job
//   schedule: function(laterParser) {},//*required* when to run the job
//   job: function() {}, //*required* the code to run
// });
SyncedCron.add = function(entry) {
  check(entry.name, String);
  check(entry.schedule, Function);
  check(entry.job, Function);
  check(entry.persist, Match.Optional(Boolean));

  if (entry.persist === undefined) {
    entry.persist = true;
  }

  // check
  if (!this._entries[entry.name]) {
    this._entries[entry.name] = entry;

    // If cron is already running, start directly.
    if (this.running) {
      scheduleEntry(entry);
    }
  }
}

// Start processing added jobs
SyncedCron.start = function() {
  var self = this;

  Meteor.startup(function() {
    // Schedule each job with later.js
    _.each(self._entries, function(entry) {
      scheduleEntry(entry);
    });
    self.running = true;
  });
}

// Return the next scheduled date of the first matching entry or undefined
SyncedCron.nextScheduledAtDate = function(jobName) {
  var entry = this._entries[jobName];

  if (entry)
    return Later.schedule(entry.schedule(Later.parse)).next(1);
}

// Remove and stop the entry referenced by jobName
SyncedCron.remove = function(jobName) {
  var entry = this._entries[jobName];

  if (entry) {
    if (entry._timer)
      entry._timer.clear();

    delete this._entries[jobName];
    log.info('Removed "' + entry.name + '"');
  }
}

// Pause processing, but do not remove jobs so that the start method will
// restart existing jobs
SyncedCron.pause = function() {
  if (this.running) {
    _.each(this._entries, function(entry) {
      entry._timer.clear();
    });
    this.running = false;
  }
}

// Stop processing and remove ALL jobs
SyncedCron.stop = function() {
  _.each(this._entries, function(entry, name) {
    SyncedCron.remove(name);
  });
  this.running = false;
}

// The meat of our logic. Checks if the specified has already run. If not,
// records that it's running the job, runs it, and records the output
SyncedCron._entryWrapper = function(entry) {
  var self = this;

  return function(intendedAt) {
    intendedAt = new Date(intendedAt.getTime());
    intendedAt.setMilliseconds(0);

    var jobHistory;

    if (entry.persist) {
      jobHistory = {
        intendedAt: intendedAt,
        name: entry.name,
        startedAt: new Date()
      };

      // If we have a dup key error, another instance has already tried to run
      // this job.
      try {
        jobHistory._id = self._collection.insert(jobHistory);
      } catch(e) {
        // http://www.mongodb.org/about/contributors/error-codes/
        // 11000 == duplicate key error
        if (e.code === 11000) {
          log.info('Not running "' + entry.name + '" again.');
          return;
        }

        throw e;
      };
    }

    // run and record the job
    try {
      log.info('Starting "' + entry.name + '".');
      var output = entry.job(intendedAt,entry.name); // <- Run the actual job

      log.info('Finished "' + entry.name + '".');
      if(entry.persist) {
        self._collection.update({_id: jobHistory._id}, {
          $set: {
            finishedAt: new Date(),
            result: output
          }
        });
      }
    } catch(e) {
      log.info('Exception "' + entry.name +'" ' + ((e && e.stack) ? e.stack : e));
      if(entry.persist) {
        self._collection.update({_id: jobHistory._id}, {
          $set: {
            finishedAt: new Date(),
            error: (e && e.stack) ? e.stack : e
          }
        });
      }
    }
  };
}

// for tests
SyncedCron._reset = function() {
  this._entries = {};
  this._collection.remove({});
  this.running = false;
}

// ---------------------------------------------------------------------------
// The following two functions are lifted from the later.js package, however
// I've made the following changes:
// - Use Meteor.setTimeout and Meteor.clearTimeout
// - Added an 'intendedAt' parameter to the callback fn that specifies the precise
//   time the callback function *should* be run (so we can co-ordinate jobs)
//   between multiple, potentially laggy and unsynced machines

// From: https://github.com/bunkat/later/blob/master/src/core/setinterval.js
SyncedCron._laterSetInterval = function(fn, sched) {

  var t = SyncedCron._laterSetTimeout(scheduleTimeout, sched),
      done = false;

  /**
  * Executes the specified function and then sets the timeout for the next
  * interval.
  */
  function scheduleTimeout(intendedAt) {
    if(!done) {
      try {
        fn(intendedAt);
      } catch(e) {
        log.info('Exception running scheduled job ' + ((e && e.stack) ? e.stack : e));
      }

      t = SyncedCron._laterSetTimeout(scheduleTimeout, sched);
    }
  }

  return {

    /**
    * Clears the timeout.
    */
    clear: function() {
      done = true;
      t.clear();
    }

  };

};

// From: https://github.com/bunkat/later/blob/master/src/core/settimeout.js
SyncedCron._laterSetTimeout = function(fn, sched) {

  var s = Later.schedule(sched), t;
  scheduleTimeout();

  /**
  * Schedules the timeout to occur. If the next occurrence is greater than the
  * max supported delay (2147483647 ms) than we delay for that amount before
  * attempting to schedule the timeout again.
  */
  function scheduleTimeout() {
    var now = Date.now(),
        next = s.next(2, now);

    // don't schedlue another occurence if no more exist synced-cron#41
    if (! next[0])
      return;

    var diff = next[0].getTime() - now,
        intendedAt = next[0];

    // minimum time to fire is one second, use next occurrence instead
    if(diff < 1000) {
      diff = next[1].getTime() - now;
      intendedAt = next[1];
    }

    if(diff < 2147483647) {
      t = Meteor.setTimeout(function() { fn(intendedAt); }, diff);
    }
    else {
      t = Meteor.setTimeout(scheduleTimeout, 2147483647);
    }
  }

  return {

    /**
    * Clears the timeout.
    */
    clear: function() {
      Meteor.clearTimeout(t);
    }

  };

};
// ---------------------------------------------------------------------------
<|endoftext|>


<commit_before>import {Alert, Box, Flex, Stack} from '@chakra-ui/core'
import {faMap, faPlus, faSignOutAlt} from '@fortawesome/free-solid-svg-icons'
import React from 'react'
import {useSelector} from 'react-redux'

import message from 'lib/message'
import selectRegions from 'lib/selectors/regions'

import A from './a'
import {ButtonLink} from './buttons'
import Icon from './icon'
import {ALink} from './link'
import Logo from './logo'

export default function SelectRegion() {
  const user = useSelector(s => s.user)
  const accessGroup = user.adminTempAccessGroup || user.accessGroup
  const regions = useSelector(selectRegions)

  return (
    <Flex alignItems='center' mb={6} direction='column'>
      <Box mt={8} mb={6}>
        <Logo />
      </Box>
      <Stack spacing={4} textAlign='center' width='320px'>
        <Box>
          signed in as

            {' '}
            {user.email} ({accessGroup})

        </Box>
        <Alert status='info' borderRadius='4px'>

            April 18, 2020 — We added some new features to the
            application. Click here to learn more.

        </Alert>
        <Box>
          <ButtonLink to='regionCreate' style='success' block>
            <Icon icon={faPlus} /> {message('region.createAction')}
          </ButtonLink>
        </Box>
        {regions.length > 0 && <Box>{message('region.goToExisting')}</Box>}
        {regions.length > 0 && (
          <Box className='list-group'>
            {regions.map(region => (
              <ALink
                className='list-group-item'
                key={region._id}
                regionId={region._id}
                to='projects'
              >

                  <Icon icon={faMap} /> {region.name}

              </ALink>
            ))}
          </Box>
        )}
        <Box>
          <ALink to='logout'>
            <Icon icon={faSignOutAlt} /> {message('authentication.logOut')}
          </ALink>
        </Box>
      </Stack>
    </Flex>
  )
}
<commit_msg>feat(changelog): announcement<commit_after>import {Alert, Box, Flex, Stack} from '@chakra-ui/core'
import {faMap, faPlus, faSignOutAlt} from '@fortawesome/free-solid-svg-icons'
import React from 'react'
import {useSelector} from 'react-redux'

import message from 'lib/message'
import selectRegions from 'lib/selectors/regions'

import A from './a'
import {ButtonLink} from './buttons'
import Icon from './icon'
import {ALink} from './link'
import Logo from './logo'

export default function SelectRegion() {
  const user = useSelector(s => s.user)
  const accessGroup = user.adminTempAccessGroup || user.accessGroup
  const regions = useSelector(selectRegions)

  return (
    <Flex alignItems='center' mb={6} direction='column'>
      <Box mt={8} mb={6}>
        <Logo />
      </Box>
      <Stack spacing={4} textAlign='center' width='320px'>
        <Box>
          signed in as

            {' '}
            {user.email} ({accessGroup})

        </Box>
        <Alert status='info' borderRadius='4px'>

            April 18, 2020 — Conveyal has improved ways to manage your
            transportation network data. Click here to learn more.

        </Alert>
        <Box>
          <ButtonLink to='regionCreate' style='success' block>
            <Icon icon={faPlus} /> {message('region.createAction')}
          </ButtonLink>
        </Box>
        {regions.length > 0 && <Box>{message('region.goToExisting')}</Box>}
        {regions.length > 0 && (
          <Box className='list-group'>
            {regions.map(region => (
              <ALink
                className='list-group-item'
                key={region._id}
                regionId={region._id}
                to='projects'
              >

                  <Icon icon={faMap} /> {region.name}

              </ALink>
            ))}
          </Box>
        )}
        <Box>
          <ALink to='logout'>
            <Icon icon={faSignOutAlt} /> {message('authentication.logOut')}
          </ALink>
        </Box>
      </Stack>
    </Flex>
  )
}
<|endoftext|>


<commit_before>import {Box, Flex, Stack} from '@chakra-ui/core'
import {
  faMap,
  faPlus,
  faSignOutAlt,
  faSpinner
} from '@fortawesome/free-solid-svg-icons'
import React from 'react'
import {useSelector} from 'react-redux'

import message from 'lib/message'
import selectRegions from 'lib/selectors/regions'

import {ButtonLink} from './buttons'
import Icon from './icon'
import {ALink} from './link'
import Logo from './logo'
import P from './p'

export default function SelectRegion() {
  const regions = useSelector(selectRegions)

  return (
    <Flex alignItems='center' direction='column'>
      <Box mt={8} mb={6}>
        <Logo />
      </Box>
      <Stack spacing={4} textAlign='center' width='320px'>
        <Box>
          <ButtonLink to='regionCreate' style='success' block>
            <Icon icon={faPlus} /> {message('region.createAction')}
          </ButtonLink>
        </Box>
        {regions.length > 0 && <Box>{message('region.goToExisting')}</Box>}
        {regions.length > 0 && (
          <Box className='list-group'>
            {regions.map(region => (
              <ALink
                className='list-group-item'
                key={region._id}
                regionId={region._id}
                to='projects'
              >
                {region.statusCode === 'DONE' ? (

                    <Icon icon={faMap} /> {region.name}

                ) : (
                  <>

                      <Icon icon={faSpinner} spin /> {region.name}

                    {message(`region.statusCode.${region.statusCode}`)}
                  </>
                )}
              </ALink>
            ))}
          </Box>
        )}
        <Box mb={6}>
          <ALink to='logout'>
            <Icon icon={faSignOutAlt} /> {message('authentication.logOut')}
          </ALink>
        </Box>
      </Stack>
    </Flex>
  )
}
<commit_msg>Set margin on flex box<commit_after>import {Box, Flex, Stack} from '@chakra-ui/core'
import {
  faMap,
  faPlus,
  faSignOutAlt,
  faSpinner
} from '@fortawesome/free-solid-svg-icons'
import React from 'react'
import {useSelector} from 'react-redux'

import message from 'lib/message'
import selectRegions from 'lib/selectors/regions'

import {ButtonLink} from './buttons'
import Icon from './icon'
import {ALink} from './link'
import Logo from './logo'
import P from './p'

export default function SelectRegion() {
  const regions = useSelector(selectRegions)

  return (
    <Flex alignItems='center' mb={6} direction='column'>
      <Box mt={8} mb={6}>
        <Logo />
      </Box>
      <Stack spacing={4} textAlign='center' width='320px'>
        <Box>
          <ButtonLink to='regionCreate' style='success' block>
            <Icon icon={faPlus} /> {message('region.createAction')}
          </ButtonLink>
        </Box>
        {regions.length > 0 && <Box>{message('region.goToExisting')}</Box>}
        {regions.length > 0 && (
          <Box className='list-group'>
            {regions.map(region => (
              <ALink
                className='list-group-item'
                key={region._id}
                regionId={region._id}
                to='projects'
              >
                {region.statusCode === 'DONE' ? (

                    <Icon icon={faMap} /> {region.name}

                ) : (
                  <>

                      <Icon icon={faSpinner} spin /> {region.name}

                    {message(`region.statusCode.${region.statusCode}`)}
                  </>
                )}
              </ALink>
            ))}
          </Box>
        )}
        <Box>
          <ALink to='logout'>
            <Icon icon={faSignOutAlt} /> {message('authentication.logOut')}
          </ALink>
        </Box>
      </Stack>
    </Flex>
  )
}
<|endoftext|>


<commit_before>
const CollectingWalker = require('../import/collecting-walker');
const ScriptCollector = require('../import/script-collector');
const ConfigurationCollector = require('../import/configuration-collector');
const LibraryImporter = require('../import/lib-import/library-importer');
const Providers = require('../providers/providers');
const fs = require('fs');
const path = require('path');

/**
  * Static utilities. Uses an internal Builder to
  * construct the appropriate context.
  *
  */
const ContextBuilder = (function(module, undefined) {
  'use strict';

  let explicitRoot, explicitLib, instance;

  function compose(root) {
    if (!fs.lstatSync(root).isDirectory) {
      root = path.dirname(root);
    }
    explicitRoot = root;
    return instance;
  }

  function overrideLib(newLib) {
    explicitLib = newLib;
    return instance;
  }

  function getRoot() {
    return explicitRoot || module.parent.filename;
  }

  function build(resourceName, additionalContext) {
    const builder = new Builder()
      .forNamedResource(resourceName)
      .addContext(additionalContext);
    return {
      forRest: (restConfig) => {
        return builder
          .withProvidersImpl(Providers.rest)
          .withRestConfig(restConfig)
          .build();
      },
      forLocal: (store) => {
        return builder
          .withProvidersImpl(Providers.local)
          .withLocalStore(store)
          .build();
      }
    };
  }

  function getLibImports(scripts) {
    new LibraryImporter(libNormalize).getImportedScripts(scripts);
  }

  function normalize(name) {
    return path.resolve(getRoot(), name);
  }

  function libNormalize(name) {
    if (explicitLib) {
      let lib = path.resolve(getRoot(), explicitLib, name);
      return lib;
    }
    return resolveStandardLib(name);
  }

  function resolveStandardLib(name) {
    let libRoot = path.join(getRoot(), '..', 'lib');
    return path.resolve(libRoot, name);
  }

  function read(name) {
    if (fs.lstatSync(name).isDirectory()) {
      return readModule(name);
    }
    return readFile(name);
  }

  function readModule(moduleName) {
    return new CollectingWalker()
      .withDefaultOptions()
      .withCollectors(new ScriptCollector(), new ConfigurationCollector())
      .walk(moduleName);
  }

  function readFile(filename, errHandler) {
    try {
      return {
        'scripts': [fs.readFileSync(filename, 'utf-8')]
      };
    } catch (err) {
      if (errHandler) {
        errHandler(err);
      } else {
        throw err;
      }
    }
  }

  /**
   * Internal Builder class, allows us to defer the decision
   * around which providers and seed to use.
   */
  class Builder {

    constructor() {
      this.resourceName = null;
      this.additionalContext = {};
      this.providersImpl = null;
      this.seedValue = null;
      this.root = null;
      this.libRoot = null;
    }

    fromRoot(root) {
      this.root = root;
      return this;
    }

    withLibrary(library) {
      this.libRoot = library;
      return this;
    }

    forNamedResource(resourceName) {
      this.resourceName = resourceName;
      return this;
    }

    addContext(additionalContext) {
      Object.assign(this.additionalContext, additionalContext);
      return this;
    }

    withProvidersImpl(providersImpl) {
      this.providersImpl = providersImpl;
      return this;
    }

    withLocalStore(store) {
      this.seedValue = store;
      return this;
    }

    withRestConfig(restConfig) {
      this.seedValue = restConfig;
      return this;
    }

    build() {
      const normalizedName = normalize(this.resourceName);
      const {
        scripts,
        configurations
      } = read(this.resourceName);
      const imports = getLibImports(scripts);
      const code = scripts
        .concat(imports)
        .join('\n');
      const sandbox = Object.assign({}, {
        Providers: this.providersImpl.seed(this.seedValue, configurations)
      }, this.additionalContext || {});
      return {
        code: code,
        sandbox: sandbox
      };
    }
  }

  instance = {
    compose: compose,
    overrideLib: overrideLib,
    build: build
  };

  return instance;
}());

module.exports = ContextBuilder;
<commit_msg>removing uneeded dup<commit_after><|endoftext|>


<commit_before>var AtCommand = require('./AtCommand');
var at        = require('./at');

module.exports = AtCommandCreator;
function AtCommandCreator() {
  this._number   = 0;
}

AtCommandCreator.prototype.raw = function(type, args) {
  args = (Array.isArray(args))
    ? args
    : Array.prototype.slice.call(arguments, 1);

  return new AtCommand(type, this._number++, args);
};

AtCommandCreator.REF_FLAGS = {
  emergency : (1 << 8),
  fly       : (1 << 9),
};

// Used for fly/land as well as emergency trigger/recover
AtCommandCreator.prototype.ref = function(options) {
  options = options || {};

  var args = [0];
  for (var key in options) {
    args[0] = args[0] | AtCommandCreator.REF_FLAGS[key];
  }

  return this.raw('REF', args);
};

AtCommandCreator.PCMD_FLAGS = {
  progressive : (1 << 0),
};

AtCommandCreator.PCMD_ALIASES = {
  left             : {index: 1, invert: true},
  right            : {index: 1, invert: false},
  front            : {index: 2, invert: true},
  back             : {index: 2, invert: false},
  up               : {index: 3, invert: false},
  down             : {index: 3, invert: true},
  clockwise        : {index: 4, invert: false},
  counterclockwise : {index: 4, invert: true},
};

// Used to fly the drone around
AtCommandCreator.prototype.pcmd = function(options) {
  options = options || {};

  // flags, leftRight, frontBack, upDown, clockWise
  var args = [0, 0, 0, 0, 0];

  for (var key in options) {
    var alias = AtCommandCreator.PCMD_ALIASES[key];
    var value = options[key];

    if (alias.invert) {
      value = -value;
    }

    args[alias.index] = value;
    args[0]           = args[0] | AtCommandCreator.PCMD_FLAGS.progressive;
  }

  for (var i = 1; i < args.length; i++) {
    args[i] = at.floatString(args[i]);
  }

  return this.raw('PCMD', args);
};
<commit_msg>Slightly nicer<commit_after>var AtCommand = require('./AtCommand');
var at        = require('./at');

var exports = module.exports = AtCommandCreator;
function AtCommandCreator() {
  this._number   = 0;
}

AtCommandCreator.prototype.raw = function(type, args) {
  args = (Array.isArray(args))
    ? args
    : Array.prototype.slice.call(arguments, 1);

  return new AtCommand(type, this._number++, args);
};

// Used for fly/land as well as emergency trigger/recover
AtCommandCreator.prototype.ref = function(options) {
  options = options || {};

  var args = [0];
  for (var key in options) {
    args[0] = args[0] | REF_FLAGS[key];
  }

  return this.raw('REF', args);
};

// Used to fly the drone around
AtCommandCreator.prototype.pcmd = function(options) {
  options = options || {};

  // flags, leftRight, frontBack, upDown, clockWise
  var args = [0, 0, 0, 0, 0];

  for (var key in options) {
    var alias = PCMD_ALIASES[key];
    var value = options[key];

    if (alias.invert) {
      value = -value;
    }

    args[alias.index] = value;
    args[0]           = args[0] | PCMD_FLAGS.progressive;
  }

  for (var i = 1; i < args.length; i++) {
    args[i] = at.floatString(args[i]);
  }

  return this.raw('PCMD', args);
};

// Constants

var REF_FLAGS = exports.REF_FLAGS = {
  emergency : (1 << 8),
  fly       : (1 << 9),
};

var PCMD_FLAGS = exports.REF_FLAGS = {
  progressive : (1 << 0),
};

var PCMD_ALIASES = exports.PCMD_ALIASES = {
  left             : {index: 1, invert: true},
  right            : {index: 1, invert: false},
  front            : {index: 2, invert: true},
  back             : {index: 2, invert: false},
  up               : {index: 3, invert: false},
  down             : {index: 3, invert: true},
  clockwise        : {index: 4, invert: false},
  counterclockwise : {index: 4, invert: true},
};
<|endoftext|>


<commit_before>define([
    'google-code-prettify/prettify',
    'common/html',
    'common/runtime',
    'widgets/appWidgets2/errorControl',
    'util/string',
    'css!google-code-prettify/prettify.css',
], (PR, html, Runtime, ErrorControlFactory, StringUtil) => {
    'use strict';

    const t = html.tag,
        div = t('div'),
        label = t('label'),
        strong = t('strong'),
        span = t('span'),
        iTag = t('i'),
        cssBaseClass = 'kb-field-cell',
        messageBaseClass = `${cssBaseClass}__message_panel`,
        MESSAGE = {
            error: {
                prefix: 'Error',
                messageClass: `${messageBaseClass}__error`,
                containerClass: `${cssBaseClass}__error_message`,
                icon: 'fa fa-exclamation-triangle',
            },
            warning: {
                prefix: 'Warning',
                messageClass: `${messageBaseClass}__warning`,
                icon: 'fa fa-exclamation-circle',
            },
        };

    function factory(config) {
        const runtime = Runtime.make(),
            bus = runtime.bus().makeChannelBus({
                description: 'Field bus',
            }),
            inputControlFactory = config.inputControlFactory,
            spec = config.parameterSpec,
            state = {
                isValid: true,
                isDuplicate: false,
            };
        let places, parent, container, inputControl;

        try {
            const controlConfig = Object.assign({}, config, { bus, channelName: bus.channelName });
            inputControl = inputControlFactory.make(controlConfig);
        } catch (ex) {
            console.error('Error creating input control', ex);
            inputControl = ErrorControlFactory.make({
                message: ex.message,
            }).make();
        }

        function render() {
            const ids = {
                fieldPanel: html.genId(),
                inputControl: html.genId(),
            };

            const content = div(
                {
                    class: `${cssBaseClass}__rowCell`,
                    id: ids.fieldPanel,
                    dataElement: 'field-panel',
                },
                [
                    label(
                        {
                            class: `${cssBaseClass}__cell_label`,
                            title: spec.ui.label || spec.ui.id,
                            for: ids.inputControl,
                        },
                        [spec.ui.label || spec.ui.id]
                    ),
                    div({
                        class: `${cssBaseClass}__input_control`,
                        id: ids.inputControl,
                        dataElement: 'input-control',
                    }),
                    div({
                        class: `${messageBaseClass} hidden`,
                        dataElement: 'message-panel',
                    }),
                    div({
                        class: `${messageBaseClass}__duplicate hidden`,
                        dataElement: 'duplicate-message-panel',
                    }),
                ]
            );

            return {
                content,
                ids,
            };
        }

        // LIFECYCLE

        function attach(node) {
            parent = node;
            const containerDiv = document.createElement('div');
            containerDiv.classList.add(`${cssBaseClass}__param_container`);

            container = parent.appendChild(containerDiv);

            const rendered = render();
            container.innerHTML = rendered.content;
            PR.prettyPrint(null, container);

            places = {
                inputControl: container.querySelector('#' + rendered.ids.inputControl),
            };
        }

        function generateMessage(messageInfo, text) {
            return (
                span(
                    {
                        class: `${messageInfo.messageClass}__title`,
                    },
                    [
                        iTag({
                            class: messageInfo.icon,
                        }),
                        strong(` ${messageInfo.prefix}: `),
                    ]
                ) + text
            );
        }

        function renderMessage(messageInfo, text, messagePanelSelector) {
            const message = generateMessage(messageInfo, text);
            if (messageInfo.containerClass) {
                parent
                    .querySelector(`.${cssBaseClass}__rowCell`)
                    .classList.add(messageInfo.containerClass);
            }
            const msgPanel = parent.querySelector(messagePanelSelector);
            msgPanel.innerHTML = message;
            msgPanel.classList.add(messageInfo.messageClass);
            msgPanel.classList.remove('hidden');
        }

        function showMessage(messageInfo, text) {
            clearMessage(messageBaseClass);
            renderMessage(messageInfo, text, `.${messageBaseClass}`);
        }

        function clearMessage(selector) {
            if (state.isValid && !state.isDuplicate) {
                parent
                    .querySelector(`.${cssBaseClass}__rowCell`)
                    .classList.remove(`${cssBaseClass}__error_message`);
            }
            const msgPanel = parent.querySelector(`.${selector}`);
            msgPanel.className = `${selector} hidden`;
        }

        /**
         * Validates the field by showing a message to the user if it's in a few different states.
         * States included are:
         *  - error - if the value is invalid, or missing yet required, an error message is shown
         *  - suspect - if the value is "suspect", a warning is shown. "Suspect" values are
         *      technically valid, but might not be what the user wants, like overwriting existing
         *      data
         *  - valid or optional and missing - if the value is ok, don't show anything, and hide any
         *      previously shown messages
         * @param {object} message expected to have various keys from the Validator module, especially:
         *   - diagnosis (string), one of valid, required-missing, optional-empty, suspect, invalid
         *   - isError (boolean, optional)
         *   - shortMessage (string, optional)
         *   - errorMessage (string, optional), only present if isError is present, and true
         */
        function validateField(message) {
            // always clear the existing message to start with
            switch (message.diagnosis) {
                case 'required-missing':
                case 'invalid':
                    state.isValid = false;
                    showMessage(MESSAGE.error, message.errorMessage);
                    break;
                case 'suspect':
                    state.isValid = true;
                    showMessage(MESSAGE.warning, message.shortMessage);
                    break;
                default:
                    state.isValid = true;
                    clearMessage(messageBaseClass);
                    break;
            }
        }

        /**
         * Most of the code here is wrangling the English language.
         * This translates a structure like
         * {
         *   thisTab: [1, 2],
         *   otherTabs: {
         *     "Elsewhere": [3]
         *   }
         * }
         * into text like:
         * "duplicate values found on rows 1 and 2, and on tab "Elsewhere" row 3"
         * @param {object} rows
         */
        function setDuplicateValue(rows) {
            state.isDuplicate = true;
            let message = 'duplicate value';
            let rowMessage = '';
            let tabMessage = '';
            let tabPrefix = ' on tab';
            let rowTabSeparator = '';
            let plural = false;

            function buildRowsText(rows) {
                let rowsText = 'row';
                if (rows.length > 1) {
                    rowsText += 's';
                }
                rowsText += ' ' + StringUtil.arrayToEnglish(rows);
                return rowsText;
            }

            // text for this tab's rows
            if (rows && rows.thisTab && rows.thisTab.length) {
                rowMessage = ' on ';
                if (rows.thisTab.length > 1) {
                    plural = true;
                }
                rowMessage += buildRowsText(rows.thisTab);
            }

            // get text for other tab rows
            if (rows && rows.otherTabs) {
                const tabs = Object.keys(rows.otherTabs);
                tabMessage = StringUtil.arrayToEnglish(tabs.map((tab) => {
                    return `"${tab}" ${buildRowsText(rows.otherTabs[tab])}`;
                }));
                if (tabs.length > 1) {
                    tabPrefix += 's';
                    plural = true;
                }
            }

            // if we have dups on both this tab and other tab(s), combine them
            if (rowMessage.length && tabMessage.length) {
                rowTabSeparator = ', and';
                plural = true;
            }
            message += (plural ? 's' : '') + ' found' + rowMessage + rowTabSeparator;
            if (tabMessage.length) {
                message += tabPrefix + ' ' + tabMessage;
            }
            renderMessage(MESSAGE.error, message, `.${messageBaseClass}__duplicate`);
        }

        function clearDuplicateValue() {
            state.isDuplicate = false;
            clearMessage(`${messageBaseClass}__duplicate`);
        }

        function start(arg) {
            attach(arg.node);
            bus.on('validation', validateField);

            return inputControl
                .start({
                    node: places.inputControl,
                })
                .then(() => {
                    // TODO: get rid of this pattern
                    bus.emit('run', {
                        node: places.inputControl,
                    });
                })
                .catch((error) => {
                    throw new Error(`Unable to start fieldTableCellWidget: ${error}`);
                });
        }

        function stop() {
            const clearElements = () => {
                if (parent && container) {
                    parent.removeChild(container);
                }
                bus.stop();
            };
            return inputControl
                .stop()
                .then(() => {
                    clearElements();
                    return null;
                })
                .catch((err) => {
                    console.error('Error stopping fieldTableCellWidget: ', err);
                    clearElements();
                });
        }

        return {
            start,
            stop,
            bus,
            setDuplicateValue,
            clearDuplicateValue,
        };
    }

    return {
        make: function (config) {
            return factory(config);
        },
    };
});
<commit_msg>prettier<commit_after>define([
    'google-code-prettify/prettify',
    'common/html',
    'common/runtime',
    'widgets/appWidgets2/errorControl',
    'util/string',
    'css!google-code-prettify/prettify.css',
], (PR, html, Runtime, ErrorControlFactory, StringUtil) => {
    'use strict';

    const t = html.tag,
        div = t('div'),
        label = t('label'),
        strong = t('strong'),
        span = t('span'),
        iTag = t('i'),
        cssBaseClass = 'kb-field-cell',
        messageBaseClass = `${cssBaseClass}__message_panel`,
        MESSAGE = {
            error: {
                prefix: 'Error',
                messageClass: `${messageBaseClass}__error`,
                containerClass: `${cssBaseClass}__error_message`,
                icon: 'fa fa-exclamation-triangle',
            },
            warning: {
                prefix: 'Warning',
                messageClass: `${messageBaseClass}__warning`,
                icon: 'fa fa-exclamation-circle',
            },
        };

    function factory(config) {
        const runtime = Runtime.make(),
            bus = runtime.bus().makeChannelBus({
                description: 'Field bus',
            }),
            inputControlFactory = config.inputControlFactory,
            spec = config.parameterSpec,
            state = {
                isValid: true,
                isDuplicate: false,
            };
        let places, parent, container, inputControl;

        try {
            const controlConfig = Object.assign({}, config, { bus, channelName: bus.channelName });
            inputControl = inputControlFactory.make(controlConfig);
        } catch (ex) {
            console.error('Error creating input control', ex);
            inputControl = ErrorControlFactory.make({
                message: ex.message,
            }).make();
        }

        function render() {
            const ids = {
                fieldPanel: html.genId(),
                inputControl: html.genId(),
            };

            const content = div(
                {
                    class: `${cssBaseClass}__rowCell`,
                    id: ids.fieldPanel,
                    dataElement: 'field-panel',
                },
                [
                    label(
                        {
                            class: `${cssBaseClass}__cell_label`,
                            title: spec.ui.label || spec.ui.id,
                            for: ids.inputControl,
                        },
                        [spec.ui.label || spec.ui.id]
                    ),
                    div({
                        class: `${cssBaseClass}__input_control`,
                        id: ids.inputControl,
                        dataElement: 'input-control',
                    }),
                    div({
                        class: `${messageBaseClass} hidden`,
                        dataElement: 'message-panel',
                    }),
                    div({
                        class: `${messageBaseClass}__duplicate hidden`,
                        dataElement: 'duplicate-message-panel',
                    }),
                ]
            );

            return {
                content,
                ids,
            };
        }

        // LIFECYCLE

        function attach(node) {
            parent = node;
            const containerDiv = document.createElement('div');
            containerDiv.classList.add(`${cssBaseClass}__param_container`);

            container = parent.appendChild(containerDiv);

            const rendered = render();
            container.innerHTML = rendered.content;
            PR.prettyPrint(null, container);

            places = {
                inputControl: container.querySelector('#' + rendered.ids.inputControl),
            };
        }

        function generateMessage(messageInfo, text) {
            return (
                span(
                    {
                        class: `${messageInfo.messageClass}__title`,
                    },
                    [
                        iTag({
                            class: messageInfo.icon,
                        }),
                        strong(` ${messageInfo.prefix}: `),
                    ]
                ) + text
            );
        }

        function renderMessage(messageInfo, text, messagePanelSelector) {
            const message = generateMessage(messageInfo, text);
            if (messageInfo.containerClass) {
                parent
                    .querySelector(`.${cssBaseClass}__rowCell`)
                    .classList.add(messageInfo.containerClass);
            }
            const msgPanel = parent.querySelector(messagePanelSelector);
            msgPanel.innerHTML = message;
            msgPanel.classList.add(messageInfo.messageClass);
            msgPanel.classList.remove('hidden');
        }

        function showMessage(messageInfo, text) {
            clearMessage(messageBaseClass);
            renderMessage(messageInfo, text, `.${messageBaseClass}`);
        }

        function clearMessage(selector) {
            if (state.isValid && !state.isDuplicate) {
                parent
                    .querySelector(`.${cssBaseClass}__rowCell`)
                    .classList.remove(`${cssBaseClass}__error_message`);
            }
            const msgPanel = parent.querySelector(`.${selector}`);
            msgPanel.className = `${selector} hidden`;
        }

        /**
         * Validates the field by showing a message to the user if it's in a few different states.
         * States included are:
         *  - error - if the value is invalid, or missing yet required, an error message is shown
         *  - suspect - if the value is "suspect", a warning is shown. "Suspect" values are
         *      technically valid, but might not be what the user wants, like overwriting existing
         *      data
         *  - valid or optional and missing - if the value is ok, don't show anything, and hide any
         *      previously shown messages
         * @param {object} message expected to have various keys from the Validator module, especially:
         *   - diagnosis (string), one of valid, required-missing, optional-empty, suspect, invalid
         *   - isError (boolean, optional)
         *   - shortMessage (string, optional)
         *   - errorMessage (string, optional), only present if isError is present, and true
         */
        function validateField(message) {
            // always clear the existing message to start with
            switch (message.diagnosis) {
                case 'required-missing':
                case 'invalid':
                    state.isValid = false;
                    showMessage(MESSAGE.error, message.errorMessage);
                    break;
                case 'suspect':
                    state.isValid = true;
                    showMessage(MESSAGE.warning, message.shortMessage);
                    break;
                default:
                    state.isValid = true;
                    clearMessage(messageBaseClass);
                    break;
            }
        }

        /**
         * Most of the code here is wrangling the English language.
         * This translates a structure like
         * {
         *   thisTab: [1, 2],
         *   otherTabs: {
         *     "Elsewhere": [3]
         *   }
         * }
         * into text like:
         * "duplicate values found on rows 1 and 2, and on tab "Elsewhere" row 3"
         * @param {object} rows
         */
        function setDuplicateValue(rows) {
            state.isDuplicate = true;
            let message = 'duplicate value';
            let rowMessage = '';
            let tabMessage = '';
            let tabPrefix = ' on tab';
            let rowTabSeparator = '';
            let plural = false;

            function buildRowsText(rows) {
                let rowsText = 'row';
                if (rows.length > 1) {
                    rowsText += 's';
                }
                rowsText += ' ' + StringUtil.arrayToEnglish(rows);
                return rowsText;
            }

            // text for this tab's rows
            if (rows && rows.thisTab && rows.thisTab.length) {
                rowMessage = ' on ';
                if (rows.thisTab.length > 1) {
                    plural = true;
                }
                rowMessage += buildRowsText(rows.thisTab);
            }

            // get text for other tab rows
            if (rows && rows.otherTabs) {
                const tabs = Object.keys(rows.otherTabs);
                tabMessage = StringUtil.arrayToEnglish(
                    tabs.map((tab) => {
                        return `"${tab}" ${buildRowsText(rows.otherTabs[tab])}`;
                    })
                );
                if (tabs.length > 1) {
                    tabPrefix += 's';
                    plural = true;
                }
            }

            // if we have dups on both this tab and other tab(s), combine them
            if (rowMessage.length && tabMessage.length) {
                rowTabSeparator = ', and';
                plural = true;
            }
            message += (plural ? 's' : '') + ' found' + rowMessage + rowTabSeparator;
            if (tabMessage.length) {
                message += tabPrefix + ' ' + tabMessage;
            }
            renderMessage(MESSAGE.error, message, `.${messageBaseClass}__duplicate`);
        }

        function clearDuplicateValue() {
            state.isDuplicate = false;
            clearMessage(`${messageBaseClass}__duplicate`);
        }

        function start(arg) {
            attach(arg.node);
            bus.on('validation', validateField);

            return inputControl
                .start({
                    node: places.inputControl,
                })
                .then(() => {
                    // TODO: get rid of this pattern
                    bus.emit('run', {
                        node: places.inputControl,
                    });
                })
                .catch((error) => {
                    throw new Error(`Unable to start fieldTableCellWidget: ${error}`);
                });
        }

        function stop() {
            const clearElements = () => {
                if (parent && container) {
                    parent.removeChild(container);
                }
                bus.stop();
            };
            return inputControl
                .stop()
                .then(() => {
                    clearElements();
                    return null;
                })
                .catch((err) => {
                    console.error('Error stopping fieldTableCellWidget: ', err);
                    clearElements();
                });
        }

        return {
            start,
            stop,
            bus,
            setDuplicateValue,
            clearDuplicateValue,
        };
    }

    return {
        make: function (config) {
            return factory(config);
        },
    };
});
<|endoftext|>


<commit_before>'use strict';

const HTTP = require('http');
const bad = require('../validation/badRequest');

function send(body, ami, path, method, vault) {
  return new Promise((resolve, reject) => {
    const request = new Buffer(JSON.stringify(body, null, 2));

    const req = HTTP.request({
      hostname: vault.hostname,
      port: vault.port,
      method,
      path,
      headers: {
        'X-Vault-Token': vault.token,
        'content-length': request.length
      }
    });

    const chunks = [];

    req.on('response', function (res) {
      res.on('end', function ended(chunk) {
        if (chunk) {
          chunks.push(chunk);
        }
        try {
          const response = JSON.parse(Buffer.concat(chunks)
              .toString('utf8'));

          resolve(response);
        } catch (e) {
          reject(e);
        }
      });
      res.on('data', (chunk) => chunks.push(chunk));
    });

    req.on('error', (err) => reject(err));

    req.write(request);
    req.end();
  });
}

function getTokenTiming(accessor, vault) {
  let creation_time = null;
  let explicit_max_ttl = null;
  return send({}, '', `/v1/auth/token/lookup-accessor/${accessor}`, 'POST', vault).then((resp) => {
    creation_time = resp.data.creation_time * 1000;
    explicit_max_ttl = resp.data.explicit_max_ttl * 1000;
  }).then(() => {
    if (explicit_max_ttl === 0) {
      // We have to query the /sys/mounts/auth/token/tune endpoint
      return send({}, '', '/v1/sys/mounts/auth/token/tune', 'GET', vault).then((resp) => {
        explicit_max_ttl = resp.max_lease_ttl * 1000;
      });
    }
  }).then(() => {
    return {
      creation_time: new Date(creation_time).toISOString(),
      expiration_time: new Date(creation_time + explicit_max_ttl).toISOString()
    };
  });
}

exports.create = function(req, res, next, vault) {
  const tokenParams = {
    renewable: Config.get('vault:renewable'),
    ttl: Config.get('vault:ttl'),
    explicit_max_ttl: Config.get('vault:explicit_max_ttl'),
    no_parent: true
  };

  // If any of the tunables don't exist in Config
  // and return `undefined`, delete them
  Object.keys(tokenParams).forEach((k) => {
    if (typeof tokenParams[k] === 'undefined') {
      delete tokenParams[k];
    }
  });

  return send(tokenParams, req.document.imageId, '/v1/auth/token/create', 'POST', vault).then((status) => {
    if (!status.hasOwnProperty('auth')) {
      throw Error('Token Error');
    }
    req.auth = status.auth;
    return getTokenTiming(status.auth.accessor, vault);
  }).then((data) => {
    req.auth = Object.assign(req.auth, data);
    return next();
  }).catch((err) => {
    return bad.request(res, err.message);
  });
};
<commit_msg>Fixed linting error.<commit_after>'use strict';

const HTTP = require('http');
const bad = require('../validation/badRequest');

function send(body, ami, path, method, vault) {
  return new Promise((resolve, reject) => {
    const request = new Buffer(JSON.stringify(body, null, 2));

    const req = HTTP.request({
      hostname: vault.hostname,
      port: vault.port,
      method,
      path,
      headers: {
        'X-Vault-Token': vault.token,
        'content-length': request.length
      }
    });

    const chunks = [];

    req.on('response', function (res) {
      res.on('end', function ended(chunk) {
        if (chunk) {
          chunks.push(chunk);
        }
        try {
          const response = JSON.parse(Buffer.concat(chunks)
              .toString('utf8'));

          resolve(response);
        } catch (e) {
          reject(e);
        }
      });
      res.on('data', (chunk) => chunks.push(chunk));
    });

    req.on('error', (err) => reject(err));

    req.write(request);
    req.end();
  });
}

function getTokenTiming(accessor, vault) {
  let creation_time = null,
      explicit_max_ttl = null;

  return send({}, '', `/v1/auth/token/lookup-accessor/${accessor}`, 'POST', vault).then((resp) => {
    creation_time = resp.data.creation_time * 1000;
    explicit_max_ttl = resp.data.explicit_max_ttl * 1000;
  }).then(() => {
    if (explicit_max_ttl === 0) {
      // We have to query the /sys/mounts/auth/token/tune endpoint
      return send({}, '', '/v1/sys/mounts/auth/token/tune', 'GET', vault).then((resp) => {
        explicit_max_ttl = resp.max_lease_ttl * 1000;
      });
    }
  }).then(() => {
    return {
      creation_time: new Date(creation_time).toISOString(),
      expiration_time: new Date(creation_time + explicit_max_ttl).toISOString()
    };
  });
}

exports.create = function(req, res, next, vault) {
  const tokenParams = {
    renewable: Config.get('vault:renewable'),
    ttl: Config.get('vault:ttl'),
    explicit_max_ttl: Config.get('vault:explicit_max_ttl'),
    no_parent: true
  };

  // If any of the tunables don't exist in Config
  // and return `undefined`, delete them
  Object.keys(tokenParams).forEach((k) => {
    if (typeof tokenParams[k] === 'undefined') {
      delete tokenParams[k];
    }
  });

  return send(tokenParams, req.document.imageId, '/v1/auth/token/create', 'POST', vault).then((status) => {
    if (!status.hasOwnProperty('auth')) {
      throw Error('Token Error');
    }
    req.auth = status.auth;
    return getTokenTiming(status.auth.accessor, vault);
  }).then((data) => {
    req.auth = Object.assign(req.auth, data);
    return next();
  }).catch((err) => {
    return bad.request(res, err.message);
  });
};
<|endoftext|>