text: (function ($, cloudStack) {
      /**
       * Instance wizard
       */
      cloudStack.uiCustom.instanceWizard = function (args) {
          return function (listViewArgs) {
              var context = listViewArgs.context;
  
              var instanceWizard = function (data) {
                  var $wizard = $('#template').find('div.instance-wizard').clone();
                  var $progress = $wizard.find('div.progress ul li');
                  var $steps = $wizard.find('div.steps').children().hide();
                  var $diagramParts = $wizard.find('div.diagram').children().hide();
                  var $form = $wizard.find('form');
  
                  $form.validate();
  
                  // Close instance wizard
                  var close = function () {
                      $wizard.dialog('destroy');
                      $('div.overlay').fadeOut(function () {
                          $('div.overlay').remove();
                      });
                  };
  
                  // Save instance and close wizard
                  var completeAction = function () {
                      var data = cloudStack.serializeForm($form);
                      var $wizardLoading = $('<div>').addClass('loading-overlay').appendTo($wizard).css('z-index', '10000');
  
                      // Pass network IPs
                      data['my-network-ips'] = [];
                      $form.find('.my-networks .select .specify-ip input[type=text]').each(function () {
                          var $input = $(this);
  
                          if (!$input.closest('.select').find('input[type=checkbox]').is(':checked')) return true;
  
                          data['my-network-ips'].push(
                              $input.closest('.select').hasClass('advanced') ?
                                  $input.val() : null
                          );
                      });
                      data['new-network-ip'] = $form.find('.new-network .select.advanced .specify-ip input[type=text]').val();
  
                      // Pass network MACs
                      data['my-network-macs'] = [];
                      $form.find('.my-networks .select .specify-mac input[type=text]').each(function () {
                          var $input = $(this);
  
                          if (!$input.closest('.select').find('input[type=checkbox]').is(':checked')) return true;
  
                          data['my-network-macs'].push(
                              $input.closest('.select').hasClass('advanced') ?
                                  $input.val() : null
                          );
                      });
                      data['new-network-mac'] = $form.find('.new-network .select.advanced .specify-mac input[type=text]').val();
  
                      // Handle multi-disk service offerings
                      if ($form.find('.multi-disk-select-container').size()) {
                          data['disk-offerings-multi'] = [];
  
                          var $diskGroups = $form.find('.disk-select-group');
                          var $selectedDisks = $.grep($diskGroups, function (diskGroup) {
                              return $(diskGroup).find('input[type=checkbox]:checked').size();
                          });
  
                          $selectedDisks.map(function (disk) {
                              data['disk-offerings-multi'].push(
                                  $.extend($(disk).data('json-obj'), {
                                      _diskOfferingId: $(disk).find('input[type=radio]:checked').val()
                                  })
                              );
                          });
                      }
  
                      args.action({
                          // Populate data
                          context: context,
                          data: data,
                          $wizard: $wizard,
                          response: {
                              success: function (args) {
                                  var $listView = $('.list-view.instances');
  
                                  if ($listView.size()) {
                                      var $loading = $('.list-view.instances').listView('prependItem', {
                                          data: [{
                                              name: data.displayname ? data.displayname : _l('label.new.vm'),
                                              zonename: $wizard.find('select[name=zoneid] option').filter(function () {
                                                  return $(this).val() == data.zoneid;
                                              }).html(),
                                              state: 'Creating'
                                          }],
                                          actionFilter: function (args) {
                                              return [];
                                          }
                                      });
                                  }
  
                                  listViewArgs.complete({
                                      _custom: args._custom,
                                      messageArgs: cloudStack.serializeForm($form),
                                      $item: $listView.size() ? $loading : $('<div>')
                                  });
  
                                  close();
                              },
                              error: function (message) {
                                  $wizard.remove();
                                  $('div.overlay').remove();
  
                                  if (message) {
                                      cloudStack.dialog.notice({
                                          message: message
                                      });
                                  }
                              }
                          }
                      });
                  };
  
                  var makeSelects = function (name, data, fields, options, selectedObj, selectedObjNonEditable) {
                      var $selects = $('<div>');
                      options = options ? options : {};
  
                      $(data).each(function () {
                          var item = this;
                          var id = item[fields.id];
  
                          var $select = $('<div>')
                              .addClass('select')
                              .append(
                                  $('<input>')
                                      .attr({
                                          type: (function (type) {
                                              return type ? type : 'radio';
                                          })(options ? options.type : null),
                                          name: name,
                                          'wizard-field': options['wizard-field']
                                      })
                                      .val(id)
                                      .click(function () {
                                          var $select = $(this).closest('.select');
                                          var isSingleSelect = $select.hasClass('single-select');
                                          var $radio = $select.find('input[type=radio]');
                                          var $newNetwork = $(this).closest('.content').find('.select.new-network');
                                          var $otherSelects = $select.siblings().filter(':visible');
                                          var isCheckbox = $(this).attr('type') == 'checkbox';
  
                                          if (isCheckbox) {
                                              if (isSingleSelect) {
                                                  $select.siblings('.single-select:visible').find('input[type=checkbox]')
                                                      .attr('checked', false);
  
                                                  var $checkedOtherSelect = $otherSelects.filter(function () {
                                                      return $(this).not('.single-select') &&
                                                          $(this).find('input[type=checkbox]:checked').size() &&
                                                          $(this).find('input[type=radio]:checked').size();
                                                  });
  
                                                  if (!$checkedOtherSelect.size() && !$('.new-network:visible input[type=radio]:checked').size()) {
                                                      $(this).closest('.select').find('input[type=radio]').click();
                                                  }
                                              }
  
                                              if ((!$otherSelects.size()) &&
                                                  $newNetwork.find('input[type=checkbox]').is(':unchecked')) {
                                                  // Set as default
                                                  $(this).closest('.select').find('input[type=radio]').click();
                                              }
                                          }
  
                                          if ($radio.is(':checked') && !$(this).is(':checked')) {
                                              if (!$radio.closest('.select').index()) {
                                                  return false;
                                              } else {
                                                  $otherSelects.filter(':first')
                                                      .find('input[type=radio]').click();
                                              }
                                          }
  
                                          return true;
                                      })
                              )
                              .append(
                                  $('<div>').addClass('select-desc')
                                      .append($('<div>').addClass('name').html(_s(this[fields.name])))
                                      .append($('<div>').addClass('desc').html(_s(this[fields.desc])))
                              )
                              .data('json-obj', this);
  
                          if (selectedObj != null && selectedObj.id == item.id) {
                              $select.find('input[type=checkbox]').attr('checked', 'checked');
  
                              if (selectedObjNonEditable) {
                                  $select.find('input[type=checkbox]').attr('disabled', 'disabled');
                                  $select.find('input[type=checkbox]').clone().attr({
                                      type: 'hidden',
                                      disabled: false
                                  }).appendTo($selects);
                              }
                          }
  
                          $selects.append($select);
  
                          if (item._singleSelect) {
                              $select.addClass('single-select');
                          }
  
                          if (options.secondary) {
                              var $secondary = $('<div>').addClass('secondary-input').append(
                                  $('<input>')
                                      .attr({
                                          type: options.secondary.type,
                                          name: options.secondary.name,
                                          'wizard-field': options.secondary['wizard-field']
                                      })
                                      .val(id)
                                      .click(function () {
                                          var $checkbox = $(this).closest('.select').find('input[type=checkbox]');
  
                                          if (!$checkbox.is(':checked')) {
                                              $checkbox.attr('checked', true);
                                          }
  
                                          if ($(this).closest('.select-container').hasClass('single-select')) {
                                              $(this).closest('.select').siblings().find('input[type=checkbox]')
                                                  .attr('checked', false);
                                          }
  
                                          if ($select.hasClass('single-select')) {
                                              $select.siblings('.single-select:visible').find('input[type=checkbox]')
                                                  .attr('checked', false);
                                          }
                                      })
                                      .after(
                                          $('<div>').addClass('name').html(options.secondary.desc)
                                      )
                              ).appendTo($select);
                          }
                      });
  
                      cloudStack.evenOdd($selects, 'div.select', {
                          even: function ($elem) {
                              $elem.addClass('even');
                          },
                          odd: function ($elem) {
                              $elem.addClass('odd');
                          }
                      });
  
                      return $selects.children();
                  };
  
                  var dataProvider = function (step, providerArgs, callback) {
                      // Call appropriate data provider
                      args.steps[step - 1]($.extend(providerArgs, {
                          currentData: cloudStack.serializeForm($form),
                          initArgs: args,
                          context: context
                      }));
                  };
  
                  var dataGenerators = {
                      setup: function ($step, formData) {
                          var originalValues = function (formData) {
                              $step.find('select').val(
                                  formData.zoneid
                              );
  
                              $step.find('input[type=radio]').filter(function () {
                                  return $(this).val() == formData['select-template'];
                              }).click();
                          };
  
                          return {
                              response: {
                                  success: function (args) {
                                      // Zones
                                      $(args.data.zones).each(function () {
                                          $step.find('.select-zone select').append(
                                              $('<option>')
                                                  .attr({
                                                      value: this.id,
                                                      'wizard-field': 'zone'
                                                  })
                                                  .html(this.name)
                                          );
                                      });
  
                                      originalValues(formData);
                                  }
                              }
                          };
                      },
  
                      'select-iso': function ($step, formData) {
                          $step.find('.section.custom-size').hide();
  
                          var originalValues = function (formData) {
                              var $inputs = $step.find('.wizard-step-conditional:visible')
                                  .find('input[type=radio]');
                              var $selected = $inputs.filter(function () {
                                  return $(this).val() == formData.templateid;
                              });
  
                              if (!$selected.size()) {
                                  $inputs.filter(':first').click();
                              } else {
                                  $selected.click();
                              }
                              $step.find('select[name=hypervisorid]:visible').val(
                                  formData.hypervisorid
                              );
                          };
  
                          $step.find('.wizard-step-conditional').hide();
  
                          return {
                              response: {
                                  success: function (args) {
                                      if (formData['select-template']) {
                                          $step.find('.wizard-step-conditional').filter(function () {
                                              return $(this).hasClass(formData['select-template']);
                                          }).show();
                                      } else {
                                          $step.find('.select-iso').show();
                                      }
                                      var makeIsos = function (type, append) {
                                          var $selects = makeSelects('templateid', args.data.templates[type], {
                                              name: 'name',
                                              desc: 'displaytext',
                                              id: 'id'
                                          }, {
                                              'wizard-field': 'template'
                                          });
                                          var $templateHypervisor = $step.find('input[type=hidden][wizard-field=hypervisor]');
  
                                          // Get hypervisor from template
                                          if (type == 'featuredtemplates' || type == 'communitytemplates' || type == 'mytemplates' || type == 'sharedtemplates') {
                                              $selects.each(function () {
                                                  var $select = $(this);
                                                  var template = $.grep(args.data.templates[type], function (tmpl, v) {
                                                      return tmpl.id == $select.find('input').val();
                                                  })[0];
  
                                                  $select.change(function () {
                                                      $templateHypervisor
                                                          .attr('disabled', false)
                                                          .val(template.hypervisor);
                                                  });
                                              });
                                          } else {
                                              $templateHypervisor.attr('disabled', 'disabled');
                                          }
  
                                          if (type == 'featuredisos' || type == 'communityisos' || type == 'myisos' || type == 'sharedisos') {
                                              // Create hypervisor select
                                              $selects.find('input').bind('click', function () {
                                                  var $select = $(this).closest('.select');
  
                                                  //$select.siblings().removeClass('selected').find('.hypervisor').remove(); //SelectISO has 3 tabs now. This line only remove hypervisor div in the same tab, not enough. The following 3 lines will remove hypervisor div in all of 3 tabs.
                                                  $("#instance-wizard-featured-isos .select-container div.selected").removeClass('selected').find('div.hypervisor').remove();
                                                  $("#instance-wizard-community-isos .select-container div.selected").removeClass('selected').find('div.hypervisor').remove();
                                                  $("#instance-wizard-my-isos .select-container div.selected").removeClass('selected').find('div.hypervisor').remove();
                                                  $("#instance-wizard-shared-isos .select-container div.selected").removeClass('selected').find('div.hypervisor').remove();
  
                                                  $select.addClass('selected').append(
                                                      $('<div>').addClass('hypervisor')
                                                          .append($('<label>').html('Hypervisor:'))
                                                          .append($('<select>').attr({
                                                              name: 'hypervisorid'
                                                          }))
                                                  );
  
                                                  // Get hypervisor data
                                                  $(args.data.hypervisors).each(function () {
                                                      $select.find('select').append(
                                                          $('<option>').attr({
                                                              value: this[args.hypervisor.idField],
                                                              'wizard-field': 'hypervisor'
                                                          })
                                                              .html(this[args.hypervisor.nameField])
                                                      );
                                                  });
                                              });
                                          }
  
                                          append($selects);
                                      };
  
                                      // Featured ISOs
                                      $(
                                          [
                                              // Templates
                                              ['featuredtemplates', 'instance-wizard-featured-templates'],
                                              ['communitytemplates', 'instance-wizard-community-templates'],
                                              ['mytemplates', 'instance-wizard-my-templates'],
                                              ['sharedtemplates', 'instance-wizard-shared-templates'],
  
                                              // ISOs
                                              ['featuredisos', 'instance-wizard-featured-isos'],
                                              ['communityisos', 'instance-wizard-community-isos'],
                                              ['myisos', 'instance-wizard-my-isos'],
                                              ['sharedisos', 'instance-wizard-shared-isos']
                                              //['isos', 'instance-wizard-all-isos']
                                          ]
                                      ).each(function () {
                                          var item = this;
                                          var $selectContainer = $wizard.find('#' + item[1]).find('.select-container');
  
                                          makeIsos(item[0], function ($elem) {
                                              $selectContainer.append($elem);
                                          });
                                      });
  
                                      var custom = args.customHidden({
                                          context: context,
                                          data: args.data
                                      });
  
                                      $step.find('.custom-size-label').remove();
  
                                      if (custom) {
                                          $step.find('.section.custom-size').hide();
                                          $step.removeClass('custom-disk-size');
                                      }
  
                                      $step.find('input[type=radio]').bind('change', function () {
                                          var $target = $(this);
                                          var val = $target.val();
                                          var item = null;
                                          if (item == null) {
                                              item = $.grep(args.data.templates.featuredtemplates, function (elem) {
                                                  return elem.id == val;
                                              })[0];
                                          }
                                          if (item == null) {
                                              item = $.grep(args.data.templates.communitytemplates, function (elem) {
                                                  return elem.id == val;
                                              })[0];
                                          }
                                          if (item == null) {
                                              item = $.grep(args.data.templates.mytemplates, function (elem) {
                                                  return elem.id == val;
                                              })[0];
                                          }
                                          if (item == null) {
                                              item = $.grep(args.data.templates.sharedtemplates, function (elem) {
                                                  return elem.id == val;
                                              })[0];
                                          }
  
                                          if (!item) return true;
  
                                          var hypervisor = item['hypervisor'];
                                          if (hypervisor == 'KVM') {
                                              $step.find('.section.custom-size').show();
                                              $step.addClass('custom-disk-size');
                                          } else {
                                              $step.find('.section.custom-size').hide();
                                              $step.removeClass('custom-disk-size');
                                          }
  
                                          return true;
                                      });
  
                                      $(args.data.rootDiskControllers).each(function () {
                                          $step.find('select[name=rootdiskcontroller]').append(
                                              $('<option>').attr({
                                                  value: this.id,
                                                  'wizard-field': 'rootdisk-controller'
                                              }).html(this.displaytext)
                                          );
                                      });
  
                                      originalValues(formData);
  
                                  }
                              }
                          };
                      },
  
                      'service-offering': function ($step, formData) {
                          var originalValues = function (formData) {
                              if (formData.serviceofferingid) {
                                  $step.find('input[type=radio]').filter(function () {
                                      return $(this).val() == formData.serviceofferingid;
                                  }).click();
                              } else {
                                  $step.find('input[type=radio]:first').click();
                              }
                          };
  
                          return {
                              response: {
                                  success: function (args) {
                                      $step.find('.content .select-container').append(
                                          makeSelects('serviceofferingid', args.data.serviceOfferings, {
                                              name: 'name',
                                              desc: 'displaytext',
                                              id: 'id'
                                          }, {
                                              'wizard-field': 'service-offering'
                                          })
                                      );
  
                                      $step.find('input[type=radio]').bind('change', function () {
                                          var $target = $(this);
                                          var val = $target.val();
                                          var item = $.grep(args.data.serviceOfferings, function (elem) {
                                              return elem.id == val;
                                          })[0];
  
                                          if (!item) return true;
  
                                          var custom = item[args.customFlag];
  
                                          if (custom) {
                                              $step.addClass('custom-size');
                                          } else {
                                              $step.removeClass('custom-size');
                                          }
  
                                          var customIops = item[args.customIopsFlag];
  
                                          if (customIops && args.canShowCustomIops) {
                                              $step.addClass('custom-iops');
                                          } else {
                                              $step.removeClass('custom-iops');
                                          }
  
                                          return true;
                                      });
  
                                      originalValues(formData);
                                  }
                              }
                          };
                      },
  
                      'data-disk-offering': function ($step, formData) {
                          var originalValues = function (formData) {
                              var $targetInput = $step.find('input[type=radio]').filter(function () {
                                  return $(this).val() == formData.diskofferingid;
                              }).click();
  
                              if (!$targetInput.size()) {
                                  $step.find('input[type=radio]:visible').filter(':first').click();
                              }
                          };
  
                          $step.find('.section.custom-size').hide();
  
                          return {
                              response: {
                                  success: function (args) {
                                      var multiDisk = args.multiDisk;
  
                                      $step.find('.multi-disk-select-container').remove();
                                      $step.removeClass('custom-disk-size');
  
                                      if (args.required) {
                                          $step.find('.section.no-thanks').hide();
                                          $step.addClass('required');
                                      } else {
                                          $step.find('.section.no-thanks').show();
                                          $step.removeClass('required');
                                      }
  
                                      var $selectContainer = $step.find('.content .select-container:not(.multi-disk)');
  
                                      if (multiDisk) { // Render as multiple groups for each disk
                                          var $multiDiskSelect = $('<div>').addClass('multi-disk-select-container');
  
                                          $(multiDisk).map(function (index, disk) {
                                              var $group = $('<div>').addClass('disk-select-group');
                                              var $header = $('<div>').addClass('disk-select-header').append(
                                                  $('<div>').addClass('title').html(disk.label)
                                              ).appendTo($group);
                                              var $checkbox = $('<input>').addClass('multi-disk-select')
                                                  .attr({
                                                      type: 'checkbox',
                                                      'disk-id': disk.id
                                                  })
                                                  .prependTo($header);
                                              var $multiSelectContainer = $selectContainer.clone().append(
                                                  makeSelects('diskofferingid.' + disk.id, args.data.diskOfferings, {
                                                      id: 'id',
                                                      name: 'name',
                                                      desc: 'displaytext'
                                                  }, {
                                                      'wizard-field': 'disk-offering'
                                                  })
                                              ).appendTo($group).addClass('multi-disk');
  
                                              $group.appendTo($multiDiskSelect);
                                              $group.data('json-obj', disk);
  
                                              // Show-hide disk group selects
                                              $checkbox.click(function () {
                                                  $group.toggleClass('selected');
                                                  $group.find('.select:first input[type=radio]').click();
  
                                                  if (!$multiDiskSelect.find('input[type=checkbox]:checked').size()) {
                                                      $step.find('.no-thanks input[type=radio]').click();
                                                  } else {
                                                      $step.find('.no-thanks input[type=radio]').attr('checked', false);
                                                  }
                                              });
  
                                              // Add custom disk size box
                                              $step.find('.section.custom-size').clone().hide().appendTo($group);
                                          });
  
                                          $multiDiskSelect.insertAfter($selectContainer);
                                          $selectContainer.hide();
  
                                          // Fix issue with containers always showing after reload
                                          $multiDiskSelect.find('.select-container').attr('style', null);
                                      } else {
                                          $selectContainer.show();
                                          $step.find('.content .select-container').append(
                                              makeSelects('diskofferingid', args.data.diskOfferings, {
                                                  id: 'id',
                                                  name: 'name',
                                                  desc: 'displaytext'
                                              }, {
                                                  'wizard-field': 'disk-offering'
                                              })
                                          );
                                      }
  
                                      $step.find('input[type=radio]').bind('change', function () {
                                          var $target = $(this);
                                          var val = $target.val();
                                          var item = $.grep(args.data.diskOfferings, function (elem) {
                                              return elem.id == val;
                                          })[0];
                                          var isMultiDisk = $step.find('.multi-disk-select').size();
  
                                          // Uncheck any multi-select groups
                                          if ($target.closest('.no-thanks').size() && isMultiDisk) {
                                              $step.find('.disk-select-group input[type=checkbox]:checked').click();
                                              $(this).attr('checked', true);
  
                                              return true;
                                          }
  
                                          if (!item) {
                                              if (isMultiDisk) {
                                                  $(this).closest('.disk-select-group .section.custom-size').hide();
                                                  $(this).closest('.disk-select-group').removeClass('custom-size');
                                              } else {
                                                  // handle removal of custom size controls
                                                  $step.find('.section.custom-size').hide();
                                                  $step.removeClass('custom-disk-size');
  
                                                  // handle removal of custom IOPS controls
                                                  $step.removeClass('custom-iops-do');
                                              }
  
                                              return true;
                                          }
  
                                          var custom = item[args.customFlag];
  
                                          if (!isMultiDisk) $step.find('.custom-size-label').remove();
  
                                          if (custom && !isMultiDisk) {
                                              $target.parent().find('.name')
                                                  .append(
                                                      $('<span>').addClass('custom-size-label')
                                                          .append(': ')
                                                          .append(
                                                              $('<span>').addClass('custom-disk-size').html(
                                                                  $step.find('.custom-size input[name=size]').val()
                                                              )
                                                          )
                                                          .append(' GB')
                                                  );
                                              $target.parent().find('.select-desc .desc')
                                                  .append(
                                                      $('<span>').addClass('custom-size-label')
                                                          .append(', ')
                                                          .append(
                                                              $('<span>').addClass('custom-disk-size').html(
                                                                  $step.find('.custom-size input[name=size]').val()
                                                              )
                                                          )
                                                          .append(' GB')
                                                  );
                                              $step.find('.section.custom-size').show();
                                              $step.addClass('custom-disk-size');
                                              $target.closest('.select-container').scrollTop(
                                                  $target.position().top
                                              );
                                          } else if (custom && isMultiDisk) {
                                              $(this).closest('.disk-select-group').addClass('custom-size');
                                          } else {
                                              if (isMultiDisk) {
                                                  $(this).closest('.disk-select-group').removeClass('custom-size');
                                              } else {
                                                  $step.find('.section.custom-size').hide();
                                                  $step.removeClass('custom-disk-size');
                                              }
                                          }
  
                                          var customIops = item[args.customIopsDoFlag];
  
                                          if (customIops) {
                                              $step.addClass('custom-iops-do');
                                          } else {
                                              $step.removeClass('custom-iops-do');
                                          }
  
                                          return true;
                                      });
  
                                      originalValues(formData);
                                  }
                              }
                          };
                      },
  
                      'affinity': function ($step, formData) {
                          return {
                              response: {
                                  success: function (args) {
                                      // Cleanup
                                      $step.find('.main-desc, p.no-affinity-groups').remove();
  
                                      if (args.data.affinityGroups && args.data.affinityGroups.length) {
                                          $step.prepend(
                                              $('<div>').addClass('main-desc').append(
                                                  $('<p>').html(_l('message.select.affinity.groups'))
                                              )
                                          );
                                          $step.find('.select-container').append(
                                              makeSelects(
                                                  'affinity-groups',
                                                  args.data.affinityGroups, {
                                                      name: 'name',
                                                      desc: 'description',
                                                      id: 'id'
                                                  }, {
                                                      type: 'checkbox',
                                                      'wizard-field': 'affinity-groups'
                                                  },
                                                  args.data.selectedObj,
                                                  args.data.selectedObjNonEditable
                                              )
                                          );
                                      } else {
                                          $step.find('.select-container').append(
                                              $('<p>').addClass('no-affinity-groups').html(_l('message.no.affinity.groups'))
                                          );
                                      }
                                  }
                              }
                          };
                      },
  
                      'sshkeyPairs': function ($step, formData) {
                          var originalValues = function (formData) {
                              if (formData.sshkeypair) {
                                  $step.find('input[type=radio]').filter(function () {
                                      return $(this).val() == formData.sshkeypair;
                                  }).click();
                              } else {
                                  $step.find('input[type=radio]:first').click();
                              }
                          };
                          return {
                              response: {
                                  success: function (args) {
                                      $step.find('.main-desc, p.no-sshkey-pairs').remove();
  
                                      if (args.data.sshkeyPairs && args.data.sshkeyPairs.length) {
                                          $step.prepend(
                                              $('<div>').addClass('main-desc').append(
                                                  $('<p>').html(_l('message.please.select.ssh.key.pair.use.with.this.vm'))
                                              )
                                          );
                                          $step.find('.section.no-thanks').show();
                                          $step.find('.select-container').append(
                                              makeSelects(
                                                  'sshkeypair',
                                                  args.data.sshkeyPairs, {
                                                      name: 'name',
                                                      id: 'name'
                                                  }, {
                                                      'wizard-field': 'sshkey-pairs'
                                                  }
                                              )
                                          );
                                          originalValues(formData); // if we can select only one.
                                      } else {
                                          $step.find('.section.no-thanks').hide();
                                          $step.find('.select-container').append(
                                              $('<p>').addClass('no-sshkey-pairs').html(_l('You do not have any ssh key pairs. Please continue to the next step.'))
                                          );
                                      }
                                  }
                              }
                          };
                      },
  
                      'network': function ($step, formData) {
                          var showAddNetwork = true;
  
                          var checkShowAddNetwork = function ($newNetwork) {
                              if (!showAddNetwork) {
                                  $newNetwork.hide();
                              } else {
                                  $newNetwork.show();
                              }
                          };
  
                          var originalValues = function (formData) {
                              // Default networks
                              $step.find('input[type=radio]').filter(function () {
                                  return $(this).val() == formData['defaultNetwork'];
                              }).click();
  
                              // Optional networks
                              var selectedOptionalNetworks = [];
  
                              if ($.isArray(formData['shared-networks']) != -1) {
                                  $(formData['shared-networks']).each(function () {
                                      selectedOptionalNetworks.push(this);
                                  });
                              } else {
                                  selectedOptionalNetworks.push(formData['shared-networks']);
                              }
  
                              var $checkboxes = $step.find('input[name=shared-networks]');
                              $(selectedOptionalNetworks).each(function () {
                                  var networkID = this;
                                  $checkboxes.filter(function () {
                                      return $(this).val() == networkID;
                                  }).attr('checked', 'checked');
                              });
                          };
  
                          var $newNetwork = $step.find('.new-network');
                          var $newNetworkCheckbox = $newNetwork.find('input[type=checkbox]');
  
                          // Setup new network field
                          $newNetworkCheckbox.unbind('click');
                          $newNetworkCheckbox.click(function () {
                              $newNetwork.toggleClass('unselected');
  
                              // Select another default if hiding field
                              if ($newNetwork.hasClass('unselected')) {
                                  $step.find('input[type=radio]:visible:first').click();
                              } else {
                                  $newNetwork.find('input[type=radio]').click();
                              }
                          });
  
                          setTimeout(function () {
                              var $checkbox = $step.find('.new-network input[type=checkbox]');
                              var $newNetwork = $checkbox.closest('.new-network');
  
                              if ($step.find('.select.my-networks .select-container .select:visible').size()) {
                                  $checkbox.attr('checked', false);
                                  $newNetwork.addClass('unselected');
                              } else {
                                  $newNetwork.find('input[name=defaultNetwork]').filter('[value=new-network]').click();
                              }
  
                              $checkbox.change();
                          });
  
                          // Show relevant conditional sub-step if present
                          $step.find('.wizard-step-conditional').hide();
  
                          if ($.isFunction(args.showAddNetwork)) {
                              showAddNetwork = args.showAddNetwork({
                                  data: formData,
                                  context: context
                              });
                          }
  
                          // Filter network list by VPC ID
                          var filterNetworkList = function (vpcID) {
                              var $selects = $step.find('.my-networks .select-container .select');
                              var $visibleSelects = $($.grep($selects, function (select) {
                                  var $select = $(select);
  
                                  return args.vpcFilter($select.data('json-obj'), vpcID);
                              }));
                              var $addNetworkForm = $step.find('.select.new-network');
                              var $addNewNetworkCheck = $addNetworkForm.find('input[name=new-network]');
  
                              // VPC networks cannot be created via instance wizard
                              if (vpcID != -1) {
                                  $step.find('.my-networks .select-container').addClass('single-select');
                                  $addNetworkForm.hide();
  
                                  if ($addNewNetworkCheck.is(':checked')) {
                                      $addNewNetworkCheck.click();
                                      $addNewNetworkCheck.attr('checked', false);
                                  }
                              } else {
                                  $step.find('.my-networks .select-container').removeClass('single-select');
                                  $addNetworkForm.show();
                                  checkShowAddNetwork($addNetworkForm);
                              }
  
                              $selects.find('input[type=checkbox]').attr('checked', false);
                              $selects.hide();
                              $visibleSelects.show();
  
                              // Select first visible item by default
                              $visibleSelects.filter(':first')
                                  .find('input[type=radio]')
                                  .click();
  
                              cloudStack.evenOdd($visibleSelects, 'div.select', {
                                  even: function ($elem) {
                                      $elem.removeClass('odd');
                                      $elem.addClass('even');
                                  },
                                  odd: function ($elem) {
                                      $elem.removeClass('even');
                                      $elem.addClass('odd');
                                  }
                              });
                          };
  
                          var $vpcSelect = $step.find('select[name=vpc-filter]');
  
                          $vpcSelect.unbind('change');
                          $vpcSelect.change(function () {
                              filterNetworkList($vpcSelect.val());
                          });
  
                          return {
                              response: {
                                  success: function (args) {
                                      var vpcs = args.data.vpcs;
                                      var addClass = args.addClass;
                                      var removeClass = args.removeClass;
  
                                      // Populate VPC drop-down
                                      $vpcSelect.html('');
                                      $(vpcs).map(function (index, vpc) {
                                          var $option = $('<option>');
                                          var id = vpc.id;
                                          var description = vpc.name;
  
                                          $option.attr('value', id);
                                          $option.html(description);
                                          $option.appendTo($vpcSelect);
                                      });
  
                                      // 'No VPC' option
                                      $('<option>').attr('value', '-1').html(_l('ui.listView.filters.all')).prependTo($vpcSelect);
  
                                      $vpcSelect.val(-1);
  
                                      // Populate network offering drop-down
                                      $(args.data.networkOfferings).each(function () {
                                          $('<option>')
                                              .val(this.id)
                                              .html(this.name)
                                              .appendTo($newNetwork.find('select'));
                                      });
  
                                      if (args.type) {
                                          $step.find('.wizard-step-conditional').filter(function () {
                                              return $(this).hasClass(args.type);
                                          }).show();
                                      } else {
                                          $step.find('.select-network').show();
                                      }
  
                                      // My networks
                                      $step.find('.my-networks .select-container').append(
                                          makeSelects('my-networks', args.data.networkObjs, {
                                              name: 'name',
                                              desc: 'type',
                                              id: 'id'
                                          }, {
                                              type: 'checkbox',
                                              'wizard-field': 'my-networks',
                                              secondary: {
                                                  desc: 'Default',
                                                  name: 'defaultNetwork',
                                                  type: 'radio',
                                                  'wizard-field': 'default-network'
                                              }
                                          })
                                      );
  
                                      // Add IP/advanced option fields
                                      $step.find('.my-networks .select-container .select, .select.new-network .select').each(function () {
                                          var $select = $(this);
                                          var $advancedLink = $('<div>').addClass('advanced-options hide-if-unselected');
                                          var $specifyIpField = $('<div>').addClass('specify-ip hide-if-unselected').append(
                                              $('<div>').addClass('table-view').append(
                                                  $('<label>').html(_l('label.ip.address')),
                                                  $('<input>').attr({type: 'text'})
                                              )
                                          );
                                          var $specifyMacField = $('<div>').addClass('specify-mac hide-if-unselected').append(
                                              $('<div>').addClass('table-view').append(
                                                  $('<label>').html(_l('label.macaddress')),
                                                  $('<input>').attr({type: 'text'})
                                              )
                                          );
  
                                          // Cleanup
                                          if ($select.closest('.new-network').size()) {
                                              $select.find('.advanced-options, .specify-ip').remove();
                                              $select.find('.advanced-options, .specify-mac').remove();
                                          }
  
                                          $select.append($advancedLink, $specifyIpField);
                                          $select.append($advancedLink, $specifyMacField);
                                          $advancedLink.click(function () {
                                              $select.toggleClass('advanced');
                                          });
                                      });
  
                                      // Show non-VPC networks by default
                                      filterNetworkList(-1);
  
                                      originalValues(formData);
                                      checkShowAddNetwork($newNetwork);
                                  }
                              }
                          };
                      },
  
                      'review': function ($step, formData) {
                          $step.find('[wizard-field]').each(function () {
                              var field = $(this).attr('wizard-field');
                              var fieldName;
                              var $input = $wizard.find('[wizard-field=' + field + ']').filter(function () {
                                  return ($(this).is(':selected') ||
                                      $(this).is(':checked') ||
                                      $(this).attr('type') == 'hidden' ||
                                      $(this).attr('review') == 'yes') &&
                                      $(this).is(':not(:disabled)');
                              });
  
                              if ($input.is('option')) {
                                  fieldName = $input.html();
                              } else if ($input.is('input[type=radio]')) {
                                  // Choosen New network as default
                                  if ($input.parents('div.new-network').size()) {
                                      fieldName = $input.closest('div.new-network').find('input[name="new-network-name"]').val();
                                      // Choosen Network from existed
                                  } else if ($input.parents('div.my-networks').size()) {
                                      fieldName = $input.closest('div.select').find('.select-desc .name').html();
                                  } else {
                                      fieldName = $input.parent().find('.select-desc .name').html();
                                  }
                              } else if ($input.eq(0).is('input[type=checkbox]')) {
                                  fieldName = '';
                                  $input.each(function (index) {
                                      if (index != 0) fieldName += '<br />';
                                      fieldName += $(this).next('div.select-desc').find('.name').html();
                                  });
                              } else if ($input.is('input[type=hidden]')) {
                                  fieldName = $input.val();
                              } else if ($input.is('input[review=yes]')) {
                                  fieldName = $wizard.find('[wizard-field=' + field + ']').val();
                              }
  
                              if (fieldName) {
                                  $(this).html(fieldName);
                              } else {
                                  $(this).html('(' + _l('label.none') + ')');
                              }
  
                              var conditionalFieldFrom = $(this).attr('conditional-field');
                              if (conditionalFieldFrom) {
                                  if ($wizard.find('.' + conditionalFieldFrom).css('display') == 'block') {
                                      $(this).closest('div.select').show();
                                  } else {
                                      $(this).closest('div.select').hide();
                                  }
                              }
                          });
                      }
                  };
  
                  $wizard.bind('cloudStack.instanceWizard.showStep', function (e, args) {
                      showStep(args.index, {refresh: true});
                  });
  
                  // Go to specified step in wizard,
                  // updating nav items and diagram
                  var showStep = function (index, options) {
                      if (!options) options = {};
                      var targetIndex = index - 1;
  
                      if (index <= 1) targetIndex = 0;
                      if (targetIndex == $steps.size()) {
                          completeAction();
                          return;
                      }
  
                      var $targetStep = $($steps.hide()[targetIndex]).show();
                      var stepID = $targetStep.attr('wizard-step-id');
                      var formData = cloudStack.serializeForm($form);
  
                      if (options.refresh) {
                          $targetStep.removeClass('loaded');
                      }
  
                      if (!$targetStep.hasClass('loaded')) {
                          // Remove previous content
                          if (!$targetStep.hasClass('review')) { // Review row content is not autogenerated
                              $targetStep.find('.select-container:not(.fixed) div, option:not(:disabled)').remove();
                          }
  
                          dataProvider(
                              index,
                              dataGenerators[stepID](
                                  $targetStep,
                                  formData
                              )
                          );
  
                          if (!$targetStep.hasClass('repeat') && !$targetStep.hasClass('always-load')) $targetStep.addClass('loaded');
                      }
  
                      // Show launch vm button if last step
                      var $nextButton = $wizard.find('.button.next');
                      $nextButton.find('span').html(_l('label.next'));
                      $nextButton.removeClass('final');
                      if ($targetStep.hasClass('review')) {
                          $nextButton.find('span').html(_l('label.launch.vm'));
                          $nextButton.addClass('final');
                      }
  
                      // Hide previous button on first step
                      var $previousButton = $wizard.find('.button.previous');
                      if (index == 1) $previousButton.hide();
                      else $previousButton.show();
  
                      // Update progress bar
                      var $targetProgress = $progress.removeClass('active').filter(function () {
                          return $(this).index() <= targetIndex;
                      }).toggleClass('active');
  
                      // Update diagram; show/hide as necessary
                      $diagramParts.filter(function () {
                          return $(this).index() <= targetIndex;
                      }).fadeIn('slow');
                      $diagramParts.filter(function () {
                          return $(this).index() > targetIndex;
                      }).fadeOut('slow');
  
                      setTimeout(function () {
                          if (!$targetStep.find('input[type=radio]:checked').size()) {
                              $targetStep.find('input[type=radio]:first').click();
                          }
                      }, 50);
                  };
  
                  // Events
                  $wizard.click(function (event) {
                      var $target = $(event.target);
                      var $activeStep = $form.find('.step:visible');
  
                      // Next button
                      if ($target.closest('div.button.next').size()) {
                          //step 2 - select template/ISO
                          if ($activeStep.hasClass('select-iso')) {
                              if ($activeStep.find('.content:visible input:checked').size() == 0) {
                                  cloudStack.dialog.notice({
                                      message: 'message.step.1.continue'
                                  });
                                  return false;
                              }
                              $(window).trigger("cloudStack.module.instanceWizard.clickNextButton", {
                                  $form: $form,
                                  currentStep: 2
                              });
                          }
  
                          //step 6 - select network
                          if ($activeStep.find('.wizard-step-conditional.select-network:visible').size() > 0) {
                              var data = $activeStep.data('my-networks');
  
                              if (!data) {
                                  $activeStep.closest('form').data('my-networks', cloudStack.serializeForm(
                                      $activeStep.closest('form')
                                  )['my-networks']);
                              }
  
                              if ($activeStep.find('input[type=checkbox]:checked').size() == 0) { //if no checkbox is checked
                                  cloudStack.dialog.notice({
                                      message: 'message.step.4.continue'
                                  });
                                  return false;
                              }
                          }
  
                          //step 6 - review (spcifiy displyname, group as well)
                          if ($activeStep.hasClass('review')) {
                              if ($activeStep.find('input[name=displayname]').size() > 0 && $activeStep.find('input[name=displayname]').val().length > 0) {
                                  //validate
                                  var b = cloudStack.validate.vmHostName($activeStep.find('input[name=displayname]').val());
                                  if (b == false)
                                      return false;
                              }
                          }
  
                          if (!$form.valid()) {
                              if ($form.find('input.error:visible, select.error:visible').size()) {
                                  return false;
                              }
                          }
  
                          if ($activeStep.hasClass('repeat')) {
                              showStep($steps.filter(':visible').index() + 1);
                          } else {
                              showStep($steps.filter(':visible').index() + 2);
                          }
  
                          return false;
                      }
  
                      // Previous button
                      if ($target.closest('div.button.previous').size()) {
                          var $step = $steps.filter(':visible');
                          var $networkStep = $steps.filter('.network');
                          var index = $step.index();
  
                          if (index) {
                              showStep(index);
                          }
  
                          return false;
                      }
  
                      // Close button
                      if ($target.closest('div.button.cancel').size()) {
                          close();
  
                          return false;
                      }
  
                      // Edit link
                      if ($target.closest('div.edit').size()) {
                          var $edit = $target.closest('div.edit');
  
                          showStep($edit.find('a').attr('href'));
  
                          return false;
                      }
  
                      return true;
                  });
  
                  showStep(1);
  
                  $wizard.bind('change', function (event) {
                      var $target = $(event.target);
                      var $step = $target.closest('.step');
                      var $futureSteps = $step.siblings().filter(function () {
                          return $(this).index() > $step.index();
                      });
  
                      // Reset all fields in futher steps
                      $futureSteps.removeClass('loaded');
                  });
  
                  var minCustomDiskSize = args.minDiskOfferingSize ?
                      args.minDiskOfferingSize() : 1;
  
                  var maxCustomDiskSize = args.maxDiskOfferingSize ?
                      args.maxDiskOfferingSize() : 100;
  
                  // Setup tabs and slider
                  $wizard.find('.section.custom-size.custom-disk-size .size.min span').html(minCustomDiskSize);
                  $wizard.find('.section.custom-size.custom-disk-size input[type=text]').val(minCustomDiskSize);
                  $wizard.find('.section.custom-size.custom-disk-size .size.max span').html(maxCustomDiskSize);
                  $wizard.find('.tab-view').tabs();
                  $wizard.find('.slider').each(function () {
                      var $slider = $(this);
  
                      $slider.slider({
                          min: minCustomDiskSize,
                          max: maxCustomDiskSize,
                          start: function (event) {
                              $slider.closest('.section.custom-size').find('input[type=radio]').click();
                          },
                          slide: function (event, ui) {
                              $slider.closest('.section.custom-size').find('input[type=text]').val(
                                  ui.value
                              );
                              $slider.closest('.step').find('span.custom-disk-size').html(
                                  ui.value
                              );
                          }
                      });
                  });
  
                  $wizard.find('div.data-disk-offering div.custom-size input[type=text]').bind('change', function () {
                      var old = $wizard.find('div.data-disk-offering div.custom-size input[type=text]').val();
                      $wizard.find('div.data-disk-offering span.custom-disk-size').html(_s(old));
                  });
  
  
                  return $wizard.dialog({
                      title: _l('label.vm.add'),
                      width: 896,
                      height: 570,
                      closeOnEscape: false,
                      zIndex: 5000
                  })
                      .closest('.ui-dialog').overlay();
              };
  
              instanceWizard(args);
          };
      };
  })(jQuery, cloudStack);
  