').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(
                      $('
')
                        .attr({
                          value: this.id,
                          'wizard-field': 'zone'
                        })
                        .html(this.name)
                    );
                  });
                  originalValues(formData);
                }
              }
            };
          },
          'select-iso': function($step, formData) {
            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'
                    });
                    if (type == 'featuredisos' || type == 'communityisos' || type == 'myisos') {
                      // 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();
                        $select.addClass('selected').append(
                          $('').addClass('hypervisor')
                            .append($('').html('Hypervisor:'))
                            .append($('').attr({ name: 'hypervisorid' }))
                        );
                        // Get hypervisor data
                        $(args.data.hypervisors).each(function() {
                          $select.find('select').append(
                            $('').attr({
                              value: this[args.hypervisor.idField],
                              'wizard-field': 'hypervisor'
                            })
                              .html(this[args.hypervisor.nameField])
                          );
                        });
                      });
                    }
                    append($selects);
                  };
                  // Featured ISOs
                  $(
                    [
                      ['featuredtemplates', 'instance-wizard-featured-templates'],
                      ['communitytemplates', 'instance-wizard-community-templates'],
                      ['mytemplates', 'instance-wizard-my-templates'],
                      ['featuredisos', 'instance-wizard-featured-isos'],
                      ['communityisos', 'instance-wizard-community-isos'],
                      ['myisos', 'instance-wizard-my-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);
                    });
                  });
                  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'
                    })
                  );
                  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) {
                  $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');
                  }
                  $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];
                    if (!item) return true;
                    var custom = item[args.customFlag];
                    $step.find('.custom-size-label').remove();
                    if (custom) {
                      $target.parent().find('.name')
                        .append(
                          $('').addClass('custom-size-label')
                            .append(': ')
                            .append(
                              $('').addClass('custom-disk-size').html(
                                $step.find('.custom-size input[name=size]').val()
                              )
                            )
                            .append(' GB')
                        );
                      $target.parent().find('.select-desc .desc')
                        .append(
                          $('').addClass('custom-size-label')
                            .append(', ')
                            .append(
                              $('').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 {
                      $step.find('.section.custom-size').hide();
                      $step.removeClass('custom-disk-size');
                    }
                    return true;
                  });
                  originalValues(formData);
                }
              }
            };
          },
          'network': function($step, formData) {
            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]: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').size()) {
                $checkbox.attr('checked', false);
                $newNetwork.addClass('unselected');
              } else {
                $checkbox.attr('checked', true);
                $newNetwork.removeClass('unselected');
              }
              $checkbox.change();
            });
            // Show relevant conditional sub-step if present
            $step.find('.wizard-step-conditional').hide();
            // 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();
              }
              
              $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;
                  // Populate VPC drop-down
                  $vpcSelect.html('');
                  $(vpcs).map(function(index, vpc) {
                    var $option = $('');
                    var id = vpc.id;
                    var description = vpc.name;
                    $option.attr('value', id);
                    $option.html(description);
                    $option.appendTo($vpcSelect);
                  });
                  // 'No VPC' option
                  $(' ').attr('value', '-1').html('None').prependTo($vpcSelect);
                  $vpcSelect.val(-1);
                  
                  // Populate network offering drop-down
                  $(args.data.networkOfferings).each(function() {
                    $(' ')
                      .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', $.merge(args.data.myNetworks, args.data.sharedNetworks), {
                      name: 'name',
                      desc: 'type',
                      id: 'id'
                    }, {
                      type: 'checkbox',
                      'wizard-field': 'my-networks',
                      secondary: {
                        desc: 'Default',
                        name: 'defaultNetwork',
                        type: 'radio',
                        'wizard-field': 'default-network'
                      }
                    })
                  );
                  // Show non-VPC networks by default
                  filterNetworkList(-1);
                  // Security groups (alt. page)
                  $step.find('.security-groups .select-container').append(
                    makeSelects('security-groups', args.data.securityGroups, {
                      name: 'name',
                      desc: 'description',
                      id: 'id'
                    }, {
                      type: 'checkbox',
                      'wizard-field': 'security-groups'
                    })
                  );
                  originalValues(formData);
                }
              }
            };
          },
          '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');
                    });
                    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 += '