~maas-committers/maas/2.3

« back to all changes in this revision

Viewing changes to src/maasserver/static/js/bundle/maas-min.js.map

  • Committer: deadlight
  • Date: 2018-03-07 09:56:36 UTC
  • Revision ID: git-v1:b0cda2b247fdf4ac3828c196ecfc68cfbc3ac98c
Remove sticky header javascript

Removed instances of the sticky javascript and the source files

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/maasserver/static/js/angular/controllers/add_device.js","webpack:///./src/maasserver/static/js/angular/controllers/add_domain.js","webpack:///./src/maasserver/static/js/angular/controllers/add_hardware.js","webpack:///./src/maasserver/static/js/angular/controllers/dashboard.js","webpack:///./src/maasserver/static/js/angular/controllers/domain_details.js","webpack:///./src/maasserver/static/js/angular/controllers/domains_list.js","webpack:///./src/maasserver/static/js/angular/controllers/fabric_details.js","webpack:///./src/maasserver/static/js/angular/controllers/images.js","webpack:///./src/maasserver/static/js/angular/controllers/intro.js","webpack:///./src/maasserver/static/js/angular/controllers/intro_user.js","webpack:///./src/maasserver/static/js/angular/controllers/networks_list.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details_networking.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details_storage.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details_storage_filesystems.js","webpack:///./src/maasserver/static/js/angular/controllers/node_events.js","webpack:///./src/maasserver/static/js/angular/controllers/node_result.js","webpack:///./src/maasserver/static/js/angular/controllers/node_results.js","webpack:///./src/maasserver/static/js/angular/controllers/nodes_list.js","webpack:///./src/maasserver/static/js/angular/controllers/pod_details.js","webpack:///./src/maasserver/static/js/angular/controllers/pods_list.js","webpack:///./src/maasserver/static/js/angular/controllers/prefs.js","webpack:///./src/maasserver/static/js/angular/controllers/settings.js","webpack:///./src/maasserver/static/js/angular/controllers/space_details.js","webpack:///./src/maasserver/static/js/angular/controllers/subnet_details.js","webpack:///./src/maasserver/static/js/angular/controllers/vlan_details.js","webpack:///./src/maasserver/static/js/angular/controllers/zone_details.js","webpack:///./src/maasserver/static/js/angular/controllers/zones_list.js","webpack:///./src/maasserver/static/js/angular/directives/accordion.js","webpack:///./src/maasserver/static/js/angular/directives/boot_images.js","webpack:///./src/maasserver/static/js/angular/directives/call_to_action.js","webpack:///./src/maasserver/static/js/angular/directives/card_loader.js","webpack:///./src/maasserver/static/js/angular/directives/code_lines.js","webpack:///./src/maasserver/static/js/angular/directives/contenteditable.js","webpack:///./src/maasserver/static/js/angular/directives/controller_image_status.js","webpack:///./src/maasserver/static/js/angular/directives/controller_status.js","webpack:///./src/maasserver/static/js/angular/directives/dbl_click_overlay.js","webpack:///./src/maasserver/static/js/angular/directives/enter.js","webpack:///./src/maasserver/static/js/angular/directives/enter_blur.js","webpack:///./src/maasserver/static/js/angular/directives/error_overlay.js","webpack:///./src/maasserver/static/js/angular/directives/error_toggle.js","webpack:///./src/maasserver/static/js/angular/directives/ipranges.js","webpack:///./src/maasserver/static/js/angular/directives/maas_obj_form.js","webpack:///./src/maasserver/static/js/angular/directives/mac_address.js","webpack:///./src/maasserver/static/js/angular/directives/machines_table.js","webpack:///./src/maasserver/static/js/angular/directives/notifications.js","webpack:///./src/maasserver/static/js/angular/directives/os_select.js","webpack:///./src/maasserver/static/js/angular/directives/placeholder.js","webpack:///./src/maasserver/static/js/angular/directives/pod_parameters.js","webpack:///./src/maasserver/static/js/angular/directives/power_parameters.js","webpack:///./src/maasserver/static/js/angular/directives/proxy_settings.js","webpack:///./src/maasserver/static/js/angular/directives/release_name.js","webpack:///./src/maasserver/static/js/angular/directives/release_options.js","webpack:///./src/maasserver/static/js/angular/directives/script_results_list.js","webpack:///./src/maasserver/static/js/angular/directives/script_runtime.js","webpack:///./src/maasserver/static/js/angular/directives/script_select.js","webpack:///./src/maasserver/static/js/angular/directives/script_status.js","webpack:///./src/maasserver/static/js/angular/directives/ssh_keys.js","webpack:///./src/maasserver/static/js/angular/directives/switches_table.js","webpack:///./src/maasserver/static/js/angular/directives/toggle_control.js","webpack:///./src/maasserver/static/js/angular/directives/type.js","webpack:///./src/maasserver/static/js/angular/directives/version_reloader.js","webpack:///./src/maasserver/static/js/angular/directives/window_width.js","webpack:///./src/maasserver/static/js/angular/factories/bootresources.js","webpack:///./src/maasserver/static/js/angular/factories/configs.js","webpack:///./src/maasserver/static/js/angular/factories/controllers.js","webpack:///./src/maasserver/static/js/angular/factories/devices.js","webpack:///./src/maasserver/static/js/angular/factories/dhcpsnippets.js","webpack:///./src/maasserver/static/js/angular/factories/discoveries.js","webpack:///./src/maasserver/static/js/angular/factories/domains.js","webpack:///./src/maasserver/static/js/angular/factories/events.js","webpack:///./src/maasserver/static/js/angular/factories/fabrics.js","webpack:///./src/maasserver/static/js/angular/factories/general.js","webpack:///./src/maasserver/static/js/angular/factories/ipranges.js","webpack:///./src/maasserver/static/js/angular/factories/machines.js","webpack:///./src/maasserver/static/js/angular/factories/node_results.js","webpack:///./src/maasserver/static/js/angular/factories/nodes.js","webpack:///./src/maasserver/static/js/angular/factories/notifications.js","webpack:///./src/maasserver/static/js/angular/factories/packagerepositories.js","webpack:///./src/maasserver/static/js/angular/factories/pods.js","webpack:///./src/maasserver/static/js/angular/factories/region.js","webpack:///./src/maasserver/static/js/angular/factories/scripts.js","webpack:///./src/maasserver/static/js/angular/factories/services.js","webpack:///./src/maasserver/static/js/angular/factories/spaces.js","webpack:///./src/maasserver/static/js/angular/factories/sshkeys.js","webpack:///./src/maasserver/static/js/angular/factories/staticroutes.js","webpack:///./src/maasserver/static/js/angular/factories/subnets.js","webpack:///./src/maasserver/static/js/angular/factories/switches.js","webpack:///./src/maasserver/static/js/angular/factories/tags.js","webpack:///./src/maasserver/static/js/angular/factories/users.js","webpack:///./src/maasserver/static/js/angular/factories/vlans.js","webpack:///./src/maasserver/static/js/angular/factories/zones.js","webpack:///./src/maasserver/static/js/angular/filters/by_fabric.js","webpack:///./src/maasserver/static/js/angular/filters/by_space.js","webpack:///./src/maasserver/static/js/angular/filters/by_subnet.js","webpack:///./src/maasserver/static/js/angular/filters/by_vlan.js","webpack:///./src/maasserver/static/js/angular/filters/nodes.js","webpack:///./src/maasserver/static/js/angular/filters/order_by_date.js","webpack:///./src/maasserver/static/js/angular/filters/remove_default_vlan.js","webpack:///./src/maasserver/static/js/angular/maas.js","webpack:///./src/maasserver/static/js/angular/services/browser.js","webpack:///./src/maasserver/static/js/angular/services/converter.js","webpack:///./src/maasserver/static/js/angular/services/error.js","webpack:///./src/maasserver/static/js/angular/services/json.js","webpack:///./src/maasserver/static/js/angular/services/log.js","webpack:///./src/maasserver/static/js/angular/services/manager.js","webpack:///./src/maasserver/static/js/angular/services/managerhelper.js","webpack:///./src/maasserver/static/js/angular/services/pollingmanager.js","webpack:///./src/maasserver/static/js/angular/services/search.js","webpack:///./src/maasserver/static/js/angular/services/validation.js","webpack:///./src/maasserver/static/js/io.js","webpack:///./src/maasserver/static/js/os_distro_select.js","webpack:///./src/maasserver/static/js/prefs.js","webpack:///./src/maasserver/static/js/reveal.js","webpack:///./src/maasserver/static/js/shortpoll.js","webpack:///./src/maasserver/static/js/ui/maas-ui.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","r","value","n","__esModule","object","property","prototype","hasOwnProperty","p","s","angular","controller","$scope","DevicesManager","SubnetsManager","DomainsManager","ManagerHelperService","ValidationService","newDevice","cloneDevice","isObject","domain","interfaces","mac","ipAssignment","subnetId","ipAddress","getDefaultDomain","$parent","addDeviceScope","subnets","getItems","domains","viewable","error","ipAssignments","title","device","show","hide","$emit","nameHasError","length","validateHostname","macHasError","deviceInterface","validateMAC","ipHasError","validateIP","validateIPInNetwork","cidr","isNumber","subnet","getItemFromList","deviceHasError","externalIpError","staticIpError","addInterface","push","isPrimaryInterface","indexOf","deleteInterface","splice","cancel","save","addAnother","convertedDevice","hostname","primary_mac","extra_macs","forEach","nic","ip_assignment","ip_address","convertDeviceToProtocol","create","then","parseValidationError","loadManagers","addDomainScope","authoritative","validateDomainName","domainHasError","copy","convertDomainToProtocol","$http","ZonesManager","MachinesManager","GeneralManager","RegionConnection","addHardwareScope","model","zones","architectures","getData","hwe_kernels","default_min_hwe_kernel","power_types","macAddressRegex","machine","chassis","virshFields","label","field_type","default","choices","required","defaultArchitecture","newMachine","cloneMachine","macs","zone","architecture","min_hwe_kernel","power","type","parameters","text","newChassis","cloneChassis","chassisPowerTypes","description","fields","mode","startPolling","stopPolling","showMachine","showChassis","addMac","removeMac","idx","invalidName","validateMac","machineHasError","in_error","chassisHasErrors","power_type","field","isUndefined","powerParametersHasError","saveMachine","pxe_mac","shift","map","power_parameters","id","saveChassis","params","chassis_type","username","method","url","data","$","param","headers","Content-Type","loadManager","$on","$window","$rootScope","$routeParams","$location","DiscoveriesManager","VLANsManager","ConfigsManager","deviceIPOptions","page","loaded","discoveredDevices","machines","devices","configManager","networkDiscovery","column","selectedDevice","convertTo","predicate","last_seen","sortTable","reverse","proxyManager","updateItem","createItem","createInterface","Error","getDiscoveryName","discovery","getSubnetName","getName","getVLANName","vlanId","vlan","toggleSelected","deviceId","discovered","getDomainByName","slice","split","parent","goTo","saved","filter","option","preProcess","item","mac_address","ip","afterSave","obj","_removeItem","isString","path","search","tab","UsersManager","ErrorService","domainLoaded","displayname","isSuperUser","isDefaultDomain","canBeDeleted","rrsets","deleteButton","confirmingDelete","cancelDeleteButton","deleteConfirmButton","deleteDomain","activeDomain","getActiveItem","requestedDomain","parseInt","domain_id","isNaN","raiseError","setActiveItem","$filter","currentpage","loading","addDomain","cancelAddDomain","FabricsManager","SpacesManager","ControllersManager","fabricLoaded","fabric","$watch","updateVLANs","rows","racks","vlans","space","space_name","row","vlan_name","subnet_name","rack_sids","rack_sid","rack","system_id","keys","key","fabricManager","editSummary","controllers","enterEditSummary","exitEditSummary","isDefaultFabric","deleteFabric","reply","activeFabric","requestedFabric","fabric_id","BootResourcesManager","bootResources","autoImport","isArray","resources","PackageRepositoriesManager","repoManager","hasImages","maasName","upstreamDNS","mainArchive","portsArchive","httpProxy","skip","clickContinue","welcomeInError","form","$maasForm","hasErrors","networkInError","inError","objs","canContinue","force","location","reload","MAAS_config","completed_intro","managers","repo","user","sshkeys_count","markIntroComplete","user_completed_intro","getAuthUser","filterByVLAN","filterByFabric","filterBySpace","filterByNullSpace","getURLParameters","by","groupBy","ADD_FABRIC_ACTION","selectedTitle","objectName","ADD_VLAN_ACTION","ADD_SPACE_ACTION","ADD_SUBNET_ACTION","subnetManager","fabrics","spaceManager","spaces","vlanManager","group","orphanVLANs","actionObjectInitializers","vlan_ids","updateGroupBy","previous_space","index","updateOrphanVLANs","previous_fabric","previous_vlan","fabric_name","updateFabricsGroupBy","updateActions","actionOptions","actionChanged","newObject","actionOption","cancelAction","getFabricNameById","fabricId","actionSubnetPreSave","$interval","TagsManager","ServicesManager","ScriptsManager","DEVICE_IP_ASSIGNMENT","external","dynamic","static","updateTitle","node","fqdn","updateHeader","header","editing","editing_domain","options","selected","updateAvailableActionOptions","action","availableOptions","allOptions","getAllActionOptions","node_type","actions","updatePower","bmc_node_count","power_bmc_node_count","canEdit","updateSummary","summary","tags","hasUsableArchitectures","hasInvalidArchitecture","updateServices","isController","services","getServices","service","updateDevices","child","nicIdx","deviceWithMAC","links","link","lIdx","deviceWithLink","nodeLoaded","$watchCollection","storageController","networkingController","showing_confirmation","osinfo","section","area","osSelection","osystem","release","hwe_kernel","commissionOptions","enableSSH","skipNetworking","skipStorage","updateFirmware","configureHBA","commissioningSelection","testSelection","releaseOptions","checkingPower","scripts","getDeviceIPAssignment","events","limit","0","1","2","3","4","updateNode","queryPower","nodesManager","checkPowerState","console","log","tagsAutocomplete","query","autocomplete","getPowerStateClass","power_state","getPowerStateText","canCheckPowerState","isUbuntuOS","isUbuntuCoreOS","isCustomOS","isActionError","isDeployError","missing_osinfo","osystems","isSSHKeyError","getSSHKeyCount","optionChanged","actionCancel","actionGo","extra","distro_series","enable_ssh","skip_networking","skip_storage","commissioning_scripts","testing_scripts","status_code","erase","secure_erase","secureErase","quick_erase","quickErase","performAction","$reset","getArchitecturePlaceholder","isDevice","invalidArchitecture","isRackControllerConnected","isLocked","locked","editHeaderDomain","editHeader","editHeaderInvalid","cancelEditHeader","saveEditHeader","cancelEditSummary","saveEditSummary","tag","invalidPowerType","editPower","cancelEditPower","saveEditPower","allowShowMoreEvents","showMoreEvents","getEventText","event","getPowerEventError","level","hasPowerEventError","getPowerEventErrorText","hasActionPowerError","actionName","hasPowerError","missing_packages","getPowerErrors","result","packages","sort","getServiceClass","status","hasCustomCommissioningScripts","script_type","controllerLoaded","scope","showFailedTestWarning","testing_status","getCPUSubtext","cpu_count","cpu_speed","type_name","type_name_title","activeNode","originalInterfaces","filtered","usedVLANs","inter","parents","vlan_id","childInterface","found","link_id","interfaceType","vid","modes","isFunction","getValue","this","nicType","allowLinkUp","JSONService","INTERFACE_TYPE","PHYSICAL","BOND","BRIDGE","VLAN","ALIAS","INTERFACE_TYPE_TEXTS","physical","bond","bridge","alias","LINK_MODE","AUTO","STATIC","DHCP","LINK_UP","LINK_MODE_TEXTS","auto","dhcp","link_up","SELECTION_MODE","NONE","SINGLE","MULTI","DELETE","ADD","CREATE_BOND","CREATE_BRIDGE","CREATE_PHYSICAL","EDIT","IP_ASSIGNMENT","updateLoaded","nodeHasLoaded","managersHaveLoaded","updateInterfaces","vlanTable","addedVlans","children","editInterface","selectedMode","formatted","members","vlanRecord","primary_rack","secondary_rack","sort_key","getVLANText","a","b","localeCompare","nic_copy","subnet_id","interfaceLinksMap","linkMaps","newInterface","parentId","linkId","newParent","iType","isAlias","isVLAN","canAddAlias","canAddVLAN","addTypeChanged","leaveSingleSelectionMode","updateNewInterface","mapNICToOriginalLink","nic_id","originalInteface","getDefaultVLAN","default_vlan_id","getUnusedVLANs","ignoreVLANs","getSelectedInterfaces","selectedInterfaces","splitKey","getNextName","prefix","tableInfo","interfaceErrorsByLinkId","newBondInterface","newBridgeInterface","bondOptions","isLimitedEditingAllowed","isAllNetworkingDisabled","isBootInterface","is_boot","getInterfaceTypeText","isDefined","getLinkModeText","getSubnetText","getSubnet","isInterfaceNameInvalid","otherNic","isLinkModeDisabled","getInterfaceError","isIPAddressInvalid","getUniqueKey","toggleInterfaceSelect","isInterfaceSelected","cannotEditInterface","isEditing","edit","undefined","defaultSubnet","fabricChanged","vlanChanged","fabricChangedForm","updateValue","vlanChangedForm","subnetChanged","subnetChangedForm","modeChanged","modeChangedForm","originalLink","editCancel","preProcessInterface","interface_id","saveInterface","updateInterface","saveInterfaceLink","linkSubnet","editSave","isShowingDeleteConfirm","isShowingAdd","canAddAliasOrVLAN","canAddAnotherVLAN","getRemoveTypeText","canBeRemoved","remove","quickRemove","confirmRemove","unlinkSubnet","add","defaultVLAN","defaultMode","quickAdd","getAddName","aliasIdx","createVLANInterface","isDisabled","canCreateBond","isShowingCreateBond","showCreateBond","primary","lacpRate","xmitHashPolicy","hasBootInterface","getInterfacePlaceholderMACAddress","isMACAddressInvalid","invalidEmpty","showLACPRate","showXMITHashPolicy","cannotAddBond","addBond","bond_mode","bond_lacp_rate","bond_xmit_hash_policy","createBondInterface","canCreateBridge","isShowingCreateBridge","showCreateBridge","bridge_stp","bridge_fd","cannotAddBridge","addBridge","createBridgeInterface","isShowingCreatePhysical","showCreatePhysical","macError","errorMsg","cannotAddPhysicalInterface","addPhysicalInterface","createPhysicalInterface","errorStr","tryParse","disks","availableNew","single","disk","ConverterService","MIN_PARTITION_SIZE","MUTLI","UNMOUNT","UNFORMAT","FORMAT_AND_MOUNT","PARTITION","BCACHE","RAID","VOLUME_GROUP","LOGICAL_VOLUME","RAID_MODES","min_disks","allows_spares","calculateSize","minSize","numDisks","hasMountedFilesystem","filesystem","mount_point","hasFormattedUnmountedFilesystem","fstype","isInUse","is_format_fstype","available_size","getTags","cache_set_id","block_id","partition_id","updateDisks","used","cachesets","filesystems","has_disks","size_human","mount_options","filesystem_id","original_type","original","parent_type","partitions","partition","special_filesystems","oldFilesystem","filesystemsMap","$selected","updateFilesystemSelection","used_by","used_for","cacheset","oldCacheSet","cachesetsMap","updateCacheSetsSelection","available","has_partitions","available_size_human","used_size_human","serial","test_status","firmware_version","oldDisk","availableMap","$options","newDevices","updateAvailableSelection","updateAvailable","filesystemMode","filesystemAllSelected","cachesetsMode","cachesetsAllSelected","availableMode","availableAllSelected","deselectAll","items","capitalizeFirstLetter","string","charAt","toUpperCase","getIndexFromName","match","RegExp","exec","dIdx","Math","max","isNameAlreadyInUse","exclude_disk","j","isLogicalVolume","showMembers","isBootDiskDisabled","setAsBootDisk","setBootDisk","getSelectedFilesystems","toggleFilesystemSelect","toggleFilesystemAllSelect","isFilesystemsDisabled","isAllStorageDisabled","filesystemCancel","filesystemUnmount","quickFilesystemUnmount","filesystemConfirmUnmount","updateFilesystem","filesystemDelete","quickFilesystemDelete","filesystemConfirmDelete","unmountSpecialFilesystem","deletePartition","deleteFilesystem","hasUnmountedFilesystem","showFreeSpace","getDeviceType","getSelectedAvailable","toggleAvailableSelect","toggleAvailableAllSelect","isAvailableDisabled","canFormatAndMount","getPartitionButtonText","availablePartitionSpace","space_to_reserve","partition_table_type","INITIAL_PARTITION_OFFSET","roundByBlockSize","canAddPartition","isNameInvalid","nameHasChanged","parentName","availableCancel","usesMountPoint","usesStorage","isMountPointInvalid","mountPoint","canDelete","used_size","availableDelete","availableQuickDelete","availableEdit","editingTags","editingFilesystem","availableQuickEdit","availableConfirmEdit","mountOptions","updateDisk","availableConfirmDelete","deleteVolumeGroup","deleteDisk","availablePartition","size_and_units","size","sizeUnits","availableQuickPartition","getAddPartitionName","isAddPartitionSizeInvalid","test","bytes","unitsToBytes","roundUnits","availableConfirmPartition","removeDisk","available_space","createPartition","getSelectedCacheSets","toggleCacheSetSelect","toggleCacheSetAllSelect","isCacheSetsDisabled","cacheSetCancel","canDeleteCacheSet","cacheSetDelete","quickCacheSetDelete","cacheSetConfirmDelete","deleteCacheSet","canCreateCacheSet","createCacheSet","getCannotCreateBcacheMsg","canCreateBcache","createBcache","cacheMode","fstypeChanged","isNewDiskNameInvalid","createBcacheCanSave","availableConfirmCreateBcache","cache_set","cache_mode","canCreateRAID","createRAID","spares","getAvailableRAIDModes","getTotalNumberOfAvailableSpares","diff","getNumberOfRemainingSpares","allowed","showSparesColumn","RAIDModeChanged","isActiveRAIDMember","isSpareRAIDMember","setAsActiveRAIDMember","setAsSpareRAIDMember","getNewRAIDSize","Number","MAX_VALUE","deviceSize","min","bytesToUnits","createRAIDCanSave","availableConfirmCreateRAID","block_devices","spare_devices","spare_partitions","canCreateVolumeGroup","createVolumeGroup","getNewVolumeGroupSize","total","createVolumeGroupCanSave","availableConfirmCreateVolumeGroup","canAddLogicalVolume","availableLogicalVolume","namePrefix","isLogicalVolumeNameInvalid","newLogicalVolumeNameChanged","isAddLogicalVolumeSizeInvalid","availableConfirmLogicalVolume","createLogicalVolume","authUser","is_superuser","owner","hasStorageLayoutIssues","storage_layout_issues","SpecialFilesystem","isValid","startsWith","describe","parts","join","dropdown","addSpecialFilesystem","addSpecialFilesystemFinished","canMount","mount","mountSpecialFilesystem","EventsManagerFactory","eventsManager","getManager","days","getMaximumDays","loadItems","eventsLoaded","loadMore","loadMaximumDays","destroy","NodeResultsManagerFactory","nodeResultsManager","requestedResult","getItem","get_result_data","output","resultLoaded","updateLogs","had_installation","logs","installation_results","selectedLog","commissioning_results","testing_results","results","updateLogOutput","resultsLoaded","logOutput","getSummaryXML","getSummaryYAML","hlist","history_list","SearchService","SwitchesManager","isViewingSelected","tabs","toLowerCase","enterViewSelected","previous_search","leaveViewSelected","updateFilters","updateAllViewableChecked","filtered_items","allViewableChecked","clearAction","resetActionProgress","zoneSelection","shouldClearAction","selectedItems","removeEmptyFilter","updateActionErrorCount","actionErrorCount","supportsAction","action_failed","progress","actionProgress","completed","errors","affected_nodes","updateSelectedItems","hasActionsFailed","manager","unselectItem","hasActionsInProgress","nodes","switches","showswitches","pagetitle","searchValid","getSelectedItems","metadata","getMetadata","filters","getEmptyFilter","takeActionOptions","syncStatuses","addController","registerUrl","register_url","registerSecret","register_secret","addHardwareOption","addHardwareOptions","toggleTab","clearSearch","toggleChecked","isSelected","selectItem","toggleCheckAll","onNodeListingChanged","showSelected","toggleFilter","filtersToString","isFilterActive","getCurrentFilters","selectColumnOrSort","actionOptionSelected","zone_id","addErrorToActionProgress","addHardwareOptionChanged","addDevice","cancelAddDevice","statusPoll","storeFilters","nodesFilter","retrieveFilters","devicesFilter","controllersFilter","switchesFilter","PodsManager","pod","podManager","sentence","operation","bind","refresh","deleteItem","inProgress","compose","storage","boot","machinesSearch","editPodConfiguration","exitEditPodConfiguration","actionOptionChanged","getPodTypeTitle","canCompose","capabilities","composeMachine","composePreProcess","sorted","constraint","cancelCompose","composeAddStorage","composeSetBootDisk","composeRemoveDisk","startWatching","now","getDefaultZone","activePod","pods","filteredItems","open","powerTypes","action_error","addPod","cancelAddPod","getPowerTypeTitle","powerType","DHCPSnippetsManager","snippetsManager","snippets","known_architectures","pockets_to_disable","components_to_disable","packageRepositoriesManager","repositories","newSnippet","editSnippet","deleteSnippet","snippetTypes","newRepository","editRepository","deleteRepository","repositoryEnabledToggle","repository","repositoryEnterRemove","repositoryExitRemove","repositoryConfirmRemove","isPPA","isMirror","repositoryEnterEdit","repositoryExitEdit","repositoryAdd","enabled","arches","distributions","components","repositoryAddCancel","getSnippetTypeText","snippet","getSnippetAppliesToObject","getSnippetAppliesToText","snippetEnterRemove","snippetExitRemove","snippetConfirmRemove","snippetEnterEdit","snippetExitEdit","snippetToggle","snippetAdd","snippetAddCancel","spaceLoaded","updateSubnets","isDefaultSpace","subnet_ids","deleteSpace","activeSpace","requestedSpace","space_id","source","version","StaticRoutesManager","active_discovery_data","active_discovery_interval","staticRoutes","staticRoutesManager","actionError","newStaticRoute","editStaticRoute","deleteStaticRoute","MAP_SUBNET_ACTION","DELETE_ACTION","ALLOC_TYPES","5","6","NODE_TYPES","updateIPVersion","ipVersion","subnetLoaded","updateFabric","ipSort","ipv4ToInteger","ipv6Expand","getAllocType","allocType","str","getSubnetCIDR","destId","allocTypeSort","alloc_type","getUsageForIP","node_summary","nodeType","bmcs","dns_records","nodeTypeSort","ownerSort","sortIPTable","actionRetry","scanSubnet","scan_started_on","deleteSubnet","subnetPreSave","changedFields","addStaticRoute","gateway_ip","destination","metric","cancelAddStaticRoute","isStaticRouteInEditMode","route","staticRouteToggleEditMode","isStaticRouteInDeleteMode","staticRouteEnterDeleteMode","staticRouteCancelDelete","staticRouteConfirmDelete","choice","activeSubnet","requestedSubnet","objects","self","vm","updateManagementRacks","primaryRack","secondaryRack","updateRelatedControllers","relatedControllers","updateRelatedSubnets","relatedSubnets","updatePossibleActions","relay_vlan","RELAY_DHCP_ACTION","DISABLE_DHCP_ACTION","dhcp_on","PROVIDE_DHCP_ACTION","isFabricDefault","vlanLoaded","provideDHCPAction","getSpaceName","getActionByName","initProvideDHCP","forRelay","relayVLAN","maxIPs","startIP","endIP","gatewayIP","needsDynamicRange","iprange","statistics","suggested_dynamic_range","needsGatewayIP","subnetMissingGatewayIP","updatePrimaryRack","updateSecondaryRack","updateSubnet","filterPrimaryRack","suggested_gateway","num_addresses","startPlaceholder","start","endPlaceholder","end","gatewayPlaceholder","canPerformAction","gateway","configureDHCP","extraDHCP","relay","disableDHCP","deleteVLAN","getFullVLANName","getDHCPStatus","activeVLAN","requestedVLAN","zoneLoaded","zoneManager","isDefaultZone","activeZone","requestedZone","addZone","closeZone","directive","restrict","element","attrs","clickHandler","evt","toggleClass","find","on","off","template","$element","$document","design","templateUrl","files_version","saving","stopping","ubuntuImages","isNew","tooMany","showingAdvanced","connecting","errorMessage","source_type","keyring_filename","keyring_data","releases","selections","changed","ubuntuCoreImages","ubuntu_core","images","otherImages","other","generatedImages","customImages","ubuntuDeleteId","removingImage","getTitleIcon","showMirrorPath","isShowingAdvancedOptions","toggleAdvancedOptions","bothKeyringOptionsSet","showConnectButton","sourceChanged","currentSources","ubuntu","sources","prevNew","updateSource","regenerateUbuntuImages","connect","isConnectButtonDisabled","getSourceParams","selectDefaults","arch","fetch","fromJson","showConnectBlock","showSelections","getUbuntuLTSReleases","deleted","getUbuntuNonLTSReleases","getArchitectures","toggleSelection","showImagesTable","getResource","resource","resource_os","rtype","image","icon","beingDeleted","resourceId","downloading","name_split","regenerateUbuntuCoreImages","ubuntuCoreImage","checked","regenerateOtherImages","otherImage","_regenerateImages","image_id","regenerateGeneratedImages","regenerateCustomImages","ltsIsSelected","commissioningSeriesSelected","commissioning_series","cancelRemove","deleteImage","showStopImportButton","region_import_running","showSaveSelection","canSaveSelection","commissioning_series_being_deleted","commissioning_series_arches","getSaveSelectionText","canStopImport","getStopImportText","stopImport","saveSelection","saveUbuntu","getNewSelections","newObjs","oldSelections","newSelections","selection","source_len","toggleUbuntuCoreSelection","saveUbuntuCoreSelection","saveUbuntuCore","toggleOtherSelection","saveOtherSelection","saveOther","confirmDeleteImage","ready","ubuntu_core_images","other_images","run","$templateCache","put","replace","require","maasCta","ngModel","ngModelCtrl","defaultTitle","select","shown","$setViewValue","getTitle","$modelValue","secondary","getOptionTitle","$viewChangeListeners","$eval","ngChange","stopPropagation","$apply","$compile","include","maasCardLoader","html","contents","maasCodeLines","attributes","empty","lines","newLine","insert","each","ngDisabled","maasEditing","focusHandler","blur","changeHandler","$render","$viewValue","unbind","$timeout","statuses","updateStatuses","controllerIds","checkImageStates","register","known","runningInterval","startTimeout","CHECK_INTERVAL","unregister","showSpinner","getImageStatus","ControllerImageStatusService","systemId","unwatch","registered","textOnly","getClass","countClass","classes","class_name","counter","updateStatusClass","serviceClass","serviceText","styleElement","document","createElement","innerHTML","getElementsByTagName","appendChild","BrowserService","transclude","maasDblClickOverlay","clickElement","overlay","tagName","createEvent","initMouseEvent","window","dispatchEvent","css","cursor","triggerHandler","overlayClick","preventDefault","overlayDblClick","browser","addClass","which","maasEnter","jasmine","Image","src","markDisconnected","connected","showDisconnected","clientError","wasConnected","watchConnection","isConnected","_error","disconnectedPromise","cancelTimeout","watchConnectionAndError","removeClass","IPRangesManager","ipranges","iprangeManager","newRange","editIPRange","deleteIPRange","addRange","start_ip","end_ip","comment","cancelAddRange","ipRangeCanBeModified","range","isIPRangeInEditMode","ipRangeToggleEditMode","ipRangeClearEditMode","isIPRangeInDeleteMode","ipRangeEnterDeleteMode","ipRangeCancelDelete","ipRangeConfirmDelete","ipRangeSort","MAASFormController","savingKeys","managerMethod","cloneObject","clonedObj","isTableForm","tableForm","saveOnBlur","isSaving","showInputSaving","errorScope","registerField","unregisterField","startEditingField","stopEditingField","clearErrors","updatedObj","newObj","errorJson","errorField","setErrors","v","saveForm","newValue","inline","MAASGroupController","timeout","formController","keyIdx","pre","onChange","subtleText","subtle","missingAttrs","disableLabel","labelElement","attr","labelWidth","labelLeft","append","labelInfo","infoWrapper","infoIcon","infoTooltip","inputWrapper","inputWidth","placeholder","inputElement","blurOnEnter","val","currentValue","disabled","placeholderEnabled","childScope","$new","_ngDisabled","_selectValue","_selectNgChange","_change","values","checkScope","_selectedValues","_checked","_toggleChecked","tagsScope","_tags","switchScope","_toggle","_changed","onValue","offValue","inputClass","errorsElement","helpText","helpTextElement","setTimeout","focus","hasClass","subtleTextElement","removeAttr","ul","ele","macAddressFormat","numbers","$parsers","$formatters","hideCheckboxes","onListingChange","onCheckAll","onCheck","SPINNER_STATUSES","table","filteredMachines","updateAllChecked","$machine","showNodeStatus","other_test_status","getReleaseTitle","os_release","getStatusText","releaseTitle","trim","$machines","NotificationsManager","notifications","dismiss","categories","categoryTitles","warning","success","info","categoryClasses","categoryNotifications","cns","category","notification","maasOsSelect","getSelectableReleases","allChoices","getSelectableKernels","kernels","os","osKernels","getDefaultOrFirst","array","defaultValue","weightValue","first","weightedPresent","setDefault","default_osystem","default_release","kernel","selectedOSChanged","selectedReleaseChanged","ngPlaceholder","hideType","podTypes","fieldsElement","updateFields","podType","$destroy","maasObjForm","getType","driver_type","req","input_type","replaceWith","maasPowerParameters","$sce","enableHttpProxy","usePeerProxy","proxy_type","releaseName","setText","maasReleaseOptions","onEraseChange","globalOptions","startTime","runTime","estimatedRunTime","scriptStatus","incrementCounter","start_date","Date","setSeconds","seconds","floor","minutes","hours","new_counter","promise","$q","scriptType","allScripts","getScripts","script","tags_string","onTagAdding","refocus","tagsInput","tagsInputScope","isolateScope","eventHandlers","input","change","for_hardware","getIcon","SSHKeysManager","groupedKeys","authId","sourceTitles","lp","gh","upload","openRow","rowMode","trustAsHtml","close","canImportKeys","importKeys","protocol","auth_id","__all__","confirmDelete","keyMap","groupObj","keysource","keysourceKey","switchHasError","filteredSwitches","switch_","$switch_","$switches","$attr","isToggled","toggleMenu","target","ngType","valid_types","LogService","reloadPage","enableAutoReload","site","href","oldValue","onResize","windowWidth","innerWidth","message","factory","_loaded","_data","_polling","_nextPromise","_pollTimeout","_pollErrorTimeout","_pollEmptyTimeout","isLoaded","isPolling","_poll","_loadData","callMethod","newData","_pollAgain","pollTimeout","connection_error","defer","resolve","Manager","_pk","_handler","registerNotifier","onNotify","NodesManager","service_ids","service_id","_metadataAttributes","_replaceItem","PollingManager","_batchKey","_items","EventsManager","nodeId","_nodeId","_factory","_maxDays","_managers","_initBatchLoadParameters","node_id","max_days","destroyManager","setMaximumDays","isLoading","_getManager","machine_actions","polling","nextPromise","device_actions","region_controller_actions","rack_controller_actions","region_and_rack_controller_actions","min_hwe_kernels","replaceData","oldData","isEmpty","bond_options","newPowerType","oldPowerType","newItem","release_options","_autoReload","_type","_scopes","_getInternalData","isDataLoaded","isDataPolling","apply","waitingCount","_reloadFunc","registerHandler","disableAutoReload","unregisterHandler","storage_tags","NodeResultsManager","_node","hardware_type","_getStorageSubtext","deviceinfo","_updateObject","existing","updated","_addOrReplace","showing_results","showing_history","showing_menu","_processItem","result_section","result_type","subtext","hardware_type_results","physical_blockdevice","_getIndexOfItem","_updateMetadata","_removeItemByIdFromArray","_selectedItems","hw_type","ret","_area","has_surfaced","script_id","data_type","state","updateInterfaceForm","volume_group_id","blockdevice_id","partition_size","$cookies","MSG_TYPE","RESPONSE_TYPE","callbacks","requests","requestId","websocket","autoReconnect","retryTimeout","defaultConnectDefer","handlers","notifiers","newRequestId","func","unregisterNotifier","buildSocket","WebSocket","_buildUrl","onopen","onerror","onclose","onmessage","onMessage","_getProtocol","host","port","pathname","proto","csrftoken","base","newPath","newPort","encodeURIComponent","defaultConnect","opened","errored","reject","msg","onResponse","request_id","remembered_request","request","handler","remember","send","toJson","getLargestRange","largest_range","ranges","equals","purpose","hasDynamicRange","matching","_authUser","authuser","_loadAuthUser","reloadItems","addRackController","foreign_objects","standardFilter","mappings","cpu","cores","ram","memory","pod-id","isInteger","matches","lowerTerm","exact","negate","parseFloat","_matches","terms","term","matched","mapFunc","substring","no_match","field2","aDate","bDate","getTime","config","$interpolateProvider","$routeProvider","$httpProvider","versionedPath","startSymbol","endSymbol","defaults","xsrfCookieName","xsrfHeaderName","routes","when","redirectTo","reloadOnSearch","controllerAs","superuser","otherwise","next","current","ga","q","arguments","userId","analytics_user_id","uuid","hash","regex","matcher","navigator","userAgent","UNITS","unit","converted","abs","toFixed","units","block_size","ipv4ToOctets","octets","part","pow","expandedAddress","groups","substr","ipv6ToGroups","jsonString","JSON","parse","_typeof","e","logging","logLevel","performance","_debug","debug","_log","_info","_warn","warn","formatMilliseconds","milliseconds","__log","args","Array","unshift","METADATA_ACTIONS","CREATE","UPDATE","_name_field","_isLoading","_extraLoadDefers","_extraReloadDefers","_actionQueue","_activeItem","_metadata","pk_value","len","_replaceItemInArray","_batchLoadItems","extra_func","callLoad","_resolveDefers","defersArray","_rejectDefers","clear","processActions","updatedIdx","updatedItem","updateItems","clearActiveItem","canProcessActions","_getMetadataValue","metadatas","_addMetadataValue","count","_removeMetadataValue","_updateMetadataArrayEntry","added","oldArray","_updateMetadataValueEntry","_updateMetadataEntry","oldItem","loadedManagers","loadedManager","tryParsingJSON","SyntaxError","getPrintableString","dict","showNames","emptyFilter","_","getSplitSearch","fixedTerms","spanningParentheses","startIdx","searchTerms","_getFilterValueIndex","storedFilters","domainnamePattern","hostnamePattern","macPattern","ipv4Pattern","cidrMatcher","one","two","bits","domainname","macAddress","validateIPv4","validateIPv6","network","networkSplit","networkAddress","cidrBits","validateIPInRange","lowAddress","highAddress","ipOctets","lowOctets","highOctets","YUI","Y","namespace","getIO","io","IO","Cookie","requires","OSReleaseWidget","_io","maas","superclass","constructor","NAME","extend","Widget","initializer","cfg","initialSkip","bindTo","osNode","event_name","osValue","currentTarget","switchTo","newOSValue","all","sel","modifyOption","selectVisableOption","split_value","set","first_option","use","releaseWidget","os_distro_select","srcNode","render","TokenWidget","ATTRS","nb_tokens","readOnly","displayError","status_node","create_link","Node","spinnerNode","confirm","_x","_confirm","toString","bindDeleteRow","deleteToken","bindUI","requestKeys","token_key","QueryString","stringify","op","sync","hideSpinner","out","failure","uris","account_handler","createTokenFromKeys","consumer_key","token_secret","addToken","token","list","response","Reveal","get_style_int","attribute","getStyle","targetNode","linkNode","hideText","showText","quick","renderUI","reveal","syncUI","fire","setStyle","set_hidden_link","is_visible","new_text","set_visible_link","get_animation_duration","suggested_duration","create_slide_in","publisher","anim","Anim","duration","to","height","create_slide_out","content_node","new_height","script_entry","ShortPollManager","shortpoll_start_event","shortpoll_fail_event","MAX_SHORT_DELAY_FAILED_ATTEMPTS","SHORT_DELAY","LONG_DELAY","_repoll","uri","eventKey","valueFn","guid","Base","_started","_failed_attempts","_sequence","successPoll","responseText","failurePoll","_pollDelay","repoll","failed","delay","later","poll","that","Lang","isValue","poll_uri","dropdowns","click","openMenu","closeAllMenus","MAASUI","utils","fn","attachEvent","readyState","addEventListener","el","className","classList","toggle","existingIndex","contains","init","querySelectorAll","sublinks"],"mappings":"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","file":"maas-min.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Add Device Controller\n */\n\nangular.module('MAAS').controller('AddDeviceController', [\n    '$scope', 'DevicesManager', 'SubnetsManager', 'DomainsManager',\n    'ManagerHelperService', 'ValidationService', function(\n        $scope, DevicesManager, SubnetsManager, DomainsManager,\n        ManagerHelperService, ValidationService) {\n\n        // Set the addDeviceScope in the parent, so it can call functions\n        // in this controller.\n        var parentScope = $scope.$parent;\n        parentScope.addDeviceScope = $scope;\n\n        // Set initial values.\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.domains = DomainsManager.getItems();\n        $scope.viewable = false;\n        $scope.error = null;\n\n        // Device ip assignment options.\n        $scope.ipAssignments = [\n            {\n                name: \"external\",\n                title: \"External\"\n            },\n            {\n                name: \"dynamic\",\n                title: \"Dynamic\"\n            },\n            {\n                name: \"static\",\n                title: \"Static\"\n            }\n        ];\n\n        // Makes a new interface.\n        function makeInterface() {\n            return {\n                mac: \"\",\n                ipAssignment: null,\n                subnetId: null,\n                ipAddress: \"\"\n            };\n        }\n\n        // Makes a new device.\n        function newDevice(cloneDevice) {\n            if(angular.isObject(cloneDevice)) {\n                return {\n                    name: \"\",\n                    domain: cloneDevice.domain,\n                    interfaces: [makeInterface()]\n                };\n            } else {\n                return {\n                    name: \"\",\n                    domain: DomainsManager.getDefaultDomain(),\n                    interfaces: [makeInterface()]\n                };\n            }\n        }\n\n        // Input values.\n        $scope.device = null;\n\n        // Converts the device information from how it is held in the UI to\n        // how it is handled over the websocket.\n        function convertDeviceToProtocol(device) {\n            // Return the new object.\n            var convertedDevice = {\n                hostname: device.name,\n                domain: device.domain,\n                primary_mac: device.interfaces[0].mac,\n                extra_macs: [],\n                interfaces: []\n            };\n            var i;\n            for(i = 1; i < device.interfaces.length; i++) {\n                convertedDevice.extra_macs.push(device.interfaces[i].mac);\n            }\n            angular.forEach(device.interfaces, function(nic) {\n                convertedDevice.interfaces.push({\n                    mac: nic.mac,\n                    ip_assignment: nic.ipAssignment.name,\n                    ip_address: nic.ipAddress,\n                    \"subnet\": nic.subnetId\n                });\n            });\n            return convertedDevice;\n        }\n\n        // Called by the parent scope when this controller is viewable.\n        $scope.show = function() {\n            // Exit early if already viewable.\n            if($scope.viewable) {\n                return;\n            }\n            $scope.device = newDevice();\n            $scope.viewable = true;\n        };\n\n        // Called by the parent scope when this controller is hidden.\n        $scope.hide = function() {\n            $scope.viewable = false;\n\n            // Emit the hidden event.\n            $scope.$emit('addDeviceHidden');\n        };\n\n        // Returns true if the name is in error.\n        $scope.nameHasError = function() {\n            // If the name is empty don't show error.\n            if($scope.device === null || $scope.device.name.length === 0) {\n                return false;\n            }\n            return !ValidationService.validateHostname($scope.device.name);\n        };\n\n        // Returns true if the MAC is in error.\n        $scope.macHasError = function(deviceInterface) {\n            // If the MAC is empty don't show error.\n            if(deviceInterface.mac.length === 0) {\n                return false;\n            }\n            // If the MAC is invalid show error.\n            if(!ValidationService.validateMAC(deviceInterface.mac)) {\n                return true;\n            }\n            // If the MAC is the same as another MAC show error.\n            var i;\n            for(i = 0; i < $scope.device.interfaces.length; i++) {\n                var isSelf = $scope.device.interfaces[i] === deviceInterface;\n                if(!isSelf &&\n                    $scope.device.interfaces[i].mac === deviceInterface.mac) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Returns true if the IP address is in error.\n        $scope.ipHasError = function(deviceInterface) {\n            // If the IP is empty don't show error.\n            if(deviceInterface.ipAddress.length === 0) {\n                return false;\n            }\n            // If ip address is invalid, then exit early.\n            if(!ValidationService.validateIP(deviceInterface.ipAddress)) {\n                return true;\n            }\n            var i, inNetwork;\n            if(angular.isObject(deviceInterface.ipAssignment)){\n                if(deviceInterface.ipAssignment.name === \"external\") {\n                    // External IP address cannot be within a known subnet.\n                    for(i = 0; i < $scope.subnets.length; i++) {\n                        inNetwork = ValidationService.validateIPInNetwork(\n                            deviceInterface.ipAddress,\n                            $scope.subnets[i].cidr);\n                        if(inNetwork) {\n                            return true;\n                        }\n                    }\n                } else if(deviceInterface.ipAssignment.name === \"static\" &&\n                    angular.isNumber(deviceInterface.subnetId)) {\n                    // Static IP address must be within a subnet.\n                    var subnet = SubnetsManager.getItemFromList(\n                        deviceInterface.subnetId);\n                    inNetwork = ValidationService.validateIPInNetwork(\n                        deviceInterface.ipAddress, subnet.cidr);\n                    if(!inNetwork) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Return true when the device is missing information or invalid\n        // information.\n        $scope.deviceHasError = function() {\n            if($scope.device === null || $scope.device.name === '' ||\n                    $scope.nameHasError()) {\n                return true;\n            }\n\n            var i;\n            for(i = 0; i < $scope.device.interfaces.length; i++) {\n                var deviceInterface = $scope.device.interfaces[i];\n                if(deviceInterface.mac === '' ||\n                    $scope.macHasError(deviceInterface) ||\n                    !angular.isObject(deviceInterface.ipAssignment)) {\n                    return true;\n                }\n                var externalIpError = (\n                    deviceInterface.ipAssignment.name === \"external\" && (\n                        deviceInterface.ipAddress === '' ||\n                        $scope.ipHasError(deviceInterface)));\n                var staticIpError = (\n                    deviceInterface.ipAssignment.name === \"static\" && (\n                        !angular.isNumber(deviceInterface.subnetId) ||\n                        $scope.ipHasError(deviceInterface)));\n                if(externalIpError || staticIpError) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Adds new interface to device.\n        $scope.addInterface = function() {\n            $scope.device.interfaces.push(makeInterface());\n        };\n\n        // Returns true if the first interface in the device interfaces array.\n        $scope.isPrimaryInterface = function(deviceInterface) {\n            return $scope.device.interfaces.indexOf(deviceInterface) === 0;\n        };\n\n        // Removes the interface from the devices interfaces array.\n        $scope.deleteInterface = function(deviceInterface) {\n            // Don't remove the primary.\n            if($scope.isPrimaryInterface(deviceInterface)) {\n                return;\n            }\n            $scope.device.interfaces.splice(\n                $scope.device.interfaces.indexOf(deviceInterface), 1);\n        };\n\n        // Called when cancel clicked.\n        $scope.cancel = function() {\n            $scope.error = null;\n            $scope.device = newDevice();\n            $scope.hide();\n        };\n\n        // Called when save is clicked.\n        $scope.save = function(addAnother) {\n            // Do nothing if device in error.\n            if($scope.deviceHasError()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the device.\n            $scope.error = null;\n\n            // Create the device.\n            var device = convertDeviceToProtocol($scope.device);\n            DevicesManager.create(device).then(function(device) {\n                if(addAnother) {\n                    $scope.device = newDevice($scope.device);\n                } else {\n                    $scope.device = newDevice();\n                    // Hide the scope if not adding another.\n                    $scope.hide();\n                }\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load subnets to get the available subnets.\n        ManagerHelperService.loadManagers(\n            $scope, [SubnetsManager, DomainsManager]).then(function() {\n                // Initial device.\n                $scope.device = newDevice();\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Add Domain Controller\n */\n\nangular.module('MAAS').controller('AddDomainController', [\n    '$scope', 'DomainsManager', 'ManagerHelperService',\n    'ValidationService', function($scope, DomainsManager,\n        ManagerHelperService, ValidationService) {\n\n        // Set the addDomainScope in the parent, so it can call functions\n        // in this controller.\n        var parentScope = $scope.$parent;\n        parentScope.addDomainScope = $scope;\n\n        // Set initial values.\n        $scope.viewable = false;\n        $scope.error = null;\n\n        // Makes a new domain.\n        function makeDomain() {\n            return {\n                name: \"\",\n                authoritative: true\n            };\n        }\n\n        // Initial domain.\n        $scope.domain = makeDomain();\n\n        // Converts the domain information from how it is held in the UI to\n        // how it is handled over the websocket.  Since they're identical, we\n        // just return a copy: some day, they might be different, so we retain\n        // the function against that day.\n        function convertDomainToProtocol(domain) {\n            return angular.copy(domain);\n        }\n\n        // Called by the parent scope when this controller is viewable.\n        $scope.show = function() {\n            // Exit early if already viewable.\n            if($scope.viewable) {\n                return;\n            }\n            $scope.domain = makeDomain();\n            $scope.viewable = true;\n        };\n\n        // Called by the parent scope when this controller is hidden.\n        $scope.hide = function() {\n            $scope.viewable = false;\n\n            // Emit the hidden event.\n            $scope.$emit('addDomainHidden');\n        };\n\n        // Returns true if the name is in error.\n        $scope.nameHasError = function() {\n            // If the name is empty don't show error.\n            if($scope.domain.name.length === 0) {\n                return false;\n            }\n            return !ValidationService.validateDomainName($scope.domain.name);\n        };\n\n        // Return true when the domain is missing information or invalid\n        // information.\n        $scope.domainHasError = function() {\n            if($scope.domain.name === '' || $scope.nameHasError()) {\n                return true;\n            }\n\n            return false;\n        };\n\n        // Called when cancel clicked.\n        $scope.cancel = function() {\n            $scope.error = null;\n            $scope.domain = makeDomain();\n            $scope.hide();\n        };\n\n        // Called when save is clicked.\n        $scope.save = function(addAnother) {\n            // Do nothing if domain in error.\n            if($scope.domainHasError()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the domain.\n            $scope.error = null;\n\n            // Create the domain.\n            var domain = convertDomainToProtocol($scope.domain);\n            DomainsManager.create(domain).then(function() {\n                $scope.domain = makeDomain();\n                if(!addAnother) {\n                    // Hide the scope if not adding another.\n                    $scope.hide();\n                }\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n    }]);\n","/* Copyright 2015-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Add Hardware Controller\n */\n\nangular.module('MAAS').controller('AddHardwareController', [\n    '$scope', '$http', 'ZonesManager', 'MachinesManager',\n    'GeneralManager', 'DomainsManager', 'RegionConnection',\n    'ManagerHelperService', 'ValidationService', function(\n        $scope, $http, ZonesManager, MachinesManager,\n        GeneralManager, DomainsManager, RegionConnection,\n        ManagerHelperService, ValidationService) {\n\n        // Set the addHardwareScope in the parent, so it can call functions\n        // in this controller.\n        var parentScope = $scope.$parent;\n        parentScope.addHardwareScope = $scope;\n\n        // Set initial values.\n        $scope.viewable = false;\n        $scope.model = 'machine';\n        $scope.zones = ZonesManager.getItems();\n        $scope.domains = DomainsManager.getItems();\n        $scope.architectures = GeneralManager.getData(\"architectures\");\n        $scope.hwe_kernels = GeneralManager.getData(\"hwe_kernels\");\n        $scope.default_min_hwe_kernel = GeneralManager.getData(\n            \"default_min_hwe_kernel\");\n        $scope.power_types = GeneralManager.getData(\"power_types\");\n        $scope.error = null;\n        $scope.macAddressRegex = /^([0-9A-F]{2}[::]){5}([0-9A-F]{2})$/gmi;\n\n        // Input values.\n        $scope.machine = null;\n        $scope.chassis = null;\n\n        // Hard coded chassis types. This is because there is no method in\n        // MAAS to get a full list of supported chassis. This needs to be\n        // fixed ASAP.\n        var virshFields = [\n            {\n                name: 'hostname',\n                label: 'Address',\n                field_type: 'string',\n                \"default\": '',  // Using \"default\" to make lint happy.\n                choices: [],\n                required: true\n            },\n            {\n                name: 'password',\n                label: 'Password',\n                field_type: 'string',\n                \"default\": '',\n                choices: [],\n                required: false\n            },\n            {\n                name: 'prefix_filter',\n                label: 'Prefix filter',\n                field_type: 'string',\n                \"default\": '',\n                choices: [],\n                required: false\n            }\n        ];\n        $scope.chassisPowerTypes = [\n            {\n                name: 'mscm',\n                description: 'Moonshot Chassis Manager',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Host',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'powerkvm',\n                description: 'PowerKVM',\n                fields: virshFields\n            },\n            {\n                name: 'recs_box',\n                description: 'Christmann RECS|Box',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Hostname',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'port',\n                        label: 'Port',\n                        field_type: 'string',\n                        \"default\": '80',\n                        choices: [],\n                        required: false\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'seamicro15k',\n                description: 'SeaMicro 15000',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Hostname',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'power_control',\n                        label: 'Power Control',\n                        field_type: 'choice',\n                        \"default\": 'restapi2',\n                        choices: [\n                            ['restapi2', 'REST API V2.0'],\n                            ['restapi', 'REST API V0.9'],\n                            ['ipmi', 'IPMI']\n                        ],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'ucsm',\n                description: 'UCS Chassis Manager',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'URL',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'virsh',\n                description: 'Virsh (virtual systems)',\n                fields: virshFields\n            },\n            {\n                name: 'vmware',\n                description: 'VMware',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Host',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'prefix_filter',\n                        label: 'Prefix filter',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: false\n                    }\n                ]\n            }\n        ];\n\n        // Get the default zone from the loaded zones.\n        function defaultZone() {\n            if($scope.zones.length === 0) {\n                return null;\n            } else {\n                return $scope.zones[0];\n            }\n        }\n\n        // Get the default architecture from the loaded architectures.\n        function defaultArchitecture() {\n            if($scope.architectures.length === 0) {\n                return '';\n            } else {\n                // Return amd64/generic first if available.\n                var i;\n                for(i = 0; i < $scope.architectures.length; i++) {\n                    if($scope.architectures[i] === \"amd64/generic\") {\n                        return $scope.architectures[i];\n                    }\n                }\n                return $scope.architectures[0];\n            }\n        }\n\n        // Return a new MAC address object.\n        function newMAC() {\n            return {\n                mac: '',\n                error: false\n            };\n        }\n\n        // Return a new machine object.\n        function newMachine(cloneMachine) {\n            // Clone the machine instead of just creating a new one.\n            // This helps the user by already having the previous selected\n            // items selected for the new machine.\n            if(angular.isObject(cloneMachine)) {\n                return {\n                    name: '',\n                    domain: cloneMachine.domain,\n                    macs: [newMAC()],\n                    zone: cloneMachine.zone,\n                    architecture: cloneMachine.architecture,\n                    min_hwe_kernel: cloneMachine.min_hwe_kernel,\n                    power: {\n                        type: cloneMachine.power.type,\n                        parameters: {}\n                    }\n                };\n            }\n\n            // No clone machine. So create a new blank machine.\n            return {\n                name: '',\n                domain: DomainsManager.getDefaultDomain(),\n                macs: [newMAC()],\n                zone: defaultZone(),\n                architecture: defaultArchitecture(),\n                min_hwe_kernel: $scope.default_min_hwe_kernel.text,\n                power: {\n                    type: null,\n                    parameters: {}\n                }\n            };\n        }\n\n        // Return a new chassis object.\n        function newChassis(cloneChassis) {\n            // Clone the chassis instead of just creating a new one.\n            // This helps the user by already having the previous selected\n            // items selected for the new machine.\n            if(angular.isObject(cloneChassis)) {\n                return {\n                    domain: cloneChassis.domain,\n                    power: {\n                        type: null,\n                        parameters: {}\n                    }\n                };\n            } else {\n                return {\n                    domain: DomainsManager.getDefaultDomain(),\n                    power: {\n                        type: null,\n                        parameters: {}\n                    }\n                };\n            }\n        }\n\n        // Converts the machine information from how it is held in the UI to\n        // how it is handled over the websocket.\n        function convertMachineToProtocol(machine) {\n            // Convert the mac addresses.\n            var macs = angular.copy(machine.macs);\n            var pxe_mac = macs.shift().mac;\n            var extra_macs = macs.map(function(mac) { return mac.mac; });\n\n            // Return the new object.\n            return {\n                hostname: machine.name,\n                domain: machine.domain,\n                architecture: machine.architecture,\n                min_hwe_kernel: machine.min_hwe_kernel,\n                pxe_mac: pxe_mac,\n                extra_macs: extra_macs,\n                power_type: machine.power.type.name,\n                power_parameters: angular.copy(machine.power.parameters),\n                zone: {\n                    id: machine.zone.id,\n                    name: machine.zone.name\n                }\n            };\n        }\n\n        // Validate that all the parameters are there for the given power type.\n        function powerParametersHasError(power_type, parameters) {\n            var i;\n            for(i = 0; i < power_type.fields.length; i++) {\n                var field = power_type.fields[i];\n                var value = parameters[field.name];\n                if(field.required) {\n                    if(angular.isUndefined(value) || value === '') {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        }\n\n        // Called by the parent scope when this controller is viewable.\n        $scope.show = function(mode) {\n            // Change the mode.\n            if($scope.mode !== mode) {\n                if($scope.mode === \"machine\") {\n                    $scope.machine = newMachine();\n                } else if($scope.mode === \"chassis\") {\n                    $scope.chassis = newChassis();\n                }\n                $scope.error = null;\n                $scope.mode = mode;\n            }\n\n            // Exit early if alreayd viewable.\n            if($scope.viewable) {\n                return;\n            }\n            $scope.viewable = true;\n\n            // Start the polling of architectures.\n            GeneralManager.startPolling($scope, \"architectures\");\n\n            // Start the polling of hwe_kernels.\n            GeneralManager.startPolling($scope, \"hwe_kernels\");\n        };\n\n        // Called by the parent scope when this controller is hidden.\n        $scope.hide = function() {\n            $scope.viewable = false;\n\n            // Stop the polling of architectures.\n            GeneralManager.stopPolling($scope, \"architectures\");\n\n            // Stop the polling of hwe_kernels.\n            GeneralManager.stopPolling($scope, \"hwe_kernels\");\n\n            // Emit the hidden event.\n            $scope.$emit('addHardwareHidden');\n        };\n\n        // Return True when architectures loaded and in machine mode.\n        $scope.showMachine = function() {\n            if($scope.architectures.length === 0) {\n                return false;\n            }\n            return $scope.mode === \"machine\";\n        };\n\n        // Return True when architectures loaded and in chassis mode.\n        $scope.showChassis = function() {\n            if($scope.architectures.length === 0) {\n                return false;\n            }\n            return $scope.mode === \"chassis\";\n        };\n\n        // Add a new MAC address to the machine.\n        $scope.addMac = function() {\n            $scope.machine.macs.push(newMAC());\n        };\n\n        // Remove a MAC address to the machine.\n        $scope.removeMac = function(mac) {\n            var idx = $scope.machine.macs.indexOf(mac);\n            if(idx > -1) {\n                $scope.machine.macs.splice(idx, 1);\n            }\n        };\n\n        // Return true if the machine name is invalid.\n        $scope.invalidName = function() {\n            // Not invalid if empty.\n            if($scope.machine.name.length === 0) {\n                return false;\n            }\n            return !ValidationService.validateHostname($scope.machine.name);\n        };\n\n        // Validate that the mac address is valid.\n        $scope.validateMac = function(mac) {\n            if(mac.mac === '') {\n                mac.error = false;\n            } else {\n                mac.error = !ValidationService.validateMAC(mac.mac);\n            }\n        };\n\n        // Return true when the machine is missing information or invalid\n        // information.\n        $scope.machineHasError = function() {\n            // Early-out for errors.\n            in_error = (\n                $scope.machine === null ||\n                $scope.machine.zone === null ||\n                $scope.machine.architecture === '' ||\n                $scope.machine.power.type === null ||\n                $scope.invalidName($scope.machine));\n            if(in_error) {\n                return in_error;\n            }\n\n            // Make sure none of the mac addresses are in error. The first one\n            // cannot be blank the remaining are allowed to be empty.\n            if($scope.machine.macs[0].mac === '' ||\n                $scope.machine.macs[0].error) {\n                return true;\n            }\n            var i;\n            for(i = 1; i < $scope.machine.macs.length; i++) {\n                var mac = $scope.machine.macs[i];\n                if(mac.mac !== '' && mac.error) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Return true if the chassis has errors.\n        $scope.chassisHasErrors = function() {\n            // Early-out for errors.\n            in_error = (\n                $scope.chassis === null ||\n                $scope.chassis.power.type === null);\n            if(in_error) {\n                return in_error;\n            }\n            return powerParametersHasError(\n                $scope.chassis.power.type, $scope.chassis.power.parameters);\n        };\n\n        // Called when the cancel button is pressed.\n        $scope.cancel = function() {\n            $scope.error = null;\n            $scope.machine = newMachine();\n            $scope.chassis = newChassis();\n\n            // Hide the controller.\n            $scope.hide();\n        };\n\n        // Called to perform the saving of the machine.\n        $scope.saveMachine = function(addAnother) {\n            // Does nothing if machine has errors.\n            if($scope.machineHasError()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the device.\n            $scope.error = null;\n\n            // Add the machine.\n            MachinesManager.create(\n                convertMachineToProtocol($scope.machine)).then(\n                    function() {\n                        if(addAnother) {\n                            $scope.machine = newMachine($scope.machine);\n                        } else {\n                            $scope.machine = newMachine();\n\n                            // Hide the scope if not adding another.\n                            $scope.hide();\n                        }\n                    }, function(error) {\n                        $scope.error =\n                            ManagerHelperService.parseValidationError(error);\n                    });\n        };\n\n        // Called to perform the saving of the chassis.\n        $scope.saveChassis = function(addAnother) {\n            // Does nothing if error exists.\n            if($scope.chassisHasErrors()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the device.\n            $scope.error = null;\n\n            // Create the parameters.\n            var params = angular.copy($scope.chassis.power.parameters);\n            params.chassis_type = $scope.chassis.power.type.name;\n            params.domain = $scope.chassis.domain.name;\n\n            // XXX ltrager 24-02-2016: Something is adding the username field\n            // even though its not defined in virshFields. The API rejects\n            // requests with improper fields so remove it before we send the\n            // request.\n            if(\n                    params.chassis_type === \"powerkvm\" ||\n                    params.chassis_type === \"virsh\") {\n                delete params.username;\n            }\n            // Add the chassis. For now we use the API as the websocket doesn't\n            // support probe and enlist.\n            $http({\n                method: 'POST',\n                url: 'api/2.0/machines/?op=add_chassis',\n                data: $.param(params),\n                headers: {\n                    'Content-Type': 'application/x-www-form-urlencoded'\n                }\n            }).then(function() {\n                if(addAnother) {\n                    $scope.chassis = newChassis($scope.chassis);\n                } else {\n                    $scope.chassis = newChassis();\n                    // Hide the scope if not adding another.\n                    $scope.hide();\n                }\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error.data);\n            });\n        };\n\n        // Load zones and domains. Once loaded create the first machine and\n        // chassis.\n        ManagerHelperService.loadManagers(\n            $scope, [ZonesManager, DomainsManager]).then(function() {\n                // Add the first machine and chassis.\n                $scope.machine = newMachine();\n                $scope.chassis = newChassis();\n            });\n\n        // Load the general manager.\n        ManagerHelperService.loadManager(\n            $scope, GeneralManager).then(function() {\n            if($scope.architectures.length > 0) {\n                // If the machine doesn't have an architecture\n                // set then it was created before all of the\n                // architectures were loaded. Set the default\n                // architecture for that machine.\n                if(angular.isObject($scope.machine) &&\n                    $scope.machine.architecture === '') {\n                    $scope.machine.architecture = defaultArchitecture();\n                }\n            }\n        });\n\n        // Stop polling when the scope is destroyed.\n        $scope.$on(\"$destroy\", function() {\n            GeneralManager.stopPolling($scope, \"architectures\");\n            GeneralManager.stopPolling($scope, \"hwe_kernels\");\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Dashboard Controller\n */\n\nangular.module('MAAS').controller('DashboardController', [\n    '$scope', '$window', '$rootScope', '$routeParams', '$location',\n    'DiscoveriesManager', 'DomainsManager', 'MachinesManager',\n    'DevicesManager', 'SubnetsManager', 'VLANsManager', 'ConfigsManager',\n    'ManagerHelperService',\n    function($scope, $window, $rootScope, $routeParams, $location,\n             DiscoveriesManager, DomainsManager, MachinesManager,\n             DevicesManager, SubnetsManager, VLANsManager, ConfigsManager,\n             ManagerHelperService) {\n\n        // Default device IP options.\n        var deviceIPOptions = [\n            ['static', 'Static'],\n            ['dynamic', 'Dynamic'],\n            ['external', 'External']\n        ];\n\n        // Set title and page.\n        $rootScope.title = \"Dashboard\";\n        $rootScope.page = \"dashboard\";\n\n        // Set initial values.\n        $scope.loaded = false;\n        $scope.discoveredDevices = DiscoveriesManager.getItems();\n        $scope.domains = DomainsManager.getItems();\n        $scope.machines = MachinesManager.getItems();\n        $scope.devices = DevicesManager.getItems();\n        $scope.configManager = ConfigsManager;\n        $scope.networkDiscovery = null;\n        $scope.column = 'mac';\n        $scope.selectedDevice = null;\n        $scope.convertTo = null;\n\n        // Set default predicate to last_seen.\n        $scope.predicate = $scope.last_seen;\n\n        // Sorts the table by predicate.\n        $scope.sortTable = function(predicate) {\n            $scope.predicate = predicate;\n            $scope.reverse = !$scope.reverse;\n        };\n\n        // Proxy manager that the maas-obj-form directive uses to call the\n        // correct method based on current type.\n        $scope.proxyManager = {\n            updateItem: function(params) {\n                if($scope.convertTo.type === 'device') {\n                    return DevicesManager.createItem(params);\n                } else if($scope.convertTo.type === 'interface') {\n                    return DevicesManager.createInterface(params);\n                } else {\n                    throw new Error(\"Unknown type: \" + $scope.convertTo.type);\n                }\n            }\n        };\n\n        // Return the name name for the Discovery.\n        $scope.getDiscoveryName = function(discovery) {\n            if(discovery.hostname === null) {\n                return 'unknown';\n            }\n            else {\n                return discovery.hostname;\n            }\n        };\n\n        // Get the name of the subnet from its ID.\n        $scope.getSubnetName = function(subnetId) {\n            var subnet = SubnetsManager.getItemFromList(subnetId);\n            return SubnetsManager.getName(subnet);\n        };\n\n        // Get the name of the VLAN from its ID.\n        $scope.getVLANName = function(vlanId) {\n            var vlan = VLANsManager.getItemFromList(vlanId);\n            return VLANsManager.getName(vlan);\n        };\n\n        // Sets selected device\n        $scope.toggleSelected = function(deviceId) {\n            if($scope.selectedDevice === deviceId) {\n                $scope.selectedDevice = null;\n            } else {\n                var discovered = DiscoveriesManager.getItemFromList(deviceId);\n                var hostname = $scope.getDiscoveryName(discovered);\n                var domain;\n                if(hostname === 'unknown') {\n                    hostname = '';\n                }\n                if(hostname.indexOf('.') > 0) {\n                    domain = DomainsManager.getDomainByName(\n                        hostname.slice(hostname.indexOf('.') + 1));\n                    hostname = hostname.split(\".\", 1)[0];\n                    if(domain === null) {\n                        domain = DomainsManager.getDefaultDomain();\n                    }\n                } else {\n                    domain = DomainsManager.getDefaultDomain();\n                }\n                $scope.convertTo = {\n                    type: 'device',\n                    hostname: hostname,\n                    domain: domain,\n                    parent: null,\n                    ip_assignment: 'dynamic',\n                    goTo: false,\n                    saved: false,\n                    deviceIPOptions: deviceIPOptions.filter(\n                        function(option) {\n                            // Filter the options to not include static if\n                            // a subnet is not defined for this discovered\n                            // item.\n                            if(option[0] === 'static' &&\n                                !angular.isNumber(discovered.subnet)) {\n                                return false;\n                            } else {\n                                return true;\n                            }\n                        })\n                };\n                $scope.selectedDevice = deviceId;\n            }\n        };\n\n        // Called before the createItem is called to adjust the values\n        // passed over the call.\n        $scope.preProcess = function(item) {\n            var discovered = DiscoveriesManager.getItemFromList(\n                $scope.selectedDevice);\n            item = angular.copy(item);\n            if($scope.convertTo.type === 'device') {\n                item.primary_mac = discovered.mac_address;\n                item.extra_macs = [];\n                item.interfaces = [{\n                    mac: discovered.mac_address,\n                    ip_assignment: item.ip_assignment,\n                    ip_address: discovered.ip,\n                    subnet: discovered.subnet\n                }];\n            } else if($scope.convertTo.type === 'interface') {\n                item.mac_address = discovered.mac_address;\n                item.ip_address = discovered.ip;\n                item.subnet = discovered.subnet;\n            }\n            return item;\n        };\n\n        // Called after the createItem has been successful.\n        $scope.afterSave = function(obj) {\n            DiscoveriesManager._removeItem($scope.selectedDevice);\n            $scope.selectedDevice = null;\n            $scope.convertTo.hostname = obj.hostname;\n            $scope.convertTo.parent = obj.parent;\n            $scope.convertTo.saved = true;\n            if($scope.convertTo.goTo) {\n                if(angular.isString(obj.parent)) {\n                    $location.path('/node/' + obj.parent);\n                } else {\n                    $location.path('/nodes').search({tab: 'devices'});\n                }\n            }\n        };\n\n        // Load all the managers and get the network discovery config item.\n        ManagerHelperService.loadManagers($scope, [\n            DiscoveriesManager, DomainsManager, MachinesManager,\n            DevicesManager, SubnetsManager, VLANsManager, ConfigsManager]).then(\n            function() {\n                $scope.loaded = true;\n                $scope.networkDiscovery = ConfigsManager.getItemFromList(\n                    'network_discovery');\n            });\n    }\n]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Domain Details Controller\n */\n\nangular.module('MAAS').controller('DomainDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$location',\n    'DomainsManager', 'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $location,\n        DomainsManager, UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"domains\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.domain = null;\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.domain.displayname;\n        }\n\n        // Called when the domain has been loaded.\n        function domainLoaded(domain) {\n            $scope.domain = domain;\n            $scope.loaded = true;\n\n            updateTitle();\n        }\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if this is the default domain.\n        $scope.isDefaultDomain = function() {\n            if(angular.isObject($scope.domain)) {\n                return $scope.domain.id === 0;\n            }\n            return false;\n        };\n\n        // Called to check if the space can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.domain)) {\n                return $scope.domain.rrsets.length === 0;\n            }\n            return false;\n        };\n\n        // Called when the delete domain button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete domain button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete domain button is pressed.\n        $scope.deleteConfirmButton = function() {\n            DomainsManager.deleteDomain($scope.domain).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/domains\");\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers(\n            $scope, [DomainsManager, UsersManager]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this domain set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeDomain = DomainsManager.getActiveItem();\n            var requestedDomain = parseInt($routeParams.domain_id, 10);\n            if(isNaN(requestedDomain)) {\n                ErrorService.raiseError(\"Invalid domain identifier.\");\n            } else if(angular.isObject(activeDomain) &&\n                activeDomain.id === requestedDomain) {\n                domainLoaded(activeDomain);\n            } else {\n                DomainsManager.setActiveItem(\n                    requestedDomain).then(function(domain) {\n                        domainLoaded(domain);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Domains List Controller\n */\n\nangular.module('MAAS').controller('DomainsListController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', 'DomainsManager',\n    'UsersManager', 'ManagerHelperService',\n    function($scope, $rootScope, $routeParams, $filter, DomainsManager,\n        UsersManager, ManagerHelperService) {\n\n        // Load the filters that are used inside the controller.\n\n        // Set title and page.\n        $rootScope.title = \"DNS\";\n        $rootScope.page = \"domains\";\n\n        // Set initial values.\n        $scope.domains = DomainsManager.getItems();\n        $scope.currentpage = \"domains\";\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n        $scope.loading = true;\n\n        // This will hold the AddDomainController once it's initialized.  The\n        // controller will set this variable as it's always a child of this\n        // scope.\n        $scope.addDomainScope = null;\n\n        // Called when the add domain button is pressed.\n        $scope.addDomain = function() {\n            $scope.addDomainScope.show();\n        };\n\n        // Called when the cancel add domain button is pressed.\n        $scope.cancelAddDomain = function() {\n            $scope.addDomainScope.cancel();\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        ManagerHelperService.loadManagers(\n            $scope, [DomainsManager, UsersManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n        }\n    ]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Fabric Details Controller\n */\n\nangular.module('MAAS').controller('FabricDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'FabricsManager', 'VLANsManager', 'SubnetsManager', 'SpacesManager',\n    'ControllersManager',\n    'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $filter, $location,\n        FabricsManager, VLANsManager, SubnetsManager, SpacesManager,\n        ControllersManager,\n        UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        // Initial values.\n        $scope.fabric = null;\n        $scope.fabricManager = FabricsManager;\n        $scope.editSummary = false;\n        $scope.vlans = VLANsManager.getItems();\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.controllers = ControllersManager.getItems();\n        $scope.loaded = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.fabric.name;\n        }\n\n        // Called when the \"edit\" button is cliked in the fabric summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the fabric summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Called when the fabric has been loaded.\n        function fabricLoaded(fabric) {\n            if(angular.isObject(fabric)) {\n                $scope.fabric = fabric;\n                updateTitle();\n                $scope.$watch(\"vlans\", updateVLANs, true);\n                $scope.$watch(\"subnets\", updateVLANs, true);\n                $scope.$watch(\"controllers\", updateVLANs, true);\n                $scope.loaded = true;\n                // Initial table sort order.\n                $scope.predicate = \"['vlan_name', 'vlan.id', 'subnet_name']\";\n            }\n        }\n\n        // Generate a table that can easily be rendered in the view.\n        function updateVLANs() {\n            var rows = [];\n            var racks = {};\n            angular.forEach($filter('filter')(\n                    $scope.vlans, {fabric:$scope.fabric.id}, true),\n                    function(vlan) {\n                var subnets =\n                    $filter('filter')($scope.subnets, {vlan:vlan.id}, true);\n                if(subnets.length > 0) {\n                    angular.forEach(subnets, function(subnet) {\n                        var space = SpacesManager.getItemFromList(subnet.space);\n                        var space_name = (space === null) ?\n                            \"(undefined)\" : space.name;\n                        var row = {\n                            vlan: vlan,\n                            vlan_name: VLANsManager.getName(vlan),\n                            subnet: subnet,\n                            subnet_name: SubnetsManager.getName(subnet),\n                            space: space,\n                            space_name: space_name\n                        };\n                        rows.push(row);\n                    });\n                } else {\n                    // If there are no subnets, populate a row based on the\n                    // information we have (just the VLAN).\n                    var row = {\n                        vlan: vlan,\n                        vlan_name: VLANsManager.getName(vlan),\n                        subnet: null,\n                        subnet_name: null,\n                        space: null,\n                        space_name: null\n                    };\n                    rows.push(row);\n                }\n                // Enumerate racks for vlan.\n                angular.forEach(vlan.rack_sids, function(rack_sid) {\n                    var rack = ControllersManager.getItemFromList(rack_sid);\n                    if(angular.isObject(rack)) {\n                        racks[rack.system_id] = rack;\n                    }\n                });\n            });\n            $scope.rows = rows;\n            $scope.racks = Object.keys(racks).map(function(key) {\n                return racks[key];\n            });\n        }\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if this is the default Fabric\n        $scope.isDefaultFabric = function() {\n            if(!angular.isObject($scope.fabric)) {\n                return false;\n            }\n            return $scope.fabric.id === 0;\n        };\n\n        // Called to check if the space can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.fabric)) {\n                return $scope.fabric.id !== 0;\n            }\n            return false;\n        };\n\n        // Called when the delete fabric button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete fabric button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete fabric button is pressed.\n        $scope.deleteConfirmButton = function() {\n            FabricsManager.deleteFabric($scope.fabric).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/networks\");\n                $location.search('by', 'fabric');\n            }, function(reply) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(reply.error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            FabricsManager, VLANsManager, SubnetsManager, SpacesManager,\n            ControllersManager, UsersManager]).then(\n            function() {\n                // Possibly redirected from another controller that already had\n                // this fabric set to active. Only call setActiveItem if not\n                // already the activeItem.\n                var activeFabric = FabricsManager.getActiveItem();\n                var requestedFabric = parseInt($routeParams.fabric_id, 10);\n\n                if(isNaN(requestedFabric)) {\n                    ErrorService.raiseError(\"Invalid fabric identifier.\");\n                } else if(angular.isObject(activeFabric) &&\n                    activeFabric.id === requestedFabric) {\n                    fabricLoaded(activeFabric);\n                } else {\n                    FabricsManager.setActiveItem(\n                        requestedFabric).then(function(fabric) {\n                            fabricLoaded(fabric);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                }\n            });\n    }\n]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Images Controller\n */\n\nangular.module('MAAS').controller('ImagesController', [\n    '$rootScope', '$scope', 'BootResourcesManager',\n    'ConfigsManager', 'UsersManager', 'ManagerHelperService', function(\n        $rootScope, $scope, BootResourcesManager,\n        ConfigsManager, UsersManager, ManagerHelperService) {\n\n            $rootScope.page = \"images\";\n            $rootScope.title = \"Loading...\";\n\n            $scope.loading = true;\n            $scope.bootResources = BootResourcesManager.getData();\n            $scope.configManager = ConfigsManager;\n            $scope.autoImport = null;\n\n            // Return true if the user is a super user.\n            $scope.isSuperUser = function() {\n                return UsersManager.isSuperUser();\n            };\n\n            // Load the required managers.\n            ManagerHelperService.loadManagers(\n                $scope, [ConfigsManager, UsersManager]).then(function() {\n                $scope.autoImport = ConfigsManager.getItemFromList(\n                    \"boot_images_auto_import\");\n            });\n\n            // The boot-images directive will load the bootResources manager,\n            // we just watch until resources is set. That means the page is\n            // loaded.\n            $scope.$watch(\"bootResources.resources\", function() {\n                if(angular.isArray($scope.bootResources.resources)) {\n                    $scope.loading = false;\n                    $rootScope.title = \"Images\";\n                }\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Intro Controller\n */\n\nangular.module('MAAS').controller('IntroController', [\n    '$rootScope', '$scope', '$window', '$location',\n    'ConfigsManager', 'PackageRepositoriesManager', 'BootResourcesManager',\n    'ManagerHelperService',\n    function(\n        $rootScope, $scope, $window, $location,\n        ConfigsManager, PackageRepositoriesManager, BootResourcesManager,\n        ManagerHelperService) {\n\n            $rootScope.page = \"intro\";\n            $rootScope.title = \"Welcome\";\n\n            $scope.loading = true;\n            $scope.configManager = ConfigsManager;\n            $scope.repoManager = PackageRepositoriesManager;\n            $scope.bootResources = BootResourcesManager.getData();\n            $scope.hasImages = false;\n            $scope.maasName = null;\n            $scope.upstreamDNS = null;\n            $scope.mainArchive = null;\n            $scope.portsArchive = null;\n            $scope.httpProxy = null;\n\n            // Set the skip function on the rootScope to allow skipping the\n            // intro view.\n            $rootScope.skip = function() {\n                $scope.clickContinue(true);\n            };\n\n            // Return true if the welcome section is not in error.\n            $scope.welcomeInError = function() {\n                var form = $scope.maasName.$maasForm;\n                if(angular.isObject(form)) {\n                    return form.hasErrors();\n                } else {\n                    return false;\n                }\n            };\n\n            // Return true if the network section is in error.\n            $scope.networkInError = function() {\n                var inError = false;\n                var objs = [\n                    $scope.upstreamDNS,\n                    $scope.mainArchive,\n                    $scope.portsArchive,\n                    $scope.httpProxy];\n                angular.forEach(objs, function(obj) {\n                    var form = obj.$maasForm;\n                    if(angular.isObject(form) && form.hasErrors()) {\n                        inError = true;\n                    }\n                });\n                return inError;\n            };\n\n            // Return true if continue can be clicked.\n            $scope.canContinue = function() {\n                return (\n                    !$scope.welcomeInError() &&\n                    !$scope.networkInError() &&\n                    $scope.hasImages);\n            };\n\n            // Called when continue button is clicked.\n            $scope.clickContinue = function(force) {\n                if(angular.isUndefined(force)) {\n                    force = false;\n                }\n                if(force || $scope.canContinue()) {\n                    ConfigsManager.updateItem({\n                        'name': 'completed_intro',\n                        'value': true\n                    }).then(function() {\n                        // Reload the whole page so that the MAAS_config will be\n                        // set to the new value.\n                        $window.location.reload();\n                    });\n                }\n            };\n\n            // If intro has been completed redirect to '/'.\n            if(MAAS_config.completed_intro) {\n                $location.path('/');\n            } else {\n                // Load the required managers.\n                var managers = [ConfigsManager, PackageRepositoriesManager];\n                ManagerHelperService.loadManagers(\n                    $scope, managers).then(function() {\n                    $scope.loading = false;\n                    $scope.maasName = ConfigsManager.getItemFromList(\n                        \"maas_name\");\n                    $scope.upstreamDNS = ConfigsManager.getItemFromList(\n                        \"upstream_dns\");\n                    $scope.httpProxy = ConfigsManager.getItemFromList(\n                        \"http_proxy\");\n                    $scope.mainArchive = (\n                        PackageRepositoriesManager.getItems().filter(\n                            function(repo) {\n                                return (repo['default'] &&\n                                    repo.name === \"main_archive\");\n                            })[0]);\n                    $scope.portsArchive = (\n                        PackageRepositoriesManager.getItems().filter(\n                            function(repo) {\n                                return (repo['default'] &&\n                                    repo.name === \"ports_archive\");\n                            })[0]);\n                });\n\n                // Don't load the boot resources as the boot-images directive\n                // performs that action. Just watch and make sure that\n                // at least one resource exists before continuing.\n                $scope.$watch(\"bootResources.resources\", function() {\n                    if(angular.isArray($scope.bootResources.resources) &&\n                        $scope.bootResources.resources.length > 0) {\n                        $scope.hasImages = true;\n                    } else {\n                        $scope.hasImages = false;\n                    }\n                });\n            }\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Intro Controller\n */\n\nangular.module('MAAS').controller('IntroUserController', [\n    '$rootScope', '$scope', '$window', '$location',\n    'UsersManager', 'ManagerHelperService',\n    function(\n        $rootScope, $scope, $window, $location,\n        UsersManager, ManagerHelperService) {\n\n            $rootScope.page = \"intro\";\n            $rootScope.title = \"Welcome\";\n\n            $scope.loading = true;\n            $scope.user = null;\n\n            // Set the skip function on the rootScope to allow skipping the\n            // intro view.\n            $rootScope.skip = function() {\n                $scope.clickContinue(true);\n            };\n\n            // Return true if super user.\n            $scope.isSuperUser = function() {\n                return UsersManager.isSuperUser();\n            };\n\n            // Return true if continue can be clicked.\n            $scope.canContinue = function() {\n                return $scope.user.sshkeys_count > 0;\n            };\n\n            // Called when continue button is clicked.\n            $scope.clickContinue = function(force) {\n                if(angular.isUndefined(force)) {\n                    force = false;\n                }\n                if(force || $scope.canContinue()) {\n                    UsersManager.markIntroComplete().then(function() {\n                        // Reload the whole page so that the MAAS_config will\n                        // be set to the new value.\n                        $window.location.reload();\n                    });\n                }\n            };\n\n            // If intro has been completed redirect to '/'.\n            if(MAAS_config.user_completed_intro) {\n                $location.path('/');\n            } else {\n                // Load the required managers.\n                ManagerHelperService.loadManager(\n                    $scope, UsersManager).then(function() {\n                        $scope.loading = false;\n                        $scope.user = UsersManager.getAuthUser();\n                    });\n            }\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Networks List Controller\n */\n\nangular.module('MAAS').controller('NetworksListController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'SubnetsManager', 'FabricsManager', 'SpacesManager', 'VLANsManager',\n    'UsersManager', 'ManagerHelperService',\n    function($scope, $rootScope, $routeParams, $filter, $location,\n             SubnetsManager, FabricsManager, SpacesManager, VLANsManager,\n             UsersManager, ManagerHelperService) {\n\n        // Load the filters that are used inside the controller.\n        var filterByVLAN = $filter('filterByVLAN');\n        var filterByFabric = $filter('filterByFabric');\n        var filterBySpace = $filter('filterBySpace');\n        var filterByNullSpace = $filter('filterByNullSpace');\n\n        // Set title and page.\n        $rootScope.title = \"Subnets\";\n        $rootScope.page = \"networks\";\n\n        // Set the initial value of $scope.groupBy based on the URL\n        // parameters, but default to the 'fabric' groupBy if it's not found.\n        $scope.getURLParameters = function() {\n            if(angular.isString($location.search().by)) {\n                $scope.groupBy = $location.search().by;\n            } else {\n                $scope.groupBy = 'fabric';\n            }\n        };\n\n        $scope.ADD_FABRIC_ACTION = {\n            name: \"add_fabric\",\n            title: \"Fabric\",\n            selectedTitle: \"Add fabric\",\n            objectName: 'fabric'\n        };\n        $scope.ADD_VLAN_ACTION = {\n            name: \"add_vlan\",\n            title: \"VLAN\",\n            selectedTitle: \"Add VLAN\",\n            objectName: 'vlan'\n        };\n        $scope.ADD_SPACE_ACTION = {\n            name: \"add_space\",\n            title: \"Space\",\n            selectedTitle: \"Add space\",\n            objectName: 'space'\n        };\n        $scope.ADD_SUBNET_ACTION = {\n            name: \"add_subnet\",\n            title: \"Subnet\",\n            selectedTitle: \"Add subnet\",\n            objectName: 'subnet'\n        };\n\n        $scope.getURLParameters();\n\n        // Set initial values.\n        $scope.subnetManager = SubnetsManager;\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.fabricManager = FabricsManager;\n        $scope.fabrics = FabricsManager.getItems();\n        $scope.spaceManager = SpacesManager;\n        $scope.spaces = SpacesManager.getItems();\n        $scope.vlanManager = VLANsManager;\n        $scope.vlans = VLANsManager.getItems();\n        $scope.loading = true;\n\n        $scope.group = {};\n        // Used when grouping by fabrics.\n        $scope.group.fabrics = {};\n        // User when grouping by spaces.\n        $scope.group.spaces = {};\n        $scope.group.spaces.orphanVLANs = [];\n\n        // Initializers for action objects.\n        var actionObjectInitializers = {\n            fabric: function() {\n                return {};\n            },\n            vlan: function() {\n                // Set initial fabric.\n                return {\n                    fabric: $scope.fabrics[0].id\n                };\n            },\n            space: function() {\n                return {};\n            },\n            subnet: function() {\n                // Set initial VLAN and space.\n                return {\n                    vlan: $scope.fabrics[0].vlan_ids[0]\n                };\n            }\n        };\n\n        // Return the name of the subnet.\n        function getSubnetName(subnet) {\n            return SubnetsManager.getName(subnet);\n        }\n\n        // Generate a table that can be easily rendered in the view.\n        // Traverses the fabrics and VLANs in-order so that if previous\n        // fabrics and VLANs' names are identical, they can be hidden from\n        // the table cell.\n        function updateFabricsGroupBy() {\n            var rows = [];\n            var previous_fabric = {id:-1};\n            var previous_vlan = {id:-1};\n            var fabrics = $filter('orderBy')($scope.fabrics, ['name']);\n            angular.forEach(fabrics, function(fabric) {\n                var vlans = filterByFabric($scope.vlans, fabric);\n                vlans = $filter('orderBy')(vlans, ['vid']);\n                angular.forEach(vlans, function(vlan) {\n                    var subnets = filterByVLAN($scope.subnets, vlan);\n                    if(subnets.length > 0) {\n                        angular.forEach(subnets, function(subnet) {\n                            var space = SpacesManager.getItemFromList(\n                                subnet.space);\n                            var row = {\n                                fabric: fabric,\n                                fabric_name: \"\",\n                                vlan: vlan,\n                                vlan_name: \"\",\n                                space: space,\n                                subnet: subnet,\n                                subnet_name: getSubnetName(subnet)\n                            };\n                            if(fabric.id !== previous_fabric.id) {\n                                previous_fabric.id = fabric.id;\n                                row.fabric_name = fabric.name;\n                            }\n                            if(vlan.id !== previous_vlan.id) {\n                                previous_vlan.id = vlan.id;\n                                row.vlan_name = $scope.getVLANName(vlan);\n                            }\n                            rows.push(row);\n                        });\n                    } else {\n                        var row = {\n                            fabric: fabric,\n                            fabric_name: \"\",\n                            vlan: vlan,\n                            vlan_name: $scope.getVLANName(vlan)\n                        };\n                        if(fabric.id !== previous_fabric.id) {\n                            previous_fabric.id = fabric.id;\n                            row.fabric_name = fabric.name;\n                        }\n                        rows.push(row);\n                    }\n                });\n            });\n            $scope.group.fabrics.rows = rows;\n        }\n\n        // Generate a table that can be easily rendered in the view.\n        // Traverses the spaces in-order so that if the previous space's name\n        // is identical, it can be hidden from the table cell.\n        // Note that this view only shows items that can be related to a space.\n        // That is, VLANs and fabrics with no corresponding subnets (and\n        // therefore spaces) cannot be shown in this table.\n        function updateSpacesGroupBy() {\n            var rows = [];\n            var spaces = $filter('orderBy')($scope.spaces, ['name']);\n            var previous_space = {id: -1};\n            angular.forEach(spaces, function(space) {\n                var subnets = filterBySpace($scope.subnets, space);\n                subnets = $filter('orderBy')(subnets, ['cidr']);\n                var index = 0;\n                angular.forEach(subnets, function(subnet) {\n                    index++;\n                    var vlan = VLANsManager.getItemFromList(subnet.vlan);\n                    var fabric = FabricsManager.getItemFromList(vlan.fabric);\n                    var row = {\n                        fabric: fabric,\n                        vlan: vlan,\n                        vlan_name: $scope.getVLANName(vlan),\n                        subnet: subnet,\n                        subnet_name: getSubnetName(subnet),\n                        space: space,\n                        space_name: \"\"\n                    };\n                    if(space.id !== previous_space.id) {\n                        previous_space.id = space.id;\n                        row.space_name = space.name;\n                    }\n                    rows.push(row);\n                });\n                if(index === 0) {\n                    rows.push({\n                        space: space,\n                        space_name: space.name\n                    });\n                }\n            });\n            $scope.group.spaces.rows = rows;\n        }\n\n        function updateOrphanVLANs() {\n            var rows = [];\n            var subnets = filterByNullSpace($scope.subnets);\n            subnets = $filter('orderBy')(subnets, ['cidr']);\n            angular.forEach(subnets, function(subnet) {\n                var vlan = VLANsManager.getItemFromList(subnet.vlan);\n                var fabric = FabricsManager.getItemFromList(vlan.fabric);\n                var row = {\n                    fabric: fabric,\n                    vlan: vlan,\n                    vlan_name: $scope.getVLANName(vlan),\n                    subnet: subnet,\n                    subnet_name: getSubnetName(subnet),\n                    space: null\n                };\n                rows.push(row);\n            });\n            $scope.group.spaces.orphanVLANs = rows;\n        }\n\n        // Update the \"Group by\" selection. This is called from a few places:\n        // * When the $watch notices data has changed\n        // * When the URL bar is updated, after the URL is parsed and\n        //   $scope.groupBy is updated\n        // * When the drop-down \"Group by\" selection box changes\n        $scope.updateGroupBy = function() {\n            var groupBy = $scope.groupBy;\n            if(groupBy === 'space') {\n                $location.search('by', 'space');\n                updateSpacesGroupBy();\n                updateOrphanVLANs();\n            } else {\n                // The only other option is 'fabric', but in case the user\n                // made a typo on the URL bar we just assume it was 'fabric'\n                // as a fallback.\n                $location.search('by', 'fabric');\n                updateFabricsGroupBy();\n            }\n        };\n\n        // Called when the managers load to populate the actions the user\n        // is allowed to perform.\n        $scope.updateActions = function() {\n            if(UsersManager.isSuperUser()) {\n                $scope.actionOptions = [\n                    $scope.ADD_FABRIC_ACTION,\n                    $scope.ADD_VLAN_ACTION,\n                    $scope.ADD_SPACE_ACTION,\n                    $scope.ADD_SUBNET_ACTION\n                ];\n            } else {\n                $scope.actionOptions = [];\n            }\n        };\n\n        // Called when a action is selected.\n        $scope.actionChanged = function() {\n            $scope.newObject = (\n                actionObjectInitializers[$scope.actionOption.objectName]());\n        };\n\n        // Called when the \"Cancel\" button is pressed.\n        $scope.cancelAction = function() {\n            $scope.actionOption = null;\n            $scope.newObject = null;\n        };\n\n        // Return the name name for the VLAN.\n        $scope.getVLANName = function(vlan) {\n            return VLANsManager.getName(vlan);\n        };\n\n        // Return the name of the fabric from its given ID.\n        $scope.getFabricNameById = function(fabricId) {\n            return FabricsManager.getName(\n                FabricsManager.getItemFromList(fabricId));\n        };\n\n        // Called before the subnet object is saved. Sets the fabric\n        // field to be the fabric for the selected VLAN.\n        $scope.actionSubnetPreSave = function(obj) {\n            obj.fabric = VLANsManager.getItemFromList(obj.vlan).fabric;\n            return obj;\n        };\n\n        ManagerHelperService.loadManagers($scope, [\n            SubnetsManager, FabricsManager, SpacesManager, VLANsManager,\n            UsersManager]).then(\n            function() {\n                $scope.loading = false;\n\n                $scope.updateActions();\n\n                $scope.$watch(\n                    \"[subnets, fabrics, spaces, vlans]\",\n                    $scope.updateGroupBy, true);\n\n                // If the route has been updated, a new search string must\n                // potentially be rendered.\n                $scope.$on(\"$routeUpdate\", function() {\n                    $scope.getURLParameters();\n                    $scope.updateGroupBy();\n                });\n                $scope.updateGroupBy();\n            });\n    }\n]);\n","/* Copyright 2015-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Details Controller\n */\n\nangular.module('MAAS').controller('NodeDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$location', '$interval',\n    'DevicesManager', 'MachinesManager', 'ControllersManager', 'ZonesManager',\n    'GeneralManager', 'UsersManager', 'TagsManager', 'DomainsManager',\n    'ManagerHelperService', 'ServicesManager', 'ErrorService',\n    'ValidationService', 'ScriptsManager', function(\n        $scope, $rootScope, $routeParams, $location, $interval, DevicesManager,\n        MachinesManager, ControllersManager, ZonesManager, GeneralManager,\n        UsersManager, TagsManager, DomainsManager, ManagerHelperService,\n        ServicesManager, ErrorService, ValidationService, ScriptsManager) {\n\n        // Mapping of device.ip_assignment to viewable text.\n        var DEVICE_IP_ASSIGNMENT = {\n            external: \"External\",\n            dynamic: \"Dynamic\",\n            \"static\": \"Static\"\n        };\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"nodes\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.node = null;\n        $scope.action = {\n          option: null,\n          allOptions: null,\n          availableOptions: [],\n          error: null,\n          showing_confirmation: false\n        };\n        $scope.power_types = GeneralManager.getData(\"power_types\");\n        $scope.osinfo = GeneralManager.getData(\"osinfo\");\n        $scope.section = {\n            area: angular.isString(\n                $routeParams.area) ? $routeParams.area : \"summary\"\n        };\n        $scope.osSelection = {\n            osystem: null,\n            release: null,\n            hwe_kernel: null\n        };\n        $scope.commissionOptions = {\n            enableSSH: false,\n            skipNetworking: false,\n            skipStorage: false,\n            updateFirmware: false,\n            configureHBA: false\n        };\n        $scope.commissioningSelection = [];\n        $scope.testSelection = [];\n        $scope.releaseOptions = {};\n        $scope.checkingPower = false;\n        $scope.devices = [];\n        $scope.scripts = ScriptsManager.getItems();\n\n        // Node header section.\n        $scope.header = {\n            editing: false,\n            editing_domain: false,\n            hostname: {\n                value: \"\"\n            },\n            domain: {\n                selected: null,\n                options: DomainsManager.getItems()\n            }\n        };\n\n        // Summary section.\n        $scope.summary = {\n            editing: false,\n            architecture: {\n                selected: null,\n                options: GeneralManager.getData(\"architectures\")\n            },\n            min_hwe_kernel: {\n                selected: null,\n                options: GeneralManager.getData(\"min_hwe_kernels\")\n            },\n            zone: {\n                selected: null,\n                options: ZonesManager.getItems()\n            },\n            tags: []\n        };\n\n        // Service monitor section (for controllers).\n        $scope.services = {};\n\n        // Power section.\n        $scope.power = {\n            editing: false,\n            type: null,\n            bmc_node_count: 0,\n            parameters: {}\n        };\n\n        // Get the display text for device ip assignment type.\n        $scope.getDeviceIPAssignment = function(ipAssignment) {\n            return DEVICE_IP_ASSIGNMENT[ipAssignment];\n        };\n\n        // Events section.\n        $scope.events = {\n            limit: 10\n        };\n\n        // Updates the page title.\n        function updateTitle() {\n            if($scope.node && $scope.node.fqdn) {\n                $rootScope.title = $scope.node.fqdn;\n            }\n        }\n\n        function updateHeader() {\n            // Don't update the value if in editing mode. As this would\n            // overwrite the users changes.\n            if($scope.header.editing || $scope.header.editing_domain) {\n                return;\n            }\n            $scope.header.hostname.value = $scope.node.fqdn;\n            // DomainsManager gives us all Domain information while the node\n            // only contains the name and id. Because of this we need to loop\n            // through the DomainsManager options and find the option with the\n            // id matching the node id. Otherwise we end up setting our\n            // selected field to an option not from DomainsManager which\n            // doesn't work.\n            var i;\n            for(i=0;i<$scope.header.domain.options.length;i++) {\n                var option = $scope.header.domain.options[i];\n                if(option.id === $scope.node.domain.id) {\n                    $scope.header.domain.selected = option;\n                    break;\n                }\n            }\n        }\n\n        // Update the available action options for the node.\n        function updateAvailableActionOptions() {\n            $scope.action.availableOptions = [];\n            if(!angular.isObject($scope.node)) {\n                return;\n            }\n\n            // Initialize the allowed action list.\n            if($scope.action.allOptions === null) {\n                $scope.action.allOptions =\n                    $scope.getAllActionOptions($scope.node.node_type);\n            }\n\n            // Build the available action options control from the\n            // allowed actions, except set-zone which does not make\n            // sense in this view because the form has this\n            // functionality\n            angular.forEach($scope.action.allOptions, function(option) {\n                if($scope.node.actions.indexOf(option.name) >= 0\n                   && option.name !== \"set-zone\") {\n                    $scope.action.availableOptions.push(option);\n                }\n            });\n        }\n\n        // Updates the currently selected items in the power section.\n        function updatePower() {\n            // Do not update the selected items, when editing this would\n            // cause the users selection to change.\n            if($scope.power.editing) {\n                return;\n            }\n\n            var i;\n            $scope.power.type = null;\n            for(i = 0; i < $scope.power_types.length; i++) {\n                if($scope.node.power_type === $scope.power_types[i].name) {\n                    $scope.power.type = $scope.power_types[i];\n                    break;\n                }\n            }\n\n            $scope.power.bmc_node_count = $scope.node.power_bmc_node_count;\n\n            $scope.power.parameters = angular.copy(\n                $scope.node.power_parameters);\n            if(!angular.isObject($scope.power.parameters)) {\n                $scope.power.parameters = {};\n            }\n\n            // Force editing mode on, if the power_type is missing for a\n            // machine. This is placed at the bottom because we wanted the\n            // selected items to be filled in at least once.\n            if($scope.canEdit() && $scope.node.power_type === \"\" &&\n               $scope.node.node_type === 0) {\n                $scope.power.editing = true;\n            }\n        }\n\n        // Updates the currently selected items in the summary section.\n        function updateSummary() {\n            // Do not update the selected items, when editing this would\n            // cause the users selection to change.\n            if($scope.summary.editing) {\n                return;\n            }\n\n            if(angular.isObject($scope.node.zone)) {\n                $scope.summary.zone.selected = ZonesManager.getItemFromList(\n                    $scope.node.zone.id);\n            }\n            $scope.summary.architecture.selected = $scope.node.architecture;\n            $scope.summary.min_hwe_kernel.selected = $scope.node.min_hwe_kernel;\n            $scope.summary.tags = angular.copy($scope.node.tags);\n\n            // Force editing mode on, if the architecture is invalid. This is\n            // placed at the bottom because we wanted the selected items to\n            // be filled in at least once.\n            if($scope.canEdit() &&\n                $scope.hasUsableArchitectures() &&\n                $scope.hasInvalidArchitecture()) {\n                $scope.summary.editing = true;\n            }\n        }\n\n        // Updates the service monitor section.\n        function updateServices() {\n            if($scope.isController) {\n                $scope.services = {};\n                angular.forEach(ControllersManager.getServices(\n                        $scope.node), function(service) {\n                    $scope.services[service.name] = service;\n                });\n            }\n        }\n\n        // Update the devices array on the scope based on the device children\n        // on the node.\n        function updateDevices() {\n            $scope.devices = [];\n            angular.forEach($scope.node.devices, function(child) {\n                var device = {\n                    name: child.fqdn\n                };\n\n                // Add the interfaces to the device object if any exists.\n                if(angular.isArray(child.interfaces) &&\n                    child.interfaces.length > 0) {\n                    angular.forEach(child.interfaces, function(nic, nicIdx) {\n                        var deviceWithMAC = angular.copy(device);\n                        deviceWithMAC.mac_address = nic.mac_address;\n\n                        // Remove device name so it is not duplicated in the\n                        // table since this is another MAC address on this\n                        // device.\n                        if(nicIdx > 0) {\n                            deviceWithMAC.name = \"\";\n                        }\n\n                        // Add this links to the device object if any exists.\n                        if(angular.isArray(nic.links) &&\n                            nic.links.length > 0) {\n                            angular.forEach(nic.links, function(link, lIdx) {\n                                var deviceWithLink = angular.copy(\n                                    deviceWithMAC);\n                                deviceWithLink.ip_address = link.ip_address;\n\n                                // Remove the MAC address so it is not\n                                // duplicated in the table since this is\n                                // another link on this interface.\n                                if(lIdx > 0) {\n                                    deviceWithLink.mac_address = \"\";\n                                }\n\n                                $scope.devices.push(deviceWithLink);\n                            });\n                        } else {\n                            $scope.devices.push(deviceWithMAC);\n                        }\n                    });\n                } else {\n                    $scope.devices.push(device);\n                }\n            });\n        }\n\n        // Starts the watchers on the scope.\n        function startWatching() {\n            // Update the title and name when the node fqdn changes.\n            $scope.$watch(\"node.fqdn\", function() {\n                updateTitle();\n                updateHeader();\n            });\n\n            // Update the devices on the node.\n            $scope.$watch(\"node.devices\", updateDevices);\n\n            // Update the availableActionOptions when the node actions change.\n            $scope.$watch(\"node.actions\", updateAvailableActionOptions);\n\n            // Update the summary when the node or architectures list is\n            // updated.\n            $scope.$watch(\"node.architecture\", updateSummary);\n            $scope.$watchCollection(\n                $scope.summary.architecture.options, updateSummary);\n\n            // Uppdate the summary when min_hwe_kernel is updated.\n            $scope.$watch(\"node.min_hwe_kernel\", updateSummary);\n            $scope.$watchCollection(\n                $scope.summary.min_hwe_kernel.options, updateSummary);\n\n            // Update the summary when the node or zone list is\n            // updated.\n            $scope.$watch(\"node.zone.id\", updateSummary);\n            $scope.$watchCollection(\n                $scope.summary.zone.options, updateSummary);\n\n            // Update the power when the node power_type or power_parameters\n            // are updated.\n            $scope.$watch(\"node.power_type\", updatePower);\n            $scope.$watch(\"node.power_parameters\", updatePower);\n            $scope.$watchCollection(\"power_types\", updatePower);\n\n            // Update the services when the services list is updated.\n            $scope.$watch(\"node.service_ids\", updateServices);\n        }\n\n        // Called when the node has been loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n\n            updateTitle();\n            updateSummary();\n            updateServices();\n            startWatching();\n\n            // Tell the storageController and networkingController that the\n            // node has been loaded.\n            if(angular.isObject($scope.storageController)) {\n                $scope.storageController.nodeLoaded();\n            }\n            if(angular.isObject($scope.networkingController)) {\n                $scope.networkingController.nodeLoaded();\n            }\n        }\n\n        $scope.getAllActionOptions = function(node_type) {\n            if(typeof node_type !== 'number' ||\n                    node_type < 0 || node_type > 4) {\n                return [];\n            }\n            var actionTypeForNodeType = {\n                0: \"machine_actions\",\n                1: \"device_actions\",\n                2: \"rack_controller_actions\",\n                3: \"region_controller_actions\",\n                4: \"region_and_rack_controller_actions\"\n            };\n            return GeneralManager.getData(actionTypeForNodeType[node_type]);\n        };\n\n        // Update the node with new data on the region.\n        $scope.updateNode = function(node, queryPower) {\n            if(angular.isUndefined(queryPower)) {\n                queryPower = false;\n            }\n            return $scope.nodesManager.updateItem(node).then(function(node) {\n                updateHeader();\n                updateSummary();\n                if(queryPower) {\n                    $scope.checkPowerState();\n                }\n            }, function(error) {\n                console.log(error);\n                updateHeader();\n                updateSummary();\n            });\n        };\n\n        // Called for autocomplete when the user is typing a tag name.\n        $scope.tagsAutocomplete = function(query) {\n            return TagsManager.autocomplete(query);\n        };\n\n        $scope.getPowerStateClass = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return \"\";\n            }\n\n            if($scope.checkingPower) {\n                return \"checking\";\n            } else {\n                return $scope.node.power_state;\n            }\n        };\n\n        // Get the power state text to show.\n        $scope.getPowerStateText = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return \"\";\n            }\n\n            if($scope.checkingPower) {\n                return \"Checking power\";\n            } else if($scope.node.power_state === \"unknown\") {\n                return \"\";\n            } else {\n                return \"Power \" + $scope.node.power_state;\n            }\n        };\n\n        // Returns true when the \"check now\" button for updating the power\n        // state should be shown.\n        $scope.canCheckPowerState = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return false. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n            return (\n                $scope.node.power_state !== \"unknown\" &&\n                !$scope.checkingPower);\n        };\n\n        // Check the power state of the node.\n        $scope.checkPowerState = function() {\n            $scope.checkingPower = true;\n            $scope.nodesManager.checkPowerState($scope.node).then(function() {\n                $scope.checkingPower = false;\n            });\n        };\n\n        $scope.isUbuntuOS = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n\n            if($scope.node.osystem === \"ubuntu\") {\n                return true;\n            }\n            return false;\n        };\n\n        $scope.isUbuntuCoreOS = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n\n            if($scope.node.osystem === \"ubuntu-core\") {\n                return true;\n            }\n            return false;\n        };\n\n        $scope.isCustomOS = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n\n            if($scope.node.osystem === \"custom\") {\n                return true;\n            }\n            return false;\n        };\n\n        // Return true if there is an action error.\n        $scope.isActionError = function() {\n            return $scope.action.error !== null;\n        };\n\n        // Return True if in deploy action and the osinfo is missing.\n        $scope.isDeployError = function() {\n            // Never a deploy error when there is an action error.\n            if($scope.isActionError()) {\n                return false;\n            }\n\n            var missing_osinfo = (\n                angular.isUndefined($scope.osinfo.osystems) ||\n                $scope.osinfo.osystems.length === 0);\n            if(angular.isObject($scope.action.option) &&\n                $scope.action.option.name === \"deploy\" &&\n                missing_osinfo) {\n                return true;\n            }\n            return false;\n        };\n\n        // Return True if unable to deploy because of missing ssh keys.\n        $scope.isSSHKeyError = function() {\n            // Never a deploy error when there is an action error.\n            if($scope.isActionError()) {\n                return false;\n            }\n            if(angular.isObject($scope.action.option) &&\n                $scope.action.option.name === \"deploy\" &&\n                UsersManager.getSSHKeyCount() === 0) {\n                return true;\n            }\n            return false;\n        };\n\n        // Called when the actionOption has changed.\n        $scope.action.optionChanged = function() {\n            // Clear the action error.\n            $scope.action.error = null;\n            $scope.action.showing_confirmation = false;\n        };\n\n        // Cancel the action.\n        $scope.actionCancel = function() {\n            $scope.action.option = null;\n            $scope.action.error = null;\n            $scope.action.showing_confirmation = false;\n        };\n\n        // Perform the action.\n        $scope.actionGo = function() {\n            var extra = {};\n            var i;\n            // Set deploy parameters if a deploy.\n            if($scope.action.option.name === \"deploy\" &&\n                angular.isString($scope.osSelection.osystem) &&\n                angular.isString($scope.osSelection.release)) {\n\n                // Set extra. UI side the release is structured os/release, but\n                // when it is sent over the websocket only the \"release\" is\n                // sent.\n                extra.osystem = $scope.osSelection.osystem;\n                var release = $scope.osSelection.release;\n                release = release.split(\"/\");\n                release = release[release.length-1];\n                extra.distro_series = release;\n                // hwe_kernel is optional so only include it if its specified\n                if(angular.isString($scope.osSelection.hwe_kernel) &&\n                   ($scope.osSelection.hwe_kernel.indexOf('hwe-') >= 0 ||\n                    $scope.osSelection.hwe_kernel.indexOf('ga-') >= 0)) {\n                    extra.hwe_kernel = $scope.osSelection.hwe_kernel;\n                }\n            } else if($scope.action.option.name === \"commission\") {\n                extra.enable_ssh = $scope.commissionOptions.enableSSH;\n                extra.skip_networking = (\n                    $scope.commissionOptions.skipNetworking);\n                extra.skip_storage = $scope.commissionOptions.skipStorage;\n                extra.commissioning_scripts = [];\n                for(i=0;i<$scope.commissioningSelection.length;i++) {\n                    extra.commissioning_scripts.push(\n                        $scope.commissioningSelection[i].id);\n                }\n                if($scope.commissionOptions.updateFirmware) {\n                    extra.commissioning_scripts.push('update_firmware')\n                }\n                if($scope.commissionOptions.configureHBA) {\n                    extra.commissioning_scripts.push('configure_hba')\n                }\n                if(extra.commissioning_scripts.length === 0) {\n                    // Tell the region not to run any custom commissioning\n                    // scripts.\n                    extra.commissioning_scripts.push('none');\n                }\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.testSelection.length;i++) {\n                    extra.testing_scripts.push($scope.testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.action.option.name === \"test\") {\n                if($scope.node.status_code === 6 &&\n                        !$scope.action.showing_confirmation) {\n                    $scope.action.showing_confirmation = true;\n                    return;\n                }\n                // Set the test options.\n                extra.enable_ssh = $scope.commissionOptions.enableSSH;\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.testSelection.length;i++) {\n                    extra.testing_scripts.push($scope.testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.action.option.name === \"release\") {\n                // Set the release options.\n                extra.erase = $scope.releaseOptions.erase;\n                extra.secure_erase = $scope.releaseOptions.secureErase;\n                extra.quick_erase = $scope.releaseOptions.quickErase;\n            }\n\n            $scope.nodesManager.performAction(\n                $scope.node, $scope.action.option.name, extra).then(function() {\n                    // If the action was delete, then go back to listing.\n                    if($scope.action.option.name === \"delete\") {\n                        $location.path(\"/nodes\");\n                    }\n                    $scope.action.option = null;\n                    $scope.action.error = null;\n                    $scope.action.showing_confirmation = false;\n                    $scope.osSelection.$reset();\n                    $scope.commissionOptions.enableSSH = false;\n                    $scope.commissionOptions.skipNetworking = false;\n                    $scope.commissionOptions.skipStorage = false;\n                    $scope.commissionOptions.updateFirmware = false;\n                    $scope.commissionOptions.configureHBA = false;\n                    $scope.commissioningSelection = [];\n                    $scope.testSelection = [];\n                }, function(error) {\n                    $scope.action.error = error;\n                });\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if their are usable architectures.\n        $scope.hasUsableArchitectures = function() {\n            return $scope.summary.architecture.options.length > 0;\n        };\n\n        // Return the placeholder text for the architecture dropdown.\n        $scope.getArchitecturePlaceholder = function() {\n            if($scope.hasUsableArchitectures()) {\n                return \"Choose an architecture\";\n            } else {\n                return \"-- No usable architectures --\";\n            }\n        };\n\n        // Return true if the saved architecture is invalid.\n        $scope.hasInvalidArchitecture = function() {\n            if(angular.isObject($scope.node)) {\n                return (\n                    !$scope.isDevice && (\n                        $scope.node.architecture === \"\" ||\n                        $scope.summary.architecture.options.indexOf(\n                            $scope.node.architecture) === -1));\n            } else {\n                return false;\n            }\n        };\n\n        // Return true if the current architecture selection is invalid.\n        $scope.invalidArchitecture = function() {\n            return (\n                !$scope.isDevice && !$scope.isController && (\n                    $scope.summary.architecture.selected === \"\" ||\n                    $scope.summary.architecture.options.indexOf(\n                        $scope.summary.architecture.selected) === -1));\n        };\n\n        // Return true if at least a rack controller is connected to the\n        // region controller.\n        $scope.isRackControllerConnected = function() {\n            // If power_types exist then a rack controller is connected.\n            return $scope.power_types.length > 0;\n        };\n\n        // Return true if the node is locked\n        $scope.isLocked = function() {\n            if ($scope.node === null) {\n                return false;\n            }\n\n            return $scope.node.locked;\n        };\n\n        // Return true when the edit buttons can be clicked.\n        $scope.canEdit = function() {\n            return (\n                $scope.isRackControllerConnected() &&\n                    $scope.isSuperUser() &&\n                    ! $scope.isLocked());\n        };\n\n        // Called to edit the domain name.\n        $scope.editHeaderDomain = function() {\n            if($scope.canEdit()) {\n                return;\n            }\n\n            // Do nothing if already editing because we don't want to reset\n            // the current value.\n            if($scope.header.editing_domain) {\n                return;\n            }\n            $scope.header.editing = false;\n            $scope.header.editing_domain = true;\n\n            // Set the value to the hostname, as hostname and domain are edited\n            // using different fields.\n            $scope.header.hostname.value = $scope.node.hostname;\n        };\n\n        // Called to edit the node name.\n        $scope.editHeader = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n\n            // Do nothing if already editing because we don't want to reset\n            // the current value.\n            if($scope.header.editing) {\n                return;\n            }\n            $scope.header.editing = true;\n            $scope.header.editing_domain = false;\n\n            // Set the value to the hostname, as hostname and domain are edited\n            // using different fields.\n            $scope.header.hostname.value = $scope.node.hostname;\n        };\n\n        // Return true when the hostname or domain in the header is invalid.\n        $scope.editHeaderInvalid = function() {\n            // Not invalid unless editing.\n            if(!$scope.header.editing && !$scope.header.editing_domain) {\n                return false;\n            }\n\n            // The value cannot be blank.\n            var value = $scope.header.hostname.value;\n            if(value.length === 0) {\n                return true;\n            }\n            return !ValidationService.validateHostname(value);\n        };\n\n        // Called to cancel editing of the node hostname and domain.\n        $scope.cancelEditHeader = function() {\n            $scope.header.editing = false;\n            $scope.header.editing_domain = false;\n            updateHeader();\n        };\n\n        // Called to save editing of node hostname or domain.\n        $scope.saveEditHeader = function() {\n            // Does nothing if invalid.\n            if($scope.editHeaderInvalid()) {\n                return;\n            }\n            $scope.header.editing = false;\n            $scope.header.editing_domain = false;\n\n            // Copy the node and make the changes.\n            var node = angular.copy($scope.node);\n            node.hostname = $scope.header.hostname.value;\n            node.domain = $scope.header.domain.selected;\n\n            // Update the node.\n            $scope.updateNode(node);\n        };\n\n        // Called to enter edit mode in the summary section.\n        $scope.editSummary = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n            $scope.summary.editing = true;\n        };\n\n        // Called to cancel editing in the summary section.\n        $scope.cancelEditSummary = function() {\n            // Leave edit mode only if node has valid architecture.\n            if($scope.isDevice || $scope.isController) {\n                $scope.summary.editing = false;\n            } else if(!$scope.hasInvalidArchitecture()) {\n                $scope.summary.editing = false;\n            }\n\n            updateSummary();\n        };\n\n        // Called to save the changes made in the summary section.\n        $scope.saveEditSummary = function() {\n            // Do nothing if invalidArchitecture.\n            if($scope.invalidArchitecture()) {\n                return;\n            }\n\n            $scope.summary.editing = false;\n\n            // Copy the node and make the changes.\n            var node = angular.copy($scope.node);\n            node.zone = angular.copy($scope.summary.zone.selected);\n            node.architecture = $scope.summary.architecture.selected;\n            if($scope.summary.min_hwe_kernel.selected === null) {\n                node.min_hwe_kernel = \"\";\n            }else{\n                node.min_hwe_kernel = $scope.summary.min_hwe_kernel.selected;\n            }\n            node.tags = [];\n            angular.forEach($scope.summary.tags, function(tag) {\n                node.tags.push(tag.text);\n            });\n\n            // Update the node.\n            $scope.updateNode(node);\n        };\n\n        // Return true if the current power type selection is invalid.\n        $scope.invalidPowerType = function() {\n            return !angular.isObject($scope.power.type);\n        };\n\n        // Called to enter edit mode in the power section.\n        $scope.editPower = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n            $scope.power.editing = true;\n        };\n\n        // Called to cancel editing in the power section.\n        $scope.cancelEditPower = function() {\n            // If the node is not a machine, only leave edit mode if node has\n            // valid power type.\n            if ($scope.node.node_type !== 0 || $scope.node.power_type !== \"\") {\n                $scope.power.editing = false;\n            }\n            updatePower();\n        };\n\n        // Called to save the changes made in the power section.\n        $scope.saveEditPower = function() {\n            // Does nothing if invalid power type.\n            if($scope.invalidPowerType()) {\n                return;\n            }\n            $scope.power.editing = false;\n\n            // Copy the node and make the changes.\n            var node = angular.copy($scope.node);\n            node.power_type = $scope.power.type.name;\n            node.power_parameters = angular.copy($scope.power.parameters);\n\n            // Update the node.\n            $scope.updateNode(node, true);\n        };\n\n        // Return true if the \"load more\" events button should be available.\n        $scope.allowShowMoreEvents = function() {\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n            if(!angular.isArray($scope.node.events)) {\n                return false;\n            }\n            return (\n                $scope.node.events.length > 0 &&\n                $scope.node.events.length > $scope.events.limit &&\n                $scope.events.limit < 50);\n        };\n\n        // Show another 10 events.\n        $scope.showMoreEvents = function() {\n            $scope.events.limit += 10;\n        };\n\n        // Return the nice text for the given event.\n        $scope.getEventText = function(event) {\n            var text = event.type.description;\n            if(angular.isString(event.description) &&\n                event.description.length > 0) {\n                text += \" - \" + event.description;\n            }\n            return text;\n        };\n\n        $scope.getPowerEventError = function() {\n            if(!angular.isObject($scope.node) ||\n                !angular.isArray($scope.node.events)) {\n                return;\n            }\n\n            var i;\n            for(i = 0; i < $scope.node.events.length; i++) {\n                var event = $scope.node.events[i];\n                if(event.type.level === \"warning\" &&\n                   event.type.description === \"Failed to query node's BMC\") {\n                    // Latest power event is an error\n                    return event;\n                } else if(event.type.level === \"info\" &&\n                          event.type.description === \"Queried node's BMC\") {\n                    // Latest power event is not an error\n                    return;\n                }\n            }\n            // No power event found, thus no error\n            return;\n        };\n\n        $scope.hasPowerEventError = function() {\n            var event = $scope.getPowerEventError();\n            return angular.isObject(event);\n        };\n\n        $scope.getPowerEventErrorText = function() {\n            var event = $scope.getPowerEventError();\n            if(angular.isObject(event)) {\n                // Return text\n                return event.description;\n            } else {\n                return \"\";\n            }\n        };\n\n        // true if power error prevents the provided action\n        $scope.hasActionPowerError = function(actionName) {\n            if(!$scope.hasPowerError()) {\n                return false; // no error, no need to check state\n            }\n            // these states attempt to manipulate power\n            var powerChangingStates = [\n                'commission',\n                'deploy',\n                'on',\n                'off',\n                'release'\n            ];\n            if(actionName && powerChangingStates.indexOf(actionName) > -1) {\n                return true;\n            }\n            return false;\n        };\n\n        // Check to see if the power type has any missing system packages.\n        $scope.hasPowerError = function() {\n            if(angular.isObject($scope.power.type)) {\n                return $scope.power.type.missing_packages.length > 0;\n            } else {\n                return false;\n            }\n        };\n\n        // Returns a formatted string of missing system packages.\n        $scope.getPowerErrors = function() {\n            var i;\n            var result = \"\";\n            if(angular.isObject($scope.power.type)) {\n                var packages = $scope.power.type.missing_packages;\n                packages.sort();\n                for(i = 0; i < packages.length; i++) {\n                    result += packages[i];\n                    if(i+2 < packages.length) {\n                        result += \", \";\n                    }\n                    else if(i+1 < packages.length) {\n                        result += \" and \";\n                    }\n                }\n                result += packages.length > 1 ? \" packages\" : \" package\";\n            }\n            return result;\n        };\n\n        // Return the class to apply to the service.\n        $scope.getServiceClass = function(service) {\n            if(!angular.isObject(service)) {\n                return \"none\";\n            } else {\n                if(service.status === \"running\") {\n                    return \"success\";\n                } else if(service.status === \"dead\") {\n                    return \"error\";\n                } else if(service.status === \"degraded\") {\n                    return \"warning\";\n                } else {\n                    return \"none\";\n                }\n            }\n        };\n\n        $scope.hasCustomCommissioningScripts = function() {\n            var i;\n            for(i=0;i<$scope.scripts.length;i++) {\n                if($scope.scripts[i].script_type === 0) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Called by the children controllers to let the parent know.\n        $scope.controllerLoaded = function(name, scope) {\n            $scope[name] = scope;\n            if(angular.isObject(scope.node)) {\n              scope.nodeLoaded();\n            }\n        };\n\n        // Only show a warning that tests have failed if there are failed tests\n        // and the node isn't currently commissioning or testing.\n        $scope.showFailedTestWarning = function() {\n            // Devices can't have failed tests and don't have status_code\n            // defined.\n            if($scope.node.node_type === 1 || !$scope.node.status_code) {\n                return false;\n            }\n            switch($scope.node.status_code) {\n                // NEW\n                case 0:\n                // COMMISSIONING\n                case 1:\n                // FAILED_COMMISSIONING\n                case 2:\n                // TESTING\n                case 21:\n                // FAILED_TESTING\n                case 22:\n                    return false;\n            }\n            switch($scope.node.testing_status) {\n                // Tests havn't been run\n                case -1:\n                // Tests have passed\n                case 2:\n                    return false;\n            }\n            return true;\n        };\n\n        // Get the subtext for the CPU card. Only nodes commissioned after\n        // MAAS 2.4 will have the CPU speed.\n        $scope.getCPUSubtext = function() {\n            var label = $scope.node.cpu_count + \" cores\";\n            if(!$scope.node.cpu_speed || $scope.node.cpu_speed === 0) {\n                return label;\n            }else if($scope.node.cpu_speed < 1000) {\n                return label + \" @ \" + $scope.node.cpu_speed + \" Mhz\";\n            }else{\n                return label + \" @ \" + ($scope.node.cpu_speed / 1000) + \" Ghz\";\n            }\n        }\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            MachinesManager,\n            DevicesManager,\n            ControllersManager,\n            ZonesManager,\n            GeneralManager,\n            UsersManager,\n            TagsManager,\n            DomainsManager,\n            ServicesManager,\n            ScriptsManager\n        ]).then(function() {\n            if('controller' === $routeParams.type) {\n                $scope.nodesManager = ControllersManager;\n                $scope.isController = true;\n                $scope.isDevice = false;\n                $scope.type_name = 'controller';\n                $scope.type_name_title = 'Controller';\n            }else if('device' === $routeParams.type) {\n                $scope.nodesManager = DevicesManager;\n                $scope.isController = false;\n                $scope.isDevice = true;\n                $scope.type_name = 'device';\n                $scope.type_name_title = 'Device';\n            }else{\n                $scope.nodesManager = MachinesManager;\n                $scope.isController = false;\n                $scope.isDevice = false;\n                $scope.type_name = 'machine';\n                $scope.type_name_title = 'Machine';\n            }\n\n            // Possibly redirected from another controller that already had\n            // this node set to active. Only call setActiveItem if not already\n            // the activeItem.\n            var activeNode = $scope.nodesManager.getActiveItem();\n            if(angular.isObject(activeNode) &&\n                activeNode.system_id === $routeParams.system_id) {\n                nodeLoaded(activeNode);\n            } else {\n                $scope.nodesManager.setActiveItem(\n                    $routeParams.system_id).then(function(node) {\n                        nodeLoaded(node);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n                activeNode = $scope.nodesManager.getActiveItem();\n            }\n            if($scope.isDevice) {\n                $scope.ip_assignment = activeNode.ip_assignment;\n            }\n\n            // Poll for architectures, hwe_kernels, and osinfo the whole\n            // time. This is because the user can always see the architecture\n            // and operating system. Need to keep this information up-to-date\n            // so the user is viewing current data.\n            GeneralManager.startPolling($scope, \"architectures\");\n            GeneralManager.startPolling($scope, \"hwe_kernels\");\n            GeneralManager.startPolling($scope, \"osinfo\");\n        });\n\n        // Stop polling for architectures, hwe_kernels, and osinfo when the\n        // scope is destroyed.\n        $scope.$on(\"$destroy\", function() {\n            GeneralManager.stopPolling($scope, \"architectures\");\n            GeneralManager.stopPolling($scope, \"hwe_kernels\");\n            GeneralManager.stopPolling($scope, \"osinfo\");\n        });\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Networking Controller\n */\n\n// Filter that is specific to the NodeNetworkingController. Filters the\n// list of VLANs to be only those that are unused by the interface.\nangular.module('MAAS').filter('filterByUnusedForInterface', function() {\n    return function(vlans, nic, originalInterfaces) {\n        var filtered = [];\n        if(!angular.isObject(nic) ||\n            !angular.isObject(originalInterfaces)) {\n            return filtered;\n        }\n        var usedVLANs = [];\n        angular.forEach(originalInterfaces, function(inter) {\n            if(inter.type === \"vlan\") {\n                var parent = inter.parents[0];\n                if(parent === nic.id) {\n                    usedVLANs.push(inter.vlan_id);\n                }\n            }\n        });\n        angular.forEach(vlans, function(vlan) {\n            var idx = usedVLANs.indexOf(vlan.id);\n            if(idx === -1) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n\n\n// Filter that is specific to the NodeNetworkingController. Filters the\n// list of interfaces to not include the current parent interfaces being\n// bonded together.\nangular.module('MAAS').filter('removeInterfaceParents', function() {\n    return function(interfaces, childInterface, skip) {\n        if(skip || !angular.isObject(childInterface) ||\n            !angular.isArray(childInterface.parents)) {\n            return interfaces;\n        }\n        var filtered = [];\n        angular.forEach(interfaces, function(nic) {\n            var i, parent, found = false;\n            for(i = 0; i < childInterface.parents.length; i++) {\n                parent = childInterface.parents[i];\n                if(parent.id === nic.id && parent.link_id === nic.link_id) {\n                    found = true;\n                    break;\n                }\n            }\n            if(!found) {\n                filtered.push(nic);\n            }\n        });\n        return filtered;\n    };\n});\n\n\n// Filter that is specific to the NodeNetworkingController. Remove the default\n// VLAN if the interface is a VLAN interface.\nangular.module('MAAS').filter('removeDefaultVLANIfVLAN', function() {\n    return function(vlans, interfaceType) {\n        if(!angular.isString(interfaceType)) {\n            return vlans;\n        }\n        var filtered = [];\n        angular.forEach(vlans, function(vlan) {\n            if(interfaceType !== \"vlan\") {\n                filtered.push(vlan);\n            } else if(vlan.vid !== 0) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n\n\n// Filter that is specific to the NodeNetworkingController. Only provide the\n// available modes for that interface type.\nangular.module('MAAS').filter('filterLinkModes', function() {\n    return function(modes, nic) {\n        if(!angular.isObject(nic)) {\n            return modes;\n        }\n        var filtered = [];\n\n        // If this is not a $maasForm, make it work like one.\n        // We need to use getValue() to access attributes, because each\n        // type of maas-obj-form gets to define how values come out.\n        if(!angular.isFunction(nic.getValue)) {\n            nic.getValue = function(name) {\n                return this[name];\n            };\n        }\n\n        if(!angular.isObject(nic.getValue('subnet'))) {\n            // No subnet is configure so the only allowed mode\n            // is 'link_up'.\n            angular.forEach(modes, function(mode) {\n                if(mode.mode === \"link_up\") {\n                    filtered.push(mode);\n                }\n            });\n        } else {\n            // Don't add LINK_UP if more than one link exists or\n            // if the interface is an alias.\n            var links = nic.getValue('links');\n            var nicType = nic.getValue('type');\n            var allowLinkUp = (\n                (angular.isObject(links) && links.length > 1) ||\n                (nicType === \"alias\"));\n            angular.forEach(modes, function(mode) {\n                if(allowLinkUp && mode.mode === \"link_up\") {\n                    return;\n                }\n                // Can't run DHCP twice on one NIC.\n                if(nicType === \"alias\" && mode.mode === \"dhcp\") {\n                    return;\n                }\n                filtered.push(mode);\n            });\n        }\n        return filtered;\n    };\n});\n\n\nangular.module('MAAS').controller('NodeNetworkingController', [\n    '$scope', '$filter', 'FabricsManager', 'VLANsManager', 'SubnetsManager',\n    'MachinesManager', 'ControllersManager', 'DevicesManager',\n    'GeneralManager', 'UsersManager',\n    'ManagerHelperService', 'ValidationService', 'JSONService',\n    function(\n        $scope, $filter, FabricsManager, VLANsManager, SubnetsManager,\n        MachinesManager, ControllersManager, DevicesManager,\n        GeneralManager, UsersManager,\n        ManagerHelperService, ValidationService, JSONService) {\n\n        // Different interface types.\n        var INTERFACE_TYPE = {\n            PHYSICAL: \"physical\",\n            BOND: \"bond\",\n            BRIDGE: \"bridge\",\n            VLAN: \"vlan\",\n            ALIAS: \"alias\"\n        };\n        var INTERFACE_TYPE_TEXTS = {\n            \"physical\": \"Physical\",\n            \"bond\": \"Bond\",\n            \"bridge\": \"Bridge\",\n            \"vlan\": \"VLAN\",\n            \"alias\": \"Alias\"\n        };\n\n        // Different link modes for an interface.\n        var LINK_MODE = {\n            AUTO: \"auto\",\n            STATIC: \"static\",\n            DHCP: \"dhcp\",\n            LINK_UP: \"link_up\"\n        };\n        var LINK_MODE_TEXTS = {\n            \"auto\": \"Auto assign\",\n            \"static\": \"Static assign\",\n            \"dhcp\": \"DHCP\",\n            \"link_up\": \"Unconfigured\"\n        };\n\n        // Different selection modes.\n        var SELECTION_MODE = {\n            NONE: null,\n            SINGLE: \"single\",\n            MULTI: \"multi\",\n            DELETE: \"delete\",\n            ADD: \"add\",\n            CREATE_BOND: \"create-bond\",\n            CREATE_BRIDGE: \"create-bridge\",\n            CREATE_PHYSICAL: \"create-physical\",\n            EDIT: \"edit\"\n        };\n\n        var IP_ASSIGNMENT = {\n            DYNAMIC: \"dynamic\",\n            EXTERNAL: \"external\",\n            STATIC: \"static\"\n        };\n\n        // Device ip assignment options.\n        $scope.ipAssignments = [\n            {\n                name: IP_ASSIGNMENT.EXTERNAL,\n                text: \"External\"\n            },\n            {\n                name: IP_ASSIGNMENT.DYNAMIC,\n                text: \"Dynamic\"\n            },\n            {\n                name: IP_ASSIGNMENT.STATIC,\n                text: \"Static\"\n            }\n        ];\n\n        // Set the initial values for this scope.\n        $scope.loaded = false;\n        $scope.nodeHasLoaded = false;\n        $scope.managersHaveLoaded = false;\n        $scope.tableInfo = {column: 'name'};\n        $scope.fabrics = FabricsManager.getItems();\n        $scope.vlans = VLANsManager.getItems();\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.interfaces = [];\n        $scope.interfaceLinksMap = {};\n        $scope.interfaceErrorsByLinkId = {};\n        $scope.originalInterfaces = {};\n        $scope.selectedInterfaces = [];\n        $scope.selectedMode = null;\n        $scope.newInterface = {};\n        $scope.newBondInterface = {};\n        $scope.newBridgeInterface = {};\n        $scope.editInterface = null;\n        $scope.bondOptions = GeneralManager.getData(\"bond_options\");\n        $scope.modes = [\n            {\n                mode: LINK_MODE.AUTO,\n                text: LINK_MODE_TEXTS[LINK_MODE.AUTO]\n            },\n            {\n                mode: LINK_MODE.STATIC,\n                text: LINK_MODE_TEXTS[LINK_MODE.STATIC]\n            },\n            {\n                mode: LINK_MODE.DHCP,\n                text: LINK_MODE_TEXTS[LINK_MODE.DHCP]\n            },\n            {\n                mode: LINK_MODE.LINK_UP,\n                text: LINK_MODE_TEXTS[LINK_MODE.LINK_UP]\n            }\n        ];\n\n        // Sets loaded to true if both the node has been loaded at the\n        // other required managers for this scope have been loaded.\n        function updateLoaded() {\n            $scope.loaded = $scope.nodeHasLoaded && $scope.managersHaveLoaded;\n            if($scope.loaded) {\n                updateInterfaces();\n            }\n        }\n\n        // Update the list of interfaces for the node. For each link on the\n        // interface, the interface is duplicated in the list to make render\n        // in a data-ng-repeat easier.\n        function updateInterfaces() {\n            $scope.originalInterfaces = {};\n            angular.forEach($scope.node.interfaces, function(nic) {\n                $scope.originalInterfaces[nic.id] = nic;\n            });\n\n            var interfaces = [];\n            // vlanTable contains data packaged for the 'Served VLANs' section,\n            // which is essentially Interface LEFT JOIN VLAN LEFT JOIN Subnet.\n            var vlanTable = [];\n            // Keep track of VLAN IDs we've processed.\n            var addedVlans = {};\n\n            angular.forEach($scope.node.interfaces, function(nic) {\n                // When a interface has a child that is a bond or bridge.\n                // Then that interface is not included in the interface list.\n                // Parent interface with a bond or bridge child can only have\n                // one child.\n                if(nic.children.length === 1) {\n                    var child = $scope.originalInterfaces[nic.children[0]];\n                    if(child.type === INTERFACE_TYPE.BOND ||\n                       child.type === INTERFACE_TYPE.BRIDGE) {\n                        // This parent now has a bond or bridge for a child.\n                        // If this was the editInterface, then it needs to be\n                        // unset. We only need to check the \"id\" (not\n                        // the \"link_id\"), because if this interface did have\n                        // aliases they have now been removed.\n                        if(angular.isObject($scope.editInterface) &&\n                            $scope.editInterface.id === nic.id) {\n                            $scope.editInterface = null;\n                            $scope.selectedMode = SELECTION_MODE.NONE;\n                        }\n                        return;\n                    }\n                }\n\n                // When the interface is a bond or a bridge, place the children\n                // as members for that interface.\n                if(nic.type === INTERFACE_TYPE.BOND ||\n                   nic.type === INTERFACE_TYPE.BRIDGE) {\n                    nic.members = [];\n                    angular.forEach(nic.parents, function(parent) {\n                        nic.members.push(\n                            angular.copy($scope.originalInterfaces[parent]));\n                    });\n                }\n\n                // Format the tags when they have not already been formatted.\n                if(angular.isArray(nic.tags) &&\n                    nic.tags.length > 0 &&\n                    !angular.isString(nic.tags[0].text)) {\n                    nic.tags = formatTags(nic.tags);\n                }\n\n                nic.vlan = VLANsManager.getItemFromList(nic.vlan_id);\n                if(angular.isObject(nic.vlan)) {\n                    nic.fabric = FabricsManager.getItemFromList(\n                            nic.vlan.fabric);\n\n                    // Build the vlanTable for controller detail page.\n                    if ($scope.$parent.isController) {\n                        // Skip duplicate VLANs (by id, they can share names).\n                        if(!(Object.prototype.hasOwnProperty.call(\n                                addedVlans, nic.vlan.id))) {\n                            addedVlans[nic.vlan.id] = true;\n                            var vlanRecord = {\n                                \"fabric\": nic.fabric,\n                                \"vlan\": nic.vlan,\n                                \"subnets\": $filter('filter')(\n                                    $scope.subnets, {vlan:nic.vlan.id}, true),\n                                \"primary_rack\": null,\n                                \"secondary_rack\": null,\n                                \"sort_key\": nic.fabric.name + \"|\" +\n                                    $scope.getVLANText(nic.vlan)\n                            };\n                            if(nic.vlan.primary_rack) {\n                                vlanRecord.primary_rack =\n                                    ControllersManager.getItemFromList(\n                                        nic.vlan.primary_rack);\n                            }\n                            if(nic.vlan.secondary_rack) {\n                                vlanRecord.secondary_rack =\n                                    ControllersManager.getItemFromList(\n                                        nic.vlan.secondary_rack);\n                            }\n                            vlanTable.push(vlanRecord);\n                        }\n                        // Sort the table by (VLANText, fabric.name).\n                        vlanTable.sort(function(a, b) {\n                            return a.sort_key.localeCompare(b.sort_key);\n                        });\n                    }\n                }\n\n                // Update the interface based on its links or duplicate the\n                // interface if it has multiple links.\n                if(nic.links.length === 0) {\n                    // No links on this interface. The interface is either\n                    // disabled or has no links (which means the interface\n                    // is in LINK_UP mode).\n                    nic.link_id = -1;\n                    nic.subnet = null;\n                    nic.mode = LINK_MODE.LINK_UP;\n                    nic.ip_address = \"\";\n                    interfaces.push(nic);\n                } else {\n                    var idx = 0;\n                    angular.forEach(nic.links, function(link) {\n                        var nic_copy = angular.copy(nic);\n                        nic_copy.link_id = link.id;\n                        nic_copy.subnet = SubnetsManager.getItemFromList(\n                            link.subnet_id);\n                        nic_copy.mode = link.mode;\n                        nic_copy.ip_address = link.ip_address;\n                        if(angular.isUndefined(nic_copy.ip_address)) {\n                            nic_copy.ip_address = \"\";\n                        }\n                        // We don't want to deep copy the VLAN and fabric\n                        // object so we set those back to the original.\n                        nic_copy.vlan = nic.vlan;\n                        nic_copy.fabric = nic.fabric;\n                        if(idx > 0) {\n                            // Each extra link is an alais on the original\n                            // interface.\n                            nic_copy.type = INTERFACE_TYPE.ALIAS;\n                            nic_copy.name += \":\" + idx;\n                        }\n                        idx++;\n                        interfaces.push(nic_copy);\n                    });\n                }\n            });\n\n            // Update the scopes interfaces.\n            $scope.interfaces = interfaces;\n            $scope.vlanTable = vlanTable;\n\n            // Update the scope interface links mapping.\n            $scope.interfaceLinksMap = {};\n            angular.forEach($scope.interfaces, function(nic) {\n                var linkMaps = $scope.interfaceLinksMap[nic.id];\n                if(angular.isUndefined(linkMaps)) {\n                    linkMaps = {};\n                    $scope.interfaceLinksMap[nic.id] = linkMaps;\n                }\n                linkMaps[nic.link_id] = nic;\n            });\n\n            // Clear the editInterface if it no longer exists in the\n            // interfaceLinksMap.\n            if(angular.isObject($scope.editInterface)) {\n                var links = $scope.interfaceLinksMap[$scope.editInterface.id];\n                if(angular.isUndefined(links)) {\n                    $scope.editInterface = null;\n                    $scope.selectedMode = SELECTION_MODE.NONE;\n                } else {\n                    var link = links[$scope.editInterface.link_id];\n                    if(angular.isUndefined(link)) {\n                        $scope.editInterface = null;\n                        $scope.selectedMode = SELECTION_MODE.NONE;\n                    }\n                }\n            }\n\n            // Update newInterface.parent if it has changed.\n            updateNewInterface();\n        }\n\n        // Return the original link object for the given interface.\n        function mapNICToOriginalLink(nic_id, link_id) {\n            var originalInteface = $scope.originalInterfaces[nic_id];\n            if(angular.isObject(originalInteface)) {\n                var i, link = null;\n                for(i = 0; i < originalInteface.links.length; i++) {\n                    link = originalInteface.links[i];\n                    if(link.id === link_id) {\n                        break;\n                    }\n                }\n                return link;\n            } else {\n                return null;\n            }\n        }\n\n        // Leave single selection mode.\n        function leaveSingleSelectionMode() {\n            if($scope.selectedMode === SELECTION_MODE.SINGLE ||\n                $scope.selectedMode === SELECTION_MODE.ADD ||\n                $scope.selectedMode === SELECTION_MODE.DELETE) {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n            }\n        }\n\n        // Update the new interface since the interfaces list has\n        // been reloaded.\n        function updateNewInterface() {\n            if(angular.isObject($scope.newInterface.parent)) {\n                var parentId = $scope.newInterface.parent.id;\n                var linkId = $scope.newInterface.parent.link_id;\n                var links = $scope.interfaceLinksMap[parentId];\n                if(angular.isObject(links)) {\n                    var newParent = links[linkId];\n                    if(angular.isObject(newParent)) {\n                        $scope.newInterface.parent = newParent;\n\n                        var iType = $scope.newInterface.type;\n                        var isAlias = iType === INTERFACE_TYPE.ALIAS;\n                        var isVLAN = iType === INTERFACE_TYPE.VLAN;\n                        var canAddAlias = $scope.canAddAlias(newParent);\n                        var canAddVLAN = $scope.canAddVLAN(newParent);\n                        if(!canAddAlias && !canAddVLAN) {\n                            // Cannot do any adding now.\n                            $scope.newInterface = {};\n                            leaveSingleSelectionMode();\n                        } else {\n                            if(isAlias && !canAddAlias && canAddVLAN) {\n                                $scope.newInterface.type = \"vlan\";\n                                $scope.addTypeChanged();\n                            } else if(isVLAN && !canAddVLAN && canAddAlias) {\n                                $scope.newInterface.type = \"alias\";\n                                $scope.addTypeChanged();\n                            }\n                        }\n                        return;\n                    }\n                }\n\n                // Parent no longer exists. Exit the single selection modes.\n                $scope.newInterface = {};\n                leaveSingleSelectionMode();\n            }\n        }\n\n        // Return the default VLAN for a fabric.\n        function getDefaultVLAN(fabric) {\n            return VLANsManager.getItemFromList(fabric.default_vlan_id);\n        }\n\n        // Return list of unused VLANs for an interface. Also remove the\n        // ignoreVLANs from the returned list.\n        function getUnusedVLANs(nic, ignoreVLANs) {\n            var vlans = $filter('removeDefaultVLAN')($scope.vlans);\n            vlans = $filter('filterByFabric')(vlans, nic.fabric);\n            vlans = $filter('filterByUnusedForInterface')(\n                vlans, nic, $scope.originalInterfaces);\n\n            // Remove the VLAN's that should be ignored when getting the unused\n            // VLANs. This is done to help the selection of the next default.\n            if(angular.isUndefined(ignoreVLANs)) {\n                ignoreVLANs = [];\n            }\n            angular.forEach(ignoreVLANs, function(vlan) {\n                var i;\n                for(i = 0; i < vlans.length; i++) {\n                    if(vlans[i].id === vlan.id) {\n                        vlans.splice(i, 1);\n                        break;\n                    }\n                }\n            });\n            return vlans;\n        }\n\n        // Return the currently selected interface objects.\n        function getSelectedInterfaces() {\n            var interfaces = [];\n            angular.forEach($scope.selectedInterfaces, function(key) {\n                var splitKey = key.split('/');\n                var links = $scope.interfaceLinksMap[splitKey[0]];\n                if(angular.isObject(links)) {\n                    var nic = links[splitKey[1]];\n                    if(angular.isObject(nic)) {\n                        interfaces.push(nic);\n                    }\n                }\n            });\n            return interfaces;\n        }\n\n        // Get the next available name.\n        function getNextName(prefix) {\n            var idx = 0;\n            angular.forEach($scope.originalInterfaces, function(nic) {\n                if(nic.name === prefix + idx) {\n                    idx++;\n                }\n            });\n            return prefix + idx;\n        }\n\n        // Return the tags formatted for ngTagInput.\n        function formatTags(tags) {\n            var formatted = [];\n            angular.forEach(tags, function(tag) {\n                formatted.push({ text: tag });\n            });\n            return formatted;\n        }\n\n        // Called by $parent when the node has been loaded.\n        $scope.nodeLoaded = function() {\n            $scope.$watch(\"node.interfaces\", updateInterfaces);\n            // Watch subnets for the served VLANs section.\n            if ($scope.$parent.isController) {\n                $scope.$watch(\"subnets\", updateInterfaces, true);\n            }\n            $scope.nodeHasLoaded = true;\n            updateLoaded();\n        };\n\n        // Return true if only the name or mac address of an interface can\n        // be edited.\n        $scope.isLimitedEditingAllowed = function(nic) {\n            if (!$scope.isSuperUser()) {\n                // If the user is not the superuser, pretend it's not Ready.\n                return false;\n            }\n            if ($scope.$parent.isController || $scope.$parent.isDevice) {\n                // Controllers and Devices are never in limited mode.\n                return false;\n            }\n            return (\n                angular.isObject($scope.node) &&\n                $scope.node.status === \"Deployed\" &&\n                nic.type !== \"vlan\");\n        };\n\n        // Return true if the networking information cannot be edited.\n        // (it can't be changed when the node is in any state other\n        // than Ready or Broken and the user is not a superuser)\n        $scope.isAllNetworkingDisabled = function() {\n            if (!$scope.isSuperUser()) {\n                // If the user is not a superuser, disable the networking panel.\n                return true;\n            }\n            if ($scope.$parent.isController || $scope.$parent.isDevice) {\n                // Never disable the full networking panel when its a\n                // Controller or Device.\n                return false;\n            }\n            if (angular.isObject($scope.node) &&\n                    [\"Ready\", \"Allocated\", \"Broken\"].indexOf(\n                        $scope.node.status) === -1) {\n                // If a non-controller node is not ready allocated, or broken,\n                // disable networking panel.\n                return true;\n            }\n            // User must be a superuser and the node must be\n            // either ready or broken. Enable it.\n            return false;\n        };\n\n        // Return true if the interface is the boot interface or has a parent\n        // that is the boot interface.\n        $scope.isBootInterface = function(nic) {\n            if(!angular.isObject(nic)) {\n                return false;\n            }\n\n            if(nic.is_boot && nic.type !== INTERFACE_TYPE.ALIAS) {\n                return true;\n            } else if(nic.type === INTERFACE_TYPE.BOND ||\n                      nic.type === INTERFACE_TYPE.BRIDGE) {\n                var i;\n                for(i = 0; i < nic.members.length; i++) {\n                    if(nic.members[i].is_boot) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Get the text for the type of the interface.\n        $scope.getInterfaceTypeText = function(nic) {\n            var text = INTERFACE_TYPE_TEXTS[nic.type];\n            if(angular.isDefined(text)) {\n                return text;\n            } else {\n                return nic.type;\n            }\n        };\n\n        // Get the text for the link mode of the interface.\n        $scope.getLinkModeText = function(nic) {\n            var text = LINK_MODE_TEXTS[nic.mode];\n            if(angular.isDefined(text)) {\n                return text;\n            } else {\n                return nic.mode;\n            }\n        };\n\n        // Get the text to display in the VLAN dropdown.\n        $scope.getVLANText = function(vlan) {\n            if(!angular.isObject(vlan)) {\n                return \"\";\n            }\n\n            if(vlan.vid === 0) {\n                return \"untagged\";\n            } else if(angular.isString(vlan.name) && vlan.name.length > 0) {\n                return vlan.vid + \" (\" + vlan.name + \")\";\n            } else {\n                return vlan.vid;\n            }\n        };\n\n        // Get the text to display in the subnet dropdown.\n        $scope.getSubnetText = function(subnet) {\n            if(!angular.isObject(subnet)) {\n                return \"Unconfigured\";\n            } else if(angular.isString(subnet.name) &&\n                subnet.name.length > 0 &&\n                subnet.cidr !== subnet.name) {\n                return subnet.cidr + \" (\" + subnet.name + \")\";\n            } else {\n                return subnet.cidr;\n            }\n        };\n\n        // Get the subnet from its ID.\n        $scope.getSubnet = function(subnetId) {\n            return SubnetsManager.getItemFromList(subnetId);\n        };\n\n        // Return True if the interface name that the user typed is invalid.\n        $scope.isInterfaceNameInvalid = function(nic) {\n            if(!angular.isString(nic.name) || nic.name.length === 0) {\n                return true;\n            } else if(angular.isArray($scope.node.interfaces)) {\n                var i;\n                for(i = 0; i < $scope.node.interfaces.length; i++) {\n                    var otherNic = $scope.node.interfaces[i];\n                    if(otherNic.name === nic.name && otherNic.id !== nic.id) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Return True if the link mode select should be disabled.\n        $scope.isLinkModeDisabled = function(nic) {\n            // This is only disabled when a subnet has not been selected.\n            if(angular.isFunction(nic.getValue)) {\n                return !angular.isObject(nic.getValue('subnet'));\n            } else {\n                return !angular.isObject(nic.subnet);\n            }\n        };\n\n        // Return the interface errors.\n        $scope.getInterfaceError = function(nic) {\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                return $scope.interfaceErrorsByLinkId[nic.link_id];\n            }\n            return null;\n        };\n\n        // Return True if the interface IP address that the user typed is\n        // invalid.\n        $scope.isIPAddressInvalid = function(nic) {\n            if(angular.isString(nic.ip_address) && nic.mode === 'static') {\n                return (\n                    !ValidationService.validateIP(nic.ip_address) ||\n                    !ValidationService.validateIPInNetwork(\n                        nic.ip_address, nic.subnet.cidr));\n            } else {\n                return false;\n            }\n        };\n\n        // Return unique key for the interface.\n        $scope.getUniqueKey = function(nic) {\n            return nic.id + \"/\" + nic.link_id;\n        };\n\n        // Toggle selection of the interface.\n        $scope.toggleInterfaceSelect = function(nic) {\n            var key = $scope.getUniqueKey(nic);\n            var idx = $scope.selectedInterfaces.indexOf(key);\n            if(idx > -1) {\n                $scope.selectedInterfaces.splice(idx, 1);\n            } else {\n                $scope.selectedInterfaces.push(key);\n            }\n\n            if($scope.selectedInterfaces.length > 1) {\n                if($scope.selectedMode !== SELECTION_MODE.BOND) {\n                    $scope.selectedMode = SELECTION_MODE.MULTI;\n                }\n            } else if($scope.selectedInterfaces.length === 1) {\n                $scope.selectedMode = SELECTION_MODE.SINGLE;\n            } else {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n            }\n        };\n\n        // Return true when the interface is selected.\n        $scope.isInterfaceSelected = function(nic) {\n            return $scope.selectedInterfaces.indexOf(\n                $scope.getUniqueKey(nic)) > -1;\n        };\n\n        // Returns true if the interface is not selected\n        $scope.cannotEditInterface = function(nic) {\n            if ($scope.selectedMode === SELECTION_MODE.NONE) {\n                return false;\n            } else if (\n                  $scope.selectedMode !== SELECTION_MODE.MULTI &&\n                  $scope.isInterfaceSelected(nic)) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Return true if in editing mode for the interface.\n        $scope.isEditing = function(nic) {\n            if($scope.selectedMode !== SELECTION_MODE.EDIT) {\n                return false;\n            } else {\n                return $scope.editInterface.id === nic.id;\n            }\n        };\n\n        // Start editing this interface.\n        $scope.edit = function(nic) {\n            $scope.selectedInterfaces = [$scope.getUniqueKey(nic)];\n            $scope.selectedMode = SELECTION_MODE.EDIT;\n            if($scope.$parent.isDevice) {\n                $scope.editInterface = {\n                    id: nic.id,\n                    name: nic.name,\n                    mac_address: nic.mac_address,\n                    tags: nic.tags.map(function(tag) { return tag.text; }),\n                    subnet: nic.subnet,\n                    ip_address: nic.ip_address,\n                    ip_assignment: nic.ip_assignment,\n                    link_id: nic.link_id\n                };\n                if(nic.subnet !== undefined && nic.subnet !== null) {\n                    $scope.editInterface.defaultSubnet = nic.subnet;\n                } else {\n                    $scope.editInterface.defaultSubnet = $scope.subnets[0];\n                }\n            } else {\n                $scope.editInterface = {\n                    id: nic.id,\n                    name: nic.name,\n                    mac_address: nic.mac_address,\n                    tags: nic.tags.map(function(tag) { return tag.text; }),\n                    fabric: nic.fabric,\n                    vlan: nic.vlan,\n                    subnet: nic.subnet,\n                    mode: nic.mode,\n                    ip_address: nic.ip_address,\n                    link_id: nic.link_id\n                };\n            }\n        };\n\n        // Called when the fabric is changed.\n        $scope.fabricChanged = function(nic) {\n            // Update the VLAN on the node to be the default VLAN for that\n            // fabric. The first VLAN for the fabric is the default.\n            if(nic.fabric !== null) {\n                nic.vlan = getDefaultVLAN(nic.fabric);\n            } else {\n                nic.vlan = null;\n            }\n            $scope.vlanChanged(nic);\n        };\n\n        // Called when the fabric is changed in a maas-obj-form.\n        $scope.fabricChangedForm = function(key, value, form) {\n            var vlan;\n            if(value !== null) {\n                vlan = getDefaultVLAN(value);\n            } else {\n                vlan = null;\n            }\n            form.updateValue('vlan', vlan);\n            $scope.vlanChangedForm('vlan', vlan, form);\n        };\n\n        // Called when the VLAN is changed.\n        $scope.vlanChanged = function(nic) {\n            nic.subnet = null;\n            $scope.subnetChanged(nic);\n        };\n\n        // Called when the VLAN is changed on a maas-obj-form\n        $scope.vlanChangedForm = function(key, value, form) {\n            form.updateValue('subnet', null);\n            $scope.subnetChangedForm('subnet', null, form);\n        };\n\n        // Called when the subnet is changed.\n        $scope.subnetChanged = function(nic) {\n            if(!angular.isObject(nic.subnet)) {\n                // Set to 'Unconfigured' so the link mode should be set to\n                // 'link_up'.\n                nic.mode = LINK_MODE.LINK_UP;\n            }\n            if ($scope.$parent.isDevice) {\n                nic.ip_address = null;\n            }\n            $scope.modeChanged(nic);\n        };\n\n        // Called when the subnet is changed.\n        $scope.subnetChangedForm = function(key, value, form) {\n            if(!angular.isObject(value)) {\n                // Set to 'Unconfigured' so the link mode should be set to\n                // 'link_up'.\n                form.updateValue('mode', LINK_MODE.LINK_UP);\n            }\n            mode = form.getValue('mode');\n            form.updateValue('ip_address', null);\n            $scope.modeChangedForm('mode', mode, form);\n        };\n\n        // Called when the mode is changed.\n        $scope.modeChanged = function(nic) {\n            // Clear the IP address when the mode is changed.\n            nic.ip_address = \"\";\n            if(nic.mode === 'static') {\n                var originalLink = mapNICToOriginalLink(nic.id, nic.link_id);\n                if(angular.isObject(originalLink) &&\n                    nic.subnet.id === originalLink.subnet_id) {\n                    // Set the original IP address if same subnet.\n                    nic.ip_address = originalLink.ip_address;\n                }\n            }\n        };\n\n        // Called when the mode is changed on a maas-obj-form.\n        $scope.modeChangedForm = function(key, value, form) {\n            // Clear the IP address when the mode is changed.\n            form.updateValue('ip_address', \"\");\n            if(value === 'static') {\n                var originalLink = mapNICToOriginalLink(\n                  form.getValue('id'), form.getValue('link_id'));\n                if(angular.isObject(originalLink) &&\n                    form.getValue('subnet').id === originalLink.subnet_id) {\n                    // Set the original IP address if same subnet.\n                    form.updateValue('ip_address', originalLink.ip_address);\n                }\n            }\n        };\n\n        // Called to cancel edit mode.\n        $scope.editCancel = function(nic) {\n            $scope.selectedInterfaces = [];\n            $scope.selectedMode = SELECTION_MODE.NONE;\n            $scope.editInterface = null;\n        };\n\n        // Preprocess things for updateInterfaceForm.\n        $scope.preProcessInterface = function(nic) {\n            var params = angular.copy(nic);\n\n            delete params.id;\n            params.system_id = $scope.node.system_id;\n            params.interface_id = nic.id;\n\n            // we need IDs not objects.\n            if(nic.fabric !== undefined && nic.fabric !== null) {\n                params.fabric = nic.fabric.id;\n            } else {\n                params.fabric = null;\n            }\n            if(nic.vlan !== undefined && nic.vlan !== null) {\n                params.vlan = nic.vlan.id;\n            } else {\n                params.vlan = null;\n            }\n            if(nic.subnet !== undefined && nic.subnet !== null) {\n                params.subnet = params.subnet.id;\n            } else {\n                delete params.subnet;\n            }\n\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                params.link_id = nic.link_id;\n                delete $scope.interfaceErrorsByLinkId[nic.link_id];\n            } else {\n                delete params.link_id;\n            }\n            if((nic.mode === LINK_MODE.STATIC ||\n                nic.ip_assignment !== IP_ASSIGNMENT.DYNAMIC) &&\n               angular.isString(nic.ip_address) &&\n               nic.ip_address.length > 0) {\n                params.ip_address = nic.ip_address;\n            } else {\n                delete params.ip_address;\n            }\n            return params;\n        };\n\n        // Save the following interface on the node.\n        $scope.saveInterface = function(nic) {\n            var params;\n            if($scope.$parent.isDevice) {\n                params = {\n                    \"name\": nic.name,\n                    \"mac_address\": nic.mac_address,\n                    \"ip_assignment\": nic.ip_assignment,\n                    \"ip_address\": nic.ip_address\n                };\n            } else {\n                params = {\n                    \"name\": nic.name,\n                    \"mac_address\": nic.mac_address,\n                    \"mode\": nic.mode,\n                    \"tags\": nic.tags.map(\n                        function(tag) { return tag.text; })\n                };\n            }\n            if(nic.fabric !== undefined && nic.fabric !== null) {\n                params.fabric = nic.fabric.id;\n            } else {\n                params.fabric = null;\n            }\n            if(nic.vlan !== undefined && nic.vlan !== null) {\n                params.vlan = nic.vlan.id;\n            } else {\n                params.vlan = null;\n            }\n            if (nic.subnet !== undefined && nic.subnet !== null) {\n                params.subnet = nic.subnet.id;\n            } else {\n                params.subnet = null;\n            }\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                params.link_id = nic.link_id;\n                delete $scope.interfaceErrorsByLinkId[nic.link_id];\n            }\n            if(angular.isString(nic.ip_address) && nic.ip_address.length > 0) {\n                params.ip_address = nic.ip_address;\n            }\n            return $scope.$parent.nodesManager.updateInterface(\n                $scope.node, nic.id, params).then(null, function(error) {\n                    // XXX blake_r: Just log the error in the console, but\n                    // we need to expose this as a better message to the\n                    // user.\n                    console.log(error);\n\n                    // Update the interfaces so it is back to the way it\n                    // was before the user changed it.\n                    updateInterfaces();\n                });\n        };\n\n        // Save the following link on the node.\n        $scope.saveInterfaceLink = function(nic) {\n            var params = {\n                \"mode\": nic.mode\n            };\n            if($scope.$parent.isDevice) {\n                params.ip_assignment = nic.ip_assignment;\n            }\n            if(angular.isObject(nic.subnet)) {\n                params.subnet = nic.subnet.id;\n            }\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                params.link_id = nic.link_id;\n                delete $scope.interfaceErrorsByLinkId[nic.link_id];\n            }\n            if(nic.mode === LINK_MODE.STATIC &&\n                angular.isString(nic.ip_address) &&\n                nic.ip_address.length > 0) {\n                params.ip_address = nic.ip_address;\n            }\n            return $scope.$parent.nodesManager.linkSubnet(\n                $scope.node, nic.id, params).then(null, function(error) {\n                    console.log(error);\n                    if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                        $scope.interfaceErrorsByLinkId[nic.link_id] = error;\n                    }\n                    // Update the interfaces so it is back to the way it\n                    // was before the user changed it.\n                    updateInterfaces();\n                    throw error;\n                });\n        };\n\n        // Called to save the interface.\n        $scope.editSave = function(editInterface) {\n            $scope.editCancel();\n            return editInterface;\n        };\n\n        // Return true if the interface delete confirm is being shown.\n        $scope.isShowingDeleteConfirm = function() {\n            return $scope.selectedMode === SELECTION_MODE.DELETE;\n        };\n\n        // Return true if the interface add interface is being shown.\n        $scope.isShowingAdd = function() {\n            return $scope.selectedMode === SELECTION_MODE.ADD;\n        };\n\n        // Return true if either an alias or VLAN can be added.\n        $scope.canAddAliasOrVLAN = function(nic) {\n            if($scope.$parent.isController) {\n                return false;\n            } else if ($scope.isAllNetworkingDisabled()) {\n                return false;\n            } else {\n                return $scope.canAddAlias(nic) || $scope.canAddVLAN(nic);\n            }\n        };\n\n        // Return true if the alias can be added to interface.\n        $scope.canAddAlias = function(nic) {\n            if(!angular.isObject(nic)) {\n                return false;\n            } else if(nic.type === INTERFACE_TYPE.ALIAS) {\n                return false;\n            } else if(nic.links.length === 0 ||\n                nic.links[0].mode === LINK_MODE.LINK_UP) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Return true if the VLAN can be added to interface.\n        $scope.canAddVLAN = function(nic) {\n            if(!angular.isObject(nic)) {\n                return false;\n            } else if(nic.type === INTERFACE_TYPE.ALIAS ||\n                nic.type === INTERFACE_TYPE.VLAN) {\n                return false;\n            }\n            var unusedVLANs = getUnusedVLANs(nic);\n            return unusedVLANs.length > 0;\n        };\n\n        // Return true if another VLAN can be added to this already being\n        // added interface.\n        $scope.canAddAnotherVLAN = function(nic) {\n            if(!$scope.canAddVLAN(nic)) {\n                return false;\n            }\n            var unusedVLANs = getUnusedVLANs(nic);\n            return unusedVLANs.length > 1;\n        };\n\n        // Return the text to use for the remove link and message.\n        $scope.getRemoveTypeText = function(nic) {\n            if(nic.type === INTERFACE_TYPE.PHYSICAL) {\n                return \"interface\";\n            } else if(nic.type === INTERFACE_TYPE.VLAN) {\n                return \"VLAN\";\n            } else {\n                return nic.type;\n            }\n        };\n\n        // Return true if the interface can be removed.\n        $scope.canBeRemoved = function() {\n            return (\n                !$scope.$parent.isController &&\n                !$scope.isAllNetworkingDisabled());\n        };\n\n        // Enter remove mode.\n        $scope.remove = function() {\n            $scope.selectedMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter remove by selecting the node first.\n        $scope.quickRemove = function(nic) {\n            $scope.selectedInterfaces = [$scope.getUniqueKey(nic)];\n            $scope.remove();\n        };\n\n        // Cancel the current mode go back to sinle selection mode.\n        $scope.cancel = function() {\n            $scope.newInterface = {};\n            $scope.newBondInterface = {};\n            $scope.newBridgeInterface = {};\n            if($scope.selectedMode === SELECTION_MODE.CREATE_BOND) {\n                $scope.selectedMode = SELECTION_MODE.MULTI;\n            } else if($scope.selectedMode === SELECTION_MODE.CREATE_PHYSICAL) {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n            } else {\n                $scope.selectedMode = SELECTION_MODE.SINGLE;\n            }\n        };\n\n        // Confirm the removal of interface.\n        $scope.confirmRemove = function(nic) {\n            $scope.selectedMode = SELECTION_MODE.NONE;\n            $scope.selectedInterfaces = [];\n            if(nic.type !== INTERFACE_TYPE.ALIAS) {\n                $scope.$parent.nodesManager.deleteInterface(\n                    $scope.node, nic.id);\n            } else {\n                $scope.$parent.nodesManager.unlinkSubnet(\n                    $scope.node, nic.id, nic.link_id);\n            }\n\n            // Remove the interface from available interfaces\n            var idx = $scope.interfaces.indexOf(nic);\n            if(idx > -1) {\n                $scope.interfaces.splice(idx, 1);\n            }\n        };\n\n        // Enter add mode.\n        $scope.add = function(type, nic) {\n            // When this is called right after another VLAN was just added, we\n            // remove its used VLAN from the available list.\n            var ignoreVLANs = [];\n            if(angular.isObject($scope.newInterface.vlan)) {\n                ignoreVLANs.push($scope.newInterface.vlan);\n            }\n\n            // Get the default VLAN for the new interface.\n            var vlans = getUnusedVLANs(nic, ignoreVLANs);\n            var defaultVLAN = null;\n            if(vlans.length > 0) {\n                defaultVLAN = vlans[0];\n            }\n            var defaultSubnet = null;\n            var defaultMode = LINK_MODE.LINK_UP;\n\n            // Alias used defaults based from its parent.\n            if(type === INTERFACE_TYPE.ALIAS) {\n                defaultVLAN = nic.vlan;\n                defaultSubnet = $filter('filter')(\n                    $scope.subnets, {vlan:defaultVLAN.id}, true)[0];\n                defaultMode = LINK_MODE.AUTO;\n            }\n\n            // Setup the new interface and enter add mode.\n            $scope.newInterface = {\n                type: type,\n                vlan: defaultVLAN,\n                subnet: defaultSubnet,\n                mode: defaultMode,\n                parent: nic,\n                tags: []\n            };\n            $scope.selectedMode = SELECTION_MODE.ADD;\n        };\n\n        // Quickly enter add by selecting the node first.\n        $scope.quickAdd = function(nic) {\n            $scope.selectedInterfaces = [$scope.getUniqueKey(nic)];\n            var type = 'alias';\n            if(!$scope.canAddAlias(nic)) {\n                type = 'vlan';\n            }\n            $scope.add(type, nic);\n        };\n\n        // Return the name of the interface being added.\n        $scope.getAddName = function() {\n            if($scope.newInterface.type === INTERFACE_TYPE.ALIAS) {\n                var aliasIdx = $scope.newInterface.parent.links.length;\n                return $scope.newInterface.parent.name + \":\" + aliasIdx;\n            } else if ($scope.newInterface.type === INTERFACE_TYPE.VLAN) {\n                return (\n                    $scope.newInterface.parent.name + \".\" +\n                    $scope.newInterface.vlan.vid);\n            }\n        };\n\n        // Called when the type of interface is changed.\n        $scope.addTypeChanged = function() {\n            if($scope.newInterface.type === INTERFACE_TYPE.ALIAS) {\n                $scope.newInterface.vlan = $scope.newInterface.parent.vlan;\n                $scope.newInterface.subnet = $filter('filter')(\n                    $scope.subnets,\n                    {vlan:$scope.newInterface.vlan.id}, true)[0];\n                $scope.newInterface.mode = LINK_MODE.AUTO;\n            } else if($scope.newInterface.type === INTERFACE_TYPE.VLAN) {\n                var vlans = getUnusedVLANs($scope.newInterface.parent);\n                $scope.newInterface.vlan = null;\n                if(vlans.length > 0) {\n                    $scope.newInterface.vlan = vlans[0];\n                }\n                $scope.newInterface.subnet = null;\n                $scope.newInterface.mode = LINK_MODE.LINK_UP;\n            }\n        };\n\n        // Perform the add action over the websocket.\n        $scope.addInterface = function(type) {\n            var nic;\n            if($scope.$parent.isDevice) {\n                nic = {\n                    id: $scope.newInterface.parent.id,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; }),\n                    ip_assignment: $scope.newInterface.ip_assignment,\n                    subnet: $scope.newInterface.subnet,\n                    ip_address: $scope.newInterface.ip_address\n                };\n                $scope.saveInterfaceLink(nic);\n            } else if($scope.newInterface.type === INTERFACE_TYPE.ALIAS) {\n                // Add a link to the current interface.\n                nic = {\n                    id: $scope.newInterface.parent.id,\n                    mode: $scope.newInterface.mode,\n                    subnet: $scope.newInterface.subnet,\n                    ip_address: $scope.newInterface.ip_address\n                };\n                $scope.saveInterfaceLink(nic);\n            } else if($scope.newInterface.type === INTERFACE_TYPE.VLAN) {\n                var params = {\n                    parent: $scope.newInterface.parent.id,\n                    vlan: $scope.newInterface.vlan.id,\n                    mode: $scope.newInterface.mode,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; })\n                };\n                if(angular.isObject($scope.newInterface.subnet)) {\n                    params.subnet = $scope.newInterface.subnet.id;\n                    params.ip_address = $scope.newInterface.ip_address;\n                }\n                $scope.$parent.nodesManager.createVLANInterface(\n                    $scope.node, params).then(null, function(error) {\n                        // Should do something better but for now just log\n                        // the error.\n                        console.log(error);\n                    });\n            }\n\n            // Add again based on the clicked option.\n            if(angular.isString(type)) {\n                $scope.add(type, $scope.newInterface.parent);\n            } else {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n                $scope.selectedInterfaces = [];\n                $scope.newInterface = {};\n            }\n        };\n\n        // Return true if the networking information cannot be edited\n        // or if this interface should be disabled in the list. Only\n        // returns true when in create bond mode.\n        $scope.isDisabled = function() {\n            if ($scope.isAllNetworkingDisabled()) {\n                return true;\n            } else {\n                return (\n                    $scope.selectedMode !== SELECTION_MODE.NONE &&\n                    $scope.selectedMode !== SELECTION_MODE.SINGLE &&\n                    $scope.selectedMode !== SELECTION_MODE.MULTI);\n            }\n        };\n\n        // Return true when a bond can be created based on the current\n        // selection. Only can be done if no aliases are selected and all\n        // selected interfaces are on the same VLAN.\n        $scope.canCreateBond = function() {\n            if($scope.selectedMode !== SELECTION_MODE.MULTI) {\n                return false;\n            }\n            var interfaces = getSelectedInterfaces();\n            var i, vlan;\n            for(i = 0; i < interfaces.length; i++) {\n                var nic = interfaces[i];\n                if(nic.type === INTERFACE_TYPE.ALIAS ||\n                    nic.type === INTERFACE_TYPE.BOND) {\n                    return false;\n                } else if(!angular.isObject(vlan)) {\n                    vlan = nic.vlan;\n                } else if(vlan !== nic.vlan) {\n                    return false;\n                }\n            }\n            return true;\n        };\n\n        // Return true when the create bond view is being shown.\n        $scope.isShowingCreateBond = function() {\n            return $scope.selectedMode === SELECTION_MODE.CREATE_BOND;\n        };\n\n        // Show the create bond view.\n        $scope.showCreateBond = function() {\n            if($scope.selectedMode === SELECTION_MODE.MULTI &&\n                $scope.canCreateBond()) {\n                $scope.selectedMode = SELECTION_MODE.CREATE_BOND;\n\n                var parents = getSelectedInterfaces();\n                $scope.newBondInterface = {\n                    name: getNextName(\"bond\"),\n                    tags: [],\n                    parents: parents,\n                    primary: parents[0],\n                    mac_address: \"\",\n                    mode: \"active-backup\",\n                    lacpRate: \"slow\",\n                    xmitHashPolicy: \"layer2\"\n                };\n            }\n        };\n\n        // Return true if the interface has a parent that is a boot interface.\n        $scope.hasBootInterface = function(nic) {\n            if(!angular.isArray(nic.parents)) {\n                return false;\n            }\n            var i;\n            for(i = 0; i < nic.parents.length; i++) {\n                if(nic.parents[i].is_boot) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Return the MAC address that should be shown as a placeholder. This\n        // this is the MAC address of the primary interface.\n        $scope.getInterfacePlaceholderMACAddress = function(nic) {\n            if(!angular.isObject(nic.primary)) {\n                return \"\";\n            } else {\n                return nic.primary.mac_address;\n            }\n        };\n\n        // Return true if the user has inputed a value in the MAC address field\n        // but it is invalid.\n        $scope.isMACAddressInvalid = function(mac_address, invalidEmpty) {\n            if(angular.isUndefined(invalidEmpty)) {\n                invalidEmpty = false;\n            }\n            if(!angular.isString(mac_address) || mac_address === \"\") {\n                return invalidEmpty;\n            }\n            return !ValidationService.validateMAC(mac_address);\n        };\n\n        // Return true when the LACR rate selection should be shown.\n        $scope.showLACPRate = function() {\n            return $scope.newBondInterface.mode === \"802.3ad\";\n        };\n\n        // Return true when the XMIT hash policy should be shown.\n        $scope.showXMITHashPolicy = function() {\n            return (\n                $scope.newBondInterface.mode === \"balance-xor\" ||\n                $scope.newBondInterface.mode === \"802.3ad\" ||\n                $scope.newBondInterface.mode === \"balance-tlb\");\n        };\n\n        // Return true if cannot add the bond.\n        $scope.cannotAddBond = function() {\n            return (\n                $scope.isInterfaceNameInvalid($scope.newBondInterface) ||\n                $scope.isMACAddressInvalid(\n                    $scope.newBondInterface.mac_address));\n        };\n\n        // Actually add the bond.\n        $scope.addBond = function() {\n            if($scope.cannotAddBond()) {\n               return;\n            }\n\n            var parents = $scope.newBondInterface.parents.map(\n                function(nic) { return nic.id; });\n            var mac_address = $scope.newBondInterface.mac_address;\n            if(mac_address === \"\") {\n                mac_address = $scope.newBondInterface.primary.mac_address;\n            }\n            var vlan_id, vlan = $scope.newBondInterface.primary.vlan;\n            if(angular.isObject(vlan)) {\n                vlan_id = vlan.id;\n            } else {\n                vlan_id = null;\n            }\n            var params = {\n                name: $scope.newBondInterface.name,\n                mac_address: mac_address,\n                tags: $scope.newBondInterface.tags.map(\n                    function(tag) { return tag.text; }),\n                parents: parents,\n                vlan: vlan_id,\n                bond_mode: $scope.newBondInterface.mode,\n                bond_lacp_rate: $scope.newBondInterface.lacpRate,\n                bond_xmit_hash_policy: $scope.newBondInterface.xmitHashPolicy\n            };\n            $scope.$parent.nodesManager.createBondInterface(\n                $scope.node, params).then(null, function(error) {\n                    // Should do something better but for now just log\n                    // the error.\n                    console.log(error);\n                });\n\n            // Remove the parent interfaces so that they don't show up\n            // in the listing unti the new bond appears.\n            angular.forEach($scope.newBondInterface.parents, function(parent) {\n                var idx = $scope.interfaces.indexOf(parent);\n                if(idx > -1) {\n                    $scope.interfaces.splice(idx, 1);\n                }\n            });\n\n            // Clear the bond interface and reset the mode.\n            $scope.newBondInterface = {};\n            $scope.selectedInterfaces = [];\n            $scope.selectedMode = SELECTION_MODE.NONE;\n        };\n\n        // Return true when a bridge can be created based on the current\n        // selection. Only can be done if no aliases are selected and only\n        // one interface is selected.\n        $scope.canCreateBridge = function() {\n            if($scope.selectedMode !== SELECTION_MODE.SINGLE) {\n                return false;\n            }\n            var nic = getSelectedInterfaces()[0];\n            if(nic.type === INTERFACE_TYPE.ALIAS ||\n                nic.type === INTERFACE_TYPE.BRIDGE) {\n                return false;\n            }\n            return true;\n        };\n\n        // Return true when the create bridge view is being shown.\n        $scope.isShowingCreateBridge = function() {\n            return $scope.selectedMode === SELECTION_MODE.CREATE_BRIDGE;\n        };\n\n        // Show the create bridge view.\n        $scope.showCreateBridge = function() {\n            if($scope.selectedMode === SELECTION_MODE.SINGLE &&\n                $scope.canCreateBridge()) {\n                $scope.selectedMode = SELECTION_MODE.CREATE_BRIDGE;\n\n                var parents = getSelectedInterfaces();\n                $scope.newBridgeInterface = {\n                    name: getNextName(\"br\"),\n                    tags: [],\n                    parents: parents,\n                    primary: parents[0],\n                    mac_address: \"\",\n                    bridge_stp: false,\n                    bridge_fd: 15\n                };\n            }\n        };\n\n        // Return true if cannot add the bridge.\n        $scope.cannotAddBridge = function() {\n            return (\n                $scope.isInterfaceNameInvalid($scope.newBridgeInterface) ||\n                $scope.isMACAddressInvalid(\n                    $scope.newBridgeInterface.mac_address));\n        };\n\n        // Actually add the bridge.\n        $scope.addBridge = function() {\n            if($scope.cannotAddBridge()) {\n               return;\n            }\n\n            var parents = [$scope.newBridgeInterface.primary.id];\n            var mac_address = $scope.newBridgeInterface.mac_address;\n            if(mac_address === \"\") {\n                mac_address = $scope.newBridgeInterface.primary.mac_address;\n            }\n            var params = {\n                name: $scope.newBridgeInterface.name,\n                mac_address: mac_address,\n                tags: $scope.newBridgeInterface.tags.map(\n                    function(tag) { return tag.text; }),\n                parents: parents,\n                vlan: $scope.newBridgeInterface.primary.vlan.id,\n                bridge_stp: $scope.newBridgeInterface.bridge_stp,\n                bridge_fd: $scope.newBridgeInterface.bridge_fd\n            };\n            $scope.$parent.nodesManager.createBridgeInterface(\n                $scope.node, params).then(null, function(error) {\n                    // Should do something better but for now just log\n                    // the error.\n                    console.log(error);\n                });\n\n            // Remove the parent interface so that they don't show up\n            // in the listing unti the new bond appears.\n            var idx = $scope.interfaces.indexOf(\n                $scope.newBridgeInterface.primary);\n            if(idx > -1) {\n                $scope.interfaces.splice(idx, 1);\n            }\n\n            // Clear the bridge interface and reset the mode.\n            $scope.newBridgeInterface = {};\n            $scope.selectedInterfaces = [];\n            $scope.selectedMode = SELECTION_MODE.NONE;\n        };\n\n        // Return true when the create physical interface view is being shown.\n        $scope.isShowingCreatePhysical = function() {\n            return $scope.selectedMode === SELECTION_MODE.CREATE_PHYSICAL;\n        };\n\n        // Show the create interface view.\n        $scope.showCreatePhysical = function() {\n            if($scope.selectedMode === SELECTION_MODE.NONE) {\n                $scope.selectedMode = SELECTION_MODE.CREATE_PHYSICAL;\n                if($scope.$parent.isDevice) {\n                    $scope.newInterface = {\n                        name: getNextName(\"eth\"),\n                        mac_address: \"\",\n                        macError: false,\n                        tags: [],\n                        errorMsg: null,\n                        subnet: null,\n                        ip_assignment: IP_ASSIGNMENT.DYNAMIC\n                    };\n                } else {\n                    $scope.newInterface = {\n                        name: getNextName(\"eth\"),\n                        mac_address: \"\",\n                        macError: false,\n                        tags: [],\n                        errorMsg: null,\n                        fabric: $scope.fabrics[0],\n                        vlan: getDefaultVLAN($scope.fabrics[0]),\n                        subnet: null,\n                        mode: LINK_MODE.LINK_UP\n                    };\n                }\n            }\n        };\n\n        // Return true if cannot add the interface.\n        $scope.cannotAddPhysicalInterface = function() {\n            return (\n                $scope.isInterfaceNameInvalid($scope.newInterface) ||\n                $scope.isMACAddressInvalid(\n                    $scope.newInterface.mac_address, true));\n        };\n\n        // Actually add the new physical interface.\n        $scope.addPhysicalInterface = function() {\n            if($scope.cannotAddPhysicalInterface()) {\n               return;\n            }\n\n            var params;\n            if($scope.$parent.isDevice) {\n                params = {\n                    name: $scope.newInterface.name,\n                    mac_address: $scope.newInterface.mac_address,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; }),\n                    ip_assignment: $scope.newInterface.ip_assignment,\n                    ip_address: $scope.newInterface.ip_address\n                };\n            } else {\n                params = {\n                    name: $scope.newInterface.name,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; }),\n                    mac_address: $scope.newInterface.mac_address,\n                    vlan: $scope.newInterface.vlan.id,\n                    mode: $scope.newInterface.mode\n                };\n            }\n            if(angular.isObject($scope.newInterface.subnet)) {\n                params.subnet = $scope.newInterface.subnet.id;\n            }\n            $scope.newInterface.macError = false;\n            $scope.newInterface.errorMsg = null;\n            $scope.$parent.nodesManager.createPhysicalInterface(\n                $scope.node, params).then(function() {\n                    // Clear the interface and reset the mode.\n                    $scope.newInterface = {};\n                    $scope.selectedMode = SELECTION_MODE.NONE;\n                },\n                function(errorStr) {\n                    error = JSONService.tryParse(errorStr);\n                    if(!angular.isObject(error)) {\n                        // Was not a JSON error. This is wrong here as it\n                        // should be, so just log to the console.\n                        console.log(errorStr);\n                    } else {\n                        macError = error.mac_address;\n                        if(angular.isArray(macError)) {\n                            $scope.newInterface.macError = true;\n                            $scope.newInterface.errorMsg = macError[0];\n                        }\n                    }\n                });\n        };\n\n        // Load all the required managers. NodesManager and GeneralManager\n        // are loaded by the parent controller \"NodeDetailsController\".\n        ManagerHelperService.loadManagers($scope, [\n            FabricsManager,\n            VLANsManager,\n            SubnetsManager,\n            UsersManager,\n            ControllersManager\n        ]).then(function() {\n            $scope.managersHaveLoaded = true;\n            updateLoaded();\n        });\n\n        // Tell $parent that the networkingController has been loaded.\n        $scope.$parent.controllerLoaded('networkingController', $scope);\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Storage Controller\n */\n\n\n// Filter that is specific to the NodeStorageController. Remove the available\n// disks from the list if being used in the availableNew.\nangular.module('MAAS').filter('removeAvailableByNew', function() {\n    return function(disks, availableNew) {\n        if(!angular.isObject(availableNew) || (\n            !angular.isObject(availableNew.device) &&\n            !angular.isArray(availableNew.devices))) {\n            return disks;\n        }\n\n        var filtered = [];\n        var single = true;\n        if(angular.isArray(availableNew.devices)) {\n            single = false;\n        }\n        angular.forEach(disks, function(disk) {\n            if(single) {\n                if(disk !== availableNew.device) {\n                    filtered.push(disk);\n                }\n            } else {\n                var i, found = false;\n                for(i = 0; i < availableNew.devices.length; i++) {\n                    if(disk === availableNew.devices[i]) {\n                        found = true;\n                        break;\n                    }\n                }\n                if(!found) {\n                    filtered.push(disk);\n                }\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').controller('NodeStorageController', [\n    '$scope', 'MachinesManager', 'ConverterService', 'UsersManager',\n    function($scope, MachinesManager, ConverterService, UsersManager) {\n\n        // From models/partitiontable.py - must be kept in sync.\n        var INITIAL_PARTITION_OFFSET = 4 * 1024 * 1024;\n        var END_OF_PARTITION_TABLE_SPACE = 1024 * 1024;\n        var PARTITION_TABLE_EXTRA_SPACE = INITIAL_PARTITION_OFFSET +\n            END_OF_PARTITION_TABLE_SPACE;\n        var PREP_PARTITION_SIZE = 8 * 1024 * 1024;\n\n        // From models/partition.py - must be kept in sync.\n        var PARTITION_ALIGNMENT_SIZE = 4 * 1024 * 1024;\n        var MIN_PARTITION_SIZE = PARTITION_ALIGNMENT_SIZE;\n\n        // Different selection modes.\n        var SELECTION_MODE = {\n            NONE: null,\n            SINGLE: \"single\",\n            MUTLI: \"multi\",\n            UNMOUNT: \"unmount\",\n            UNFORMAT: \"unformat\",\n            EDIT: \"edit\",\n            DELETE: \"delete\",\n            FORMAT_AND_MOUNT: \"format-mount\",\n            PARTITION: \"partition\",\n            BCACHE: \"bcache\",\n            RAID: \"raid\",\n            VOLUME_GROUP: \"volume-group\",\n            LOGICAL_VOLUME: \"logical-volume\"\n        };\n\n        // Different available raid modes.\n        var RAID_MODES = [\n            {\n                level: \"raid-0\",\n                title: \"RAID 0\",\n                min_disks: 2,\n                allows_spares: false,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * numDisks;\n                }\n            },\n            {\n                level: \"raid-1\",\n                title: \"RAID 1\",\n                min_disks: 2,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize;\n                }\n            },\n            {\n                level: \"raid-5\",\n                title: \"RAID 5\",\n                min_disks: 3,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * (numDisks - 1);\n                }\n            },\n            {\n                level: \"raid-6\",\n                title: \"RAID 6\",\n                min_disks: 4,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * (numDisks - 2);\n                }\n            },\n            {\n                level: \"raid-10\",\n                title: \"RAID 10\",\n                min_disks: 3,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * numDisks / 2;\n                }\n            }\n        ];\n\n        $scope.tableInfo = {column: 'name'};\n        $scope.has_disks = false;\n        $scope.filesystems = [];\n        $scope.filesystemsMap = {};\n        $scope.filesystemMode = SELECTION_MODE.NONE;\n        $scope.filesystemAllSelected = false;\n        $scope.cachesets = [];\n        $scope.cachesetsMap = {};\n        $scope.cachesetsMode = SELECTION_MODE.NONE;\n        $scope.cachesetsAllSelected = false;\n        $scope.available = [];\n        $scope.availableMap = {};\n        $scope.availableMode = SELECTION_MODE.NONE;\n        $scope.availableAllSelected = false;\n        $scope.availableNew = {};\n        $scope.used = [];\n        $scope.showMembers = [];\n\n        // Return True if the filesystem is mounted.\n        function isMountedFilesystem(filesystem) {\n            return angular.isObject(filesystem) &&\n                angular.isString(filesystem.mount_point) &&\n                filesystem.mount_point !== \"\";\n        }\n\n        // Return True if the item has a filesystem and it's mounted.\n        function hasMountedFilesystem(item) {\n            return angular.isObject(item) &&\n                isMountedFilesystem(item.filesystem);\n        }\n\n        // Returns the fstype if the item has a filesystem and its unmounted.\n        function hasFormattedUnmountedFilesystem(item) {\n            if(angular.isObject(item.filesystem) &&\n                angular.isString(item.filesystem.fstype) &&\n                item.filesystem.fstype !== '' &&\n                (angular.isString(item.filesystem.mount_point) === false ||\n                    item.filesystem.mount_point === '')) {\n                return item.filesystem.fstype;\n            }else{\n                return null;\n            }\n        }\n\n        // Return True if the item is in use.\n        function isInUse(item) {\n            if(item.type === \"cache-set\") {\n                return true;\n            } else if(angular.isObject(item.filesystem)) {\n                if(item.filesystem.is_format_fstype &&\n                    angular.isString(item.filesystem.mount_point) &&\n                    item.filesystem.mount_point !== \"\") {\n                    return true;\n                } else if(!item.filesystem.is_format_fstype) {\n                    return true;\n                }\n                return false;\n            }\n            return item.available_size < MIN_PARTITION_SIZE;\n        }\n\n        // Return the tags formatted for ngTagInput.\n        function getTags(disk) {\n            var tags = [];\n            angular.forEach(disk.tags, function(tag) {\n                tags.push({ text: tag });\n            });\n            return tags;\n        }\n\n        // Return a unique key that will never change.\n        function getUniqueKey(disk) {\n            if(disk.type === \"cache-set\") {\n                return \"cache-set-\" + disk.cache_set_id;\n            } else {\n                var key = disk.type + \"-\" + disk.block_id;\n                if(angular.isNumber(disk.partition_id)) {\n                    key += \"-\" + disk.partition_id;\n                }\n                return key;\n            }\n        }\n\n        // Update the list of filesystems. Only filesystems with a mount point\n        // set go here. If no mount point is set, it goes in available.\n        function updateFilesystems() {\n            // Create the new list of filesystems.\n            var filesystems = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(hasMountedFilesystem(disk)) {\n                    var data = {\n                        \"type\": \"filesystem\",\n                        \"name\": disk.name,\n                        \"size_human\": disk.size_human,\n                        \"fstype\": disk.filesystem.fstype,\n                        \"mount_point\": disk.filesystem.mount_point,\n                        \"mount_options\": disk.filesystem.mount_options,\n                        \"block_id\": disk.id,\n                        \"partition_id\": null,\n                        \"filesystem_id\": disk.filesystem.id,\n                        \"original_type\": disk.type,\n                        \"original\": disk\n                    };\n                    if(disk.type === \"virtual\") {\n                        disk.parent_type = disk.parent.type;\n                    }\n                    filesystems.push(data);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    if(hasMountedFilesystem(partition)) {\n                        filesystems.push({\n                            \"type\": \"filesystem\",\n                            \"name\": partition.name,\n                            \"size_human\": partition.size_human,\n                            \"fstype\": partition.filesystem.fstype,\n                            \"mount_point\": partition.filesystem.mount_point,\n                            \"mount_options\":\n                                partition.filesystem.mount_options,\n                            \"block_id\": disk.id,\n                            \"partition_id\": partition.id,\n                            \"filesystem_id\": partition.filesystem.id,\n                            \"original_type\": \"partition\",\n                            \"original\": partition\n                        });\n                    }\n                });\n            });\n\n            // Add special filesystems to the filesystem list. A special\n            // filesystem cannot exist unless mounted, so we don't need\n            // to check.\n            angular.forEach(\n                $scope.node.special_filesystems,\n                function(filesystem) {\n                    filesystems.push({\n                        \"type\": \"filesystem\",\n                        \"name\": \"—\",\n                        \"size_human\": \"—\",\n                        \"fstype\": filesystem.fstype,\n                        \"mount_point\": filesystem.mount_point,\n                        \"mount_options\": filesystem.mount_options,\n                        \"block_id\": null,\n                        \"partition_id\": null,\n                        \"original_type\": \"special\"\n                    });\n                });\n\n            // Update the selected filesystems with the currently selected\n            // filesystems.\n            angular.forEach(filesystems, function(filesystem) {\n                var key = getUniqueKey(filesystem);\n                var oldFilesystem = $scope.filesystemsMap[key];\n                if(angular.isObject(oldFilesystem)) {\n                    filesystem.$selected = oldFilesystem.$selected;\n                } else {\n                    filesystem.$selected = false;\n                }\n            });\n\n            // Update the filesystems and filesystemsMap on the scope.\n            $scope.filesystems = filesystems;\n            $scope.filesystemsMap = {};\n            angular.forEach(filesystems, function(filesystem) {\n                $scope.filesystemsMap[getUniqueKey(filesystem)] = filesystem;\n            });\n\n            // Update the selection mode.\n            $scope.updateFilesystemSelection(false);\n        }\n\n        // Update the list of cache sets.\n        function updateCacheSets() {\n            // Create the new list of cache sets.\n            var cachesets = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(disk.type === \"cache-set\") {\n                    cachesets.push({\n                        \"type\": \"cache-set\",\n                        \"name\": disk.name,\n                        \"size_human\": disk.size_human,\n                        \"cache_set_id\": disk.id,\n                        \"used_by\": disk.used_for\n                    });\n                }\n            });\n\n            // Update the selected cache sets with the currently selected\n            // cache sets.\n            angular.forEach(cachesets, function(cacheset) {\n                var key = getUniqueKey(cacheset);\n                var oldCacheSet = $scope.cachesetsMap[key];\n                if(angular.isObject(oldCacheSet)) {\n                    cacheset.$selected = oldCacheSet.$selected;\n                } else {\n                    cacheset.$selected = false;\n                }\n            });\n\n            // Update the cachesets and cachesetsMap on the scope.\n            $scope.cachesets = cachesets;\n            $scope.cachesetsMap = {};\n            angular.forEach(cachesets, function(cacheset) {\n                $scope.cachesetsMap[getUniqueKey(cacheset)] = cacheset;\n            });\n\n            // Update the selection mode.\n            $scope.updateCacheSetsSelection(false);\n        }\n\n        // Update list of all available disks.\n        function updateAvailable() {\n            var available = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(!isInUse(disk)) {\n                    var has_partitions = false;\n                    if(angular.isArray(disk.partitions) &&\n                        disk.partitions.length > 0) {\n                        has_partitions = true;\n                    }\n                    var data = {\n                        \"name\": disk.name,\n                        \"size_human\": disk.size_human,\n                        \"available_size_human\": disk.available_size_human,\n                        \"used_size_human\": disk.used_size_human,\n                        \"type\": disk.type,\n                        \"model\": disk.model,\n                        \"serial\": disk.serial,\n                        \"tags\": getTags(disk),\n                        \"fstype\": hasFormattedUnmountedFilesystem(disk),\n                        \"mount_point\": null,\n                        \"mount_options\": null,\n                        \"block_id\": disk.id,\n                        \"partition_id\": null,\n                        \"has_partitions\": has_partitions,\n                        \"is_boot\": disk.is_boot,\n                        \"original\": disk,\n                        \"test_status\": disk.test_status,\n                        \"firmware_version\": disk.firmware_version\n                    };\n                    if(disk.type === \"virtual\") {\n                        data.parent_type = disk.parent.type;\n                    }\n                    available.push(data);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    if(!isInUse(partition)) {\n                        available.push({\n                            \"name\": partition.name,\n                            \"size_human\": partition.size_human,\n                            \"available_size_human\": (\n                                partition.available_size_human),\n                            \"used_size_human\": partition.used_size_human,\n                            \"type\": \"partition\",\n                            \"model\": \"\",\n                            \"serial\": \"\",\n                            \"tags\": [],\n                            \"fstype\":\n                                hasFormattedUnmountedFilesystem(partition),\n                            \"mount_point\": null,\n                            \"mount_options\": null,\n                            \"block_id\": disk.id,\n                            \"partition_id\": partition.id,\n                            \"has_partitions\": false,\n                            \"is_boot\": false,\n                            \"original\": partition\n                        });\n                    }\n                });\n            });\n\n            // Update the selected available disks with the currently selected\n            // available disks. Also copy the $options so they are not lost\n            // for the current action.\n            angular.forEach(available, function(disk) {\n                var key = getUniqueKey(disk);\n                var oldDisk = $scope.availableMap[key];\n                if(angular.isObject(oldDisk)) {\n                    disk.$selected = oldDisk.$selected;\n                    disk.$options = oldDisk.$options;\n                } else {\n                    disk.$selected = false;\n                    disk.$options = {};\n                }\n            });\n\n            // Update available and availableMap on the scope.\n            $scope.available = available;\n            $scope.availableMap = {};\n            angular.forEach(available, function(disk) {\n                $scope.availableMap[getUniqueKey(disk)] = disk;\n            });\n\n            // Update device or devices on the availableNew object to be\n            // there new objects.\n            if(angular.isObject($scope.availableNew)) {\n                // Update device.\n                if(angular.isObject($scope.availableNew.device)) {\n                    var key = getUniqueKey($scope.availableNew.device);\n                    $scope.availableNew.device = $scope.availableMap[key];\n                // Update devices.\n                } else if(angular.isArray($scope.availableNew.devices)) {\n                    var newDevices = [];\n                    angular.forEach(\n                        $scope.availableNew.devices, function(device) {\n                            var key = getUniqueKey(device);\n                            var newDevice = $scope.availableMap[key];\n                            if(angular.isObject(newDevice)) {\n                                newDevices.push(newDevice);\n                            }\n                        });\n                    $scope.availableNew.devices = newDevices;\n                }\n            }\n\n            // Update the selection mode.\n            $scope.updateAvailableSelection(false);\n        }\n\n        // Update list of all used disks.\n        function updateUsed() {\n            var used = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(isInUse(disk) && disk.type !== \"cache-set\") {\n                    var has_partitions = false;\n                    if(angular.isArray(disk.partitions) &&\n                        disk.partitions.length > 0) {\n                        has_partitions = true;\n                    }\n                    var data = {\n                        \"name\": disk.name,\n                        \"type\": disk.type,\n                        \"model\": disk.model,\n                        \"serial\": disk.serial,\n                        \"tags\": getTags(disk),\n                        \"used_for\": disk.used_for,\n                        \"is_boot\": disk.is_boot,\n                        \"has_partitions\": has_partitions,\n                        \"test_status\": disk.test_status,\n                        \"firmware_version\": disk.firmware_version\n                    };\n                    if(disk.type === \"virtual\") {\n                        data.parent_type = disk.parent.type;\n                    }\n                    used.push(data);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    if(isInUse(partition) && partition.type !== \"cache-set\") {\n                        used.push({\n                            \"name\": partition.name,\n                            \"type\": \"partition\",\n                            \"model\": \"\",\n                            \"serial\": \"\",\n                            \"tags\": [],\n                            \"used_for\": partition.used_for,\n                            \"is_boot\": false\n                        });\n                    }\n                });\n            });\n            $scope.used = used;\n        }\n\n        // Updates the filesystem, available, and used list.\n        function updateDisks() {\n            if(angular.isArray($scope.node.disks)) {\n                $scope.has_disks = $scope.node.disks.length > 0;\n                updateFilesystems();\n                updateCacheSets();\n                updateAvailable();\n                updateUsed();\n            } else {\n                $scope.has_disks = false;\n                $scope.filesystems = [];\n                $scope.filesystemsMap = {};\n                $scope.filesystemMode = SELECTION_MODE.NONE;\n                $scope.filesystemAllSelected = false;\n                $scope.cachesets = [];\n                $scope.cachesetsMap = {};\n                $scope.cachesetsMode = SELECTION_MODE.NONE;\n                $scope.cachesetsAllSelected = false;\n                $scope.available = [];\n                $scope.availableMap = {};\n                $scope.availableMode = SELECTION_MODE.NONE;\n                $scope.availableAllSelected = false;\n                $scope.availableNew = {};\n                $scope.used = [];\n            }\n        }\n\n        // Deselect all items in the array.\n        function deselectAll(items) {\n            angular.forEach(items, function(item) {\n                item.$selected = false;\n            });\n        }\n\n        // Capitalize the first letter of the string.\n        function capitalizeFirstLetter(string) {\n            return string.charAt(0).toUpperCase() + string.slice(1);\n        }\n\n        // Return true if the string is a number.\n        function isNumber(string) {\n            var pattern = /^-?\\d+\\.?\\d*$/;\n            return pattern.test(string);\n        }\n\n        // Extract the index from the name based on prefix.\n        function getIndexFromName(prefix, name) {\n            var pattern = new RegExp(\"^\" + prefix + \"([0-9]+)$\");\n            var match = pattern.exec(name);\n            if(angular.isArray(match) && match.length === 2) {\n                return parseInt(match[1], 10);\n            }\n        }\n\n        // Get the next device name based on prefix.\n        function getNextName(prefix) {\n            var idx = -1;\n            angular.forEach($scope.node.disks, function(disk) {\n                var dIdx = getIndexFromName(prefix, disk.name);\n                if(angular.isNumber(dIdx)) {\n                    idx = Math.max(idx, dIdx);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    dIdx = getIndexFromName(prefix, partition.name);\n                    if(angular.isNumber(dIdx)) {\n                        idx = Math.max(idx, dIdx);\n                    }\n                });\n            });\n            return prefix + (idx + 1);\n        }\n\n        // Return true if another disk exists with name.\n        function isNameAlreadyInUse(name, exclude_disk) {\n            if(!angular.isArray($scope.node.disks)) {\n                return false;\n            }\n\n            var i, j;\n            for(i = 0; i < $scope.node.disks.length; i++) {\n                var disk = $scope.node.disks[i];\n                if(disk.name === name) {\n                    if(!angular.isObject(exclude_disk) ||\n                        exclude_disk.type === \"partition\" ||\n                        exclude_disk.block_id !== disk.id) {\n                        return true;\n                    }\n                }\n                if(angular.isArray(disk.partitions)) {\n                    for(j = 0; j < disk.partitions.length; j++) {\n                        var partition = disk.partitions[j];\n                        if(partition.name === name) {\n                            if(!angular.isObject(exclude_disk) ||\n                                exclude_disk.type !== \"partition\" ||\n                                exclude_disk.partition_id !== partition.id) {\n                                return true;\n                            }\n                        }\n                    }\n                }\n            }\n            return false;\n        }\n\n        // Return true if the disk is a logical volume.\n        function isLogicalVolume(disk) {\n            return disk.type === \"virtual\" && disk.parent_type === \"lvm-vg\";\n        }\n\n        // Called by $parent when the node has been loaded.\n        $scope.nodeLoaded = function() {\n            $scope.$watch(\"node.disks\", updateDisks);\n        };\n\n        // Return true if the item can be a boot disk.\n        $scope.isBootDiskDisabled = function(item, section) {\n            // Only superusers can change the boot disk.\n            if(!$scope.isSuperUser()) {\n                return true;\n            }\n\n            // Not ready or allocated so the boot disk cannot be changed.\n            if (angular.isObject($scope.node) &&\n                [\"Ready\", \"Allocated\"].indexOf(\n                    $scope.node.status) === -1) {\n                return true;\n            }\n\n            // Only physical disks can be the boot disk.\n            if(item.type !== \"physical\") {\n                return true;\n            }\n\n            // If the disk is in the used section and does not have any\n            // partitions then it cannot be a boot disk. Boot disk either\n            // require that it be unused or that some partitions exists\n            // on the disk. This is because the boot disk has to have a\n            // partition table header.\n            if(section === \"used\") {\n                return !item.has_partitions;\n            }\n            return false;\n        };\n\n        // Called to change the disk to a boot disk.\n        $scope.setAsBootDisk = function(item) {\n            // Do nothing if already the boot disk.\n            if(item.is_boot) {\n                return;\n            }\n            // Do nothing if disabled.\n            if($scope.isBootDiskDisabled(item)) {\n                return;\n            }\n\n            MachinesManager.setBootDisk($scope.node, item.block_id);\n        };\n\n        // Return array of selected filesystems.\n        $scope.getSelectedFilesystems = function() {\n            var filesystems = [];\n            angular.forEach($scope.filesystems, function(filesystem) {\n                if(filesystem.$selected) {\n                    filesystems.push(filesystem);\n                }\n            });\n            return filesystems;\n        };\n\n        // Update the currect mode for the filesystem section and the all\n        // selected value.\n        $scope.updateFilesystemSelection = function(force) {\n            if(angular.isUndefined(force)) {\n                force = false;\n            }\n            var filesystems = $scope.getSelectedFilesystems();\n            if(filesystems.length === 0) {\n                $scope.filesystemMode = SELECTION_MODE.NONE;\n            } else if(filesystems.length === 1 && force) {\n                $scope.filesystemMode = SELECTION_MODE.SINGLE;\n            } else if(force) {\n                $scope.filesystemMode = SELECTION_MODE.MUTLI;\n            }\n\n            if($scope.filesystems.length === 0) {\n                $scope.filesystemAllSelected = false;\n            } else if(filesystems.length === $scope.filesystems.length) {\n                $scope.filesystemAllSelected = true;\n            } else {\n                $scope.filesystemAllSelected = false;\n            }\n        };\n\n        // Toggle the selection of the filesystem.\n        $scope.toggleFilesystemSelect = function(filesystem) {\n            filesystem.$selected = !filesystem.$selected;\n            $scope.updateFilesystemSelection(true);\n        };\n\n        // Toggle the selection of all filesystems.\n        $scope.toggleFilesystemAllSelect = function() {\n            angular.forEach($scope.filesystems, function(filesystem) {\n                if($scope.filesystemAllSelected) {\n                    filesystem.$selected = false;\n                } else {\n                    filesystem.$selected = true;\n                }\n            });\n            $scope.updateFilesystemSelection(true);\n        };\n\n        // Return true if checkboxes in the filesystem section should be\n        // disabled.\n        $scope.isFilesystemsDisabled = function() {\n            return ((\n                $scope.filesystemMode !== SELECTION_MODE.NONE &&\n                $scope.filesystemMode !== SELECTION_MODE.SINGLE &&\n                $scope.filesystemMode !== SELECTION_MODE.MUTLI) ||\n                $scope.isAllStorageDisabled());\n        };\n\n        // Cancel the current filesystem operation.\n        $scope.filesystemCancel = function() {\n            deselectAll($scope.filesystems);\n            $scope.updateFilesystemSelection(true);\n        };\n\n        // Enter unmount mode.\n        $scope.filesystemUnmount = function() {\n            $scope.filesystemMode = SELECTION_MODE.UNMOUNT;\n        };\n\n        // Quickly enter unmount by selecting the filesystem first.\n        $scope.quickFilesystemUnmount = function(filesystem) {\n            deselectAll($scope.filesystems);\n            filesystem.$selected = true;\n            $scope.updateFilesystemSelection(true);\n            $scope.filesystemUnmount();\n        };\n\n        // Confirm the unmount action for filesystem.\n        $scope.filesystemConfirmUnmount = function(filesystem) {\n            MachinesManager.updateFilesystem(\n                $scope.node,\n                filesystem.block_id, filesystem.partition_id,\n                filesystem.fstype, null, null);\n\n            var idx = $scope.filesystems.indexOf(filesystem);\n            $scope.filesystems.splice(idx, 1);\n            $scope.updateFilesystemSelection();\n        };\n\n        // Enter delete mode.\n        $scope.filesystemDelete = function() {\n            $scope.filesystemMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter delete by selecting the filesystem first.\n        $scope.quickFilesystemDelete = function(filesystem) {\n            deselectAll($scope.filesystems);\n            filesystem.$selected = true;\n            $scope.updateFilesystemSelection(true);\n            $scope.filesystemDelete();\n        };\n\n        // Confirm the delete action for filesystem.\n        $scope.filesystemConfirmDelete = function(filesystem) {\n            if(filesystem.original_type === \"special\") {\n                // Delete the special filesystem.\n                MachinesManager.unmountSpecialFilesystem(\n                    $scope.node, filesystem.mount_point);\n            } else if(filesystem.original_type === \"partition\") {\n                // Delete the partition.\n                MachinesManager.deletePartition(\n                    $scope.node, filesystem.original.id);\n            } else {\n                // Delete the disk.\n                MachinesManager.deleteFilesystem(\n                    $scope.node, filesystem.block_id, filesystem.partition_id,\n                    filesystem.filesystem_id);\n            }\n\n            var idx = $scope.filesystems.indexOf(filesystem);\n            $scope.filesystems.splice(idx, 1);\n            $scope.updateFilesystemSelection();\n        };\n\n        // Return true if the disk has an unmouted filesystem.\n        $scope.hasUnmountedFilesystem = function(disk) {\n            if(angular.isString(disk.fstype) && disk.fstype !== \"\") {\n                if(!angular.isString(disk.mount_point) ||\n                    disk.mount_point === \"\") {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Return true if the free space label should be shown.\n        $scope.showFreeSpace = function(disk) {\n            if(disk.type === \"lvm-vg\") {\n                return true;\n            } else if(disk.type === \"physical\" || disk.type === \"virtual\") {\n                return disk.has_partitions;\n            } else {\n                return false;\n            }\n        };\n\n        // Return the device type for the disk.\n        $scope.getDeviceType = function(disk) {\n            if(angular.isUndefined(disk)) {\n                return \"\";\n            }\n\n            if(disk.type === \"virtual\") {\n                if(disk.parent_type === \"lvm-vg\") {\n                    return \"Logical volume\";\n                } else if(disk.parent_type.indexOf(\"raid-\") === 0) {\n                    return \"RAID \" + disk.parent_type.split(\"-\")[1];\n                } else {\n                    return capitalizeFirstLetter(disk.parent_type);\n                }\n            } else if(disk.type === \"lvm-vg\") {\n                return \"Volume group\";\n            } else {\n                return capitalizeFirstLetter(disk.type);\n            }\n        };\n\n        // Return array of selected available disks.\n        $scope.getSelectedAvailable = function() {\n            var available = [];\n            angular.forEach($scope.available, function(disk) {\n                if(disk.$selected) {\n                    available.push(disk);\n                }\n            });\n            return available;\n        };\n\n        // Update the currect mode for the available section and the all\n        // selected value.\n        $scope.updateAvailableSelection = function(force) {\n            if(angular.isUndefined(force)) {\n                force = false;\n            }\n            var available = $scope.getSelectedAvailable();\n            if(available.length === 0) {\n                $scope.availableMode = SELECTION_MODE.NONE;\n            } else if(available.length === 1 && force) {\n                $scope.availableMode = SELECTION_MODE.SINGLE;\n            } else if(force) {\n                $scope.availableMode = SELECTION_MODE.MUTLI;\n            }\n\n            if($scope.available.length === 0) {\n                $scope.availableAllSelected = false;\n            } else if(available.length === $scope.available.length) {\n                $scope.availableAllSelected = true;\n            } else {\n                $scope.availableAllSelected = false;\n            }\n        };\n\n        // Toggle the selection of the available disk.\n        $scope.toggleAvailableSelect = function(disk) {\n            disk.$selected = !disk.$selected;\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Toggle the selection of all available disks.\n        $scope.toggleAvailableAllSelect = function() {\n            angular.forEach($scope.available, function(disk) {\n                if(!$scope.availableAllSelected) {\n                    disk.$selected = true;\n                } else {\n                    disk.$selected = false;\n                }\n            });\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if checkboxes in the avaiable section should be\n        // disabled.\n        $scope.isAvailableDisabled = function() {\n            return ((\n                $scope.availableMode !== SELECTION_MODE.NONE &&\n                $scope.availableMode !== SELECTION_MODE.SINGLE &&\n                $scope.availableMode !== SELECTION_MODE.MUTLI) ||\n                $scope.isAllStorageDisabled());\n        };\n\n        // Return true if the disk can be formatted and mounted.\n        $scope.canFormatAndMount = function(disk) {\n            if($scope.isAllStorageDisabled()) {\n                return false;\n            } else if(disk.type === \"lvm-vg\" || disk.has_partitions) {\n                return false;\n            } else if(disk.type === \"physical\" && disk.original.is_boot) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Return the text for the partition button.\n        $scope.getPartitionButtonText = function(disk) {\n            if(disk.has_partitions) {\n                return \"Add partition\";\n            } else {\n                return \"Partition\";\n            }\n        };\n\n        $scope.availablePartitionSpace = function(disk) {\n            var space_to_reserve = 0;\n            if(!angular.isString(disk.original.partition_table_type)\n                || disk.original.partition_table_type === \"\") {\n                // Disk has no partition table, so reserve space for it.\n                space_to_reserve = PARTITION_TABLE_EXTRA_SPACE;\n                // ppc64el node requires that space be saved for the prep\n                // partition.\n                if($scope.node.architecture.indexOf(\"ppc64el\") === 0) {\n                    space_to_reserve += PREP_PARTITION_SIZE;\n                }\n            }\n            return ConverterService.roundByBlockSize(\n                disk.original.available_size - space_to_reserve,\n                PARTITION_ALIGNMENT_SIZE);\n        };\n\n        // Return true if a partition can be added to disk.\n        $scope.canAddPartition = function(disk) {\n            if(!$scope.isSuperUser() || $scope.isAllStorageDisabled()) {\n                return false;\n            } else if(disk.type === \"partition\" || disk.type === \"lvm-vg\") {\n                return false;\n            } else if(disk.type === \"virtual\" &&\n                (disk.parent_type === \"lvm-vg\" ||\n                    disk.parent_type === \"bcache\")) {\n                return false;\n            } else if(angular.isString(disk.fstype) && disk.fstype !== \"\") {\n                return false;\n            }\n            // If we can fit a minimum partition, we're golden.\n            return ($scope.availablePartitionSpace(disk) -\n                MIN_PARTITION_SIZE) >= 0;\n        };\n\n        // Return true if the name is invalid.\n        $scope.isNameInvalid = function(disk) {\n            if(disk.name === \"\") {\n                return false;\n            } else if(isNameAlreadyInUse(disk.name, disk)) {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Prevent logical volumes from changing the volume group prefix.\n        $scope.nameHasChanged = function(disk) {\n            if(isLogicalVolume(disk)) {\n                var parentName = disk.original.name.split(\"-\")[0] + \"-\";\n                var startsWith = disk.name.indexOf(parentName);\n                if(startsWith !== 0) {\n                    disk.name = parentName;\n                }\n            }\n        };\n\n        // Cancel the current available operation.\n        $scope.availableCancel = function(disk) {\n            $scope.updateAvailableSelection(true);\n            $scope.availableNew = {};\n        };\n\n        // Return true if the filesystem can be mounted at a directory.\n        $scope.usesMountPoint = function(fstype) {\n            return angular.isString(fstype) && fstype !== \"swap\";\n        };\n\n        // Return true if the filesystem uses storage (partition or\n        // block device).\n        $scope.usesStorage = function(fstype) {\n            return angular.isString(fstype) &&\n                fstype !== \"tmpfs\" && fstype !== \"ramfs\";\n        };\n\n        // Return true if the mount point is invalid.\n        $scope.isMountPointInvalid = function(mountPoint) {\n            if(angular.isUndefined(mountPoint) || mountPoint === \"\") {\n                return false;\n            } else if (mountPoint === \"none\") {\n                // XXX: Hack to allow \"swap\" filesystems to be mounted.\n                // This should be allowed only when fstype is 'swap' but\n                // doing that would require more refactoring (or more\n                // hacks) that I have time for right now.\n                return false;\n            } else if(mountPoint[0] !== \"/\") {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Return true if the disk can be deleted.\n        $scope.canDelete = function(disk) {\n            if (!$scope.isSuperUser() || $scope.isAllStorageDisabled()) {\n                return false;\n            } else if(disk.type === \"lvm-vg\") {\n                return disk.original.used_size === 0;\n            } else {\n                return !disk.has_partitions;\n            }\n        };\n\n        // Enter delete mode.\n        $scope.availableDelete = function() {\n            $scope.availableMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter delete mode.\n        $scope.availableQuickDelete = function(disk) {\n            deselectAll($scope.available);\n            disk.$selected = true;\n            $scope.updateAvailableSelection(true);\n            $scope.availableDelete();\n        };\n\n        // Return true if it can be edited.\n        $scope.canEdit = function(disk) {\n          if (!$scope.isSuperUser() || $scope.isAllStorageDisabled()) {\n              return false;\n          } else {\n              return true;\n          }\n        };\n\n        // Enter Edit mode, disable certain fields based on disk type\n        $scope.availableEdit = function(disk) {\n            $scope.availableMode = SELECTION_MODE.EDIT;\n\n            if (disk.type === \"lvm-vg\") {\n                disk.$options = {\n                    editingTags: false,\n                    editingFilesystem: false\n                };\n            } else if (disk.type === \"partition\") {\n                disk.$options = {\n                    editingTags: false,\n                    editingFilesystem: true,\n                    fstype: disk.fstype\n                };\n            } else {\n                disk.$options = {\n                    editingFilesystem: true,\n                    editingTags: true,\n                    tags: angular.copy(disk.tags),\n                    fstype: disk.fstype\n                };\n                if (!$scope.canFormatAndMount(disk)) {\n                    disk.$options.editingFilesystem = false;\n                }\n            }\n        };\n\n        // Quickly enter Edit mode\n        $scope.availableQuickEdit = function(disk) {\n            deselectAll($scope.available);\n            disk.$selected = true;\n            $scope.updateAvailableSelection(true);\n            $scope.availableEdit(disk);\n        };\n\n        // Save the disk which is in Edit mode\n        $scope.availableConfirmEdit = function(disk) {\n            var params = {\n                name: disk.name\n            };\n\n            // Do nothing if not valid.\n            if($scope.isNameInvalid(disk) ||\n                $scope.isMountPointInvalid(disk.$options.mountPoint)) {\n                return;\n            }\n\n            // Reset the name if its blank.\n            if(disk.name === \"\") {\n                disk.name = disk.original.name;\n            }\n\n            // Ensure logical volume has parent prefix in its name.\n            if(isLogicalVolume(disk)){\n                var parentName = disk.original.name.split(\"-\")[0] + \"-\";\n                params.name = disk.name.slice(parentName.length);\n            }\n\n            // Set filesystem options so formatting and mounting is performed.\n            if(angular.isDefined(disk.$options.fstype)) {\n                params.fstype = disk.$options.fstype;\n                params.mount_point = disk.$options.mountPoint || '';\n                params.mount_options = disk.$options.mountOptions || '';\n            }\n\n            // Update the tags for the disk.\n            if(angular.isArray(disk.$options.tags)) {\n                params.tags = disk.$options.tags.map(\n                    function(tag) { return tag.text; });\n            }\n\n            // Save the options.\n            MachinesManager.updateDisk(\n                $scope.node, disk.block_id, params);\n\n            // Set the options on the object so no flicker occurs while waiting\n            // for the new object to be received.\n            disk.fstype = disk.$options.fstype;\n            disk.mount_point = disk.$options.mountPoint;\n            disk.mount_options = disk.$options.mountOptions;\n            disk.tags = disk.$options.tags;\n            disk.$options = {};\n\n            // If the mount_point is set the we need to transition this to\n            // the filesystem section.\n            if(angular.isString(disk.mount_point) && disk.mount_point !== \"\") {\n                $scope.filesystems.push({\n                    \"name\": disk.name,\n                    \"size_human\": disk.size_human,\n                    \"fstype\": disk.fstype,\n                    \"mount_point\": disk.mount_point,\n                    \"mount_options\": disk.mount_options,\n                    \"block_id\": disk.block_id,\n                    \"partition_id\": disk.partition_id\n                });\n\n                // Remove the selected disk from available.\n                var idx = $scope.available.indexOf(disk);\n                $scope.available.splice(idx, 1);\n            }\n\n            // Deselect the disk after saving\n            disk.$selected = false;\n\n            // Update the current selections.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return the text for remove confirmation message.\n        $scope.getRemoveTypeText = function(disk) {\n            if(disk.type === \"filesystem\") {\n                if (angular.isObject(disk.original)) {\n                    disk = disk.original;\n                } else {\n                    return \"special filesystem\";\n                }\n            }\n\n            if(disk.type === \"physical\") {\n                return \"physical disk\";\n            } else if(disk.type === \"partition\") {\n                return \"partition\";\n            } else if(disk.type === \"lvm-vg\") {\n                return \"volume group\";\n            } else if(disk.type === \"virtual\") {\n                if(disk.parent_type === \"lvm-vg\") {\n                    return \"logical volume\";\n                } else if(disk.parent_type.indexOf(\"raid-\") === 0) {\n                    return \"RAID \" + disk.parent_type.split(\"-\")[1] + \" disk\";\n                } else {\n                    return disk.parent_type + \" disk\";\n                }\n            }\n        };\n\n        // Delete the disk, partition, or volume group.\n        $scope.availableConfirmDelete = function(disk) {\n            if(disk.type === \"lvm-vg\") {\n                // Delete the volume group.\n                MachinesManager.deleteVolumeGroup(\n                    $scope.node, disk.block_id);\n            } else if(disk.type === \"partition\") {\n                // Delete the partition.\n                MachinesManager.deletePartition(\n                    $scope.node, disk.partition_id);\n            } else {\n                // Delete the disk.\n                MachinesManager.deleteDisk(\n                    $scope.node, disk.block_id);\n            }\n\n            // Remove the selected disk from available.\n            var idx = $scope.available.indexOf(disk);\n            $scope.available.splice(idx, 1);\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Enter partition mode.\n        $scope.availablePartition = function(disk) {\n            $scope.availableMode = SELECTION_MODE.PARTITION;\n            // Set starting size to the maximum available space.\n            var size_and_units = disk.available_size_human.split(\" \");\n            disk.$options = {\n                size: size_and_units[0],\n                sizeUnits: size_and_units[1],\n                fstype: null,\n                mountPoint: \"\",\n                mountOptions: \"\"\n            };\n        };\n\n        // Quickly enter partition mode.\n        $scope.availableQuickPartition = function(disk) {\n            deselectAll($scope.available);\n            disk.$selected = true;\n            $scope.updateAvailableSelection(true);\n            $scope.availablePartition(disk);\n        };\n\n        // Get the new name of the partition.\n        $scope.getAddPartitionName = function(disk) {\n            var length, partitions = disk.original.partitions;\n            if(angular.isArray(partitions)) {\n                length = partitions.length;\n            } else {\n                length = 0;\n            }\n            if(disk.original.partition_table_type === \"mbr\" &&\n                length > 2) {\n                return disk.name + \"-part\" + (length + 2);\n            } else if($scope.node.architecture.indexOf(\"ppc64el\") === 0 &&\n                disk.original.is_boot) {\n                // Boot disk on ppc64el machines skip the first partition as\n                // its reserved for the prep partition.\n                return disk.name + \"-part\" + (length + 2);\n            } else {\n                return disk.name + \"-part\" + (length + 1);\n            }\n        };\n\n        // Return true if the size is invalid.\n        $scope.isAddPartitionSizeInvalid = function(disk) {\n            if(disk.$options.size === \"\" || !isNumber(disk.$options.size)) {\n                return true;\n            } else {\n                var bytes = ConverterService.unitsToBytes(\n                    disk.$options.size, disk.$options.sizeUnits);\n                if(bytes < MIN_PARTITION_SIZE) {\n                    return true;\n                } else if(bytes > disk.original.available_size) {\n                    // Round the size down to the lowest tolerance for that\n                    // to see if it now fits.\n                    var rounded = ConverterService.roundUnits(\n                        disk.$options.size, disk.$options.sizeUnits);\n                    if(rounded > disk.original.available_size) {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                } else {\n                    return false;\n                }\n            }\n        };\n\n        // Confirm the partition creation.\n        $scope.availableConfirmPartition = function(disk) {\n            // Do nothing if not valid.\n            if($scope.isAddPartitionSizeInvalid(disk) ||\n                $scope.isMountPointInvalid(disk.$options.mountPoint)) {\n                return;\n            }\n\n            // Get the bytes to create the partition.\n            var bytes = ConverterService.unitsToBytes(\n                disk.$options.size, disk.$options.sizeUnits);\n\n            // Accepting prefilled defaults means use whole disk (lp:1509535).\n            var size_and_units = disk.original.available_size_human.split(\" \");\n            if(disk.$options.size === size_and_units[0] &&\n               disk.$options.sizeUnits === size_and_units[1]) {\n                bytes = disk.original.available_size;\n            }\n\n            var removeDisk = false;\n            var available_space = $scope.availablePartitionSpace(disk);\n            if(bytes >= available_space) {\n                // Clamp to available space.\n                bytes = available_space;\n                // Remove the disk if partition uses all the remaining space.\n                removeDisk = true;\n            }\n\n            // Create the partition.\n            var params = {};\n            if(angular.isString(disk.$options.fstype) &&\n                disk.$options.fstype !== \"\") {\n                params.fstype = disk.$options.fstype;\n                if(disk.$options.mountPoint !== \"\") {\n                    params.mount_point = disk.$options.mountPoint;\n                    params.mount_options = disk.$options.mountOptions;\n                }\n            }\n            MachinesManager.createPartition(\n                $scope.node, disk.block_id, bytes, params);\n\n            // Remove the disk if needed.\n            if(removeDisk) {\n                var idx = $scope.available.indexOf(disk);\n                $scope.available.splice(idx, 1);\n            }\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return array of selected cache sets.\n        $scope.getSelectedCacheSets = function() {\n            var cachesets = [];\n            angular.forEach($scope.cachesets, function(cacheset) {\n                if(cacheset.$selected) {\n                    cachesets.push(cacheset);\n                }\n            });\n            return cachesets;\n        };\n\n        // Update the currect mode for the cache sets section and the all\n        // selected value.\n        $scope.updateCacheSetsSelection = function(force) {\n            if(angular.isUndefined(force)) {\n                force = false;\n            }\n            var cachesets = $scope.getSelectedCacheSets();\n            if(cachesets.length === 0) {\n                $scope.cachesetsMode = SELECTION_MODE.NONE;\n            } else if(cachesets.length === 1 && force) {\n                $scope.cachesetsMode = SELECTION_MODE.SINGLE;\n            } else if(force) {\n                $scope.cachesetsMode = SELECTION_MODE.MUTLI;\n            }\n\n            if($scope.cachesets.length === 0) {\n                $scope.cachesetsAllSelected = false;\n            } else if(cachesets.length === $scope.cachesets.length) {\n                $scope.cachesetsAllSelected = true;\n            } else {\n                $scope.cachesetsAllSelected = false;\n            }\n        };\n\n        // Toggle the selection of the filesystem.\n        $scope.toggleCacheSetSelect = function(cacheset) {\n            cacheset.$selected = !cacheset.$selected;\n            $scope.updateCacheSetsSelection(true);\n        };\n\n        // Toggle the selection of all filesystems.\n        $scope.toggleCacheSetAllSelect = function() {\n            angular.forEach($scope.cachesets, function(cacheset) {\n                if($scope.cachesetsAllSelected) {\n                    cacheset.$selected = false;\n                } else {\n                    cacheset.$selected = true;\n                }\n            });\n            $scope.updateCacheSetsSelection(true);\n        };\n\n        // Return true if checkboxes in the cache sets section should be\n        // disabled.\n        $scope.isCacheSetsDisabled = function() {\n            return ((\n                $scope.isAllStorageDisabled() &&\n                !$scope.isSuperUser()) || (\n                $scope.cachesetsMode !== SELECTION_MODE.NONE &&\n                $scope.cachesetsMode !== SELECTION_MODE.SINGLE &&\n                $scope.cachesetsMode !== SELECTION_MODE.MUTLI));\n        };\n\n        // Cancel the current cache set operation.\n        $scope.cacheSetCancel = function() {\n            deselectAll($scope.cachesets);\n            $scope.updateCacheSetsSelection(true);\n        };\n\n        // Can delete the cache set.\n        $scope.canDeleteCacheSet = function(cacheset) {\n            return (cacheset.used_by === \"\" &&\n                    !$scope.isAllStorageDisabled() &&\n                    $scope.isSuperUser());\n        };\n\n        // Enter delete mode.\n        $scope.cacheSetDelete = function() {\n            $scope.cachesetsMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter delete by selecting the cache set first.\n        $scope.quickCacheSetDelete = function(cacheset) {\n            deselectAll($scope.cachesets);\n            cacheset.$selected = true;\n            $scope.updateCacheSetsSelection(true);\n            $scope.cacheSetDelete();\n        };\n\n        // Confirm the delete action for cache set.\n        $scope.cacheSetConfirmDelete = function(cacheset) {\n            MachinesManager.deleteCacheSet(\n                $scope.node, cacheset.cache_set_id);\n\n            var idx = $scope.cachesets.indexOf(cacheset);\n            $scope.cachesets.splice(idx, 1);\n            $scope.updateCacheSetsSelection();\n        };\n\n        // Return true if a cache set can be created.\n        $scope.canCreateCacheSet = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var selected = $scope.getSelectedAvailable();\n            if(selected.length === 1) {\n                return (\n                    !selected[0].has_partitions &&\n                    !$scope.hasUnmountedFilesystem(selected[0]) &&\n                    selected[0].type !== \"lvm-vg\");\n            }\n            return false;\n        };\n\n        // Called to create a cache set.\n        $scope.createCacheSet = function() {\n            if(!$scope.canCreateCacheSet()) {\n                return;\n            }\n\n            // Create cache set.\n            var disk = $scope.getSelectedAvailable()[0];\n            MachinesManager.createCacheSet(\n                $scope.node, disk.block_id, disk.partition_id);\n\n            // Remove from available.\n            var idx = $scope.available.indexOf(disk);\n            $scope.available.splice(idx, 1);\n        };\n\n        // Return the reason a bcache device cannot be created.\n        $scope.getCannotCreateBcacheMsg = function() {\n            if($scope.cachesets.length === 0) {\n                return \"Create at least one cache set to create bcache\";\n            } else {\n                var selected = $scope.getSelectedAvailable();\n                if(selected.length === 1) {\n                    if($scope.hasUnmountedFilesystem(selected[0])) {\n                        return (\n                            \"Device is formatted; unformat the \" +\n                            \"device to create bcache\");\n                    } else if(selected[0].type === \"lvm-vg\") {\n                        return (\n                            \"Cannot use a logical volume as a backing \" +\n                            \"device for bcache.\");\n                    } else if(selected[0].has_partitions) {\n                        return (\n                            \"Device has already been partitioned; create a \" +\n                            \"new partition to use as the bcache backing \" +\n                            \"device\");\n                    } else {\n                        return null;\n                    }\n                } else {\n                    return \"Select only one available device to create bcache\";\n                }\n            }\n        };\n\n        // Return true if a bcache can be created.\n        $scope.canCreateBcache = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var msg = $scope.getCannotCreateBcacheMsg();\n            if(msg === null) {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Enter bcache mode.\n        $scope.createBcache = function() {\n            if(!$scope.canCreateBcache()) {\n                return;\n            }\n            $scope.availableMode = SELECTION_MODE.BCACHE;\n            $scope.availableNew = {\n                name: getNextName(\"bcache\"),\n                device: $scope.getSelectedAvailable()[0],\n                cacheset: $scope.cachesets[0],\n                cacheMode: \"writeback\",\n                fstype: null,\n                mountPoint: \"\",\n                mountOptions: \"\",\n                tags: []\n            };\n        };\n\n        // Clear mount point when the fstype is changed.\n        $scope.fstypeChanged = function(options) {\n            if(options.fstype === null) {\n                options.mountPoint = \"\";\n                options.mountOptions = \"\";\n            }\n            else {\n                // Update the mount point to \"none\" if \"swap\" is\n                // selected, and vice-versa.\n                if ($scope.usesMountPoint(options.fstype)) {\n                    if (options.mountPoint === \"none\") {\n                        options.mountPoint = \"\";\n                    }\n                }\n                else {\n                    options.mountPoint = \"none\";\n                }\n            }\n        };\n\n        // Return true when the name of the new disk is invalid.\n        $scope.isNewDiskNameInvalid = function() {\n            if(!angular.isObject($scope.node) ||\n                !angular.isArray($scope.node.disks)) {\n                return true;\n            }\n\n            if($scope.availableNew.name === \"\") {\n                return true;\n            } else {\n                var i, j;\n                for(i = 0; i < $scope.node.disks.length; i++) {\n                    var disk = $scope.node.disks[i];\n                    if($scope.availableNew.name === disk.name) {\n                        return true;\n                    }\n                    if(angular.isArray(disk.partitions)) {\n                        for(j = 0; j < disk.partitions.length; j++) {\n                            var partition = disk.partitions[j];\n                            if($scope.availableNew.name === partition.name) {\n                                return true;\n                            }\n                        }\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Return true if bcache can be saved.\n        $scope.createBcacheCanSave = function() {\n            return (\n                !$scope.isNewDiskNameInvalid() &&\n                !$scope.isMountPointInvalid($scope.availableNew.mountPoint));\n        };\n\n        // Confirm and create the bcache device.\n        $scope.availableConfirmCreateBcache = function() {\n            if(!$scope.createBcacheCanSave()) {\n                return;\n            }\n\n            // Create the bcache.\n            var params = {\n                name: $scope.availableNew.name,\n                cache_set: $scope.availableNew.cacheset.cache_set_id,\n                cache_mode: $scope.availableNew.cacheMode\n            };\n            if($scope.availableNew.device.type === \"partition\") {\n                params.partition_id = $scope.availableNew.device.partition_id;\n            } else {\n                params.block_id = $scope.availableNew.device.block_id;\n            }\n            if(angular.isString($scope.availableNew.fstype) &&\n                $scope.availableNew.fstype !== \"\") {\n                params.fstype = $scope.availableNew.fstype;\n                // XXX: Inconsistent tests of mountPoint/mount_point; in\n                // places it's compared to \"\" (like here), in others\n                // it's tested with angular.isDefined(), others with\n                // angular.isString(), others angular.isString() ===\n                // false. This is *begging* for bugs.\n                if($scope.availableNew.mountPoint !== \"\") {\n                    params.mount_point = $scope.availableNew.mountPoint;\n                    params.mount_options = $scope.availableNew.mountOptions;\n                }\n            }\n            if(angular.isArray($scope.availableNew.tags)\n                && $scope.availableNew.tags.length > 0) {\n                params.tags = $scope.availableNew.tags.map(\n                    function(tag) { return tag.text; });\n            }\n            MachinesManager.createBcache($scope.node, params);\n\n            // Remove device from available.\n            var idx = $scope.available.indexOf($scope.availableNew.device);\n            $scope.available.splice(idx, 1);\n            $scope.availableNew = {};\n\n            // Update the selection.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if a RAID can be created.\n        $scope.canCreateRAID = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var selected = $scope.getSelectedAvailable();\n            if(selected.length > 1) {\n                var i;\n                for(i = 0; i < selected.length; i++) {\n                    if($scope.hasUnmountedFilesystem(selected[i])) {\n                        return false;\n                    } else if(selected[i].type === \"lvm-vg\") {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return false;\n        };\n\n        // Called to create a RAID.\n        $scope.createRAID = function() {\n            if(!$scope.canCreateRAID()) {\n                return;\n            }\n            $scope.availableMode = SELECTION_MODE.RAID;\n            $scope.availableNew = {\n                name: getNextName(\"md\"),\n                devices: $scope.getSelectedAvailable(),\n                mode: null,\n                spares: [],\n                fstype: null,\n                mountPoint: \"\",\n                mountOptions: \"\",\n                tags: []\n            };\n            $scope.availableNew.mode = $scope.getAvailableRAIDModes()[0];\n        };\n\n        // Get the available RAID modes.\n        $scope.getAvailableRAIDModes = function() {\n            if(!angular.isObject($scope.availableNew) ||\n                !angular.isArray($scope.availableNew.devices)) {\n                return [];\n            }\n\n            var modes = [];\n            angular.forEach(RAID_MODES, function(mode) {\n                if($scope.availableNew.devices.length >= mode.min_disks) {\n                    modes.push(mode);\n                }\n            });\n            return modes;\n        };\n\n        // Return the total number of available spares for the current mode.\n        $scope.getTotalNumberOfAvailableSpares = function() {\n            var mode = $scope.availableNew.mode;\n            if(angular.isUndefined(mode) || !mode.allows_spares) {\n                return 0;\n            } else {\n                var diff = $scope.availableNew.devices.length - mode.min_disks;\n                if(diff < 0) {\n                    diff = 0;\n                }\n                return diff;\n            }\n        };\n\n        // Return the number of remaining spares that can be selected.\n        $scope.getNumberOfRemainingSpares = function() {\n            var allowed = $scope.getTotalNumberOfAvailableSpares();\n            if(allowed <= 0) {\n                return 0;\n            } else {\n                return allowed - $scope.availableNew.spares.length;\n            }\n        };\n\n        // Return true if the spares column should be shown.\n        $scope.showSparesColumn = function() {\n            return $scope.getTotalNumberOfAvailableSpares() > 0;\n        };\n\n        // Called when the RAID mode is changed to reset the selected spares.\n        $scope.RAIDModeChanged = function() {\n            $scope.availableNew.spares = [];\n        };\n\n        // Return true if the disk is an active RAID member.\n        $scope.isActiveRAIDMember = function(disk) {\n            if(!angular.isArray($scope.availableNew.spares)) {\n                return true;\n            } else {\n                var idx = $scope.availableNew.spares.indexOf(\n                    getUniqueKey(disk));\n                return idx === -1;\n            }\n        };\n\n        // Return true if the disk is a spare RAID member.\n        $scope.isSpareRAIDMember = function(disk) {\n            return !$scope.isActiveRAIDMember(disk);\n        };\n\n        // Set the disk as an active RAID member.\n        $scope.setAsActiveRAIDMember = function(disk) {\n            var idx = $scope.availableNew.spares.indexOf(getUniqueKey(disk));\n            if(idx > -1) {\n                $scope.availableNew.spares.splice(idx, 1);\n            }\n        };\n\n        // Set the disk as a spare RAID member.\n        $scope.setAsSpareRAIDMember = function(disk) {\n            var key = getUniqueKey(disk);\n            var idx = $scope.availableNew.spares.indexOf(key);\n            if(idx === -1) {\n                $scope.availableNew.spares.push(key);\n            }\n        };\n\n        // Return the size of the new RAID device.\n        $scope.getNewRAIDSize = function() {\n            if(angular.isUndefined($scope.availableNew.mode)) {\n                return \"\";\n            }\n            var calculateSize = $scope.availableNew.mode.calculateSize;\n            if(!angular.isFunction(calculateSize)) {\n                return \"\";\n            }\n\n            // Get the number of disks and the minimum disk size in the RAID.\n            var numDisks = (\n                $scope.availableNew.devices.length -\n                $scope.availableNew.spares.length);\n            var minSize = Number.MAX_VALUE;\n            angular.forEach($scope.availableNew.devices, function(device) {\n                // Get the size of the device. For a block device it will be\n                // at available_size and for a partition it will be at size.\n                var deviceSize = (\n                    device.original.available_size || device.original.size);\n                minSize = Math.min(minSize, deviceSize);\n            });\n\n            // Calculate the new size.\n            var size = calculateSize(minSize, numDisks);\n            return ConverterService.bytesToUnits(size).string;\n        };\n\n        // Return true if RAID can be saved.\n        $scope.createRAIDCanSave = function() {\n            return (\n                !$scope.isNewDiskNameInvalid() &&\n                !$scope.isMountPointInvalid($scope.availableNew.mountPoint));\n        };\n\n        // Confirm and create the RAID device.\n        $scope.availableConfirmCreateRAID = function() {\n            if(!$scope.createRAIDCanSave()) {\n                return;\n            }\n\n            // Create the RAID.\n            var params = {\n                name: $scope.availableNew.name,\n                level: $scope.availableNew.mode.level,\n                block_devices: [],\n                partitions: [],\n                spare_devices: [],\n                spare_partitions: []\n            };\n            angular.forEach($scope.availableNew.devices, function(device) {\n                if($scope.isActiveRAIDMember(device)) {\n                    if(device.type === \"partition\") {\n                        params.partitions.push(device.partition_id);\n                    } else {\n                        params.block_devices.push(device.block_id);\n                    }\n                } else {\n                    if(device.type === \"partition\") {\n                        params.spare_partitions.push(device.partition_id);\n                    } else {\n                        params.spare_devices.push(device.block_id);\n                    }\n                }\n            });\n            if(angular.isString($scope.availableNew.fstype) &&\n                $scope.availableNew.fstype !== \"\") {\n                params.fstype = $scope.availableNew.fstype;\n                if($scope.availableNew.mountPoint !== \"\") {\n                    params.mount_point = $scope.availableNew.mountPoint;\n                    params.mount_options = $scope.availableNew.mountOptions;\n                }\n            }\n            if(angular.isArray($scope.availableNew.tags)\n                && $scope.availableNew.tags.length > 0) {\n                params.tags = $scope.availableNew.tags.map(\n                    function(tag) { return tag.text; });\n            }\n            MachinesManager.createRAID($scope.node, params);\n\n            // Remove devices from available.\n            angular.forEach($scope.availableNew.devices, function(device) {\n                var idx = $scope.available.indexOf($scope.availableNew.device);\n                $scope.available.splice(idx, 1);\n            });\n            $scope.availableNew = {};\n\n            // Update the selection.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if a volume group can be created.\n        $scope.canCreateVolumeGroup = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var selected = $scope.getSelectedAvailable();\n            if(selected.length > 0) {\n                var i;\n                for(i = 0; i < selected.length; i++) {\n                    if(selected[i].has_partitions) {\n                        return false;\n                    } else if($scope.hasUnmountedFilesystem(selected[i])) {\n                        return false;\n                    } else if(selected[i].type === \"lvm-vg\") {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return false;\n        };\n\n        // Called to create a volume group.\n        $scope.createVolumeGroup = function() {\n            if(!$scope.canCreateVolumeGroup()) {\n                return;\n            }\n            $scope.availableMode = SELECTION_MODE.VOLUME_GROUP;\n            $scope.availableNew = {\n                name: getNextName(\"vg\"),\n                devices: $scope.getSelectedAvailable()\n            };\n        };\n\n        // Return the size of the new volume group.\n        $scope.getNewVolumeGroupSize = function() {\n            var total = 0;\n            angular.forEach($scope.availableNew.devices, function(device) {\n                // Add available_size or size if available_size is not set.\n                total += (\n                    device.original.available_size || device.original.size);\n            });\n            return ConverterService.bytesToUnits(total).string;\n        };\n\n        // Return true if volume group can be saved.\n        $scope.createVolumeGroupCanSave = function() {\n            return !$scope.isNewDiskNameInvalid();\n        };\n\n        // Confirm and create the volume group device.\n        $scope.availableConfirmCreateVolumeGroup = function() {\n            if(!$scope.createVolumeGroupCanSave()) {\n                return;\n            }\n\n            // Create the RAID.\n            var params = {\n                name: $scope.availableNew.name,\n                block_devices: [],\n                partitions: []\n            };\n            angular.forEach($scope.availableNew.devices, function(device) {\n                if(device.type === \"partition\") {\n                    params.partitions.push(device.partition_id);\n                } else {\n                    params.block_devices.push(device.block_id);\n                }\n            });\n            MachinesManager.createVolumeGroup($scope.node, params);\n\n            // Remove devices from available.\n            angular.forEach($scope.availableNew.devices, function(device) {\n                var idx = $scope.available.indexOf($scope.availableNew.device);\n                $scope.available.splice(idx, 1);\n            });\n            $scope.availableNew = {};\n\n            // Update the selection.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if a logical volume can be added to disk.\n        $scope.canAddLogicalVolume = function(disk) {\n            if(disk.type !== \"lvm-vg\") {\n                return false;\n            } else if(disk.original.available_size < MIN_PARTITION_SIZE) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Enter logical volume mode.\n        $scope.availableLogicalVolume = function(disk) {\n            $scope.availableMode = SELECTION_MODE.LOGICAL_VOLUME;\n            disk.$selected = true;\n            // Set starting size to the maximum available space.\n            var size_and_units = disk.available_size_human.split(\" \");\n            var namePrefix = disk.name + \"-lv\";\n            disk.$options = {\n                name: getNextName(namePrefix),\n                size: size_and_units[0],\n                sizeUnits: size_and_units[1],\n                fstype: null,\n                tags: []\n            };\n        };\n\n        // Return true if the name of the logical volume is invalid.\n        $scope.isLogicalVolumeNameInvalid = function(disk) {\n            if(!angular.isString(disk.$options.name)) {\n                return false;\n            }\n            var startsWith = disk.$options.name.indexOf(disk.name + \"-\");\n            return (\n                startsWith !== 0 ||\n                disk.$options.name.length <= disk.name.length + 1 ||\n                isNameAlreadyInUse(disk.$options.name));\n        };\n\n        // Don't allow the name of the logical volume to remove the volume\n        // group name.\n        $scope.newLogicalVolumeNameChanged = function(disk) {\n            if(!angular.isString(disk.$options.name)) {\n                return;\n            }\n            var startsWith = disk.$options.name.indexOf(disk.name + \"-\");\n            if(startsWith !== 0) {\n                disk.$options.name = disk.name + \"-\";\n            }\n        };\n\n        // Return true if the logical volume size is invalid.\n        $scope.isAddLogicalVolumeSizeInvalid = function(disk) {\n            // Uses the same logic as the partition size checked.\n            return $scope.isAddPartitionSizeInvalid(disk);\n        };\n\n        // Confirm the logical volume creation.\n        $scope.availableConfirmLogicalVolume = function(disk) {\n            // Do nothing if not valid.\n            if($scope.isLogicalVolumeNameInvalid(disk) ||\n                $scope.isAddLogicalVolumeSizeInvalid(disk) ||\n                $scope.isMountPointInvalid(disk.$options.mountPoint)) {\n                return;\n            }\n\n            // Get the bytes to create the partition.\n            var bytes = ConverterService.unitsToBytes(\n                disk.$options.size, disk.$options.sizeUnits);\n\n            // Accepting prefilled defaults means use whole disk (lp:1509535).\n            var size_and_units = disk.original.available_size_human.split(\" \");\n            if(disk.$options.size === size_and_units[0] &&\n               disk.$options.sizeUnits === size_and_units[1]) {\n                bytes = disk.original.available_size;\n            }\n\n            // Clamp to available space.\n            if(bytes > disk.original.available_size) {\n                bytes = disk.original.available_size;\n            }\n\n            // Remove the disk if it is going to use all the remaining space.\n            var removeDisk = false;\n            if(bytes === disk.original.available_size) {\n                removeDisk = true;\n            }\n\n            // Remove the volume group name from the name.\n            var name = disk.$options.name.slice(disk.name.length + 1);\n\n            // Create the logical volume.\n            var params = {};\n            if(angular.isString(disk.$options.fstype) &&\n                disk.$options.fstype !== \"\") {\n                params.fstype = disk.$options.fstype;\n                if(disk.$options.mountPoint !== \"\") {\n                    params.mount_point = disk.$options.mountPoint;\n                    params.mount_options = disk.$options.mountOptions;\n                }\n            }\n            if(angular.isArray(disk.$options.tags)\n                && disk.$options.tags.length > 0) {\n                params.tags = disk.$options.tags.map(\n                    function(tag) { return tag.text; });\n            }\n            MachinesManager.createLogicalVolume(\n                $scope.node, disk.block_id, name, bytes, params);\n\n            // Remove the disk if needed.\n            if(removeDisk) {\n                var idx = $scope.available.indexOf(disk);\n                $scope.available.splice(idx, 1);\n            }\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Returns true if storage cannot be edited.\n        // (it can't be changed when the node is in any state other\n        //  than Ready or Allocated)\n        $scope.isAllStorageDisabled = function() {\n            var authUser = UsersManager.getAuthUser();\n            if(!angular.isObject(authUser) || !angular.isObject($scope.node) ||\n                (!authUser.is_superuser &&\n                 authUser.username !== $scope.node.owner)) {\n                return true;\n            }else if (angular.isObject($scope.node) &&\n                [\"Ready\", \"Allocated\"].indexOf(\n                    $scope.node.status) === -1) {\n                // If the node is not ready or allocated, disable storage panel.\n                return true;\n            } else {\n                // The node must be either ready or broken. Enable it.\n                return false;\n            }\n        };\n\n        // Returns true if there are storage layout errors\n        $scope.hasStorageLayoutIssues = function() {\n            if(angular.isObject($scope.node) &&\n                angular.isArray($scope.node.storage_layout_issues)) {\n                return $scope.node.storage_layout_issues.length > 0;\n            }\n            return false;\n        };\n\n        // Tell $parent that the storageController has been loaded.\n        $scope.$parent.controllerLoaded('storageController', $scope);\n    }]);\n","/*\n * Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Manage a node's filesystems, including adding special filesystems.\n */\n\n(function() {\n\n    function SpecialFilesystem() {\n        this.fstype = \"tmpfs\";\n        this.mountPoint = \"\";\n        this.mountOptions = \"\";\n    }\n\n    SpecialFilesystem.prototype.isValid = function() {\n        return this.mountPoint.startsWith(\"/\");\n    };\n\n    SpecialFilesystem.prototype.describe = function() {\n        var parts = [this.fstype];\n        // Add the mount point if specified and valid.\n        if (this.mountPoint.startsWith(\"/\")) {\n            parts.push(\"at \" + this.mountPoint);\n        }\n        // Filesystem-specific bits.\n        switch (this.fstype) {\n        case \"tmpfs\":\n            // Extract size=n parameter from mount options. Other\n            // options could be added in the future.\n            var size = this.mountOptions.match(/\\bsize=(\\d+)(%?)/);\n            if (size !== null) {\n                if (size[2] === \"%\") {\n                    parts.push(\"limited to \" + size[1] + \"% of memory\");\n                } else {\n                    parts.push(\"limited to \" + size[1] + \" bytes\");\n                }\n            }\n            break;\n        case \"ramfs\":\n            // This filesystem does not recognise any options. Consider\n            // warning about lack of a size limit.\n            break;\n        }\n        return parts.join(\" \");\n    };\n\n    function NodeFilesystemsController($scope) {\n\n        // Which drop-down is currently selected, e.g. \"special\".\n        $scope.dropdown = null;\n\n        // Select the \"special\" drop-down.\n        $scope.addSpecialFilesystem = function() {\n            $scope.dropdown = \"special\";\n        };\n\n        // Deselect the \"special\" drop-down.\n        $scope.addSpecialFilesystemFinished = function() {\n            if ($scope.dropdown === \"special\") {\n                $scope.dropdown = null;\n            }\n        };\n    }\n\n    function NodeAddSpecialFilesystemController($scope, MachinesManager) {\n\n        $scope.filesystem = new SpecialFilesystem();\n        $scope.description = null;  // Updated by watch.\n\n        $scope.$watch(\"filesystem\", function(filesystem) {\n            $scope.description = filesystem.describe();\n        }, true);\n\n        $scope.canMount = function() {\n            return $scope.filesystem.isValid();\n        };\n\n        $scope.mount = function() {\n            MachinesManager.mountSpecialFilesystem(\n                $scope.node, $scope.filesystem.fstype,\n                $scope.filesystem.mountPoint,\n                $scope.filesystem.mountOptions);\n            $scope.addSpecialFilesystemFinished();\n        };\n\n        $scope.cancel = function() {\n            $scope.filesystem = new SpecialFilesystem();\n            $scope.addSpecialFilesystemFinished();\n        };\n    }\n\n    angular.module(\"MAAS\").controller(\n        \"NodeFilesystemsController\", [\n            \"$scope\", NodeFilesystemsController\n        ]);\n\n    angular.module(\"MAAS\").controller(\n        \"NodeAddSpecialFilesystemController\", [\n            \"$scope\", \"MachinesManager\",\n            NodeAddSpecialFilesystemController\n        ]);\n\n}());\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Events Controller\n */\n\nangular.module('MAAS').controller('NodeEventsController', [\n    '$scope', '$rootScope', '$routeParams',\n    'MachinesManager', 'ControllersManager', 'EventsManagerFactory',\n    'ManagerHelperService', 'ErrorService', function($scope, $rootScope,\n        $routeParams, MachinesManager, ControllersManager, EventsManagerFactory,\n        ManagerHelperService, ErrorService) {\n\n        // Events manager that is loaded once the node is loaded.\n        var eventsManager = null;\n\n        // Set the title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"nodes\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.node = null;\n        $scope.events = [];\n        $scope.eventsLoaded = false;\n        $scope.days = 1;\n\n        // Called once the node is loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n\n            // Get the events manager and load it.\n            eventsManager = EventsManagerFactory.getManager(node.id);\n            $scope.events = eventsManager.getItems();\n            $scope.days = eventsManager.getMaximumDays();\n            eventsManager.loadItems().then(function() {\n                $scope.eventsLoaded = true;\n            });\n\n            // Update the title when the fqdn of the node changes.\n            $scope.$watch(\"node.fqdn\", function() {\n                $rootScope.title = $scope.node.fqdn + \" - events\";\n            });\n        }\n\n        // Return the nice text for the given event.\n        $scope.getEventText = function(event) {\n            var text = event.type.description;\n            if(angular.isString(event.description) &&\n                event.description.length > 0) {\n                text += \" - \" + event.description;\n            }\n            return text;\n        };\n\n        // Called to load more events.\n        $scope.loadMore = function() {\n            $scope.days += 1;\n            eventsManager.loadMaximumDays($scope.days);\n        };\n\n        if($routeParams.type === 'controller') {\n            $scope.nodesManager = ControllersManager;\n            $scope.type_name = 'controller';\n        }else{\n            $scope.nodesManager = MachinesManager;\n            $scope.type_name = 'machine';\n        }\n        // Load nodes manager.\n        ManagerHelperService.loadManager(\n            $scope, $scope.nodesManager).then(function() {\n            // If redirected from the NodeDetailsController then the node\n            // will already be active. No need to set it active again.\n            var activeNode = $scope.nodesManager.getActiveItem();\n            if(angular.isObject(activeNode) &&\n                activeNode.system_id === $routeParams.system_id) {\n                nodeLoaded(activeNode);\n            } else {\n                $scope.nodesManager.setActiveItem(\n                    $routeParams.system_id).then(function(node) {\n                        nodeLoaded(node);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n\n        // Destroy the events manager when the scope is destroyed. This is so\n        // the client will not recieve any more notifications about events\n        // for this node.\n        $scope.$on(\"$destroy\", function() {\n            if(angular.isObject(eventsManager)) {\n                eventsManager.destroy();\n            }\n        });\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Script Result Controller\n */\n\nangular.module('MAAS').controller('NodeResultController', [\n    '$scope', '$rootScope', '$routeParams', '$location',\n    'MachinesManager', 'ControllersManager', 'NodeResultsManagerFactory',\n    'ManagerHelperService', 'ErrorService',\n    function($scope, $rootScope, $routeParams, $location, MachinesManager,\n             ControllersManager, NodeResultsManagerFactory,\n             ManagerHelperService, ErrorService) {\n        // Set the title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"nodes\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.resultLoaded = false;\n        $scope.node = null;\n        $scope.output = 'combined';\n        $scope.result = null;\n\n        $scope.get_result_data = function(output) {\n            $scope.output = output;\n            $scope.data = \"Loading...\";\n            var nodeResultsManager = NodeResultsManagerFactory.getManager(\n                $scope.node);\n            nodeResultsManager.get_result_data(\n                $scope.result.id, $scope.output).then(\n                    function(data) {\n                        if(data === '') {\n                            $scope.data = \"Empty file.\";\n                        }else{\n                            $scope.data = data;\n                        }\n                    });\n        };\n\n        // Called once the node is loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n\n            // Get the NodeResultsManager and load it.\n            var nodeResultsManager = NodeResultsManagerFactory.getManager(\n                $scope.node);\n            var requestedResult = parseInt($routeParams.id, 10);\n            nodeResultsManager.getItem(requestedResult).then(function(result) {\n                $scope.result = result;\n                $scope.get_result_data($scope.output);\n                $scope.resultLoaded = true;\n                $rootScope.title = $scope.node.fqdn + \" - \" +\n                    $scope.result.name;\n            });\n        }\n\n        // Update the title when the fqdn of the node changes.\n        $scope.$watch(\"node.fqdn\", function() {\n            if(angular.isObject($scope.node) &&\n               angular.isObject($scope.result)) {\n                $rootScope.title = $scope.node.fqdn + \" - \" +\n                    $scope.result.name;\n            }\n        });\n\n        if($routeParams.type === 'controller') {\n            $scope.nodesManager = ControllersManager;\n            $scope.type_name = 'controller';\n        }else{\n            $scope.nodesManager = MachinesManager;\n            $scope.type_name = 'machine';\n        }\n        // Load nodes manager.\n        ManagerHelperService.loadManager(\n            $scope, $scope.nodesManager).then(function() {\n            // If redirected from the NodeDetailsController then the node\n            // will already be active. No need to set it active again.\n            var activeNode = $scope.nodesManager.getActiveItem();\n            if(angular.isObject(activeNode) &&\n                activeNode.system_id === $routeParams.system_id) {\n                nodeLoaded(activeNode);\n            } else {\n                $scope.nodesManager.setActiveItem(\n                    $routeParams.system_id).then(function(node) {\n                        nodeLoaded(node);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n\n        // Destroy the NodeResultsManager when the scope is destroyed. This is\n        // so the client will not recieve any more notifications about results\n        // from this node.\n        $scope.$on(\"$destroy\", function() {\n            var nodeResultsManager = NodeResultsManagerFactory.getManager(\n                $scope.node);\n            if(angular.isObject(nodeResultsManager)) {\n                nodeResultsManager.destroy();\n            }\n        });\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Results Controller\n */\n\nangular.module('MAAS').controller('NodeResultsController', [\n    '$scope', '$routeParams', 'MachinesManager', 'ControllersManager',\n    'NodeResultsManagerFactory', 'ManagerHelperService', 'ErrorService',\n    function($scope, $routeParams, MachinesManager, ControllersManager,\n             NodeResultsManagerFactory, ManagerHelperService, ErrorService) {\n\n        // NodeResultsManager that is loaded once the node is loaded.\n        $scope.nodeResultsManager = null;\n        // References to manager data used in scope.\n        $scope.commissioning_results = null;\n        $scope.testing_results = null;\n        $scope.installation_results = null;\n        $scope.results = null;\n\n        // List of logs available.\n        $scope.logs = {\n            option: null,\n            availableOptions: []\n        };\n        // Log content being displayed.\n        $scope.logOutput = 'Loading...';\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.resultsLoaded = false;\n        $scope.node = null;\n\n        function updateLogs() {\n            var i;\n            var option;\n            var had_installation = $scope.logs.availableOptions.length === 3;\n            $scope.logs.availableOptions.length = 0;\n            // XXX ltrager 2017-12-01 - Only show the current installation log\n            // if the machine is deploying, deployed, or failed deploying. The\n            // logs page needs to be redesigned to show previous installation\n            // results.\n            if($scope.installation_results &&\n                    $scope.installation_results.length > 0 && (\n                        $scope.node.status_code === 6 ||\n                        $scope.node.status_code === 9 ||\n                        $scope.node.status_code === 11)) {\n                $scope.logs.availableOptions.push({\n                    'title': 'Installation output',\n                    'id': $scope.installation_results[0].id\n                });\n            }\n            $scope.logs.availableOptions.push({\n                'title': 'Machine output (YAML)',\n                'id': 'summary_yaml'\n            });\n            $scope.logs.availableOptions.push({\n                'title': 'Machine output (XML)',\n                'id': 'summary_xml'\n            });\n            if(!had_installation &&\n               $scope.logs.availableOptions.length === 3) {\n                // A new installation log has appeared, show it.\n                $scope.logs.option = $scope.logs.availableOptions[0];\n            }else if(!$scope.selectedLog || (\n                had_installation && $scope.logs.length === 2)) {\n                // No longer in a deployed state.\n                $scope.logs.option = $scope.logs.availableOptions[0];\n            }\n        }\n\n        // Called once the node has loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n            // Get the NodeResultsManager and load it.\n            $scope.nodeResultsManager = NodeResultsManagerFactory.getManager(\n                node, $scope.section.area);\n            $scope.nodeResultsManager.loadItems().then(function() {\n                $scope.commissioning_results =\n                    $scope.nodeResultsManager.commissioning_results;\n                $scope.testing_results =\n                    $scope.nodeResultsManager.testing_results;\n                $scope.installation_results =\n                    $scope.nodeResultsManager.installation_results;\n                $scope.results = $scope.nodeResultsManager.results;\n                // Only load and monitor logs when on the logs page.\n                if($scope.section.area === \"logs\") {\n                    updateLogs();\n                    $scope.$watch(\"installation_results\", updateLogs, true);\n                    $scope.$watch(\n                        \"installation_results\", $scope.updateLogOutput, true);\n                }\n                $scope.resultsLoaded = true;\n            });\n        }\n\n        if($routeParams.type === 'controller') {\n            $scope.nodesManager = ControllersManager;\n        } else {\n            $scope.nodesManager = MachinesManager;\n        }\n        // Load nodes manager.\n        ManagerHelperService.loadManager(\n            $scope, $scope.nodesManager).then(function() {\n                // If redirected from the NodeDetailsController then the node\n                // will already be active. No need to set it active again.\n                var activeNode = $scope.nodesManager.getActiveItem();\n                if(angular.isObject(activeNode) &&\n                   activeNode.system_id === $routeParams.system_id) {\n                    nodeLoaded(activeNode);\n                } else {\n                    $scope.nodesManager.setActiveItem(\n                        $routeParams.system_id).then(function(node) {\n                            nodeLoaded(node);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                }\n            });\n\n        $scope.updateLogOutput = function() {\n            $scope.logOutput = \"Loading...\";\n            if(!$scope.node) {\n                return;\n            }else if($scope.logs.option.id === 'summary_xml') {\n                $scope.nodesManager.getSummaryXML($scope.node).then(\n                    function(output) {\n                        $scope.logOutput = output;\n                    });\n            }else if($scope.logs.option.id === 'summary_yaml') {\n                $scope.nodesManager.getSummaryYAML($scope.node).then(\n                    function(output) {\n                        $scope.logOutput = output;\n                    });\n            } else {\n                var result = null;\n                var i, j;\n                // Find the installation result to be displayed.\n                for(i = 0; i < $scope.installation_results.length; i++) {\n                    var hlist = $scope.installation_results[i].history_list;\n                    for(j = 0; j < hlist.length; j++) {\n                        if(hlist[j].id === $scope.logs.option.id) {\n                            result = hlist[j];\n                            break;\n                        }\n                    }\n                    if(result) {\n                        break;\n                    }\n                }\n                switch(result.status) {\n                    case 0:\n                        $scope.logOutput = \"System is booting...\";\n                        break;\n                    case 1:\n                        $scope.logOutput = \"Installation has begun!\";\n                        break;\n                    case 2:\n                        $scope.nodeResultsManager.get_result_data(\n                            result.id, 'combined').then(function(output) {\n                                if(output === '') {\n                                    $scope.logOutput =\n                                        \"Installation has succeeded but \" +\n                                        \"no output was given.\";\n                                } else {\n                                    $scope.logOutput = output;\n                                }\n                            });\n                        break;\n                    case 3:\n                        $scope.nodeResultsManager.get_result_data(\n                            result.id, 'combined').then(function(output) {\n                                if(output === '') {\n                                    $scope.logOutput =\n                                        \"Installation has failed and no \" +\n                                        \"output was given.\";\n                                } else {\n                                    $scope.logOutput = output;\n                                }\n                            });\n                        break;\n                    case 4:\n                        $scope.logOutput =\n                            \"Installation failed after 40 minutes.\";\n                        break;\n                    case 5:\n                        $scope.logOutput = \"Installation was aborted.\";\n                        break;\n                    default:\n                        $scope.logOutput = \"BUG: Unknown log status \" +\n                            result.status;\n                        break;\n                }\n            }\n        };\n\n        // Destroy the NodeResultsManager when the scope is destroyed. This is\n        // so the client will not recieve any more notifications about results\n        // from this node.\n        $scope.$on(\"$destroy\", function() {\n            if(angular.isObject($scope.nodeResultsManager)) {\n                $scope.nodeResultsManager.destroy();\n            }\n        });\n    }]);\n","/* Copyright 2015-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes List Controller\n */\n\nangular.module('MAAS').controller('NodesListController', [\n    '$scope', '$interval', '$rootScope', '$routeParams', '$location',\n    'MachinesManager', 'DevicesManager', 'ControllersManager',\n    'GeneralManager', 'ManagerHelperService', 'SearchService',\n    'ZonesManager', 'UsersManager', 'ServicesManager', 'ScriptsManager',\n    'SwitchesManager',\n    function($scope, $interval, $rootScope, $routeParams, $location,\n        MachinesManager, DevicesManager, ControllersManager, GeneralManager,\n        ManagerHelperService, SearchService, ZonesManager, UsersManager,\n        ServicesManager, ScriptsManager, SwitchesManager) {\n\n        // Mapping of device.ip_assignment to viewable text.\n        var DEVICE_IP_ASSIGNMENT = {\n            external: \"External\",\n            dynamic: \"Dynamic\",\n            \"static\": \"Static\"\n        };\n\n        // Set title and page.\n        $rootScope.title = \"Nodes\";\n        $rootScope.page = \"nodes\";\n\n        // Set initial values.\n        $scope.nodes = MachinesManager.getItems();\n        $scope.zones = ZonesManager.getItems();\n        $scope.devices = DevicesManager.getItems();\n        $scope.controllers = ControllersManager.getItems();\n        $scope.switches = SwitchesManager.getItems();\n        $scope.showswitches = $routeParams.switches === 'on';\n        $scope.currentpage = \"nodes\";\n        $scope.osinfo = GeneralManager.getData(\"osinfo\");\n        $scope.scripts = ScriptsManager.getItems();\n        $scope.loading = true;\n\n        $scope.tabs = {};\n        // Nodes tab.\n        $scope.tabs.nodes = {};\n        $scope.tabs.nodes.pagetitle = \"Machines\";\n        $scope.tabs.nodes.currentpage = \"nodes\";\n        $scope.tabs.nodes.manager = MachinesManager;\n        $scope.tabs.nodes.previous_search = \"\";\n        $scope.tabs.nodes.search = \"\";\n        $scope.tabs.nodes.searchValid = true;\n        $scope.tabs.nodes.selectedItems = MachinesManager.getSelectedItems();\n        $scope.tabs.nodes.metadata = MachinesManager.getMetadata();\n        $scope.tabs.nodes.filters = SearchService.getEmptyFilter();\n        $scope.tabs.nodes.actionOption = null;\n        $scope.tabs.nodes.takeActionOptions = GeneralManager.getData(\n            \"machine_actions\");\n        $scope.tabs.nodes.actionErrorCount = 0;\n        $scope.tabs.nodes.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.nodes.osSelection = {\n            osystem: null,\n            release: null,\n            hwe_kernel: null\n        };\n        $scope.tabs.nodes.zoneSelection = null;\n        $scope.tabs.nodes.commissionOptions = {\n            enableSSH: false,\n            skipNetworking: false,\n            skipStorage: false,\n            updateFirmware: false,\n            configureHBA: false\n        };\n        $scope.tabs.nodes.releaseOptions = {};\n        $scope.tabs.nodes.commissioningSelection = [];\n        $scope.tabs.nodes.testSelection = [];\n\n        // Device tab.\n        $scope.tabs.devices = {};\n        $scope.tabs.devices.pagetitle = \"Devices\";\n        $scope.tabs.devices.currentpage = \"devices\";\n        $scope.tabs.devices.manager = DevicesManager;\n        $scope.tabs.devices.previous_search = \"\";\n        $scope.tabs.devices.search = \"\";\n        $scope.tabs.devices.searchValid = true;\n        $scope.tabs.devices.selectedItems = DevicesManager.getSelectedItems();\n        $scope.tabs.devices.filtered_items = [];\n        $scope.tabs.devices.predicate = 'fqdn';\n        $scope.tabs.devices.allViewableChecked = false;\n        $scope.tabs.devices.metadata = DevicesManager.getMetadata();\n        $scope.tabs.devices.filters = SearchService.getEmptyFilter();\n        $scope.tabs.devices.column = 'fqdn';\n        $scope.tabs.devices.actionOption = null;\n        $scope.tabs.devices.takeActionOptions = GeneralManager.getData(\n            \"device_actions\");\n        $scope.tabs.devices.actionErrorCount = 0;\n        $scope.tabs.devices.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.devices.zoneSelection = null;\n\n        // Controller tab.\n        $scope.tabs.controllers = {};\n        $scope.tabs.controllers.pagetitle = \"Controllers\";\n        $scope.tabs.controllers.currentpage = \"controllers\";\n        $scope.tabs.controllers.manager = ControllersManager;\n        $scope.tabs.controllers.previous_search = \"\";\n        $scope.tabs.controllers.search = \"\";\n        $scope.tabs.controllers.searchValid = true;\n        $scope.tabs.controllers.selectedItems =\n            ControllersManager.getSelectedItems();\n        $scope.tabs.controllers.filtered_items = [];\n        $scope.tabs.controllers.predicate = 'fqdn';\n        $scope.tabs.controllers.allViewableChecked = false;\n        $scope.tabs.controllers.metadata = ControllersManager.getMetadata();\n        $scope.tabs.controllers.filters = SearchService.getEmptyFilter();\n        $scope.tabs.controllers.column = 'fqdn';\n        $scope.tabs.controllers.actionOption = null;\n        // Rack controllers contain all options\n        $scope.tabs.controllers.takeActionOptions = GeneralManager.getData(\n            \"rack_controller_actions\");\n        $scope.tabs.controllers.actionErrorCount = 0;\n        $scope.tabs.controllers.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.controllers.zoneSelection = null;\n        $scope.tabs.controllers.syncStatuses = {};\n        $scope.tabs.controllers.addController = false;\n        $scope.tabs.controllers.registerUrl = MAAS_config.register_url;\n        $scope.tabs.controllers.registerSecret = MAAS_config.register_secret;\n\n        // Switch tab.\n        $scope.tabs.switches = {};\n        $scope.tabs.switches.pagetitle = \"Switches\";\n        $scope.tabs.switches.currentpage = \"switches\";\n        $scope.tabs.switches.manager = SwitchesManager;\n        $scope.tabs.switches.previous_search = \"\";\n        $scope.tabs.switches.search = \"\";\n        $scope.tabs.switches.searchValid = true;\n        $scope.tabs.switches.selectedItems = SwitchesManager.getSelectedItems();\n        $scope.tabs.switches.predicate = 'fqdn';\n        $scope.tabs.switches.allViewableChecked = false;\n        $scope.tabs.switches.metadata = SwitchesManager.getMetadata();\n        $scope.tabs.switches.filters = SearchService.getEmptyFilter();\n        $scope.tabs.switches.column = 'fqdn';\n        $scope.tabs.switches.actionOption = null;\n        // XXX: Which actions should there be?\n        $scope.tabs.switches.takeActionOptions = GeneralManager.getData(\n            \"machine_actions\");\n        $scope.tabs.switches.actionErrorCount = 0;\n        $scope.tabs.switches.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.switches.osSelection = {\n            osystem: null,\n            release: null,\n            hwe_kernel: null\n        };\n        $scope.tabs.switches.zoneSelection = null;\n        $scope.tabs.switches.commissioningSelection = [];\n        $scope.tabs.switches.commissionOptions = {\n            enableSSH: false,\n            skipNetworking: false,\n            skipStorage: false,\n            updateFirmware: false,\n            configureHBA: false\n        };\n        $scope.tabs.switches.releaseOptions = {};\n\n\n        // Options for add hardware dropdown.\n        $scope.addHardwareOption = null;\n        $scope.addHardwareOptions = [\n            {\n                name: \"machine\",\n                title: \"Machine\"\n            },\n            {\n                name: \"chassis\",\n                title: \"Chassis\"\n            }\n        ];\n\n        // This will hold the AddHardwareController once it is initialized.\n        // The controller will set this variable as it's always a child of\n        // this scope.\n        $scope.addHardwareScope = null;\n\n        // This will hold the AddDeviceController once it is initialized.\n        // The controller will set this variable as it's always a child of\n        // this scope.\n        $scope.addDeviceScope = null;\n\n        // When the addHardwareScope is hidden it will emit this event. We\n        // clear the call to action button, so it can be used again.\n        $scope.$on(\"addHardwareHidden\", function() {\n            $scope.addHardwareOption = null;\n        });\n\n        // Return true if the tab is in viewing selected mode.\n        function isViewingSelected(tab) {\n            var search = $scope.tabs[tab].search.toLowerCase();\n            return search === \"in:(selected)\" || search === \"in:selected\";\n        }\n\n        // Sets the search bar to only show selected.\n        function enterViewSelected(tab) {\n            $scope.tabs[tab].previous_search = $scope.tabs[tab].search;\n            $scope.tabs[tab].search = \"in:(Selected)\";\n        }\n\n        // Clear search bar from viewing selected.\n        function leaveViewSelected(tab) {\n            if(isViewingSelected(tab)) {\n                $scope.tabs[tab].search = $scope.tabs[tab].previous_search;\n                $scope.updateFilters(tab);\n            }\n        }\n\n        // Called to update `allViewableChecked`.\n        function updateAllViewableChecked(tab) {\n            // Not checked when the filtered nodes are empty.\n            if($scope.tabs[tab].filtered_items.length === 0) {\n                $scope.tabs[tab].allViewableChecked = false;\n                return;\n            }\n\n            // Loop through all filtered nodes and see if all are checked.\n            var i;\n            for(i = 0; i < $scope.tabs[tab].filtered_items.length; i++) {\n                if(!$scope.tabs[tab].filtered_items[i].$selected) {\n                    $scope.tabs[tab].allViewableChecked = false;\n                    return;\n                }\n            }\n            $scope.tabs[tab].allViewableChecked = true;\n        }\n\n        function clearAction(tab) {\n            resetActionProgress(tab);\n            leaveViewSelected(tab);\n            $scope.tabs[tab].actionOption = null;\n            $scope.tabs[tab].zoneSelection = null;\n            if(tab === \"nodes\" || tab === \"switches\") {\n                // Possible for this to be called before the osSelect\n                // direction is initialized. In that case it has not\n                // created the $reset function on the model object.\n                if(angular.isFunction(\n                    $scope.tabs[tab].osSelection.$reset)) {\n                    $scope.tabs[tab].osSelection.$reset();\n                }\n                $scope.tabs[tab].commissionOptions.enableSSH = false;\n                $scope.tabs[tab].commissionOptions.skipNetworking = false;\n                $scope.tabs[tab].commissionOptions.skipStorage = false;\n                $scope.tabs[tab].commissionOptions.updateFirmware = false;\n                $scope.tabs[tab].commissionOptions.configureHBA = false;\n            }\n            $scope.tabs[tab].commissioningSelection = [];\n            $scope.tabs[tab].testSelection = [];\n        }\n\n        // Clear the action if required.\n        function shouldClearAction(tab) {\n            if($scope.tabs[tab].selectedItems.length === 0) {\n                clearAction(tab);\n            }\n            if($scope.tabs[tab].actionOption && !isViewingSelected(tab)) {\n                $scope.tabs[tab].actionOption = null;\n            }\n        }\n\n        // Called when the filtered_items are updated. Checks if the\n        // filtered_items are empty and if the search still matches the\n        // previous search. This will reset the search when no nodes match\n        // the current filter.\n        function removeEmptyFilter(tab) {\n            if($scope.tabs[tab].filtered_items.length === 0 &&\n                $scope.tabs[tab].search !== \"\" &&\n                $scope.tabs[tab].search === $scope.tabs[tab].previous_search) {\n                $scope.tabs[tab].search = \"\";\n                $scope.updateFilters(tab);\n            }\n        }\n\n        // Update the number of selected items which have an error based on the\n        // current selected action.\n        function updateActionErrorCount(tab) {\n            var i;\n            $scope.tabs[tab].actionErrorCount = 0;\n            for(i = 0; i < $scope.tabs[tab].selectedItems.length; i++) {\n                var supported = $scope.supportsAction(\n                    $scope.tabs[tab].selectedItems[i], tab);\n                if(!supported) {\n                    $scope.tabs[tab].actionErrorCount += 1;\n                }\n                $scope.tabs[tab].selectedItems[i].action_failed = false;\n            }\n        }\n\n        // Reset actionProgress on tab to zero.\n        function resetActionProgress(tab) {\n            var progress = $scope.tabs[tab].actionProgress;\n            progress.completed = progress.total = 0;\n            progress.errors = {};\n            progress.showing_confirmation = false;\n            progress.affected_nodes = 0;\n        }\n\n        // Add error to action progress and group error messages by nodes.\n        function addErrorToActionProgress(tab, error, node) {\n            var progress = $scope.tabs[tab].actionProgress;\n            progress.completed += 1;\n            var nodes = progress.errors[error];\n            if(angular.isUndefined(nodes)) {\n                progress.errors[error] = [node];\n            } else {\n                nodes.push(node);\n            }\n        }\n\n        // After an action has been performed check if we can leave all nodes\n        // selected or if an error occured and we should only show the failed\n        // nodes.\n        function updateSelectedItems(tab) {\n            if(!$scope.hasActionsFailed(tab)) {\n                if(!$scope.hasActionsInProgress(tab)) {\n                     clearAction(tab);\n                     enterViewSelected(tab);\n                }\n                return;\n            }\n            angular.forEach($scope.tabs[tab].manager.getItems(),\n                    function(node) {\n                if(node.action_failed === false) {\n                    $scope.tabs[tab].manager.unselectItem(node.system_id);\n                }\n            });\n        }\n\n        // Toggles between the current tab.\n        $scope.toggleTab = function(tab) {\n            $rootScope.title = $scope.tabs[tab].pagetitle;\n            $scope.currentpage = tab;\n            $location.search('tab', tab);\n        };\n\n        // Clear the search bar.\n        $scope.clearSearch = function(tab) {\n            $scope.tabs[tab].search = \"\";\n            $scope.updateFilters(tab);\n        };\n\n        // Mark a node as selected or unselected.\n        $scope.toggleChecked = function(node, tab) {\n            if(tab !== 'nodes' && tab !== 'switches') {\n                if($scope.tabs[tab].manager.isSelected(node.system_id)) {\n                    $scope.tabs[tab].manager.unselectItem(node.system_id);\n                } else {\n                    $scope.tabs[tab].manager.selectItem(node.system_id);\n                }\n                updateAllViewableChecked(tab);\n            }\n            updateActionErrorCount(tab);\n            shouldClearAction(tab);\n        };\n\n        // Select all viewable nodes or deselect all viewable nodes.\n        $scope.toggleCheckAll = function(tab) {\n            if(tab !== 'nodes' && tab !== 'switches') {\n                if($scope.tabs[tab].allViewableChecked) {\n                    angular.forEach(\n                        $scope.tabs[tab].filtered_items, function(node) {\n                            $scope.tabs[tab].manager.unselectItem(\n                                node.system_id);\n                    });\n                } else {\n                    angular.forEach(\n                        $scope.tabs[tab].filtered_items, function(node) {\n                            $scope.tabs[tab].manager.selectItem(\n                                node.system_id);\n                    });\n                }\n                updateAllViewableChecked(tab);\n            }\n            updateActionErrorCount(tab);\n            shouldClearAction(tab);\n        };\n\n        $scope.onNodeListingChanged = function(nodes, tab) {\n            if(nodes.length === 0 &&\n                $scope.tabs[tab].search !== \"\" &&\n                $scope.tabs[tab].search === $scope.tabs[tab].previous_search) {\n                $scope.tabs[tab].search = \"\";\n                $scope.updateFilters(tab);\n            }\n        };\n\n        // When the filtered nodes change update if all check buttons\n        // should be checked or not.\n        $scope.$watchCollection(\"tabs.devices.filtered_items\", function() {\n            updateAllViewableChecked(\"devices\");\n            removeEmptyFilter(\"devices\");\n        });\n        $scope.$watchCollection(\"tabs.controllers.filtered_items\", function() {\n            updateAllViewableChecked(\"controllers\");\n            removeEmptyFilter(\"controllers\");\n        });\n\n        // Shows the current selection.\n        $scope.showSelected = function(tab) {\n            enterViewSelected(tab);\n            $scope.updateFilters(tab);\n        };\n\n        // Adds or removes a filter to the search.\n        $scope.toggleFilter = function(type, value, tab) {\n            // Don't allow a filter to be changed when an action is\n            // in progress.\n            if(angular.isObject($scope.tabs[tab].actionOption)) {\n                return;\n            }\n            $scope.tabs[tab].filters = SearchService.toggleFilter(\n                $scope.tabs[tab].filters, type, value, true);\n            $scope.tabs[tab].search = SearchService.filtersToString(\n                $scope.tabs[tab].filters);\n        };\n\n        // Return True if the filter is active.\n        $scope.isFilterActive = function(type, value, tab) {\n            return SearchService.isFilterActive(\n                $scope.tabs[tab].filters, type, value, true);\n        };\n\n        // Update the filters object when the search bar is updated.\n        $scope.updateFilters = function(tab) {\n            var filters = SearchService.getCurrentFilters(\n                $scope.tabs[tab].search);\n            if(filters === null) {\n                $scope.tabs[tab].filters = SearchService.getEmptyFilter();\n                $scope.tabs[tab].searchValid = false;\n            } else {\n                $scope.tabs[tab].filters = filters;\n                $scope.tabs[tab].searchValid = true;\n            }\n            shouldClearAction(tab);\n        };\n\n        // Sorts the table by predicate.\n        $scope.sortTable = function(predicate, tab) {\n            $scope.tabs[tab].predicate = predicate;\n            $scope.tabs[tab].reverse = !$scope.tabs[tab].reverse;\n        };\n\n        // Sets the viewable column or sorts.\n        $scope.selectColumnOrSort = function(predicate, tab) {\n            if($scope.tabs[tab].column !== predicate) {\n                $scope.tabs[tab].column = predicate;\n            } else {\n                $scope.sortTable(predicate, tab);\n            }\n        };\n\n        // Return True if the node supports the action.\n        $scope.supportsAction = function(node, tab) {\n            if(!$scope.tabs[tab].actionOption) {\n                return true;\n            }\n            return node.actions.indexOf(\n                $scope.tabs[tab].actionOption.name) >= 0;\n        };\n\n        // Called when the action option gets changed.\n        $scope.actionOptionSelected = function(tab) {\n            updateActionErrorCount(tab);\n            enterViewSelected(tab);\n\n            // Hide the add hardware/device section.\n            if (tab === 'nodes') {\n                if(angular.isObject($scope.addHardwareScope)) {\n                    $scope.addHardwareScope.hide();\n                }\n            } else if(tab === 'devices') {\n                if(angular.isObject($scope.addDeviceScope)) {\n                    $scope.addDeviceScope.hide();\n                }\n            }\n        };\n\n        // Return True if there is an action error.\n        $scope.isActionError = function(tab) {\n            if(angular.isObject($scope.tabs[tab].actionOption) &&\n                $scope.tabs[tab].actionOption.name === \"deploy\" &&\n                $scope.tabs[tab].actionErrorCount === 0 &&\n                ($scope.osinfo.osystems.length === 0 ||\n                UsersManager.getSSHKeyCount() === 0)) {\n                return true;\n            }\n            return $scope.tabs[tab].actionErrorCount !== 0;\n        };\n\n        // Return True if unable to deploy because of missing images.\n        $scope.isDeployError = function(tab) {\n            if($scope.tabs[tab].actionErrorCount !== 0) {\n                return false;\n            }\n            if(angular.isObject($scope.tabs[tab].actionOption) &&\n                $scope.tabs[tab].actionOption.name === \"deploy\" &&\n                $scope.osinfo.osystems.length === 0) {\n                return true;\n            }\n            return false;\n        };\n\n        // Return True if unable to deploy because of missing ssh keys.\n        $scope.isSSHKeyError = function(tab) {\n            if($scope.tabs[tab].actionErrorCount !== 0) {\n                return false;\n            }\n            if(angular.isObject($scope.tabs[tab].actionOption) &&\n                $scope.tabs[tab].actionOption.name === \"deploy\" &&\n                UsersManager.getSSHKeyCount() === 0) {\n                return true;\n            }\n            return false;\n        };\n\n        // Called when the current action is cancelled.\n        $scope.actionCancel = function(tab) {\n            resetActionProgress(tab);\n            leaveViewSelected(tab);\n            $scope.tabs[tab].actionOption = null;\n        };\n\n        // Perform the action on all nodes.\n        $scope.actionGo = function(tab) {\n            var extra = {};\n            var i;\n            // Set deploy parameters if a deploy or set zone action.\n            if($scope.tabs[tab].actionOption.name === \"deploy\" &&\n                angular.isString($scope.tabs[tab].osSelection.osystem) &&\n                angular.isString($scope.tabs[tab].osSelection.release)) {\n\n                // Set extra. UI side the release is structured os/release, but\n                // when it is sent over the websocket only the \"release\" is\n                // sent.\n                extra.osystem = $scope.tabs[tab].osSelection.osystem;\n                var release = $scope.tabs[tab].osSelection.release;\n                release = release.split(\"/\");\n                release = release[release.length-1];\n                extra.distro_series = release;\n                // hwe_kernel is optional so only include it if its specified\n                if(angular.isString($scope.tabs[tab].osSelection.hwe_kernel) &&\n                   ($scope.tabs[tab].osSelection.hwe_kernel.indexOf('hwe-')\n                    >= 0 ||\n                    $scope.tabs[tab].osSelection.hwe_kernel.indexOf('ga-')\n                    >= 0)) {\n                    extra.hwe_kernel = $scope.tabs[tab].osSelection.hwe_kernel;\n                }\n            } else if($scope.tabs[tab].actionOption.name === \"set-zone\" &&\n                angular.isNumber($scope.tabs[tab].zoneSelection.id)) {\n                // Set the zone parameter.\n                extra.zone_id = $scope.tabs[tab].zoneSelection.id;\n            } else if($scope.tabs[tab].actionOption.name === \"commission\") {\n                // Set the commission options.\n                extra.enable_ssh = (\n                    $scope.tabs[tab].commissionOptions.enableSSH);\n                extra.skip_networking = (\n                    $scope.tabs[tab].commissionOptions.skipNetworking);\n                extra.skip_storage = (\n                    $scope.tabs[tab].commissionOptions.skipStorage);\n                extra.commissioning_scripts = [];\n                for(i=0;i<$scope.tabs[tab].commissioningSelection.length;i++) {\n                    extra.commissioning_scripts.push(\n                        $scope.tabs[tab].commissioningSelection[i].id);\n                }\n                if($scope.tabs[tab].commissionOptions.updateFirmware) {\n                    extra.commissioning_scripts.push('update_firmware')\n                }\n                if($scope.tabs[tab].commissionOptions.configureHBA) {\n                    extra.commissioning_scripts.push('configure_hba')\n                }\n                if(extra.commissioning_scripts.length === 0) {\n                    // Tell the region not to run any custom commissioning\n                    // scripts.\n                    extra.commissioning_scripts.push('none');\n                }\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.tabs[tab].testSelection.length;i++) {\n                    extra.testing_scripts.push(\n                        $scope.tabs[tab].testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.tabs[tab].actionOption.name === \"test\") {\n                if(!$scope.tabs[tab].actionProgress.showing_confirmation) {\n                    var progress = $scope.tabs[tab].actionProgress;\n                    for(i=0;i<$scope.tabs[tab].selectedItems.length;i++) {\n                        if($scope.tabs[tab].selectedItems[i].status_code === 6)\n                        {\n                            progress.showing_confirmation = true;\n                            progress.affected_nodes++;\n                        }\n                    }\n                    if($scope.tabs[tab].actionProgress.affected_nodes != 0) {\n                        return;\n                    }\n                }\n                // Set the test options.\n                extra.enable_ssh = (\n                    $scope.tabs[tab].commissionOptions.enableSSH);\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.tabs[tab].testSelection.length;i++) {\n                    extra.testing_scripts.push(\n                        $scope.tabs[tab].testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.tabs[tab].actionOption.name === \"release\") {\n                // Set the release options.\n                extra.erase = (\n                    $scope.tabs[tab].releaseOptions.erase);\n                extra.secure_erase = (\n                    $scope.tabs[tab].releaseOptions.secureErase);\n                extra.quick_erase = (\n                    $scope.tabs[tab].releaseOptions.quickErase);\n            }\n\n            // Setup actionProgress.\n            resetActionProgress(tab);\n            $scope.tabs[tab].actionProgress.total =\n                $scope.tabs[tab].selectedItems.length;\n\n            // Perform the action on all selected items.\n            angular.forEach($scope.tabs[tab].selectedItems, function(node) {\n                $scope.tabs[tab].manager.performAction(\n                    node, $scope.tabs[tab].actionOption.name,\n                    extra).then(function() {\n                        $scope.tabs[tab].actionProgress.completed += 1;\n                        node.action_failed = false;\n                        updateSelectedItems(tab);\n                    }, function(error) {\n                        addErrorToActionProgress(tab, error, node);\n                        node.action_failed = true;\n                        updateSelectedItems(tab);\n                    });\n            });\n        };\n\n        // Returns true when actions are being performed.\n        $scope.hasActionsInProgress = function(tab) {\n            var progress = $scope.tabs[tab].actionProgress;\n            return progress.total > 0 && progress.completed !== progress.total;\n        };\n\n        // Returns true if any of the actions have failed.\n        $scope.hasActionsFailed = function(tab) {\n            return Object.keys(\n                $scope.tabs[tab].actionProgress.errors).length > 0;\n        };\n\n        // Called to when the addHardwareOption has changed.\n        $scope.addHardwareOptionChanged = function() {\n            if($scope.addHardwareOption) {\n                $scope.addHardwareScope.show(\n                    $scope.addHardwareOption.name);\n            }\n        };\n\n        // Called when the add device button is pressed.\n        $scope.addDevice = function() {\n            $scope.addDeviceScope.show();\n        };\n\n        // Called when the cancel add device button is pressed.\n        $scope.cancelAddDevice = function() {\n            $scope.addDeviceScope.cancel();\n        };\n\n        // Get the display text for device ip assignment type.\n        $scope.getDeviceIPAssignment = function(ipAssignment) {\n            return DEVICE_IP_ASSIGNMENT[ipAssignment];\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        $scope.hasCustomCommissioningScripts = function() {\n            var i;\n            for(i=0;i<$scope.scripts.length;i++) {\n                if($scope.scripts[i].script_type === 0) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Load the required managers for this controller. The ServicesManager\n        // is required by the maasControllerStatus directive that is used\n        // in the partial for this controller.\n        ManagerHelperService.loadManagers($scope, [\n            MachinesManager, DevicesManager, ControllersManager,\n            GeneralManager, ZonesManager, UsersManager, ServicesManager,\n            ScriptsManager, SwitchesManager]).then(function() {\n                $scope.loading = false;\n            });\n\n        // Start polling for the os information.\n        GeneralManager.startPolling($scope, \"osinfo\");\n\n        // Stop polling and save the current filter when the scope is destroyed.\n        $scope.$on(\"$destroy\", function() {\n            $interval.cancel($scope.statusPoll);\n            GeneralManager.stopPolling($scope, \"osinfo\");\n            SearchService.storeFilters(\"nodes\", $scope.tabs.nodes.filters);\n            SearchService.storeFilters(\"devices\", $scope.tabs.devices.filters);\n            SearchService.storeFilters(\n                \"controllers\", $scope.tabs.controllers.filters);\n            SearchService.storeFilters(\n                \"switches\", $scope.tabs.switches.filters);\n        });\n\n        // Restore the filters if any saved.\n        var nodesFilter = SearchService.retrieveFilters(\"nodes\");\n        if(angular.isObject(nodesFilter)) {\n            $scope.tabs.nodes.search = SearchService.filtersToString(\n                nodesFilter);\n            $scope.updateFilters(\"nodes\");\n        }\n        var devicesFilter = SearchService.retrieveFilters(\"devices\");\n        if(angular.isObject(devicesFilter)) {\n            $scope.tabs.devices.search = SearchService.filtersToString(\n                devicesFilter);\n            $scope.updateFilters(\"devices\");\n        }\n        var controllersFilter = SearchService.retrieveFilters(\"controllers\");\n        if(angular.isObject(controllersFilter)) {\n            $scope.tabs.controllers.search = SearchService.filtersToString(\n                controllersFilter);\n            $scope.updateFilters(\"controllers\");\n        }\n        var switchesFilter = SearchService.retrieveFilters(\"switches\");\n        if(angular.isObject(switchesFilter)) {\n            $scope.tabs.switches.search = SearchService.filtersToString(\n                switchesFilter);\n            $scope.updateFilters(\"switches\");\n        }\n\n\n        // Switch to the specified tab, if specified.\n        if($routeParams.tab === \"nodes\" || $routeParams.tab === \"devices\" ||\n                $routeParams.tab === \"controllers\" ||\n                $routeParams.tab === \"switches\") {\n            $scope.toggleTab($routeParams.tab);\n        }\n\n        // Set the query if the present in $routeParams.\n        var query = $routeParams.query;\n        if(angular.isString(query)) {\n            $scope.tabs[$scope.currentpage].search = query;\n            $scope.updateFilters($scope.currentpage);\n        }\n    }]);\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Pod Details Controller\n */\n\nangular.module('MAAS').controller('PodDetailsController', [\n    '$scope', '$rootScope', '$location', '$routeParams',\n    'PodsManager', 'GeneralManager', 'UsersManager', 'DomainsManager',\n    'ZonesManager', 'ManagerHelperService', 'ErrorService', function(\n        $scope, $rootScope, $location, $routeParams,\n        PodsManager, GeneralManager, UsersManager, DomainsManager,\n        ZonesManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"pods\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.pod = null;\n        $scope.podManager = PodsManager;\n        $scope.action = {\n          option: null,\n          options: [\n            {\n              name: 'refresh',\n              title: 'Refresh',\n              sentence: 'refresh',\n              operation: angular.bind(PodsManager, PodsManager.refresh)\n            },\n            {\n              name: 'delete',\n              title: 'Delete',\n              sentence: 'delete',\n              operation: angular.bind(PodsManager, PodsManager.deleteItem)\n            }\n          ],\n          inProgress: false,\n          error: null\n        };\n        $scope.compose = {\n          action: {\n            name: 'compose',\n            title: 'Compose',\n            sentence: 'compose'\n          },\n          obj: {\n            storage: [{\n              type: 'local',\n              size: 8,\n              tags: [],\n              boot: true\n            }]\n          }\n        };\n        $scope.power_types = GeneralManager.getData(\"power_types\");\n        $scope.domains = DomainsManager.getItems();\n        $scope.zones = ZonesManager.getItems();\n        $scope.section = {\n          area: 'summary'\n        };\n        $scope.machinesSearch = 'pod-id:=invalid';\n        $scope.editing = false;\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if at least a rack controller is connected to the\n        // region controller.\n        $scope.isRackControllerConnected = function() {\n            // If power_types exist then a rack controller is connected.\n            return $scope.power_types.length > 0;\n        };\n\n        // Return true when the edit buttons can be clicked.\n        $scope.canEdit = function() {\n            return (\n                $scope.isRackControllerConnected() &&\n                    $scope.isSuperUser());\n        };\n\n        // Called to edit the pod configuration.\n        $scope.editPodConfiguration = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n            $scope.editing = true;\n        };\n\n        // Called when the cancel or save button is pressed.\n        $scope.exitEditPodConfiguration = function() {\n            $scope.editing = false;\n        };\n\n        // Return true if there is an action error.\n        $scope.isActionError = function() {\n            return $scope.action.error !== null;\n        };\n\n        // Called when the action.option has changed.\n        $scope.actionOptionChanged = function() {\n            // Clear the action error.\n            $scope.action.error = null;\n        };\n\n        // Cancel the action.\n        $scope.actionCancel = function() {\n            $scope.action.option = null;\n            $scope.action.error = null;\n        };\n\n        // Perform the action.\n        $scope.actionGo = function() {\n            $scope.action.inProgress = true;\n            $scope.action.option.operation($scope.pod).then(function() {\n                  // If the action was delete, then go back to listing.\n                  if($scope.action.option.name === \"delete\") {\n                      $location.path(\"/pods\");\n                  }\n                  $scope.action.inProgress = false;\n                  $scope.action.option = null;\n                  $scope.action.error = null;\n              }, function(error) {\n                  $scope.action.inProgress = false;\n                  $scope.action.error = error;\n              });\n        };\n\n        // Return the title of the pod type.\n        $scope.getPodTypeTitle = function() {\n            var i;\n            for(i = 0; i < $scope.power_types.length; i++) {\n                var power_type = $scope.power_types[i];\n                if(power_type.name === $scope.pod.type) {\n                    return power_type.description;\n                }\n            }\n            return $scope.pod.type;\n        };\n\n        // Returns true if the pod is composable.\n        $scope.canCompose = function() {\n            if(angular.isObject($scope.pod)) {\n                return ($scope.isSuperUser() &&\n                    $scope.pod.capabilities.indexOf('composable') >= 0);\n            } else {\n                return false;\n            }\n        };\n\n        // Opens the compose action menu.\n        $scope.composeMachine = function() {\n            $scope.action.option = $scope.compose.action;\n        };\n\n        // Called before the compose params is sent over the websocket.\n        $scope.composePreProcess = function(params) {\n            params = angular.copy(params);\n            params.id = $scope.pod.id;\n            // Sort boot disk first.\n            var sorted = $scope.compose.obj.storage.sort(function(a, b) {\n              if(a.boot === b.boot) {\n                return 0;\n              } else if(a.boot && !b.boot) {\n                return -1;\n              } else {\n                return 1;\n              }\n            });\n            // Create the storage constraint.\n            var storage = [];\n            angular.forEach(sorted, function(disk, idx) {\n              var constraint = idx + ':' + disk.size;\n              var tags = disk.tags.map(function(tag) {\n                return tag.text;\n              });\n              tags.splice(0, 0, disk.type);\n              constraint += '(' + tags.join(',') + ')';\n              storage.push(constraint);\n            });\n            params.storage = storage.join(',');\n            return params;\n        };\n\n        // Called to cancel composition.\n        $scope.cancelCompose = function() {\n          $scope.compose.obj = {\n            storage: [{\n              type: 'local',\n              size: 8,\n              tags: [],\n              boot: true\n            }]\n          };\n          $scope.action.option = null;\n        };\n\n        // Add another storage device.\n        $scope.composeAddStorage = function() {\n          var storage = {\n            type: 'local',\n            size: 8,\n            tags: [],\n            boot: false\n          };\n          if($scope.pod.capabilities.indexOf('iscsi_storage') >= 0) {\n            storage.type = 'iscsi';\n          }\n          $scope.compose.obj.storage.push(storage);\n        };\n\n        // Change which disk is the boot disk.\n        $scope.composeSetBootDisk = function(storage) {\n          angular.forEach($scope.compose.obj.storage, function(disk) {\n            disk.boot = false;\n          });\n          storage.boot = true;\n        };\n\n        // Remove a disk from storage config.\n        $scope.composeRemoveDisk = function(storage) {\n          var idx = $scope.compose.obj.storage.indexOf(storage);\n          if(idx >= 0) {\n            $scope.compose.obj.storage.splice(idx, 1);\n          }\n        };\n\n        // Start watching key fields.\n        $scope.startWatching = function() {\n            $scope.$watch(\"pod.name\", function() {\n                $rootScope.title = 'Pod ' + $scope.pod.name;\n            });\n            $scope.$watch(\"pod.capabilities\", function() {\n                // Show the composable action if the pod supports composition.\n                var idx = $scope.action.options.indexOf(\n                    $scope.compose.action);\n                if(!$scope.canCompose()) {\n                    if(idx >= 0) {\n                        $scope.action.options.splice(idx, 1);\n                    }\n                } else {\n                    if(idx === -1) {\n                        $scope.action.options.splice(\n                            0, 0, $scope.compose.action);\n                    }\n                }\n            });\n            $scope.$watch(\"action.option\", function(now, then) {\n                // When the compose action is selected set the default\n                // parameters.\n                if(now && now.name === 'compose') {\n                    if(!then || then.name !== 'compose') {\n                        $scope.compose.obj.domain = (\n                            DomainsManager.getDefaultDomain().id);\n                        $scope.compose.obj.zone = (\n                            ZonesManager.getDefaultZone().id);\n                    }\n                }\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            PodsManager, GeneralManager, UsersManager,\n            DomainsManager, ZonesManager]).then(function() {\n\n            // Possibly redirected from another controller that already had\n            // this pod set to active. Only call setActiveItem if not already\n            // the activeItem.\n            var activePod = PodsManager.getActiveItem();\n            if(angular.isObject(activePod) &&\n                activePod.id === parseInt($routeParams.id, 10)) {\n                $scope.pod = activePod;\n                $scope.loaded = true;\n                $scope.machinesSearch = 'pod-id:=' + $scope.pod.id;\n                $scope.startWatching();\n            } else {\n                PodsManager.setActiveItem(\n                    parseInt($routeParams.id, 10)).then(function(pod) {\n                        $scope.pod = pod;\n                        $scope.loaded = true;\n                        $scope.machinesSearch = 'pod-id:=' + $scope.pod.id;\n                        $scope.startWatching();\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Pods List Controller\n */\n\nangular.module('MAAS').controller('PodsListController', [\n    '$scope', '$rootScope',\n    'PodsManager', 'UsersManager', 'GeneralManager', 'ZonesManager',\n    'ManagerHelperService', function(\n        $scope, $rootScope, PodsManager, UsersManager, GeneralManager,\n        ZonesManager, ManagerHelperService) {\n\n        // Set title and page.\n        $rootScope.title = \"Pods\";\n        $rootScope.page = \"pods\";\n\n        // Set initial values.\n        $scope.podManager = PodsManager;\n        $scope.pods = PodsManager.getItems();\n        $scope.loading = true;\n\n        $scope.filteredItems = [];\n        $scope.selectedItems = PodsManager.getSelectedItems();\n        $scope.predicate = 'name';\n        $scope.allViewableChecked = false;\n        $scope.action = {\n          option: null,\n          options: [\n            {\n              name: 'refresh',\n              title: 'Refresh',\n              sentence: 'refresh',\n              operation: angular.bind(PodsManager, PodsManager.refresh)\n            },\n            {\n              name: 'delete',\n              title: 'Delete',\n              sentence: 'delete',\n              operation: angular.bind(PodsManager, PodsManager.deleteItem)\n            }\n          ],\n          progress: {\n              total: 0,\n              completed: 0,\n              errors: 0\n          }\n        };\n        $scope.add = {\n          open: false,\n          obj: {}\n        };\n        $scope.powerTypes = GeneralManager.getData(\"power_types\");\n        $scope.zones = ZonesManager.getItems();\n\n        // Called to update `allViewableChecked`.\n        function updateAllViewableChecked() {\n            // Not checked when no pods.\n            if($scope.pods.length === 0) {\n                $scope.allViewableChecked = false;\n                return;\n            }\n\n            // Loop through all filtered pods and see if all are checked.\n            var i;\n            for(i = 0; i < $scope.pods.length; i++) {\n                if(!$scope.pods[i].$selected) {\n                    $scope.allViewableChecked = false;\n                    return;\n                }\n            }\n            $scope.allViewableChecked = true;\n        }\n\n        function clearAction() {\n            resetActionProgress();\n            $scope.action.option = null;\n        }\n\n        // Clear the action if required.\n        function shouldClearAction() {\n            if($scope.selectedItems.length === 0) {\n                clearAction();\n                if($scope.action.option) {\n                    $scope.action.option = null;\n                }\n            }\n        }\n\n        // Reset actionProgress to zero.\n        function resetActionProgress() {\n            var progress = $scope.action.progress;\n            progress.completed = progress.total = progress.errors = 0;\n            angular.forEach($scope.pods, function(pod) {\n                delete pod.action_failed;\n            });\n        }\n\n        // After an action has been performed check if we can leave all pods\n        // selected or if an error occured and we should only show the failed\n        // pods.\n        function updateSelectedItems() {\n            if(!$scope.hasActionsFailed()) {\n                if(!$scope.hasActionsInProgress()) {\n                     clearAction();\n                }\n                return;\n            }\n            angular.forEach($scope.pods, function(pod) {\n                if(pod.action_failed === false) {\n                    PodsManager.unselectItem(pod.id);\n                }\n            });\n            shouldClearAction();\n        }\n\n        // Mark a pod as selected or unselected.\n        $scope.toggleChecked = function(pod) {\n            if(PodsManager.isSelected(pod.id)) {\n                PodsManager.unselectItem(pod.id);\n            } else {\n                PodsManager.selectItem(pod.id);\n            }\n            updateAllViewableChecked();\n            shouldClearAction();\n        };\n\n        // Select all viewable pods or deselect all viewable pods.\n        $scope.toggleCheckAll = function() {\n            if($scope.allViewableChecked) {\n                angular.forEach($scope.pods, function(pod) {\n                    PodsManager.unselectItem(pod.id);\n                });\n            } else {\n                angular.forEach($scope.pods, function(pod) {\n                    PodsManager.selectItem(pod.id);\n                });\n            }\n            updateAllViewableChecked();\n            shouldClearAction();\n        };\n\n        // When the pods change update if all check buttons should be\n        // checked or not.\n        $scope.$watchCollection(\"pods\", function() {\n            updateAllViewableChecked();\n        });\n\n        // Sorts the table by predicate.\n        $scope.sortTable = function(predicate) {\n            $scope.predicate = predicate;\n            $scope.reverse = !$scope.reverse;\n        };\n\n        // Called when the current action is cancelled.\n        $scope.actionCancel = function() {\n            resetActionProgress();\n            $scope.action.option = null;\n        };\n\n        // Perform the action on all pods.\n        $scope.actionGo = function() {\n            var extra = {};\n\n            // Setup actionProgress.\n            resetActionProgress();\n            $scope.action.progress.total = $scope.selectedItems.length;\n\n            // Perform the action on all selected items.\n            var operation = $scope.action.option.operation;\n            angular.forEach($scope.selectedItems, function(pod) {\n                operation(pod).then(function() {\n                        $scope.action.progress.completed += 1;\n                        pod.action_failed = false;\n                        updateSelectedItems();\n                    }, function(error) {\n                        $scope.action.progress.errors += 1;\n                        pod.action_error = error;\n                        pod.action_failed = true;\n                        updateSelectedItems();\n                    });\n            });\n        };\n\n        // Returns true when actions are being performed.\n        $scope.hasActionsInProgress = function() {\n            var progress = $scope.action.progress;\n            return progress.total > 0 && (\n                progress.completed + progress.errors) !== progress.total;\n        };\n\n        // Returns true if any of the actions have failed.\n        $scope.hasActionsFailed = function() {\n            var progress = $scope.action.progress;\n            return progress.errors > 0;\n        };\n\n        // Called when the add pod button is pressed.\n        $scope.addPod = function() {\n            $scope.add.open = true;\n        };\n\n        // Called when the cancel add pod button is pressed.\n        $scope.cancelAddPod = function() {\n            $scope.add.open = false;\n            $scope.add.obj = {};\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return the title of the power type.\n        $scope.getPowerTypeTitle = function(power_type) {\n            var i;\n            for(i = 0; i < $scope.powerTypes.length; i++) {\n                var powerType = $scope.powerTypes[i];\n                if(powerType.name === power_type) {\n                    return powerType.description;\n                }\n            }\n            return power_type;\n        };\n\n        // Load the required managers for this controller.\n        ManagerHelperService.loadManagers($scope, [\n            PodsManager, UsersManager, GeneralManager, ZonesManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Preferences Controller\n */\n\nangular.module('MAAS').controller('PreferencesController', [\n    '$scope', 'UsersManager', 'ManagerHelperService',\n    function(\n        $scope, UsersManager, ManagerHelperService) {\n            $scope.loading = true;\n            ManagerHelperService.loadManager(\n                $scope, UsersManager).then(function() {\n                    $scope.loading = false;\n                });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Settings Controller\n */\n\nangular.module('MAAS').controller('SettingsController', [\n    '$scope', '$rootScope', '$routeParams', 'PackageRepositoriesManager',\n    'DHCPSnippetsManager', 'MachinesManager', 'ControllersManager',\n    'DevicesManager', 'SubnetsManager', 'GeneralManager',\n    'ManagerHelperService',\n    function($scope, $rootScope, $routeParams, PackageRepositoriesManager,\n             DHCPSnippetsManager, MachinesManager, ControllersManager,\n             DevicesManager, SubnetsManager, GeneralManager,\n             ManagerHelperService) {\n\n        // Set the title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"settings\";\n\n        // Initial values.\n        $scope.loading = true;\n        $scope.snippetsManager = DHCPSnippetsManager;\n        $scope.snippets = DHCPSnippetsManager.getItems();\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.machines = MachinesManager.getItems();\n        $scope.devices = DevicesManager.getItems();\n        $scope.controllers = ControllersManager.getItems();\n        $scope.known_architectures =\n            GeneralManager.getData(\"known_architectures\");\n        $scope.pockets_to_disable =\n            GeneralManager.getData(\"pockets_to_disable\");\n        $scope.components_to_disable =\n            GeneralManager.getData(\"components_to_disable\");\n        $scope.packageRepositoriesManager = PackageRepositoriesManager;\n        $scope.repositories =\n            PackageRepositoriesManager.getItems();\n        $scope.newSnippet = null;\n        $scope.editSnippet = null;\n        $scope.deleteSnippet = null;\n        $scope.snippetTypes = [\"Global\", \"Subnet\", \"Node\"];\n        $scope.newRepository = null;\n        $scope.editRepository = null;\n        $scope.deleteRepository = null;\n\n        // Called when the enabled toggle is changed.\n        $scope.repositoryEnabledToggle = function(repository) {\n            PackageRepositoriesManager.updateItem(repository);\n        };\n\n        // Called to enter remove mode for a repository.\n        $scope.repositoryEnterRemove = function(repository) {\n            $scope.newRepository = null;\n            $scope.editRepository = null;\n            $scope.deleteRepository = repository;\n        };\n\n        // Called to exit remove mode for a repository.\n        $scope.repositoryExitRemove = function() {\n            $scope.deleteRepository = null;\n        };\n\n        // Called to confirm the removal of a repository.\n        $scope.repositoryConfirmRemove = function() {\n            PackageRepositoriesManager.deleteItem(\n                $scope.deleteRepository).then(function() {\n                    $scope.repositoryExitRemove();\n                });\n        };\n\n        // Return true if the repository is a PPA.\n        $scope.isPPA = function(data) {\n            if(!angular.isObject(data)) {\n                return false;\n            }\n            if(!angular.isString(data.url)) {\n                return false;\n            }\n            return data.url.indexOf(\"ppa:\") === 0 ||\n                data.url.indexOf(\"ppa.launchpad.net\") > -1;\n        };\n\n        // Return true if the repository is a mirror.\n        $scope.isMirror = function(data) {\n            if(!angular.isObject(data)) {\n                return false;\n            }\n            if(!angular.isString(data.name)) {\n                return false;\n            }\n            return data.name === \"main_archive\" ||\n                data.name === \"ports_archive\";\n        };\n\n        // Called to enter edit mode for a repository.\n        $scope.repositoryEnterEdit = function(repository) {\n            $scope.newRepository = null;\n            $scope.deleteRepository = null;\n            $scope.editRepository = repository;\n        };\n\n        // Called to exit edit mode for a repository.\n        $scope.repositoryExitEdit = function() {\n            $scope.editRepository = null;\n        };\n\n        // Called to start adding a new repository.\n        $scope.repositoryAdd = function(isPPA) {\n            var repo = {\n                name: \"\",\n                enabled: true,\n                url: \"\",\n                key: \"\",\n                arches: [\"i386\", \"amd64\"],\n                distributions: [],\n                components: []\n            };\n            if (isPPA) {\n                repo.url = \"ppa:\";\n            }\n            $scope.newRepository = repo;\n        };\n\n        // Called to cancel addind a new repository.\n        $scope.repositoryAddCancel = function() {\n            $scope.newRepository = null;\n        };\n\n        // Return the node from either the machines, devices, or controllers\n        // manager.\n        function getNode(system_id) {\n            var node = MachinesManager.getItemFromList(system_id);\n            if(angular.isObject(node)) {\n                return node;\n            }\n            node = DevicesManager.getItemFromList(system_id);\n            if(angular.isObject(node)) {\n                return node;\n            }\n            node = ControllersManager.getItemFromList(system_id);\n            if(angular.isObject(node)) {\n                return node;\n            }\n        }\n\n        // Return the name of the subnet.\n        $scope.getSubnetName = function(subnet) {\n            return SubnetsManager.getName(subnet);\n        };\n\n        // Return the text for the type of snippet.\n        $scope.getSnippetTypeText = function(snippet) {\n            if(angular.isString(snippet.node)) {\n                return \"Node\";\n            } else if(angular.isNumber(snippet.subnet)) {\n                return \"Subnet\";\n            } else {\n                return \"Global\";\n            }\n        };\n\n        // Return the object the snippet applies to.\n        $scope.getSnippetAppliesToObject = function(snippet) {\n            if(angular.isString(snippet.node)) {\n                return getNode(snippet.node);\n            } else if(angular.isNumber(snippet.subnet)) {\n                return SubnetsManager.getItemFromList(snippet.subnet);\n            }\n        };\n\n        // Return the applies to text that is disabled in none edit mode.\n        $scope.getSnippetAppliesToText = function(snippet) {\n            var obj = $scope.getSnippetAppliesToObject(snippet);\n            if(angular.isString(snippet.node) && angular.isObject(obj)) {\n                return obj.fqdn;\n            } else if(angular.isNumber(snippet.subnet) &&\n                angular.isObject(obj)) {\n                return SubnetsManager.getName(obj);\n            } else {\n                return \"\";\n            }\n        };\n\n        // Called to enter remove mode for a DHCP snippet.\n        $scope.snippetEnterRemove = function(snippet) {\n            $scope.newSnippet = null;\n            $scope.editSnippet = null;\n            $scope.deleteSnippet = snippet;\n        };\n\n        // Called to exit remove mode for a DHCP snippet.\n        $scope.snippetExitRemove = function() {\n            $scope.deleteSnippet = null;\n        };\n\n        // Called to confirm the removal of a snippet.\n        $scope.snippetConfirmRemove = function() {\n            DHCPSnippetsManager.deleteItem($scope.deleteSnippet).then(\n                function() {\n                    $scope.snippetExitRemove();\n                });\n        };\n\n        // Called to enter edit mode for a DHCP snippet.\n        $scope.snippetEnterEdit = function(snippet) {\n            $scope.newSnippet = null;\n            $scope.deleteSnippet = null;\n            $scope.editSnippet = snippet;\n            $scope.editSnippet.type = $scope.getSnippetTypeText(snippet);\n        };\n\n        // Called to exit edit mode for a DHCP snippet.\n        $scope.snippetExitEdit = function() {\n            $scope.editSnippet = null;\n        };\n\n        // Called when the active toggle is changed.\n        $scope.snippetToggle = function(snippet) {\n            DHCPSnippetsManager.updateItem(snippet).then(null,\n                function(error) {\n                    // Revert state change and clear toggling.\n                    snippet.enabled = !snippet.enabled;\n                    console.log(error);\n                });\n        };\n\n        // Called to start adding a new snippet.\n        $scope.snippetAdd = function() {\n            $scope.editSnippet = null;\n            $scope.deleteSnippet = null;\n            $scope.newSnippet = {\n                name: \"\",\n                type: \"Global\",\n                enabled: true\n            };\n        };\n\n        // Called to cancel addind a new snippet.\n        $scope.snippetAddCancel = function() {\n            $scope.newSnippet = null;\n        };\n\n        // Setup page variables based on section.\n        if($routeParams.section === \"dhcp\") {\n            $rootScope.title = \"DHCP snippets\";\n            $scope.currentpage = 'dhcp';\n        }\n        else if($routeParams.section === \"repositories\") {\n            $rootScope.title = \"Package repositories\";\n            $scope.currentpage = 'repositories';\n        }\n\n        // Load the required managers.\n        ManagerHelperService.loadManagers($scope, [\n                PackageRepositoriesManager, DHCPSnippetsManager,\n                MachinesManager, DevicesManager, ControllersManager,\n                SubnetsManager, GeneralManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Space Details Controller\n */\n\nangular.module('MAAS').controller('SpaceDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'SpacesManager', 'VLANsManager', 'SubnetsManager', 'FabricsManager',\n    'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $filter, $location,\n        SpacesManager, VLANsManager, SubnetsManager, FabricsManager,\n        UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        // Initial values.\n        $scope.space = null;\n        $scope.spaceManager = SpacesManager;\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.loaded = false;\n        $scope.editSummary = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.space.name;\n        }\n\n        // Called when the space has been loaded.\n        function spaceLoaded(space) {\n            $scope.space = space;\n            updateTitle();\n            $scope.predicate = \"[subnet_name, vlan_name]\";\n            $scope.$watch(\"subnets\", updateSubnets, true);\n            updateSubnets();\n            $scope.loaded = true;\n        }\n\n        // Generate a table that can easily be rendered in the view.\n        function updateSubnets() {\n            var rows = [];\n            angular.forEach($filter('filter')(\n                    $scope.subnets, {space:$scope.space.id}, true),\n                    function(subnet) {\n                var vlan = VLANsManager.getItemFromList(subnet.vlan);\n                var fabric = FabricsManager.getItemFromList(vlan.fabric);\n                var row = {\n                    vlan: vlan,\n                    vlan_name: VLANsManager.getName(vlan),\n                    subnet: subnet,\n                    subnet_name: SubnetsManager.getName(subnet),\n                    fabric: fabric,\n                    fabric_name: fabric.name\n                };\n                rows.push(row);\n            });\n            $scope.rows = rows;\n        }\n\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Called when the \"edit\" button is cliked in the space summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the space summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Return true if this is the default Space\n        $scope.isDefaultSpace = function() {\n            if(!angular.isObject($scope.space)) {\n                return false;\n            }\n            return $scope.space.id === 0;\n        };\n\n        // Called to check if the space can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.space)) {\n                return $scope.space.subnet_ids.length === 0;\n            }\n            return false;\n        };\n\n        // Called when the delete space button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete space button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete space button is pressed.\n        $scope.deleteConfirmButton = function() {\n            SpacesManager.deleteSpace($scope.space).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/networks\");\n                $location.search('by', 'space');\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            SpacesManager, SubnetsManager, VLANsManager, FabricsManager,\n            UsersManager]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this space set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeSpace = SpacesManager.getActiveItem();\n            var requestedSpace = parseInt($routeParams.space_id, 10);\n            if(isNaN(requestedSpace)) {\n                ErrorService.raiseError(\"Invalid space identifier.\");\n            } else if(angular.isObject(activeSpace) &&\n                activeSpace.id === requestedSpace) {\n                spaceLoaded(activeSpace);\n            } else {\n                SpacesManager.setActiveItem(\n                    requestedSpace).then(function(space) {\n                        spaceLoaded(space);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Subnet Details Controller\n */\n\nangular.module('MAAS').filter('filterSource', ['ValidationService',\n    function() {\n        return function(subnets, source) {\n            var filtered = [];\n            angular.forEach(subnets, function(subnet) {\n                if(subnet.id !== source.id &&\n                    subnet.version === source.version) {\n                    filtered.push(subnet);\n                }\n            });\n            return filtered;\n        };\n    }]);\n\nangular.module('MAAS').controller('SubnetDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'ConfigsManager', 'SubnetsManager', 'SpacesManager', 'VLANsManager',\n    'UsersManager', 'FabricsManager', 'StaticRoutesManager',\n    'ManagerHelperService', 'ErrorService', 'ConverterService',\n    function(\n        $scope, $rootScope, $routeParams, $filter, $location, ConfigsManager,\n        SubnetsManager, SpacesManager, VLANsManager, UsersManager,\n        FabricsManager, StaticRoutesManager, ManagerHelperService, ErrorService,\n        ConverterService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.subnet = null;\n        $scope.editSummary = false;\n        $scope.active_discovery_data = null;\n        $scope.active_discovery_interval = null;\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.subnetManager = SubnetsManager;\n        $scope.staticRoutes = StaticRoutesManager.getItems();\n        $scope.staticRoutesManager = StaticRoutesManager;\n        $scope.space = null;\n        $scope.vlans = VLANsManager.getItems();\n        $scope.fabrics = FabricsManager.getItems();\n        $scope.actionError = null;\n        $scope.actionOption = null;\n        $scope.actionOptions = [];\n        $scope.reverse = false;\n        $scope.newStaticRoute = null;\n        $scope.editStaticRoute = null;\n        $scope.deleteStaticRoute = null;\n\n        $scope.MAP_SUBNET_ACTION = {\n            name: \"map_subnet\",\n            title: \"Map subnet\"\n        };\n        $scope.DELETE_ACTION = {\n            name: \"delete\",\n            title: \"Delete\"\n        };\n\n        // Alloc type mapping.\n        var ALLOC_TYPES = {\n            0: 'Automatic',\n            1: 'Static',\n            4: 'User reserved',\n            5: 'DHCP',\n            6: 'Observed'\n        };\n\n        // Node type mapping.\n        var NODE_TYPES = {\n            0: 'Machine',\n            1: 'Device',\n            2: 'Rack controller',\n            3: 'Region controller',\n            4: 'Rack and region controller',\n            5: 'Chassis',\n            6: 'Storage'\n        };\n\n        // Updates the page title.\n        function updateTitle() {\n            subnet = $scope.subnet;\n            if(subnet && subnet.cidr) {\n                $rootScope.title = subnet.cidr;\n                if(subnet.name && subnet.cidr !== subnet.name) {\n                    $rootScope.title += \" (\" +subnet.name + \")\";\n                }\n            }\n        }\n\n        // Update the IP version of the CIDR.\n        function updateIPVersion() {\n            var ip = $scope.subnet.cidr.split('/')[0];\n            if(ip.indexOf(':') === -1) {\n                $scope.ipVersion = 4;\n            } else {\n                $scope.ipVersion = 6;\n            }\n        }\n\n        // Sort for IP address.\n        $scope.ipSort = function(ipAddress) {\n            if($scope.ipVersion === 4) {\n                return ConverterService.ipv4ToInteger(ipAddress.ip);\n            } else {\n                return ConverterService.ipv6Expand(ipAddress.ip);\n            }\n        };\n\n        // Set default predicate to the ipSort function.\n        $scope.predicate = $scope.ipSort;\n\n        // Return the name of the allocation type.\n        $scope.getAllocType = function(allocType) {\n            var str = ALLOC_TYPES[allocType];\n            if(angular.isString(str)) {\n                return str;\n            } else {\n                return \"Unknown\";\n            }\n        };\n\n        $scope.getSubnetCIDR = function(destId) {\n            return SubnetsManager.getItemFromList(destId).cidr;\n        };\n\n        // Sort based on the name of the allocation type.\n        $scope.allocTypeSort = function(ipAddress) {\n            return $scope.getAllocType(ipAddress.alloc_type);\n        };\n\n        // Return the name of the node type for the given IP.\n        $scope.getUsageForIP = function(ip) {\n            if(angular.isObject(ip.node_summary)) {\n                var nodeType = ip.node_summary.node_type;\n                var str = NODE_TYPES[nodeType];\n                if(angular.isString(str)) {\n                    return str;\n                } else {\n                    return \"Unknown\";\n                }\n            } else if(angular.isObject(ip.bmcs)) {\n                return \"BMC\";\n            } else if(angular.isObject(ip.dns_records)) {\n                return \"DNS\";\n            } else {\n                return \"Unknown\";\n            }\n        };\n\n        // Sort based on the node type string.\n        $scope.nodeTypeSort = function(ipAddress) {\n            return $scope.getUsageForIP(ipAddress);\n        };\n\n        // Sort based on the owner name.\n        $scope.ownerSort = function(ipAddress) {\n            var owner = ipAddress.user;\n            if(angular.isString(owner) && owner.length > 0) {\n                return owner;\n            } else {\n                return \"MAAS\";\n            }\n        };\n\n        // Called to change the sort order of the IP table.\n        $scope.sortIPTable = function(predicate) {\n            $scope.predicate = predicate;\n            $scope.reverse = !$scope.reverse;\n        };\n\n        // Return the name of the VLAN.\n        $scope.getVLANName = function(vlan) {\n           return VLANsManager.getName(vlan);\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        $scope.actionRetry = function() {\n            // When we clear actionError, the HTML will be re-rendered to\n            // hide the error message (and the user will be taken back to\n            // the previous action they were performing, since we reset\n            // the actionOption in the error handler.\n            $scope.actionError = null;\n        };\n\n        // Perform the action.\n        $scope.actionGo = function() {\n            if($scope.actionOption.name === \"map_subnet\") {\n                SubnetsManager.scanSubnet($scope.subnet).then(function(result) {\n                    if(result && result.scan_started_on.length === 0) {\n                        $scope.actionError =\n                            ManagerHelperService.parseValidationError(\n                                result.result);\n                    } else {\n                        $scope.actionOption = null;\n                        $scope.actionError = null;\n                    }\n                }, function(error) {\n                    $scope.actionError =\n                        ManagerHelperService.parseValidationError(error);\n                });\n            } else if($scope.actionOption.name === \"delete\") {\n                SubnetsManager.deleteSubnet(\n                    $scope.subnet).then(function(result) {\n                        $scope.actionOption = null;\n                        $scope.actionError = null;\n                        $location.path(\"/networks\");\n                    }, function(error) {\n                        $scope.actionError =\n                            ManagerHelperService.parseValidationError(error);\n                });\n            }\n        };\n\n        // Called when a action is selected.\n        $scope.actionChanged = function() {\n            $scope.actionError = null;\n        };\n\n        // Called when the \"Cancel\" button is pressed.\n        $scope.cancelAction = function() {\n            $scope.actionOption = null;\n            $scope.actionError = null;\n        };\n\n        // Called when the managers load to populate the actions the user\n        // is allowed to perform.\n        $scope.updateActions = function() {\n            if(UsersManager.isSuperUser()) {\n                $scope.actionOptions = [\n                    $scope.MAP_SUBNET_ACTION,\n                    $scope.DELETE_ACTION\n                ];\n            } else {\n                $scope.actionOptions = [];\n            }\n        };\n\n        // Called when the \"edit\" button is cliked in the subnet summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the subnet summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Called by maas-obj-form before it saves the subnet. The passed\n        // subnet is the object right before its sent over the websocket.\n        $scope.subnetPreSave = function(subnet, changedFields) {\n            // Adjust the subnet object if the fabric changed.\n            if(changedFields.indexOf(\"fabric\") !== -1) {\n                // Fabric changed, the websocket expects VLAN to be updated, so\n                // we set the VLAN to the default VLAN for the new fabric.\n                subnet.vlan = FabricsManager.getItemFromList(\n                    subnet.fabric).default_vlan_id;\n            }\n            return subnet;\n        };\n\n        // Called to start adding a new static route.\n        $scope.addStaticRoute = function() {\n            $scope.editStaticRoute = null;\n            $scope.deleteStaticRoute = null;\n            $scope.newStaticRoute = {\n                source: $scope.subnet.id,\n                gateway_ip: \"\",\n                destination: null,\n                metric: 0\n            };\n        };\n\n        // Cancel adding the new static route.\n        $scope.cancelAddStaticRoute = function() {\n            $scope.newStaticRoute = null;\n        };\n\n        // Return true if the static route is in edit mode.\n        $scope.isStaticRouteInEditMode = function(route) {\n            return $scope.editStaticRoute === route;\n        };\n\n        // Toggle edit mode for the static route.\n        $scope.staticRouteToggleEditMode = function(route) {\n            $scope.newStaticRoute = null;\n            $scope.deleteStaticRoute = null;\n            if($scope.isStaticRouteInEditMode(route)) {\n                $scope.editStaticRoute  = null;\n            } else {\n                $scope.editStaticRoute = route;\n            }\n        };\n\n        // Return true if the static route is in delete mode.\n        $scope.isStaticRouteInDeleteMode = function(route) {\n            return $scope.deleteStaticRoute === route;\n        };\n\n        // Enter delete mode for the static route.\n        $scope.staticRouteEnterDeleteMode = function(route) {\n            $scope.newStaticRoute = null;\n            $scope.editStaticRoute = null;\n            $scope.deleteStaticRoute = route;\n        };\n\n        // Exit delete mode for the statc route.\n        $scope.staticRouteCancelDelete = function() {\n            $scope.deleteStaticRoute = null;\n        };\n\n        // Perform the delete operation on the static route.\n        $scope.staticRouteConfirmDelete = function() {\n            StaticRoutesManager.deleteItem($scope.deleteStaticRoute).then(\n                function() {\n                    $scope.deleteStaticRoute = null;\n                });\n        };\n\n        // Called when the subnet has been loaded.\n        function subnetLoaded(subnet) {\n            $scope.subnet = subnet;\n            $scope.loaded = true;\n\n            updateTitle();\n\n            // Watch the vlan and fabric field so if its changed on the subnet\n            // we make sure that the fabric is updated. It is possible that\n            // fabric is removed from the subnet since it is injected from this\n            // controller, so when it is removed we add it back.\n            var updateFabric = function() {\n                $scope.subnet.fabric = (\n                    VLANsManager.getItemFromList($scope.subnet.vlan).fabric);\n                $scope.subnet.fabric_name = (\n                  FabricsManager.getItemFromList(subnet.fabric).name);\n            };\n            var updateSpace = function() {\n                $scope.space = (\n                    SpacesManager.getItemFromList($scope.subnet.space));\n            };\n            var updateVlan = function() {\n                var vlan = VLANsManager.getItemFromList($scope.subnet.vlan);\n                $scope.subnet.vlan_name = (\n                    VLANsManager.getName(vlan)\n                );\n            };\n\n            $scope.$watch(\"subnet.fabric\", updateFabric);\n            $scope.$watch(\"subnet.fabric_name\", updateFabric);\n            $scope.$watch(\"subnet.vlan\", updateFabric);\n            $scope.$watch(\"subnet.vlan_name\", updateVlan);\n            $scope.$watch(\"subnet.space\", updateSpace);\n            $scope.$watch(\"subnet.cidr\", updateIPVersion);\n        }\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            ConfigsManager, SubnetsManager, SpacesManager, VLANsManager,\n            UsersManager, FabricsManager, StaticRoutesManager\n        ]).then(function() {\n\n            $scope.updateActions();\n            $scope.active_discovery_data = ConfigsManager.getItemFromList(\n                \"active_discovery_interval\");\n            // Find active discovery interval\n            angular.forEach(\n                $scope.active_discovery_data.choices, function(choice) {\n                    if(choice[0] === $scope.active_discovery_data.value) {\n                        $scope.active_discovery_interval = choice[1];\n                    }\n                });\n\n            // Possibly redirected from another controller that already had\n            // this subnet set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeSubnet = SubnetsManager.getActiveItem();\n            var requestedSubnet = parseInt($routeParams.subnet_id, 10);\n            if(isNaN(requestedSubnet)) {\n                ErrorService.raiseError(\"Invalid subnet identifier.\");\n            } else if(angular.isObject(activeSubnet) &&\n                activeSubnet.id === requestedSubnet) {\n                subnetLoaded(activeSubnet);\n            } else {\n                SubnetsManager.setActiveItem(\n                    requestedSubnet).then(function(subnet) {\n                        subnetLoaded(subnet);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS VLAN Details Controller\n */\n\nangular.module('MAAS').filter('ignoreSelf', function () {\n    return function(objects, self) {\n        var filtered = [];\n        angular.forEach(objects, function(obj) {\n            if(obj !== self) {\n                filtered.push(obj);\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').controller('VLANDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'VLANsManager', 'SubnetsManager', 'SpacesManager', 'FabricsManager',\n    'ControllersManager', 'UsersManager', 'ManagerHelperService',\n    'ErrorService', 'ValidationService', function(\n        $scope, $rootScope, $routeParams, $filter, $location,\n        VLANsManager, SubnetsManager, SpacesManager, FabricsManager,\n        ControllersManager, UsersManager, ManagerHelperService, ErrorService,\n        ValidationService) {\n        var vm = this;\n\n        var filterByVLAN = $filter('filterByVLAN');\n        var filterControllersByVLAN = $filter('filterControllersByVLAN');\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        vm.PROVIDE_DHCP_ACTION = {\n            // Note: 'title' is set dynamically depending on whether or not\n            // DHCP is already enabled on this VLAN.\n            name: \"enable_dhcp\"\n        };\n        vm.RELAY_DHCP_ACTION = {\n            // Note: 'title' is set ndynamically depending on whether or not\n            // DHCP relay is already enabled on this VLAN.\n            name: \"relay_dhcp\"\n        };\n        vm.DISABLE_DHCP_ACTION = {\n            name: \"disable_dhcp\",\n            title: \"Disable DHCP\"\n        };\n        vm.DELETE_ACTION = {\n            name: \"delete\",\n            title: \"Delete\"\n        };\n\n        // Initial values.\n        vm.loaded = false;\n        vm.vlan = null;\n        vm.title = null;\n        vm.actionOption = null;\n        vm.actionOptions = [];\n        vm.vlanManager = VLANsManager;\n        vm.vlans = VLANsManager.getItems();\n        vm.subnets = SubnetsManager.getItems();\n        vm.spaces = SpacesManager.getItems();\n        vm.fabrics = FabricsManager.getItems();\n        vm.controllers = ControllersManager.getItems();\n        vm.actionError = null;\n        vm.relatedSubnets = [];\n        vm.relatedControllers = [];\n        vm.provideDHCPAction = {};\n        vm.primaryRack = null;\n        vm.secondaryRack = null;\n        vm.editSummary = false;\n\n\n        // Return true if the authenticated user is super user.\n        vm.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Called when the \"edit\" button is cliked in the vlan summary\n        vm.enterEditSummary = function() {\n            vm.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the vlan summary\n        vm.exitEditSummary = function() {\n            vm.editSummary = false;\n        };\n\n        // Get the space name for the VLAN.\n        vm.getSpaceName = function() {\n            var space = SpacesManager.getItemFromList(vm.vlan.space);\n            if(space) {\n              return space.name;\n            } else {\n              return \"(undefined)\";\n            }\n        };\n\n        // Get the aciton structure for the action with the specified name.\n        vm.getActionByName = function(name) {\n            var i;\n            for(i = 0 ; i < vm.actionOptions.length ; i++) {\n                if(vm.actionOptions[i].name === name) {\n                    return vm.actionOptions[i];\n                }\n            }\n            return null;\n        };\n\n        // Initialize the provideDHCPAction structure with the current primary\n        // and secondary rack, plus an indication regarding whether or not\n        // adding a dynamic IP range is required.\n        vm.initProvideDHCP = function(forRelay) {\n            vm.provideDHCPAction = {};\n            var dhcp = vm.provideDHCPAction;\n            dhcp.subnet = null;\n            dhcp.relayVLAN = null;\n            if (angular.isNumber(vm.vlan.relay_vlan)) {\n                dhcp.relayVLAN = VLANsManager.getItemFromList(\n                    vm.vlan.relay_vlan);\n            }\n            if (angular.isObject(vm.primaryRack)) {\n                dhcp.primaryRack = vm.primaryRack.system_id;\n            } else if(vm.relatedControllers.length > 0) {\n                // Select the primary controller arbitrarily by default.\n                dhcp.primaryRack = vm.relatedControllers[0].system_id;\n            }\n            if (angular.isObject(vm.secondaryRack)) {\n                dhcp.secondaryRack = vm.secondaryRack.system_id;\n            } else if(vm.relatedControllers.length > 1) {\n                // Select the secondary controller arbitrarily by default.\n                dhcp.secondaryRack = vm.relatedControllers[1].system_id;\n            }\n            dhcp.maxIPs = 0;\n            dhcp.startIP = null;\n            dhcp.endIP = null;\n            dhcp.gatewayIP = \"\";\n            if (angular.isObject(vm.relatedSubnets)) {\n                // Select a subnet arbitrarily by default.\n                if (vm.relatedSubnets.length > 0 &&\n                        angular.isObject(vm.relatedSubnets[0].subnet)) {\n                    dhcp.subnet = vm.relatedSubnets[0].subnet.id;\n                }\n                dhcp.needsDynamicRange = true;\n                var i, subnet;\n                for (i = 0; i < vm.relatedSubnets.length; i++) {\n                    subnet = vm.relatedSubnets[i].subnet;\n                    // If any related subnet already has a dynamic range, we\n                    // cannot prompt the user to enter one here. If a\n                    // suggestion does not exist, a range does not exist\n                    // already.\n                    var iprange = subnet.statistics.suggested_dynamic_range;\n                    if (!angular.isObject(iprange)) {\n                        // If there is already a dynamic range on one of the\n                        // subnets, it's the \"subnet of least surprise\" if\n                        // the user is choosing to reconfigure their rack\n                        // controllers. (if they want DHCP on *another* subnet,\n                        // they should need to be explicit about it.)\n                        dhcp.subnet = subnet.id;\n                        dhcp.needsDynamicRange = false;\n                        break;\n                    }\n                }\n                // We must prompt the user for a subnet and a gateway IP\n                // address if any subnet does not yet contain a gateway IP\n                // address.\n                dhcp.needsGatewayIP = false;\n                dhcp.subnetMissingGatewayIP = true;\n                for (i = 0; i < vm.relatedSubnets.length; i++) {\n                    subnet = vm.relatedSubnets[i].subnet;\n                    if(subnet.gateway_ip === null ||\n                        subnet.gateway_ip === '') {\n                        dhcp.needsGatewayIP = true;\n                        break;\n                    }\n                }\n            }\n            // Since we are setting default values for these three options,\n            // ensure all the appropriate updates occur.\n            if(!forRelay) {\n                vm.updatePrimaryRack();\n                vm.updateSecondaryRack();\n            }\n            vm.updateSubnet(forRelay);\n        };\n\n        // Called when the actionOption has changed.\n        vm.actionOptionChanged = function() {\n            if(vm.actionOption.name === \"enable_dhcp\") {\n                vm.initProvideDHCP(false);\n            } else if(vm.actionOption.name === \"relay_dhcp\") {\n                vm.initProvideDHCP(true);\n            }\n            // Clear the action error.\n            vm.actionError = null;\n        };\n\n        // Cancel the action.\n        vm.actionCancel = function() {\n            // When the user wants to cancel an action, we need to clear out\n            // both the actionOption (so that the action screen will not be\n            // presented again) and the actionError (so that the error screen\n            // is hidden).\n            vm.actionOption = null;\n            vm.actionError = null;\n        };\n\n        // Called from the Provide DHCP form when the primary rack changes.\n        vm.updatePrimaryRack = function() {\n            var dhcp = vm.provideDHCPAction;\n            // If the user selects the secondary controller to be the primary,\n            // then the primary controller needs to be cleared out.\n            if(dhcp.primaryRack === dhcp.secondaryRack) {\n                dhcp.secondaryRack = null;\n            }\n            var i;\n            for(i = 0 ; i < vm.relatedControllers.length ; i++) {\n                if(vm.relatedControllers[i].system_id !== dhcp.primaryRack) {\n                    dhcp.secondaryRack = vm.relatedControllers[i].system_id;\n                    break;\n                }\n            }\n        };\n\n        // Called from the Provide DHCP form when the secondary rack changes.\n        vm.updateSecondaryRack = function() {\n            var dhcp = vm.provideDHCPAction;\n            // This should no longer be possible due to the filters on the\n            // drop-down boxes, but just in case.\n            if(dhcp.primaryRack === dhcp.secondaryRack) {\n                dhcp.primaryRack = null;\n                dhcp.secondaryRack = null;\n            }\n        };\n\n        // Called from the view to exclude the primary rack when selecting\n        // the secondary rack controller.\n        vm.filterPrimaryRack = function(rack) {\n            var dhcp = vm.provideDHCPAction;\n            return rack.system_id !== dhcp.primaryRack;\n        };\n\n        // Called from the Provide DHCP form when the subnet selection changes.\n        vm.updateSubnet = function(forRelay) {\n            var dhcp = vm.provideDHCPAction;\n            var subnet = SubnetsManager.getItemFromList(dhcp.subnet);\n            if(angular.isObject(subnet)) {\n                var suggested_gateway = null;\n                var iprange = null;\n                if(angular.isObject(subnet.statistics)) {\n                    suggested_gateway = subnet.statistics.suggested_gateway;\n                    iprange = subnet.statistics.suggested_dynamic_range;\n                }\n                if(angular.isObject(iprange) && iprange.num_addresses > 0) {\n                    dhcp.maxIPs = iprange.num_addresses;\n                    if(forRelay) {\n                        dhcp.startIP = \"\";\n                        dhcp.endIP = \"\";\n                        dhcp.startPlaceholder = iprange.start + \"(optional)\";\n                        dhcp.endPlaceholder = iprange.end + \" (optional)\";\n                    } else {\n                        dhcp.startIP = iprange.start;\n                        dhcp.endIP = iprange.end;\n                        dhcp.startPlaceholder = iprange.start;\n                        dhcp.endPlaceholder = iprange.end;\n                    }\n                } else {\n                    // Need to add a dynamic range, but according to our data,\n                    // there is no room on the subnet for a dynamic range.\n                    dhcp.maxIPs = 0;\n                    dhcp.startIP = \"\";\n                    dhcp.endIP = \"\";\n                    dhcp.startPlaceholder = \"(no available IPs)\";\n                    dhcp.endPlaceholder = \"(no available IPs)\";\n                }\n                if(angular.isString(suggested_gateway)) {\n                    if(forRelay) {\n                      dhcp.gatewayIP = \"\";\n                      dhcp.gatewayPlaceholder = (\n                          suggested_gateway + \" (optional)\");\n                    } else {\n                        dhcp.gatewayIP = suggested_gateway;\n                        dhcp.gatewayPlaceholder = suggested_gateway;\n                    }\n                } else {\n                    // This means the subnet already has a gateway, so don't\n                    // bother populating it.\n                    dhcp.gatewayIP = \"\";\n                    dhcp.gatewayPlaceholder = \"\";\n                }\n            } else {\n                // Don't need to add a dynamic range, so ensure these fields\n                // are cleared out.\n                dhcp.maxIPs = 0;\n                dhcp.startIP = null;\n                dhcp.endIP = null;\n                dhcp.gatewayIP = \"\";\n            }\n            if(angular.isObject(subnet)) {\n                dhcp.subnetMissingGatewayIP = !angular.isString(\n                    subnet.gateway_ip);\n            } else {\n                dhcp.subnetMissingGatewayIP = false;\n            }\n            if(dhcp.subnetMissingGatewayIP === false) {\n                dhcp.gatewayIP = null;\n            }\n       };\n\n        vm.actionRetry = function() {\n            // When we clear actionError, the HTML will be re-rendered to\n            // hide the error message (and the user will be taken back to\n            // the previous action they were performing, since we reset\n            // the actionOption in the error handler.\n            vm.actionError = null;\n        };\n\n        // Return True if the current action can be performed.\n        vm.canPerformAction = function() {\n            if(vm.actionOption.name === \"enable_dhcp\") {\n                return vm.relatedSubnets.length > 0;\n            } else if(vm.actionOption.name === \"relay_dhcp\") {\n                return angular.isObject(vm.provideDHCPAction.relayVLAN);\n            } else {\n                return true;\n            }\n        };\n\n        // Perform the action.\n        vm.actionGo = function() {\n            // Do nothing if action cannot be performed.\n            if(!vm.canPerformAction()) {\n               return;\n            }\n\n            if(vm.actionOption.name === \"enable_dhcp\") {\n                var dhcp = vm.provideDHCPAction;\n                var controllers = [];\n                // These will be undefined if they don't exist, and the region\n                // will simply get an empty dictionary.\n                var extra = {};\n                extra.subnet = dhcp.subnet;\n                extra.start = dhcp.startIP;\n                extra.end = dhcp.endIP;\n                extra.gateway = dhcp.gatewayIP;\n                if(angular.isString(dhcp.primaryRack)) {\n                    controllers.push(dhcp.primaryRack);\n                }\n                if(angular.isString(dhcp.secondaryRack)) {\n                    controllers.push(dhcp.secondaryRack);\n                }\n                // Abort the action without calling down to the region if\n                // the user didn't select a controller.\n                if(controllers.length === 0) {\n                    vm.actionError =\n                        \"A primary rack controller must be specified.\";\n                    return;\n                }\n                VLANsManager.configureDHCP(\n                    vm.vlan, controllers, extra).then(function() {\n                        vm.actionOption = null;\n                        vm.actionError = null;\n                    }, function(result) {\n                        vm.actionError = result.error;\n                        vm.actionOption = vm.PROVIDE_DHCP_ACTION;\n                    });\n            } else if(vm.actionOption.name === \"relay_dhcp\") {\n                // These will be undefined if they don't exist, and the region\n                // will simply get an empty dictionary.\n                var extraDHCP = {};\n                extraDHCP.subnet = vm.provideDHCPAction.subnet;\n                extraDHCP.start = vm.provideDHCPAction.startIP;\n                extraDHCP.end = vm.provideDHCPAction.endIP;\n                extraDHCP.gateway = vm.provideDHCPAction.gatewayIP;\n                var relay = vm.provideDHCPAction.relayVLAN.id;\n                VLANsManager.configureDHCP(\n                    vm.vlan, [], extraDHCP, relay).then(function() {\n                        vm.actionOption = null;\n                        vm.actionError = null;\n                    }, function(result) {\n                        vm.actionError = result.error;\n                        vm.actionOption = vm.RELAY_DHCP_ACTION;\n                    });\n            } else if(vm.actionOption.name === \"disable_dhcp\") {\n                VLANsManager.disableDHCP(vm.vlan).then(function() {\n                    vm.actionOption = null;\n                    vm.actionError = null;\n                }, function(result) {\n                    vm.actionError = result.error;\n                    vm.actionOption = vm.DISABLE_DHCP_ACTION;\n                });\n            } else if(vm.actionOption.name === \"delete\") {\n                VLANsManager.deleteVLAN(vm.vlan).then(function() {\n                    $location.path(\"/networks\");\n                    vm.actionOption = null;\n                    vm.actionError = null;\n                }, function(result) {\n                    vm.actionError = result.error;\n                    vm.actionOption = vm.DELETE_ACTION;\n                });\n            }\n        };\n\n        // Return true if there is an action error.\n        vm.isActionError = function() {\n            return vm.actionError !== null;\n        };\n\n        // Return the name of the VLAN.\n        vm.getFullVLANName = function(vlan_id) {\n            var vlan = VLANsManager.getItemFromList(vlan_id);\n            var fabric = FabricsManager.getItemFromList(vlan.fabric);\n            return (\n                FabricsManager.getName(fabric) + \".\" +\n                VLANsManager.getName(vlan));\n        };\n\n        // Return the current DHCP status.\n        vm.getDHCPStatus = function() {\n            if(vm.vlan) {\n              if(vm.vlan.dhcp_on) {\n                return \"Enabled\";\n              } else if(vm.vlan.relay_vlan) {\n                return \"Relayed via \" + vm.getFullVLANName(vm.vlan.relay_vlan);\n              } else {\n                return \"Disabled\";\n              }\n            } else {\n              return \"\";\n            }\n        };\n\n        // Updates the page title.\n        function updateTitle() {\n            var vlan = vm.vlan;\n            var fabric = vm.fabric;\n            if(angular.isObject(vlan) && angular.isObject(fabric)) {\n                if (!vlan.name) {\n                    if(vlan.vid === 0) {\n                        vm.title = \"Default VLAN\";\n                    } else {\n                        vm.title = \"VLAN \" + vlan.vid;\n                    }\n                } else {\n                    vm.title = vlan.name;\n                }\n                vm.title += \" in \" + fabric.name;\n                $rootScope.title = vm.title;\n            }\n        }\n\n        // Called from a $watch when the management racks are updated.\n        function updateManagementRacks() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            if(vlan.primary_rack) {\n                vm.primaryRack = ControllersManager.getItemFromList(\n                    vlan.primary_rack);\n            } else {\n                vm.primaryRack = null;\n            }\n            if(vlan.secondary_rack) {\n                vm.secondaryRack = ControllersManager.getItemFromList(\n                    vlan.secondary_rack);\n            } else {\n                vm.secondaryRack = null;\n            }\n        }\n\n        // Called from a $watch when the related controllers may have changed.\n        function updateRelatedControllers() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            var racks = [];\n            angular.forEach(vlan.rack_sids, function(rack_sid) {\n                var rack = ControllersManager.getItemFromList(rack_sid);\n                if(angular.isObject(rack)) {\n                    racks.push(rack);\n                }\n            });\n            vm.relatedControllers = racks;\n        }\n\n        // Called from a $watch when the related subnets or spaces may have\n        // changed.\n        function updateRelatedSubnets() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            var subnets = [];\n            angular.forEach(\n                    filterByVLAN(vm.subnets, vlan), function(subnet) {\n                var space = SpacesManager.getItemFromList(subnet.space);\n                if(!angular.isObject(space)) {\n                    space = {name: \"(undefined)\"};\n                }\n                var row = {\n                    subnet: subnet,\n                    space: space\n                };\n                subnets.push(row);\n            });\n            vm.relatedSubnets = subnets;\n        }\n\n        function updatePossibleActions() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            // Clear out the actionOptions array. (this needs to be the same\n            // object, since it's watched from $scope.)\n            vm.actionOptions.length = 0;\n            if(UsersManager.isSuperUser()) {\n                if(!vlan.relay_vlan) {\n                  if(vlan.dhcp_on === true) {\n                      vm.PROVIDE_DHCP_ACTION.title = \"Reconfigure DHCP\";\n                      vm.actionOptions.push(vm.PROVIDE_DHCP_ACTION);\n                      vm.actionOptions.push(vm.DISABLE_DHCP_ACTION);\n                  } else {\n                      vm.PROVIDE_DHCP_ACTION.title = \"Provide DHCP\";\n                      vm.RELAY_DHCP_ACTION.title = \"Relay DHCP\";\n                      vm.actionOptions.push(vm.PROVIDE_DHCP_ACTION);\n                      vm.actionOptions.push(vm.RELAY_DHCP_ACTION);\n                  }\n                } else {\n                  vm.actionOptions.push(vm.RELAY_DHCP_ACTION);\n                  vm.actionOptions.push(vm.DISABLE_DHCP_ACTION);\n                  vm.RELAY_DHCP_ACTION.title = \"Reconfigure DHCP relay\";\n                }\n                if(!vm.isFabricDefault) {\n                    vm.actionOptions.push(vm.DELETE_ACTION);\n                }\n            }\n        }\n\n        // Called when the vlan has been loaded.\n        function vlanLoaded(vlan) {\n            vm.vlan = vlan;\n            vm.fabric = FabricsManager.getItemFromList(vlan.fabric);\n            vm.isFabricDefault = vm.fabric.default_vlan_id === vm.vlan.id;\n            vm.loaded = true;\n\n            updateTitle();\n            updateManagementRacks();\n            updateRelatedControllers();\n            updateRelatedSubnets();\n            updatePossibleActions();\n        }\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            VLANsManager, SubnetsManager, SpacesManager, FabricsManager,\n            ControllersManager, UsersManager\n        ]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this vlan set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeVLAN = VLANsManager.getActiveItem();\n            var requestedVLAN = parseInt($routeParams.vlan_id, 10);\n            if(isNaN(requestedVLAN)) {\n                ErrorService.raiseError(\"Invalid VLAN identifier.\");\n            } else if(angular.isObject(activeVLAN) &&\n                activeVLAN.id === requestedVLAN) {\n                vlanLoaded(activeVLAN);\n            } else {\n                VLANsManager.setActiveItem(\n                    requestedVLAN).then(function(vlan) {\n                        vlanLoaded(vlan);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n\n            $scope.$watch(\"vlanDetails.vlan.name\", updateTitle);\n            $scope.$watch(\"vlanDetails.vlan.vid\", updateTitle);\n            $scope.$watch(\"vlanDetails.vlan.dhcp_on\", updatePossibleActions);\n            $scope.$watch(\n                \"vlanDetails.vlan.relay_vlan\", updatePossibleActions);\n            $scope.$watch(\"vlanDetails.fabric.name\", updateTitle);\n            $scope.$watch(\n                \"vlanDetails.vlan.primary_rack\", updateManagementRacks);\n            $scope.$watch(\n                \"vlanDetails.vlan.secondary_rack\", updateManagementRacks);\n\n            $scope.$watchCollection(\n                \"vlanDetails.subnets\", updateRelatedSubnets);\n            $scope.$watchCollection(\n                \"vlanDetails.spaces\", updateRelatedSubnets);\n            $scope.$watchCollection(\n                \"vlanDetails.controllers\", updateRelatedControllers);\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Zone Details Controller\n */\n\nangular.module('MAAS').controller('ZoneDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$location', 'MachinesManager',\n    'DevicesManager', 'ZonesManager', 'UsersManager',\n    'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $location, MachinesManager,\n        DevicesManager, ZonesManager, UsersManager, ManagerHelperService,\n        ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"zones\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.zone = null;\n        $scope.zoneManager = ZonesManager;\n        $scope.editSummary = false;\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.zone.name;\n        }\n\n        // Called when the zone has been loaded.\n        function zoneLoaded(zone) {\n            $scope.zone = zone;\n            $scope.loaded = true;\n            updateTitle();\n        }\n\n\n        // Called when the \"edit\" button is cliked in the zone summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the zone summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if this is the default zone.\n        $scope.isDefaultZone = function() {\n            if(angular.isObject($scope.zone)) {\n                return $scope.zone.id === 1;\n            }\n            return false;\n        };\n\n        // Called to check if the zone can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.zone)) {\n                return $scope.zone.id !== 0;\n            }\n            return false;\n        };\n\n        // Called when the delete zone button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete zone button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete space button is pressed.\n        $scope.deleteConfirmButton = function() {\n            ZonesManager.deleteItem($scope.zone).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/zones\");\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers(\n            $scope, [ZonesManager, UsersManager]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this zone set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeZone = ZonesManager.getActiveItem();\n            var requestedZone = parseInt($routeParams.zone_id, 10);\n            if(isNaN(requestedZone)) {\n                ErrorService.raiseError(\"Invalid zone identifier.\");\n            } else if(angular.isObject(activeZone) &&\n                activeZone.id === requestedZone) {\n                zoneLoaded(activeZone);\n            } else {\n                ZonesManager.setActiveItem(\n                    requestedZone).then(function(zone) {\n                        zoneLoaded(zone);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Zones List Controller\n */\n\nangular.module('MAAS').controller('ZonesListController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', 'MachinesManager',\n    'DevicesManager', 'ControllersManager', 'ZonesManager', 'ServicesManager',\n    'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function($scope, $rootScope, $routeParams, $filter, MachinesManager,\n        DevicesManager, ControllersManager, ZonesManager, ServicesManager,\n        UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Zones\";\n        $rootScope.page = \"zones\";\n\n        // Set initial values.\n        $scope.zoneManager = ZonesManager;\n        $scope.zones = ZonesManager.getItems();\n        $scope.currentpage = \"zones\";\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n        $scope.loading = true;\n        $scope.action = {\n          open: false,\n          obj: {}\n        };\n\n        // Open add zone view.\n        $scope.addZone = function() {\n          $scope.action.open = true;\n        };\n\n        // Saving has completed.\n        $scope.closeZone = function() {\n          $scope.action.open = false;\n          $scope.action.obj = {};\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        ManagerHelperService.loadManagers(\n            $scope, [ZonesManager, UsersManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n        }\n    ]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Accordion directive.\n *\n * Provides an accordion effect to an element with maas-accordion class and\n * all child elements with maas-accordion-tab. Only one accordion tab is open\n * at a time, selecting another accordion will set \"active\" on that\n * accordion tab.\n */\n\n\nangular.module('MAAS').directive('maasAccordion', function() {\n    return {\n        restrict: \"C\",\n        link: function(scope, element, attrs) {\n\n            // Called when accordion tabs are clicked. Removes active on\n            // all other tabs except to the tab that was clicked.\n            var clickHandler = function(evt) {\n                var tab = evt.data.tab;\n                angular.element(tab).toggleClass(\"is-selected\");\n            };\n\n            // Listen for the click event on all tabs in the accordion.\n            var tabs = element.find(\".maas-accordion-tab\");\n            angular.forEach(tabs, function(tab) {\n                tab = angular.element(tab);\n                tab.on(\"click\", {\n                    tab: tab\n                }, clickHandler);\n            });\n\n            // Remove the handlers when the scope is destroyed.\n            scope.$on(\"$destroy\", function() {\n                angular.forEach(tabs, function(tab) {\n                    angular.element(tab).off(\"click\", clickHandler);\n                });\n            });\n        }\n    };\n});\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Boot images directive.\n*/\n\nangular.module('MAAS').directive('maasBootImagesStatus', [\n    'BootResourcesManager',\n    function(BootResourcesManager) {\n        return {\n            restrict: \"E\",\n            scope: {},\n            template: [\n                '<p class=\"page-header__status\" ',\n                    'data-ng-if=\"data.region_import_running\">',\n                    '<span class=\"u-text--loading\">',\n                        '<i class=\"p-icon--loading u-animation--spin\"></i>',\n                        'Step 1/2: Region controller importing',\n                    '</span>',\n                '</p>',\n                '<p class=\"page-header__status\" ',\n                    'data-ng-if=\"!data.region_import_running && ',\n                    'data.rack_import_running\">',\n                    '<span class=\"u-text--loading\">',\n                        '<i class=\"p-icon--loading u-animation--spin\"></i>',\n                        'Step 2/2: Rack controller(s) importing',\n                    '</span>',\n                '</p>'\n            ].join(''),\n            controller: function($scope, $rootScope, $element, $document) {\n                // This controller doesn't start the polling. The\n                // `maasBootImages` controller should be used on the page to\n                // start the polling. This just presents a nice status spinner\n                // when the polling is enabled.\n                $scope.data = BootResourcesManager.getData();\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasBootImages', [\n    '$filter', 'BootResourcesManager', 'UsersManager', 'ManagerHelperService',\n    function($filter, BootResourcesManager,\n        UsersManager, ManagerHelperService) {\n        return {\n            restrict: \"E\",\n            scope: {\n                design: \"=?\"\n            },\n            templateUrl: (\n                'static/partials/boot-images.html?v=' + (\n                    MAAS_config.files_version)),\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                $scope.saving = false;\n                $scope.stopping = false;\n                $scope.design = $scope.design || 'page';\n                $scope.bootResources = BootResourcesManager.getData();\n                $scope.ubuntuImages = [];\n                $scope.source = {\n                    isNew: false,\n                    tooMany: false,\n                    showingAdvanced: false,\n                    connecting: false,\n                    errorMessage: \"\",\n                    source_type: 'maas.io',\n                    url: '',\n                    keyring_filename: '',\n                    keyring_data: '',\n                    releases: [],\n                    arches: [],\n                    selections: {\n                        changed: false,\n                        releases: [],\n                        arches: []\n                    }\n                };\n                $scope.ubuntuCoreImages = [];\n                $scope.ubuntu_core = {\n                    changed: false,\n                    images: []\n                };\n                $scope.otherImages = [];\n                $scope.other = {\n                    changed: false,\n                    images: []\n                };\n                $scope.generatedImages = [];\n                $scope.customImages = [];\n                $scope.ubuntuDeleteId = null;\n                $scope.removingImage = null;\n\n                // Return true if the authenticated user is super user.\n                $scope.isSuperUser = function() {\n                    return UsersManager.isSuperUser();\n                };\n\n                // Return the overall title icon.\n                $scope.getTitleIcon = function() {\n                    if($scope.bootResources.resources.length === 0) {\n                        return 'p-icon--success-muted';\n                    } else {\n                        return 'p-icon--success';\n                    }\n                };\n\n                // Return true if the mirror path section should be shown.\n                $scope.showMirrorPath = function() {\n                    if($scope.source.source_type === 'custom') {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                };\n\n                // Return true if the advanced options are shown.\n                $scope.isShowingAdvancedOptions = function() {\n                    return $scope.source.showingAdvanced;\n                };\n\n                // Toggle showing the advanced options.\n                $scope.toggleAdvancedOptions = function() {\n                    $scope.source.showingAdvanced = (\n                        !$scope.source.showingAdvanced);\n                };\n\n                // Return true if both keyring options are set.\n                $scope.bothKeyringOptionsSet = function() {\n                    return (\n                        $scope.source.keyring_filename.length > 0 &&\n                        $scope.source.keyring_data.length > 0);\n                };\n\n                // Return true when the connect button for the mirror path\n                // should be shown.\n                $scope.showConnectButton = function() {\n                    return $scope.source.isNew;\n                };\n\n                // Called when the source radio chanaged.\n                $scope.sourceChanged = function() {\n                    var currentSources = $scope.bootResources.ubuntu.sources;\n                    if(currentSources.length === 0) {\n                        $scope.source.isNew = true;\n                    } else {\n                        var prevNew = $scope.source.isNew;\n                        $scope.source.isNew = (\n                            $scope.source.source_type !==\n                            currentSources[0].source_type);\n                        if($scope.source.source_type === 'custom') {\n                            $scope.source.isNew = $scope.source.isNew || (\n                                $scope.source.url !==\n                                currentSources[0].url\n                            );\n                        }\n                        if(prevNew && !$scope.source.isNew) {\n                            // No longer a new source set url and keyring to\n                            // original.\n                            $scope.source.url = currentSources[0].url;\n                            $scope.source.keyring_filename = (\n                                currentSources[0].keyring_filename);\n                            $scope.source.keyring_data = (\n                                currentSources[0].keyring_data);\n                        }\n                        $scope.source.releases = [];\n                        $scope.source.arches = [];\n                        $scope.source.selections = {\n                            changed: false,\n                            releases: [],\n                            arches: []\n                        };\n                    }\n                    $scope.updateSource();\n                    $scope.regenerateUbuntuImages();\n\n                    // When the source is new and its maas.io automatically\n                    // fetch the source information.\n                    if($scope.source.isNew &&\n                        $scope.source.source_type === 'maas.io') {\n                        $scope.connect();\n                    }\n                };\n\n                // Return true when the connect button should be disabled.\n                $scope.isConnectButtonDisabled = function() {\n                    if($scope.source.source_type === 'maas.io') {\n                        return false;\n                    } else {\n                        return ($scope.bothKeyringOptionsSet() ||\n                            $scope.source.url.length === 0 ||\n                            $scope.source.connecting);\n                    }\n                };\n\n                // Return the source parameters.\n                $scope.getSourceParams = function() {\n                    if($scope.source.source_type === 'maas.io') {\n                        return {\n                            source_type: 'maas.io'\n                        };\n                    } else {\n                        return {\n                            source_type: $scope.source.source_type,\n                            url: $scope.source.url,\n                            keyring_filename: $scope.source.keyring_filename,\n                            keyring_data: $scope.source.keyring_data\n                        };\n                    }\n                };\n\n                // Select the default images that should be selected. Current\n                // defaults are '16.04 LTS' and 'amd64'.\n                $scope.selectDefaults = function() {\n                    angular.forEach($scope.source.releases, function(release) {\n                        if(release.name === \"xenial\") {\n                            $scope.source.selections.releases.push(release);\n                        }\n                    });\n                    angular.forEach($scope.source.arches, function(arch) {\n                        if(arch.name === \"amd64\") {\n                            $scope.source.selections.arches.push(arch);\n                        }\n                    });\n                };\n\n                // Connected to the simplestreams endpoint. This only gets the\n                // information from the endpoint it does not save it into the\n                // database.\n                $scope.connect = function() {\n                    if($scope.isConnectButtonDisabled()) {\n                        return;\n                    }\n\n                    var source = $scope.getSourceParams();\n                    $scope.source.connecting = true;\n                    $scope.source.releases = [];\n                    $scope.source.arches = [];\n                    $scope.source.selections.changed = true;\n                    $scope.source.selections.releases = [];\n                    $scope.source.selections.arches = [];\n                    $scope.regenerateUbuntuImages();\n                    BootResourcesManager.fetch(source).then(function(data) {\n                        $scope.source.connecting = false;\n                        data = angular.fromJson(data);\n                        $scope.source.releases = data.releases;\n                        $scope.source.arches = data.arches;\n                        $scope.selectDefaults();\n                        $scope.regenerateUbuntuImages();\n                    }, function(error) {\n                        $scope.source.connecting = false;\n                        $scope.source.errorMessage = error;\n                    });\n                };\n\n                // Return true if the connect block should be shown.\n                $scope.showConnectBlock = function() {\n                    return $scope.source.tooMany || (\n                        $scope.source.isNew && !$scope.showSelections());\n                };\n\n                // Return true if the release and architecture selection\n                // should be shown.\n                $scope.showSelections = function() {\n                    return (\n                        $scope.source.releases.length > 0 &&\n                        $scope.source.arches.length > 0);\n                };\n\n                // Return the Ubuntu LTS releases.\n                $scope.getUbuntuLTSReleases = function() {\n                    var releases = $scope.bootResources.ubuntu.releases;\n                    if($scope.source.isNew) {\n                        releases = $scope.source.releases;\n                    }\n                    var filtered = [];\n                    angular.forEach(releases, function(release) {\n                        if(!release.deleted &&\n                            release.title.indexOf('LTS') !== -1) {\n                            filtered.push(release);\n                        }\n                    });\n                    return filtered;\n                };\n\n                // Return the Ubuntu non-LTS releases.\n                $scope.getUbuntuNonLTSReleases = function() {\n                    var releases = $scope.bootResources.ubuntu.releases;\n                    if($scope.source.isNew) {\n                        releases = $scope.source.releases;\n                    }\n                    var filtered = [];\n                    angular.forEach(releases, function(release) {\n                        if(!release.deleted &&\n                            release.title.indexOf('LTS') === -1) {\n                            filtered.push(release);\n                        }\n                    });\n                    return filtered;\n                };\n\n                // Return the available architectures.\n                $scope.getArchitectures = function() {\n                    var arches = $scope.bootResources.ubuntu.arches;\n                    if($scope.source.isNew) {\n                        arches = $scope.source.arches;\n                    }\n                    var filtered = [];\n                    angular.forEach(arches, function(arch) {\n                        if(!arch.deleted) {\n                            filtered.push(arch);\n                        }\n                    });\n                    return filtered;\n                };\n\n                // Return true if the source has this selected.\n                $scope.isSelected = function(type, obj) {\n                    return $scope.source.selections[type].indexOf(obj) >= 0;\n                };\n\n                // Toggle the selection of the release or the architecture.\n                $scope.toggleSelection = function(type, obj) {\n                    var idx = $scope.source.selections[type].indexOf(obj);\n                    if(idx === -1) {\n                        $scope.source.selections[type].push(obj);\n                    } else {\n                        $scope.source.selections[type].splice(idx, 1);\n                    }\n                    $scope.source.selections.changed = true;\n                    $scope.regenerateUbuntuImages();\n                };\n\n                // Return true if the images table should be shown.\n                $scope.showImagesTable = function() {\n                    if($scope.ubuntuImages.length > 0) {\n                        return true;\n                    } else {\n                        // Show the images table source has\n                        // releases and architectures.\n                        return (\n                            $scope.source.arches.length > 0 &&\n                            $scope.source.releases.length > 0);\n                    }\n                };\n\n                // Regenerates the Ubuntu images list for the directive.\n                $scope.regenerateUbuntuImages = function() {\n                    var getResource = function() { return null; };\n                    var resources = $scope.bootResources.resources.filter(\n                        function(resource) {\n                            var name_split = resource.name.split('/');\n                            var resource_os = name_split[0];\n                            return (\n                                resource.rtype === 0 &&\n                                resource_os === 'ubuntu');\n                        });\n                    if(!$scope.source.isNew) {\n                        getResource = function(release, arch) {\n                            var i;\n                            for(i = 0; i < resources.length; i++) {\n                                // Only care about Ubuntu images.\n                                var resource = (resources[i]);\n                                var name_split = resource.name.split('/');\n                                var resource_release = name_split[1];\n                                if(resource_release === release &&\n                                    resource.arch === arch) {\n                                    resources.splice(i, 1);\n                                    return resource;\n                                }\n                            }\n                            return null;\n                        };\n                    }\n\n                    // Create the images based on the selections.\n                    $scope.ubuntuImages.length = 0;\n                    angular.forEach($scope.source.selections.releases,\n                        function(release) {\n                            angular.forEach($scope.source.selections.arches,\n                                function(arch) {\n                                    var image = {\n                                        icon: 'p-icon--status-queued',\n                                        title: release.title,\n                                        arch: arch.title,\n                                        size: '-',\n                                        status: 'Selected for download',\n                                        beingDeleted: false,\n                                        name: release.name\n                                    };\n                                    var resource = getResource(\n                                        release.name, arch.name);\n                                    if(angular.isObject(resource)) {\n                                        image.resourceId = resource.id;\n                                        image.icon = (\n                                            'p-icon--status-' + resource.icon);\n                                        image.size = resource.size;\n                                        image.status = resource.status;\n                                        if(resource.downloading) {\n                                            image.icon += ' u-animation--pulse';\n                                        }\n                                    }\n                                    $scope.ubuntuImages.push(image);\n                                });\n                        });\n\n                    // If not a new source and images remain in resources, then\n                    // those are set to be deleted.\n                    if(!$scope.source.isNew) {\n                        angular.forEach(resources, function(resource) {\n                            var name_split = resource.name.split('/');\n                            var image = {\n                                icon: 'p-icon--status-failed',\n                                title: resource.title,\n                                arch: resource.arch,\n                                size: resource.size,\n                                status: 'Will be deleted',\n                                beingDeleted: true,\n                                name: name_split[1]\n                            };\n                            $scope.ubuntuImages.push(image);\n                        });\n                    }\n                };\n\n                // Regenerates the Ubuntu Core images list for the directive.\n                $scope.regenerateUbuntuCoreImages = function() {\n                    var isUbuntuCore = function(resource) {\n                        var name_split = resource.name.split('/');\n                        var resource_os = name_split[0];\n                        return (\n                            resource.rtype === 0 &&\n                            resource_os === 'ubuntu-core');\n                    };\n                    var resources = (\n                        $scope.bootResources.resources.filter(isUbuntuCore));\n                    var getResource = function(release, arch) {\n                        var i;\n                        for(i = 0; i < resources.length; i++) {\n                            // Only care about other images. Removing custom,\n                            // bootloaders, and Ubuntu images.\n                            var resource = (resources[i]);\n                            var name_split = resource.name.split('/');\n                            var resource_release = name_split[1];\n                            if(resource_release === release &&\n                                resource.arch === arch) {\n                                resources.splice(i, 1);\n                                return resource;\n                            }\n                        }\n                        return null;\n                    };\n\n                    // Create the images based on the selections.\n                    $scope.ubuntuCoreImages.length = 0;\n                    angular.forEach($scope.ubuntu_core.images,\n                        function(ubuntuCoreImage) {\n                            if(ubuntuCoreImage.checked) {\n                                var name_split = ubuntuCoreImage.name.split(\n                                    '/');\n                                var image = {\n                                    icon: 'p-icon--status-queued',\n                                    title: ubuntuCoreImage.title,\n                                    arch: name_split[1],\n                                    size: '-',\n                                    status: 'Selected for download',\n                                    beingDeleted: false\n                                };\n                                var resource = getResource(\n                                    name_split[3], name_split[1]);\n                                if(angular.isObject(resource)) {\n                                    image.icon = (\n                                        'p-icon--status-' + resource.icon);\n                                    image.size = resource.size;\n                                    image.status = resource.status;\n                                    if(resource.downloading) {\n                                        image.icon += ' u-animation--pulse';\n                                    }\n                                }\n                                $scope.ubuntuCoreImages.push(image);\n                            }\n                        });\n\n                    // If not a new source and images remain in resources, then\n                    // those are set to be deleted.\n                    angular.forEach(resources, function(resource) {\n                        var image = {\n                            icon: 'p-icon--status-failed',\n                            title: resource.title,\n                            arch: resource.arch,\n                            size: resource.size,\n                            status: 'Will be deleted',\n                            beingDeleted: true\n                        };\n                        $scope.ubuntuCoreImages.push(image);\n                    });\n                };\n\n                // Regenerates the other images list for the directive.\n                $scope.regenerateOtherImages = function() {\n                    var isOther = function(resource) {\n                        var name_split = resource.name.split('/');\n                        var resource_os = name_split[0];\n                        return (\n                            resource.rtype === 0 &&\n                            resource_os !== 'ubuntu' &&\n                            resource_os !== 'ubuntu-core' &&\n                            resource_os !== 'custom');\n                    };\n                    var resources = (\n                        $scope.bootResources.resources.filter(isOther));\n                    var getResource = function(release, arch) {\n                        var i;\n                        for(i = 0; i < resources.length; i++) {\n                            // Only care about other images. Removing custom,\n                            // bootloaders, and Ubuntu images.\n                            var resource = (resources[i]);\n                            var name_split = resource.name.split('/');\n                            var resource_release = name_split[1];\n                            if(resource_release === release &&\n                                resource.arch === arch) {\n                                resources.splice(i, 1);\n                                return resource;\n                            }\n                        }\n                        return null;\n                    };\n\n                    // Create the images based on the selections.\n                    $scope.otherImages.length = 0;\n                    angular.forEach($scope.other.images,\n                        function(otherImage) {\n                            if(otherImage.checked) {\n                                var name_split = otherImage.name.split('/');\n                                var image = {\n                                    icon: 'p-icon--status-queued',\n                                    title: otherImage.title,\n                                    arch: name_split[1],\n                                    size: '-',\n                                    status: 'Selected for download',\n                                    beingDeleted: false\n                                };\n                                var resource = getResource(\n                                    name_split[3], name_split[1]);\n                                if(angular.isObject(resource)) {\n                                    image.icon = (\n                                        'p-icon--status-' + resource.icon);\n                                    image.size = resource.size;\n                                    image.status = resource.status;\n                                    if(resource.downloading) {\n                                        image.icon += ' u-animation--pulse';\n                                    }\n                                }\n                                $scope.otherImages.push(image);\n                            }\n                        });\n\n                    // If not a new source and images remain in resources, then\n                    // those are set to be deleted.\n                    angular.forEach(resources, function(resource) {\n                        var image = {\n                            icon: 'p-icon--status-failed',\n                            title: resource.title,\n                            arch: resource.arch,\n                            size: resource.size,\n                            status: 'Will be deleted',\n                            beingDeleted: true\n                        };\n                        $scope.otherImages.push(image);\n                    });\n                };\n\n                // Helper for basic image generation.\n                $scope._regenerateImages = function(rtype, images) {\n                    // Create the generated images list.\n                    images.length = 0;\n                    angular.forEach($scope.bootResources.resources,\n                        function(resource) {\n                            if(resource.rtype === rtype) {\n                                var image = {\n                                    icon: 'p-icon--status-' + resource.icon,\n                                    title: resource.title,\n                                    arch: resource.arch,\n                                    image_id: resource.id,\n                                    size: resource.size,\n                                    status: resource.status\n                                };\n                                if(resource.downloading) {\n                                    image.icon += ' u-animation--pulse';\n                                }\n                                images.push(image);\n                            }\n                        });\n                };\n\n                // Regenerates the generated images list for the directive.\n                $scope.regenerateGeneratedImages = function() {\n                    $scope._regenerateImages(1, $scope.generatedImages);\n                };\n\n                // Regenerates the custom images list for the directive.\n                $scope.regenerateCustomImages = function() {\n                    $scope._regenerateImages(2, $scope.customImages);\n                };\n\n                // Returns true if at least one LTS is selected.\n                $scope.ltsIsSelected = function() {\n                    var i;\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        // Must have LTS in the title and not being deleted.\n                        if(!$scope.ubuntuImages[i].beingDeleted &&\n                            $scope.ubuntuImages[i].title.indexOf('LTS') >= 0) {\n                            // Must be greater than Ubuntu series 14.\n                            var series = parseInt(\n                                $scope.ubuntuImages[i].title.split('.')[0], 10);\n                            if(series >= 14) {\n                                return true;\n                            }\n                        }\n                    }\n                    return false;\n                };\n\n                // Returns true if the commission series is selected\n                $scope.commissioningSeriesSelected = function() {\n                    var i;\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        if(!$scope.ubuntuImages[i].beingDeleted &&\n                           $scope.ubuntuImages[i].name ===\n                           $scope.bootResources.ubuntu.commissioning_series) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n\n                // Return if we are asking about deleting this image.\n                $scope.isShowingDeleteConfirm = function(image) {\n                    return image === $scope.removingImage;\n                };\n\n                // Mark the image for deletion.\n                $scope.quickRemove = function(image) {\n                    $scope.removingImage = image;\n                };\n\n                // Cancel image deletion.\n                $scope.cancelRemove = function() {\n                    $scope.removingImage = null;\n                };\n\n                // Mark the image for deletion.\n                $scope.confirmRemove = function(image) {\n                    if(image === $scope.removingImage) {\n                        BootResourcesManager.deleteImage(\n                            {id: image.image_id});\n                    }\n                    $scope.cancelRemove();\n                };\n\n                // Return true if the stop import button should be shown.\n                $scope.showStopImportButton = function() {\n                    return $scope.bootResources.region_import_running;\n                };\n\n                // Return true if should show save selection button, this\n                // doesn't mean it can actually be clicked.\n                $scope.showSaveSelection = function() {\n                    return $scope.showImagesTable();\n                };\n\n                // Return true if can save the current selection.\n                $scope.canSaveSelection = function() {\n                    var commissioning_series_being_deleted = false;\n                    var commissioning_series_arches = 0;\n                    var i;\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        if($scope.ubuntuImages[i].name ===\n                           $scope.bootResources.ubuntu.commissioning_series) {\n                            commissioning_series_arches++;\n                        }\n                    }\n                    // Only prevent the current commissioning series from\n                    // being deleted if it isn't the commissioning series isn't\n                    // available on another architecture.. If the current\n                    // commissioning series isn't currently selected another\n                    // LTS may be choosen, downloaded, and configured as the\n                    // commissioning series.\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        if($scope.ubuntuImages[i].beingDeleted &&\n                           $scope.ubuntuImages[i].name ===\n                           $scope.bootResources.ubuntu.commissioning_series &&\n                           commissioning_series_arches === 1) {\n                            commissioning_series_being_deleted = true;\n                            break;\n                        }\n                    }\n                    return (\n                        !commissioning_series_being_deleted &&\n                        !$scope.saving &&\n                        !$scope.stopping &&\n                        $scope.ltsIsSelected());\n                };\n\n                // Return the text for the save selection button.\n                $scope.getSaveSelectionText = function() {\n                    if($scope.saving) {\n                        return \"Saving...\";\n                    } else {\n                        return \"Update selection\";\n                    }\n                };\n\n                // Return true if can stop current import.\n                $scope.canStopImport = function() {\n                    return !$scope.saving && !$scope.stopping;\n                };\n\n                // Return the text for the stop import button.\n                $scope.getStopImportText = function() {\n                    if($scope.stopping) {\n                        return \"Stopping...\";\n                    } else {\n                        return \"Stop import\";\n                    }\n                };\n\n                // Called to stop the import.\n                $scope.stopImport = function() {\n                    if(!$scope.canStopImport()) {\n                        return;\n                    }\n\n                    $scope.stopping = true;\n                    BootResourcesManager.stopImport().then(function() {\n                        $scope.stopping = false;\n                    });\n                };\n\n                // Save the selections into boot selections.\n                $scope.saveSelection = function() {\n                    if(!$scope.canSaveSelection()) {\n                        return;\n                    }\n\n                    var params = $scope.getSourceParams();\n                    params.releases = (\n                        $scope.source.selections.releases.map(function(obj) {\n                            return obj.name;\n                        }));\n                    params.arches = (\n                        $scope.source.selections.arches.map(function(obj) {\n                            return obj.name;\n                        }));\n                    $scope.saving = true;\n                    BootResourcesManager.saveUbuntu(params).then(function() {\n                        $scope.saving = false;\n                        $scope.source.isNew = false;\n                        $scope.source.selections.changed = false;\n                        $scope.updateSource();\n                    });\n                };\n\n                // Re-create an array with the new objects using the old\n                // selected array.\n                $scope.getNewSelections = function(newObjs, oldSelections) {\n                    var newSelections = [];\n                    angular.forEach(newObjs, function(obj) {\n                        angular.forEach(oldSelections, function(selection) {\n                            if(obj.name === selection.name) {\n                                newSelections.push(obj);\n                            }\n                        });\n                    });\n                    return newSelections;\n                };\n\n                // Update the source information.\n                $scope.updateSource = function() {\n                    // Do not update if the source is new.\n                    if($scope.source.isNew) {\n                        return;\n                    }\n\n                    var source_len = $scope.bootResources.ubuntu.sources.length;\n                    if(source_len === 0) {\n                        $scope.source.isNew = true;\n                        $scope.source.source_type = 'custom';\n                        $scope.source.errorMessage = (\n                            \"Currently no source exists.\");\n                    } else if(source_len === 1) {\n                        var source = $scope.bootResources.ubuntu.sources[0];\n                        $scope.source.source_type = source.source_type;\n                        if(source.source_type === \"maas.io\") {\n                            $scope.source.url = \"\";\n                            $scope.source.keyring_filename = \"\";\n                            $scope.source.keyring_data = \"\";\n                        } else {\n                            $scope.source.url = source.url;\n                            $scope.source.keyring_filename = (\n                                source.keyring_filename);\n                            $scope.source.keyring_data = source.keyring_data;\n                        }\n                        $scope.source.releases = (\n                            $scope.bootResources.ubuntu.releases);\n                        $scope.source.arches = (\n                            $scope.bootResources.ubuntu.arches);\n                        if(!$scope.source.selections.changed) {\n                            // User didn't make a change update to the\n                            // current selections server side.\n                            $scope.source.selections.releases = (\n                                $scope.source.releases.filter(function(obj) {\n                                    return obj.checked;\n                                }));\n                            $scope.source.selections.arches = (\n                                $scope.source.arches.filter(function(obj) {\n                                return obj.checked;\n                            }));\n                        } else {\n                            // Update the objects to be the new objects, with\n                            // the same selections.\n                            $scope.source.selections.releases = (\n                                $scope.getNewSelections(\n                                    $scope.source.releases,\n                                    $scope.source.selections.releases));\n                            $scope.source.selections.arches = (\n                                $scope.getNewSelections(\n                                    $scope.source.arches,\n                                    $scope.source.selections.arches));\n                        }\n                        $scope.regenerateUbuntuImages();\n                    } else {\n                        // Having more than one source prevents modification\n                        // of the sources.\n                        $scope.source.tooMany = true;\n                        $scope.source.releases = (\n                            $scope.bootResources.ubuntu.releases);\n                        $scope.source.arches = (\n                            $scope.bootResources.ubuntu.arches);\n                        $scope.source.selections.releases = (\n                            $scope.source.releases.filter(function(obj) {\n                                return obj.checked;\n                            }));\n                        $scope.source.selections.arches = (\n                            $scope.source.arches.filter(function(obj) {\n                            return obj.checked;\n                        }));\n                        $scope.source.errorMessage = (\n                            \"More than one image source exists. UI does not \" +\n                            \"support modification of sources when more than \" +\n                            \"one has been defined. Used the API to adjust \" +\n                            \"your sources.\");\n                        $scope.regenerateUbuntuImages();\n                    }\n                };\n\n                // Toggle the selection of Ubuntu Core images.\n                $scope.toggleUbuntuCoreSelection = function(image) {\n                    $scope.ubuntu_core.changed = true;\n                    image.checked = !image.checked;\n                    $scope.regenerateUbuntuCoreImages();\n                };\n\n                // Save the Ubuntu Core image selections into boot selections.\n                $scope.saveUbuntuCoreSelection = function() {\n                    var params = {\n                        images: $scope.ubuntu_core.images.filter(function(\n                                image) {\n                            return image.checked;\n                        }).map(function(image) {\n                            return image.name;\n                        })\n                    };\n                    $scope.saving = true;\n                    BootResourcesManager.saveUbuntuCore(params).then(\n                            function() {\n                        $scope.saving = false;\n                    });\n                };\n\n                // Toggle the selection of other images.\n                $scope.toggleOtherSelection = function(image) {\n                    $scope.other.changed = true;\n                    image.checked = !image.checked;\n                    $scope.regenerateOtherImages();\n                };\n\n                // Save the other image selections into boot selections.\n                $scope.saveOtherSelection = function() {\n                    var params = {\n                        images: $scope.other.images.filter(function(image) {\n                            return image.checked;\n                        }).map(function(image) {\n                            return image.name;\n                        })\n                    };\n                    $scope.saving = true;\n                    BootResourcesManager.saveOther(params).then(function() {\n                        $scope.saving = false;\n                    });\n                };\n\n                // Return True if the Ubuntu image can be removed.\n                $scope.canBeRemoved = function(image) {\n                    // Image must have a resourceId to be able to be removed.\n                    if(!angular.isNumber(image.resourceId)) {\n                        return false;\n                    }\n\n                    // If the release or architecture is set to deleted\n                    // then this image can be deleted.\n                    var i;\n                    var releases = $scope.bootResources.ubuntu.releases;\n                    var arches = $scope.bootResources.ubuntu.arches;\n                    for(i = 0; i < releases.length; i++) {\n                        var release = releases[i];\n                        if(release.deleted && image.title === release.title) {\n                            return true;\n                        }\n                    }\n                    for(i = 0; i < arches.length; i++) {\n                        var arch = arches[i];\n                        if(arch.deleted && image.arch === arch.name) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n\n                // Deletes the give image.\n                $scope.deleteImage = function(image) {\n                    if(angular.isObject(image)) {\n                        $scope.ubuntuDeleteId = image.resourceId;\n                    } else {\n                        $scope.ubuntuDeleteId = null;\n                    }\n                };\n\n                // Deletes the give image.\n                $scope.confirmDeleteImage = function() {\n                    // Delete the image by its resourceId.\n                    BootResourcesManager.deleteImage(\n                        {id: $scope.ubuntuDeleteId});\n                    $scope.ubuntuDeleteId = null;\n                };\n\n                // Start polling now that the directive is viewable and ensure\n                // the UserManager is loaded.\n                var ready = 2;\n                BootResourcesManager.startPolling().then(function() {\n                    ready -= 1;\n                    if(ready === 0) {\n                        $scope.loading = false;\n                    }\n                });\n                ManagerHelperService.loadManager(\n                    $scope, UsersManager).then(function() {\n                    ready -= 1;\n                    if(ready === 0) {\n                        $scope.loading = false;\n                    }\n                });\n\n                // Update the source information with the ubuntu source\n                // information changes.\n                $scope.$watch(\"bootResources.ubuntu\", function() {\n                    if(!angular.isObject($scope.bootResources.ubuntu)) {\n                        return;\n                    }\n                    $scope.updateSource();\n                });\n\n                // Regenerate the images array when the resources change.\n                $scope.$watch(\"bootResources.resources\", function() {\n                    if(!angular.isArray($scope.bootResources.resources)) {\n                        return;\n                    }\n                    $scope.regenerateUbuntuImages();\n                    $scope.regenerateUbuntuCoreImages();\n                    $scope.regenerateOtherImages();\n                    $scope.regenerateGeneratedImages();\n                    $scope.regenerateCustomImages();\n                });\n\n                $scope.$watch(\"bootResources.ubuntu_core_images\", function() {\n                    var images = $scope.bootResources.ubuntu_core_images;\n                    if(!angular.isArray(images)) {\n                        return;\n                    }\n                    if(!$scope.ubuntu_core.changed) {\n                        $scope.ubuntu_core.images = images;\n                    }\n                    $scope.regenerateUbuntuCoreImages();\n                });\n\n                $scope.$watch(\"bootResources.other_images\", function() {\n                    if(!angular.isArray($scope.bootResources.other_images)) {\n                        return;\n                    }\n                    if(!$scope.other.changed) {\n                        $scope.other.images = $scope.bootResources.other_images;\n                    }\n                    $scope.regenerateOtherImages();\n                });\n\n                // Stop polling when the directive is destroyed.\n                $scope.$on('$destroy', function() {\n                    BootResourcesManager.stopPolling();\n                });\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Call to action directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the cta.html into the template cache.\n    $templateCache.put('directive/templates/cta.html', [\n      '<div class=\"p-contextual-menu\">',\n        '<button ',\n          'class=\"p-button p-contextual-menu__toggle\" ',\n          'aria-controls=\"#cta-menu\" ',\n          'aria-expanded=\"false\" ',\n          'aria-haspopup=\"true\" ',\n          'data-ng-click=\"shown=!shown\"',\n        '>',\n          '{$ getTitle() $}',\n          '<i class=\"p-icon--chevron on-right\"></i>',\n        '</button>',\n        '<div class=\"p-contextual-menu__dropdown\" ',\n          'id=\"cta-menu\" ',\n          'aria-hidden=\"false\" ',\n          'aria-label=\"submenu\"',\n          'data-ng-show=\"shown\"',\n        '>',\n          '<button ',\n            'class=\"',\n              'p-button u-no-margin--left p-contextual-menu__link',\n            '\" ',\n            'data-ng-repeat=\"select in maasCta\" ',\n            'data-ng-click=\"selectItem(select)\">',\n              '{$ getOptionTitle(select) $}',\n          '</button>',\n        '</div>',\n      '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasCta', function() {\n    return {\n        restrict: \"A\",\n        replace: true,\n        require: \"ngModel\",\n        scope: {\n            maasCta: '=',\n            ngModel: '='\n        },\n        templateUrl: 'directive/templates/cta.html',\n        link : function(scope, element, attrs, ngModelCtrl) {\n            // Use the link function to grab the ngModel controller.\n\n            // Title of the button when not active.\n            var defaultTitle = \"Take action\";\n            if(angular.isString(attrs.defaultTitle) &&\n                attrs.defaultTitle !== \"\") {\n                defaultTitle = attrs.defaultTitle;\n            }\n\n            // When an item is selected in the list set the title, hide the\n            // dropdown, and set the value to the given model.\n            scope.selectItem = function(select) {\n                scope.shown = false;\n                ngModelCtrl.$setViewValue(select);\n            };\n\n            // Return the title of the dropdown button.\n            scope.getTitle = function() {\n                if(angular.isObject(ngModelCtrl.$modelValue)) {\n                    option = ngModelCtrl.$modelValue;\n                    scope.secondary = true;\n                    // Some designs have the requirement that the title of\n                    // the menu option change if it is selected.\n                    if(angular.isString(option.selectedTitle)) {\n                        return option.selectedTitle;\n                    }\n                    return option.title;\n                } else {\n                    scope.secondary = false;\n                    return defaultTitle;\n                }\n            };\n\n            // Called to get the title for each option. (Sometimes the title\n            // of an option is different when it is selected.)\n            scope.getOptionTitle = function(option) {\n                if(!scope.secondary) {\n                    return option.title;\n                } else {\n                    if(angular.isString(option.selectedTitle)) {\n                        return option.selectedTitle;\n                    } else {\n                        return option.title;\n                    }\n                }\n            };\n\n            // When the model changes in the above selectItem function this\n            // function will be called causing the ngChange directive to be\n            // fired.\n            ngModelCtrl.$viewChangeListeners.push(function() {\n                scope.$eval(attrs.ngChange);\n            });\n        },\n        controller: function($scope, $rootScope, $element, $document) {\n            // Default dropdown is hidden.\n            $scope.shown = false;\n            $scope.secondary = false;\n\n            // Don't propagate the element click. This stops the click event\n            // from firing on the body element.\n            $element.bind('click', function (evt) {\n                evt.stopPropagation();\n            });\n\n            // If a click makes it to the body element then hide the dropdown.\n            $document.find('body').bind('click', function () {\n                // Use $apply because this function will be called outside\n                // of the digest cycle.\n                $rootScope.$apply($scope.shown = false);\n            });\n        }\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Controller status icon. Used in the controllers listing on the nodes page.\n */\n\nangular.module('MAAS').directive('maasCardLoader', ['$compile',\n  function($compile) {\n      return {\n          restrict: \"A\",\n          link: function(scope, element, attrs) {\n            var templateUrl = (\n                'static/partials/cards/' + attrs.maasCardLoader + (\n                  '.html?v=' + MAAS_config.files_version));\n            var include = (\n              '<ng-include src=\"\\'' + templateUrl + '\\'\"></ng-include>');\n            element.html(include);\n            $compile(element.contents())(scope);\n          }\n      };\n  }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Accordion directive.\n *\n * Provides an accordion effect to an element with maas-accordion class and\n * all child elements with maas-accordion-tab. Only one accordion tab is open\n * at a time, selecting another accordion will set \"active\" on that\n * accordion tab.\n */\n\n\n angular.module('MAAS').directive('maasCodeLines', function () {\n     return {\n         restrict: \"A\",\n         scope: {\n             maasCodeLines: '&'\n         },\n         link: function(scope, element, attributes) {\n\n             function insertContent() {\n\n                 // Empty the element contents and include again, this asures\n                 // its the most up-to-date content\n                 element.empty();\n                 element.text(scope.maasCodeLines);\n\n                 // Count the line contents\n                 var lines = element.html().split('\\n'),\n                     newLine = '',\n                     insert = \"<code>\";\n\n                 // Each line is to be wrapped by a span which is style & given\n                 // its appropriate line number\n                 $.each(lines, function() {\n                   insert += newLine + '<span class=\"code-line\">' +\n                   this + '</span>';\n                   newLine = '\\n';\n                 });\n                 insert += \"</code>\";\n\n                 // Re-insert the contents\n                 element.html(insert);\n             }\n\n             // Watch the contents of the element so when it changes to\n             // re-add the line numbers.\n             scope.$watch(scope.maasCodeLines, insertContent);\n         }\n     };\n });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Content editable directive.\n *\n * HTML provides a feature that allows any element to be editable with\n * contenteditable attribute. This directive uses that attribute to link\n * the contents of that element to a model. This directive is not prefixed\n * with maas so Angular can identify all elements with this attribute.\n */\n\n\nangular.module('MAAS').directive('contenteditable', function() {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            ngDisabled: \"&\",\n            maasEditing: \"&\"\n        },\n        link: function(scope, element, attrs, ngModel) {\n\n            // If the element is disabled then make the element lose focus.\n            var focusHandler = function() {\n                if(scope.ngDisabled()) {\n                    element.blur();\n                } else {\n                    // Didn't lose focus, so its now editing.\n                    scope.$apply(scope.maasEditing());\n                }\n            };\n            element.bind(\"focus\", focusHandler);\n\n            // Update the value of the model when events occur that\n            // can change the value of the model.\n            var changeHandler = function() {\n                scope.$apply(ngModel.$setViewValue(element.text()));\n            };\n            element.bind(\"blur keyup change\", changeHandler);\n\n            // When the model changes set the html content for that element.\n            ngModel.$render = function() {\n                element.html(ngModel.$viewValue || \"\");\n            };\n\n            // When the model changes this function will be called causing the\n            // ngChange directive to be fired.\n            ngModel.$viewChangeListeners.push(function() {\n                scope.$eval(attrs.ngChange);\n            });\n\n            // Remove the event handler on the element when the scope is\n            // destroyed.\n            scope.$on(\"$destroy\", function() {\n                element.unbind(\"blur keyup change\", changeHandler);\n                element.unbind(\"focus\", focusHandler);\n            });\n        }\n    };\n});\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Controller image status directive.\n *\n * Shows the image status for a controller.\n */\n\n angular.module('MAAS').service('ControllerImageStatusService',\n    ['$timeout', '$interval', 'ControllersManager', function(\n        $timeout, $interval, ControllersManager) {\n     var self = this;\n\n     // How often to check the sync status of a controller in seconds.\n     var CHECK_INTERVAL = 30;\n\n     // List of controllers that need to have the image status updated.\n     this.controllers = [];\n\n     // List of current controller statues.\n     this.statuses = {};\n\n     // Interval function that is called to update the statuses.\n     this.updateStatuses = function() {\n         var controllerIds = [];\n         angular.forEach(self.controllers, function(system_id) {\n             controllerIds.push({system_id: system_id});\n         });\n\n         // Check the image states.\n         ControllersManager.checkImageStates(controllerIds).then(\n                 function(results) {\n             angular.forEach(controllerIds, function(controller) {\n                 var status = results[controller.system_id];\n                 if(status) {\n                     self.statuses[controller.system_id] = status;\n                 } else {\n                     self.statuses[controller.system_id] = \"Unknown\";\n                 }\n             });\n         });\n     };\n\n     // Register this controller system_id.\n     this.register = function(system_id) {\n         var known = self.controllers.indexOf(system_id) >= 0;\n         if(!known) {\n             self.controllers.push(system_id);\n         }\n\n         // When the interval is already running and its a new controller then\n         // the interval needs to be reset. When it already exists it doesn't\n         // need to be reset.\n         if(angular.isDefined(self.runningInterval)) {\n             if(known) {\n                 return;\n             } else {\n                 $interval.cancel(self.runningInterval);\n                 self.runningInterval = undefined;\n             }\n         }\n\n         // If its not running and the timeout has been started we re-create\n         // the timeout. This delays the start of the interval until the\n         // all directives on the page have been fully loaded.\n         if(angular.isDefined(self.startTimeout)) {\n             $timeout.cancel(self.startTimeout);\n         }\n         self.startTimeout = $timeout(function() {\n             self.startTimeout = undefined;\n             self.runningInterval = $interval(function() {\n                 self.updateStatuses();\n             }, CHECK_INTERVAL * 1000);\n             self.updateStatuses();\n         }, 100);\n     };\n\n     // Unregister the controller.\n     this.unregister = function(system_id) {\n        var idx = self.controllers.indexOf(system_id);\n        if(idx > -1) {\n            self.controllers.splice(idx, 1);\n        }\n\n        // If no controllers are left stop all intervals and timeouts.\n        if(self.controllers.length === 0) {\n            if(angular.isDefined(self.startTimeout)) {\n                $timeout.cancel(self.startTimeout);\n                self.startTimeout = undefined;\n            }\n            if(angular.isDefined(self.runningInterval)) {\n                $interval.cancel(self.runningInterval);\n                self.runningInterval = undefined;\n            }\n        }\n     };\n\n     // Return true if the spinner should be shown.\n     this.showSpinner = function(system_id) {\n         var status = self.statuses[system_id];\n         if(angular.isString(status) && status !== \"Syncing\") {\n             return false;\n         } else {\n             return true;\n         }\n     };\n\n     // Get the image status.\n     this.getImageStatus = function(system_id) {\n         var status = self.statuses[system_id];\n         if(angular.isString(status)) {\n             return status;\n         } else {\n             return \"Asking for status...\";\n         }\n     };\n}]);\n\nangular.module('MAAS').directive('maasControllerImageStatus',\n    ['ControllerImageStatusService', function(\n        ControllerImageStatusService) {\n\n    return {\n        restrict: \"E\",\n        scope: {\n            systemId: \"=\"\n        },\n        template: [\n            '<i class=\"p-icon--loading u-animation--spin\"',\n                'data-ng-if=\"showSpinner()\"></i> ',\n            '{$ getImageStatus() $}'].join(''),\n        link: function(scope, element, attrs) {\n            // Don't register until the systemId is set.\n            var unwatch, registered = false;\n            unwatch = scope.$watch(\"systemId\", function() {\n                if(angular.isDefined(scope.systemId) && !registered) {\n                    ControllerImageStatusService.register(scope.systemId);\n                    registered = true;\n                    unwatch();\n                }\n            });\n\n            scope.showSpinner = function() {\n                return ControllerImageStatusService.showSpinner(\n                    scope.systemId);\n            };\n            scope.getImageStatus = function() {\n                return ControllerImageStatusService.getImageStatus(\n                    scope.systemId);\n            };\n\n            // Unregister when destroyed.\n            scope.$on(\"$destroy\", function() {\n                if(registered) {\n                    ControllerImageStatusService.unregister(scope.systemId);\n                }\n            });\n        }\n    };\n}]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Controller status icon. Used in the controllers listing on the nodes page.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the controller-status.html into the template cache.\n    $templateCache.put('directive/templates/controller-status.html', [\n        '<span>',\n          '<span class=\"p-icon--{$ serviceClass $}\" data-ng-if=\"!textOnly\">',\n          '</span>',\n          '<span data-ng-if=\"textOnly\" data-ng-bind=\"serviceText\"></span>',\n        '</span>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasControllerStatus', [\n    \"ControllersManager\", \"ServicesManager\",\n    function(ControllersManager, ServicesManager) {\n        return {\n            restrict: \"A\",\n            scope: {\n                controller: '=maasControllerStatus',\n                textOnly: '=?maasTextOnly'\n            },\n            templateUrl: 'directive/templates/controller-status.html',\n            controller: function($scope) {\n\n                $scope.serviceClass = \"unknown\";\n                $scope.services = ServicesManager.getItems();\n                $scope.serviceText = \"\";\n                if($scope.textOnly) {\n                  $scope.textOnly = true;\n                } else {\n                  $scope.textOnly = false;\n                }\n\n                // Return the status class for the service.\n                function getClass(service) {\n                    if(service.status === \"running\") {\n                        return \"success\";\n                    } else if (service.status === \"degraded\") {\n                        return \"warning\";\n                    } else if (service.status === \"dead\") {\n                        return \"error\";\n                    } else {\n                        return \"unknown\";\n                    }\n                }\n\n                // Return the number of times class is displayed.\n                function countClass(classes, class_name) {\n                  var counter = 0;\n                  angular.forEach(classes, function(name) {\n                    if(name === class_name) {\n                      counter++;\n                    }\n                  });\n                  return counter;\n                }\n\n                // Update the class based on status of the services on the\n                // controller.\n                function updateStatusClass() {\n                    $scope.serviceClass = \"unknown\";\n                    if(angular.isObject($scope.controller)) {\n                        var services = ControllersManager.getServices(\n                            $scope.controller);\n                        if(services.length > 0) {\n                            var classes = services.map(getClass);\n                            if(classes.indexOf(\"error\") !== -1) {\n                                $scope.serviceClass = \"power-error\";\n                                $scope.serviceText = countClass(\n                                  classes, \"error\") + \" dead\";\n                            } else if(classes.indexOf(\"warning\") !== -1) {\n                                $scope.serviceClass = \"warning\";\n                                $scope.serviceText = countClass(\n                                  classes, \"warning\") + \" degraded\";\n                            } else {\n                                $scope.serviceClass = \"success\";\n                                $scope.serviceText = countClass(\n                                  classes, \"success\") + \" running\";\n                            }\n                        }\n                    }\n                }\n\n                // Watch the services array and the services on the controller,\n                // if any changes then update the status.\n                $scope.$watch(\"controller.service_ids\", updateStatusClass);\n                $scope.$watchCollection(\"services\", updateStatusClass);\n\n                // Update on creation.\n                updateStatusClass();\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Double click overlay directive.\n *\n * Provides the ability for a disabled element to still accept the\n * double click event. By default if an element is disabled then it will\n * receive no click events. This overlays the element with another element\n * that will still receive click events.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the style for the maas-dbl-overlay class. We inject the style\n    // instead of placing it in maas-styles.css because it is required for\n    // this directive to work at all.\n    var styleElement = document.createElement('style');\n    styleElement.innerHTML = [\n        '.maas-dbl-overlay {',\n            'display: inline-block;',\n            'position: relative;',\n        '}',\n        '.maas-dbl-overlay--overlay {',\n            'position: absolute;',\n            'left: 0;',\n            'right: 0;',\n            'top: 0;',\n            'bottom: 0;',\n            '-webkit-touch-callout: none;',\n            '-webkit-user-select: none;',\n            '-khtml-user-select: none;',\n            '-moz-user-select: none;',\n            '-ms-user-select: none;',\n            'user-select: none;',\n        '}'\n    ].join('');\n    document.getElementsByTagName('head')[0].appendChild(styleElement);\n\n    // Inject the double_click_overlay.html into the template cache.\n    $templateCache.put('directive/templates/double_click_overlay.html', [\n        '<div class=\"maas-dbl-overlay\">',\n            '<span data-ng-transclude></span>',\n            '<div class=\"maas-dbl-overlay--overlay\"></div>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasDblClickOverlay', ['BrowserService',\n    function(BrowserService) {\n        return {\n            restrict: \"A\",\n            transclude: true,\n            replace: true,\n            scope: {\n                maasDblClickOverlay: '&'\n            },\n            templateUrl: 'directive/templates/double_click_overlay.html',\n            link: function(scope, element, attrs) {\n                // Create the click function that will be called when the\n                // overlay is clicked. This changes based on the element that\n                // is transcluded into this directive.\n                var overlay = element.find(\".maas-dbl-overlay--overlay\");\n                var transclude = element.find(\n                    \"span[data-ng-transclude]\").children()[0];\n                var clickElement;\n                if(transclude.tagName === \"SELECT\") {\n                    clickElement = function() {\n                        // Have to create a custom mousedown event for the\n                        // select click to be handled. Using 'click()' or\n                        //'focus()' will not work.\n                        var evt = document.createEvent('MouseEvents');\n                        evt.initMouseEvent(\n                            'mousedown', true, true, window, 0, 0, 0, 0, 0,\n                            false, false, false, false, 0, null);\n                        transclude.dispatchEvent(evt);\n                    };\n\n                    // Selects use a pointer for the cursor.\n                    overlay.css({ cursor: \"pointer\" });\n                } else if(transclude.tagName === \"INPUT\") {\n                    clickElement = function() {\n                        // An input will become in focus when clicked.\n                        angular.element(transclude).triggerHandler('focus');\n                    };\n\n                    // Inputs use a text for the cursor.\n                    overlay.css({ cursor: \"text\" });\n                } else {\n                    clickElement = function() {\n                        // Standard element just call click on that element.\n                        angular.element(transclude).triggerHandler('click');\n                    };\n\n                    // Don't set cursor on other element types.\n                }\n\n                // Add the click and double click handlers.\n                var overlayClick = function(evt) {\n                    clickElement();\n                    evt.preventDefault();\n                    evt.stopPropagation();\n                };\n                var overlayDblClick = function(evt) {\n                    // Call the double click handler with in the scope.\n                    scope.$apply(scope.maasDblClickOverlay);\n                    evt.preventDefault();\n                    evt.stopPropagation();\n                };\n\n                // Enable the handlers if not Firefox. It firefox, then hide\n                // the overlay as Firefox does not allow sending click events\n                // to select elements.\n                if(BrowserService.browser !== \"firefox\") {\n                    overlay.on(\"click\", overlayClick);\n                    overlay.on(\"dblclick\", overlayDblClick);\n                } else {\n                    overlay.addClass(\"ng-hide\");\n                }\n\n                // Remove the handlers when the scope is destroyed.\n                scope.$on(\"$destroy\", function() {\n                    overlay.off(\"click\", overlayClick);\n                    overlay.off(\"dblclick\", overlayDblClick);\n                });\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n*/\n\nangular.module('MAAS').directive('maasEnter', function () {\n    return {\n        restrict: \"A\",\n        link: function (scope, element, attrs) {\n            element.bind(\"keydown keypress\", function (evt) {\n                if(evt.which === 13) {\n                    scope.$apply(function () {\n                        scope.$eval(attrs.maasEnter);\n                    });\n                    evt.preventDefault();\n                }\n            });\n        }\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Enter blur directive.\n *\n * When the enter key is pressed make the element lose focus (aka. blur event).\n */\n\n\nangular.module('MAAS').directive('maasEnterBlur', function() {\n    return {\n        restrict: \"A\",\n        link: function(scope, element, attrs) {\n            element.bind(\"keydown keypress\", function(evt) {\n                if(evt.which === 13) {\n                    element.blur();\n                    evt.preventDefault();\n                }\n            });\n        }\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Error overlay.\n *\n * Directive overrides the entire transcluded element if an error occurs or\n * connection to the region over the websocket fails or becomes disconnected.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the error_overlay.html into the template cache.\n    $templateCache.put('directive/templates/error_overlay.html', [\n        '<header id=\"error-header\" class=\"page-header\" data-ng-show=\"show()\">',\n            '<div class=\"row\">',\n                '<h1 class=\"page-header__title\">',\n                    '<span class=\"p-icon--loading u-animation--spin ',\n                        'u-margin--right-small\"',\n                        'data-ng-hide=\"clientError\"></span>',\n                    '{$ getTitle() $}',\n                '</h1>',\n                '<div class=\"page-header__controls\">',\n                    '<button class=\"button--secondary button--inline\"',\n                        'data-ng-click=\"reload()\"',\n                        'data-ng-show=\"clientError\">Reload</button>',\n                '</div>',\n                '<div class=\"page-header__dropdown is-open\" ',\n                    'data-ng-show=\"error\">',\n                    '<div class=\"page-header__section twelve-col',\n                        'u-margin--bottom-none\">',\n                        '<p class=\"page-header__message',\n                                  'page-header__message--error\">',\n                            '{$ error $}',\n                        '</p>',\n                    '</div>',\n                '</div>',\n            '</div>',\n        '</header>',\n        '<div class=\"ng-hide u-no-margin--top\" data-ng-hide=\"show()\">',\n            '<div data-ng-transclude></div>',\n        '</div>'\n    ].join(''));\n\n    // Preload the svg and png error icon. Its possible that it has never been\n    // loaded by the browser and if the region connection goes down and the\n    // directive gets shown with an error the icon will be missing.\n    //\n    // Note: This is skipped if unit testing because it will throw 404 errors\n    // continuously.\n    if(!angular.isDefined(window.jasmine)) {\n        var image = new Image();\n        image.src = \"static/assets/images/icons/error.svg\";\n        image = new Image();\n        image.src = \"static/assets/images/icons/error.png\";\n    }\n}]);\n\nangular.module('MAAS').directive('maasErrorOverlay', [\n    '$window', '$timeout', 'RegionConnection', 'ErrorService',\n    function($window, $timeout, RegionConnection, ErrorService) {\n        return {\n            restrict: \"A\",\n            transclude: true,\n            scope: true,\n            templateUrl: 'directive/templates/error_overlay.html',\n            link: function(scope, element, attrs) {\n\n                scope.connected = false;\n                scope.showDisconnected = false;\n                scope.clientError = false;\n                scope.wasConnected = false;\n\n                // Holds the promise that sets showDisconnected to true. Will\n                // be cleared when the scope is destroyed.\n                var markDisconnected;\n\n                // Returns true when the overlay should be shown.\n                scope.show = function() {\n                    // Always show if clientError.\n                    if(scope.clientError) {\n                        return true;\n                    }\n                    // Never show if connected.\n                    if(scope.connected) {\n                        return false;\n                    }\n                    // Never been connected then always show.\n                    if(!scope.wasConnected) {\n                        return true;\n                    }\n                    // Not connected.\n                    return scope.showDisconnected;\n                };\n\n                // Returns the title for the header.\n                scope.getTitle = function() {\n                    if(scope.clientError) {\n                        return \"Error occurred\";\n                    } else if(scope.wasConnected) {\n                        return \"Connection lost, reconnecting...\";\n                    } else {\n                        return \"Connecting...\";\n                    }\n                };\n\n                // Called to reload the page.\n                scope.reload = function() {\n                    $window.location.reload();\n                };\n\n                // Called to when the connection status of the region\n                // changes. Updates the scope connected and error values.\n                var watchConnection = function() {\n                    // Do nothing if already a client error.\n                    if(scope.clientError) {\n                        return;\n                    }\n\n                    // Set connected and the time it changed.\n                    var connected = RegionConnection.isConnected();\n                    if(connected !== scope.connected) {\n                        scope.connected = connected;\n                        if(!connected) {\n                            scope.showDisconnected = false;\n\n                            // Show disconnected after 1/2 second. This removes\n                            // the flicker that can occur, if it disconnecets\n                            // and reconnected quickly.\n                            markDisconnected = $timeout(function() {\n                                scope.showDisconnected = true;\n                                markDisconnected = undefined;\n                            }, 500);\n                        }\n                    }\n\n                    // Set error and whether of not the connection\n                    // has ever been made.\n                    scope.error = RegionConnection.error;\n                    if(!scope.wasConnected && connected) {\n                        scope.wasConnected = true;\n                    }\n                };\n\n                // Watch the isConnected and error value on the\n                // RegionConnection.\n                scope.$watch(function() {\n                    return RegionConnection.isConnected();\n                }, watchConnection);\n                scope.$watch(function() {\n                    return RegionConnection.error;\n                }, watchConnection);\n\n                // Called then the error value on the ErrorService changes.\n                var watchError = function() {\n                    var error = ErrorService._error;\n                    if(angular.isString(error)) {\n                        scope.clientError = true;\n                        scope.error = ErrorService._error;\n                    }\n                };\n\n                // Watch _error on the ErrorService.\n                scope.$watch(function() {\n                    return ErrorService._error;\n                }, watchError);\n\n                // Cancel the timeout on scope destroy.\n                scope.$on(\"$destroy\", function() {\n                    if(angular.isDefined(markDisconnected)) {\n                        $timeout.cancel(markDisconnected);\n                    }\n                });\n            }\n        };\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Error toggle.\n *\n * Hides the element if an error occurs or no connection to the region\n * is present.\n */\n\nangular.module('MAAS').directive('maasErrorToggle', [\n    '$timeout', 'RegionConnection', 'ErrorService',\n    function($timeout, RegionConnection, ErrorService) {\n        return {\n            restrict: \"A\",\n            link: function(scope, element, attrs) {\n\n                // Holds timeout promise for setting ng-hide when\n                // connection is lost.\n                var disconnectedPromise;\n\n                // Cancel the disconnected timeout.\n                var cancelTimeout = function() {\n                    if(angular.isDefined(disconnectedPromise)) {\n                        $timeout.cancel(disconnectedPromise);\n                        disconnectedPromise = undefined;\n                    }\n                };\n\n                // Called to when the connection status of the region\n                // changes or the error on the ErrorService is set.\n                // The element is shown when connected and no errors.\n                var watchConnectionAndError = function() {\n                    var connected = RegionConnection.isConnected();\n                    var error = ErrorService._error;\n                    if(connected && !angular.isString(error)) {\n                        cancelTimeout();\n                        element.removeClass(\"ng-hide\");\n                    } else if(angular.isString(error)) {\n                        cancelTimeout();\n                        element.addClass(\"ng-hide\");\n                    } else if(!connected) {\n                        // Hide the element after 1/2 second. This stops\n                        // flickering when the connection goes down and\n                        // reconnects quickly.\n                        cancelTimeout();\n                        disconnectedPromise = $timeout(function() {\n                            element.addClass(\"ng-hide\");\n                        }, 500);\n                    }\n                };\n\n                // Watch the RegionConnection.isConnected() and\n                // ErrorService._error value.\n                scope.$watch(function() {\n                    return RegionConnection.isConnected();\n                }, watchConnectionAndError);\n                scope.$watch(function() {\n                    return ErrorService._error;\n                }, watchConnectionAndError);\n\n                // Cancel disconnect timeout on destroy.\n                scope.$on(\"$destroy\", function() {\n                    cancelTimeout();\n                });\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * IP Ranges directive.\n*/\n\nangular.module('MAAS').directive('maasIpRanges', [\n    '$filter', 'IPRangesManager', 'UsersManager',\n    'ManagerHelperService', 'ConverterService', function(\n        $filter, IPRangesManager, UsersManager, ManagerHelperService,\n        ConverterService) {\n        return {\n            restrict: \"E\",\n            scope: {\n                subnet: \"=\",\n                vlan: \"=\"\n            },\n            templateUrl: (\n                'static/partials/ipranges.html?v=' + (\n                    MAAS_config.files_version)),\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                $scope.ipranges = IPRangesManager.getItems();\n                $scope.iprangeManager = IPRangesManager;\n                $scope.newRange = null;\n                $scope.editIPRange = null;\n                $scope.deleteIPRange = null;\n\n                // Return true if the authenticated user is super user.\n                $scope.isSuperUser = function() {\n                    return UsersManager.isSuperUser();\n                };\n\n                // Called to start adding a new IP range.\n                $scope.addRange = function(type) {\n                    $scope.newRange = {\n                        type: type,\n                        start_ip: \"\",\n                        end_ip: \"\",\n                        comment: \"\"\n                    };\n                    if(angular.isObject($scope.subnet)) {\n                        $scope.newRange.subnet = $scope.subnet.id;\n                    }\n                    if(angular.isObject($scope.vlan)) {\n                        $scope.newRange.vlan = $scope.vlan.id;\n                    }\n                    if(type === \"dynamic\") {\n                        $scope.newRange.comment = \"Dynamic\";\n                    }\n                };\n\n                // Cancel adding the new IP range.\n                $scope.cancelAddRange = function() {\n                    $scope.newRange = null;\n                };\n\n                // Return true if the IP range can be modified by the\n                // authenticated user.\n                $scope.ipRangeCanBeModified = function(range) {\n                    if($scope.isSuperUser()) {\n                        return true;\n                    } else {\n                        // Can only modify reserved and same user.\n                        return (\n                            range.type === \"reserved\" &&\n                            range.user === UsersManager.getAuthUser().id);\n                    }\n                };\n\n                // Return true if the IP range is in edit mode.\n                $scope.isIPRangeInEditMode = function(range) {\n                    return $scope.editIPRange === range;\n                };\n\n                // Toggle edit mode for the IP range.\n                $scope.ipRangeToggleEditMode = function(range) {\n                    $scope.deleteIPRange = null;\n                    if($scope.isIPRangeInEditMode(range)) {\n                        $scope.editIPRange = null;\n                    } else {\n                        $scope.editIPRange = range;\n                    }\n                };\n\n                // Clear edit mode for the IP range.\n                $scope.ipRangeClearEditMode = function() {\n                    $scope.editIPRange = null;\n                };\n\n                // Return true if the IP range is in delete mode.\n                $scope.isIPRangeInDeleteMode = function(range) {\n                    return $scope.deleteIPRange === range;\n                };\n\n                // Enter delete mode for the IP range.\n                $scope.ipRangeEnterDeleteMode = function(range) {\n                    $scope.editIPRange = null;\n                    $scope.deleteIPRange = range;\n                };\n\n                // Exit delete mode for the IP range.\n                $scope.ipRangeCancelDelete = function() {\n                    $scope.deleteIPRange = null;\n                };\n\n                // Perform the delete operation on the IP range.\n                $scope.ipRangeConfirmDelete = function() {\n                    IPRangesManager.deleteItem(\n                        $scope.deleteIPRange).then(function() {\n                            $scope.deleteIPRange = null;\n                    });\n                };\n\n                // Sort ranges by starting IP address.\n                $scope.ipRangeSort = function(range) {\n                    if(range.start_ip.indexOf(':') !== -1) {\n                        return ConverterService.ipv6Expand(range.start_ip);\n                    } else {\n                        return ConverterService.ipv4ToInteger(range.start_ip);\n                    }\n                };\n\n                // Load the reqiured managers.\n                ManagerHelperService.loadManagers($scope, [\n                    IPRangesManager, UsersManager]).then(\n                        function() {\n                            $scope.loading = false;\n                        });\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS object directive.\n *\n * Directive that connects a field to an object from the websocket. The field\n * is an instant save on blur.\n */\n\nangular.module('MAAS').directive('maasObjForm', ['JSONService',\n    function(JSONService) {\n        function MAASFormController(scope) {\n            this.obj = scope.obj;\n            this.manager = scope.manager;\n            this.fields = {};\n            this.scope = scope;\n            this.scope.saving = false;\n            this.scope.savingKeys = [];\n            if(angular.isObject(this.scope.obj)) {\n                this.scope.obj.$maasForm = this;\n            }\n\n            // Set the managerMethod.\n            this.managerMethod = scope.managerMethod;\n            if(angular.isUndefined(this.managerMethod)) {\n                this.managerMethod = \"updateItem\";\n            }\n\n            var self = this;\n            scope.$watch(\"obj\", function() {\n                // Update the object when it changes.\n                self.obj = scope.obj;\n                if(angular.isObject(self.obj)) {\n                    self.obj.$maasForm = self;\n                }\n            });\n            scope.$on(\"$destroy\", function() {\n                // Remove the $maasForm from the object when directive is\n                // deleted.\n                if(angular.isObject(self.obj)) {\n                    delete self.obj.$maasForm;\n                }\n            });\n        }\n\n        // Get the current value for a field in the form.\n        MAASFormController.prototype.getValue = function (key) {\n            var field = this.fields[key];\n            if(angular.isObject(field) && angular.isObject(field.scope)) {\n                return field.scope.getValue();\n            }\n        };\n\n        // Update the current value for a field in the form.\n        MAASFormController.prototype.updateValue = function (key, value) {\n            var field = this.fields[key];\n            if(angular.isObject(field) && angular.isObject(field.scope)) {\n                return field.scope.updateValue(value);\n            }\n        };\n\n        // Clone the current object for this form without the $maasForm\n        // property set.\n        MAASFormController.prototype.cloneObject = function() {\n            if(!angular.isObject(this.obj)) {\n                return this.obj;\n            } else {\n                delete this.obj.$maasForm;\n                var clonedObj = angular.copy(this.obj);\n                this.obj.$maasForm = this;\n                return clonedObj;\n            }\n        };\n\n        // Return true if table form.\n        MAASFormController.prototype.isTableForm = function () {\n            if(angular.isUndefined(this.scope.tableForm)) {\n                // Default is not a table form.\n                return false;\n            } else {\n                return this.scope.tableForm;\n            }\n        };\n\n        // Return true if the form should be saved on blur.\n        MAASFormController.prototype.saveOnBlur = function() {\n            if(angular.isUndefined(this.scope.saveOnBlur)) {\n                // Default is save on blur.\n                return true;\n            } else {\n                return this.scope.saveOnBlur;\n            }\n        };\n\n        // Return true if the form is saving this field.\n        MAASFormController.prototype.isSaving = function(key) {\n            return (\n                this.scope.saving && this.scope.savingKeys.indexOf(key) >= 0);\n        };\n\n        // Return true if the input should show the saving spinner. This is\n        // only show on inputs in forms that are using save on blur.\n        MAASFormController.prototype.showInputSaving = function(key) {\n            return this.saveOnBlur() && this.isSaving(key);\n        };\n\n        // Return true if any field in the form as an error.\n        MAASFormController.prototype.hasErrors = function() {\n            var hasErrors = false;\n            angular.forEach(this.fields, function(field) {\n                if(field.scope.hasErrors()) {\n                    hasErrors = true;\n                }\n            });\n            if(angular.isDefined(this.errorScope)) {\n                if(this.errorScope.hasErrors()) {\n                    hasErrors = true;\n                }\n            }\n            return hasErrors;\n        };\n\n        // Called by maas-obj-field to register it as a editable field.\n        MAASFormController.prototype.registerField = function(key, scope) {\n            // Store the state of the field and its scope.\n            this.fields[key] = {\n                editing: false,\n                scope: scope\n            };\n\n            // Watch for changes on the value of the object.\n            var self = this;\n            this.scope.$watch(\"obj.\" + key, function() {\n                if(angular.isObject(self.obj) && !self.fields[key].editing) {\n                    self.fields[key].scope.updateValue(self.obj[key]);\n                }\n            });\n\n            // Return the current value for the field.\n            if(angular.isObject(this.obj)) {\n                return this.obj[key];\n            } else {\n                return null;\n            }\n        };\n\n        // Called by maas-obj-field to unregister it as a editable field.\n        MAASFormController.prototype.unregisterField = function(key) {\n            delete this.fields[key];\n        };\n\n        // Called by maas-obj-field to place field in edit mode.\n        MAASFormController.prototype.startEditingField = function(key) {\n            this.fields[key].editing = true;\n        };\n\n        // Called by maas-obj-field to end edit mode for the field.\n        MAASFormController.prototype.stopEditingField = function(key, value) {\n            var field = this.fields[key];\n\n            // Do nothing if not save on blur.\n            if(!this.saveOnBlur()) {\n                field.editing = false;\n                return;\n            }\n\n            // Clear errors before saving.\n            field.scope.clearErrors();\n\n            // Copy the object and update the editing field.\n            var updatedObj = this.cloneObject();\n            updatedObj[key] = value;\n            if(updatedObj[key] === this.obj[key]) {\n                // Nothing changed.\n                field.editing = false;\n                return;\n            }\n\n            // Update the item in the manager.\n            this.scope.saving = true;\n            this.scope.savingKeys = [key];\n            this.updateItem(updatedObj, [key]);\n        };\n\n        // Update the item using the manager.\n        MAASFormController.prototype.updateItem = function(updatedObj, keys) {\n            var key = keys[0];\n            var field = this.fields[key];\n            var self = this;\n\n            // Pre-process the updatedObj if one is defined.\n            if(angular.isFunction(this.scope.preProcess)) {\n                updatedObj = this.scope.preProcess(updatedObj, keys);\n            }\n\n            // Update the item with the manager.\n            return this.manager[this.managerMethod](\n                updatedObj).then(function(newObj) {\n                    // Update the value of the element.\n                    field.editing = false;\n                    field.scope.updateValue(newObj[key]);\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    if(angular.isFunction(self.scope.afterSave)) {\n                        self.scope.afterSave(newObj);\n                    }\n                    return newObj;\n                }, function(error) {\n                    var errorJson = JSONService.tryParse(error);\n                    if(angular.isObject(errorJson)) {\n                        // Add the error to each field it matches.\n                        angular.forEach(errorJson, function(value, key) {\n                            var errorField = self.fields[key];\n                            if(!angular.isArray(value)) {\n                                value = [value];\n                            }\n\n                            if(angular.isObject(errorField)) {\n                                // Error on a field we know about, place the\n                                // error on that field.\n                                errorField.scope.setErrors(value);\n                            } else {\n                                // Error on a field we don't know about, place\n                                // the error on the editing field. Prefixing\n                                // the error with the field.\n                                if(key !== \"__all__\") {\n                                    value = value.map(function(v) {\n                                        return key + \": \" + v;\n                                    });\n                                }\n                                field.scope.setErrors(value);\n                            }\n                        });\n                    } else {\n                        // Add the string error to just the field error.\n                        field.scope.setErrors([error]);\n                    }\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    return error;\n                });\n        };\n\n        // Called when saveOnBlur is false to save the whole form.\n        MAASFormController.prototype.saveForm = function () {\n            var keys = [];\n            var updatedObj = this.cloneObject();\n            angular.forEach(this.fields, function(value, key) {\n                value.scope.clearErrors();\n                var newValue = value.scope.getValue();\n                if(angular.isDefined(newValue) &&\n                    updatedObj[key] !== newValue) {\n                    updatedObj[key] = newValue;\n                    keys.push(key);\n                }\n            });\n\n\n            // Pre-process the updatedObj if one is defined.\n            if(angular.isFunction(this.scope.preProcess)) {\n                updatedObj = this.scope.preProcess(updatedObj, keys);\n            }\n\n            // Clear the errors on the errorScope before save.\n            if(angular.isDefined(this.errorScope)) {\n                this.errorScope.clearErrors();\n            }\n\n            var self = this;\n            this.scope.saving = true;\n            this.scope.savingKeys = keys;\n            return this.manager[this.managerMethod](\n                updatedObj).then(function(newObj) {\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    if(angular.isFunction(self.scope.afterSave)) {\n                        self.scope.afterSave(newObj);\n                    }\n                    return newObj;\n                }, function(error) {\n                    var errorJson = JSONService.tryParse(error);\n                    if(angular.isObject(errorJson)) {\n                        // Add the error to each field it matches.\n                        angular.forEach(errorJson, function(value, key) {\n                            var errorField = self.fields[key];\n                            if(!angular.isArray(value)) {\n                                value = [value];\n                            }\n\n                            if(angular.isObject(errorField)) {\n                                // Error on a field we know about, place the\n                                // error on that field.\n                                errorField.scope.setErrors(value);\n                            } else {\n                                if(key !== \"__all__\") {\n                                    value = value.map(function(v) {\n                                        return key + \": \" + v;\n                                    });\n                                }\n                                // Error on a field we don't know about, place\n                                // the error on errorScope if set.\n                                if(angular.isDefined(self.errorScope)) {\n                                    self.errorScope.setErrors(value);\n                                } else {\n                                    // No error scope, just log to console.\n                                    console.log(value);\n                                }\n                            }\n                        });\n                    } else {\n                        // Add the string error to just the field error.\n                        if(angular.isDefined(self.errorScope)) {\n                            self.errorScope.setErrors([error]);\n                        } else {\n                            // No error scope, just log to console.\n                            console.log(error);\n                        }\n                    }\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    return error;\n                });\n        };\n\n        return {\n            restrict: \"E\",\n            scope: {\n                obj: \"=\",\n                manager: \"=\",\n                managerMethod: \"@\",\n                preProcess: \"=\",\n                afterSave: \"=\",\n                tableForm: \"=\",\n                saveOnBlur: \"=\",\n                inline: \"=\",\n                ngDisabled: \"&\"\n            },\n            transclude: true,\n            template: (\n                '<form class=\"p-form\" data-ng-class=\"{saving: saving, ' +\n                '\\'p-form--inline\\': inline, ' +\n                '\\'p-form--stacked\\': tableForm}\" ' +\n                'ng-transclude></form>'),\n            controller: ['$scope', MAASFormController]\n        };\n    }]);\n\nangular.module('MAAS').directive('maasObjFieldGroup', ['JSONService',\n    function(JSONService) {\n        // Controller for this directive.\n        function MAASGroupController(scope, timeout) {\n            this.fields = {};\n            this.scope = scope;\n            this.scope.saving = false;\n            this.scope.savingKeys = [];\n            this.timeout = timeout;\n\n            var self = this;\n            this.scope.isEditing = function() {\n                var editing = false;\n                angular.forEach(self.fields, function(value) {\n                    if(!editing) {\n                        editing = value.editing;\n                    }\n                });\n                return editing;\n            };\n        }\n\n        // Return true if table form.\n        MAASGroupController.prototype.isTableForm = function () {\n            return this.formController.isTableForm();\n        };\n\n        // Return true if should save on blur.\n        MAASGroupController.prototype.saveOnBlur = function () {\n            return this.formController.saveOnBlur();\n        };\n\n        // Return true if group is saving.\n        MAASGroupController.prototype.isSaving = function(key) {\n            return (\n                this.scope.saving && this.scope.savingKeys.indexOf(key) >= 0);\n        };\n\n        // Return true if the input should show the saving spinner. This is\n        // only show on inputs in forms that are using save on blur.\n        MAASGroupController.prototype.showInputSaving = function(key) {\n            // In a group we say the entire group is saving, not just that\n            // one key in the field is being saved.\n            return this.saveOnBlur() && this.scope.saving;\n        };\n\n        // Called by maas-obj-field to register it as a editable field.\n        MAASGroupController.prototype.registerField = function(key, scope) {\n            // Store the state of the field and its scope.\n            this.fields[key] = {\n                editing: false,\n                scope: scope\n            };\n            return this.formController.registerField(key, scope);\n        };\n\n        // Called by maas-obj-field to unregister it as a editable field.\n        MAASGroupController.prototype.unregisterField = function(key) {\n            delete this.fields[key];\n            this.formController.unregisterField(key);\n        };\n\n        // Called by maas-obj-field to place field in edit mode.\n        MAASGroupController.prototype.startEditingField = function(key) {\n            this.fields[key].editing = true;\n\n            // Set all fields in the group as editing in the formController.\n            var self = this;\n            angular.forEach(this.fields, function(value, key) {\n                self.formController.startEditingField(key);\n            });\n        };\n\n        // Called by maas-obj-field to exit edit mode for the field.\n        MAASGroupController.prototype.stopEditingField = function(key, value) {\n            var field = this.fields[key];\n            field.editing = false;\n\n            // Exit early if not save on blur.\n            if(!this.saveOnBlur()) {\n                return;\n            }\n\n            // Delay the handling of stop to make sure start is not called on\n            // the next field in the group.\n            var self = this;\n            this.timeout(function() {\n                // If any other fields are in edit mode then nothing to do.\n                var editing = false;\n                angular.forEach(self.fields, function(value) {\n                    if(!editing) {\n                        editing = value.editing;\n                    }\n                });\n                if(editing) {\n                    return;\n                }\n\n                // Copy the object and update the editing fields.\n                var keys = [];\n                var changed = false;\n                var updatedObj = self.formController.cloneObject();\n                angular.forEach(self.fields, function(value, key) {\n                    value.scope.clearErrors();\n                    var newValue = value.scope.getValue();\n                    if(angular.isDefined(newValue) &&\n                        updatedObj[key] !== newValue) {\n                        keys.push(key);\n                        updatedObj[key] = newValue;\n                        changed = true;\n                    }\n                });\n                if(!changed) {\n                    return;\n                }\n\n                // Place the field that actually triggered the update first.\n                var keyIdx = keys.indexOf(key);\n                if(keyIdx !== -1) {\n                    keys.splice(keyIdx, 1);\n                    keys.splice(0, 0, key);\n                }\n\n                // Save the object.\n                self.scope.saving = true;\n                self.scope.savingKeys = keys;\n                self.formController.updateItem(updatedObj, keys).then(\n                    function(obj) {\n                      self.scope.saving = false;\n                      self.scope.savingKeys = [];\n                      return obj;\n                  }, function(error) {\n                      self.scope.saving = false;\n                      self.scope.savingKeys = [];\n                      return error;\n                  });\n            }, 10); // Really short has to be next click.\n        };\n\n        return {\n            restrict: \"E\",\n            require: [\"^^maasObjForm\", \"maasObjFieldGroup\"],\n            scope: {},\n            transclude: true,\n            template: (\n                '<div class=\"form__siblings\" ' +\n                'data-ng-class=\"{\\'is-active\\': isEditing()}\" ' +\n                'data-ng-transclude></div>'),\n            controller: ['$scope', '$timeout', MAASGroupController],\n            link: {\n                pre: function(scope, element, attrs, controllers) {\n                    // Set formController on the MAASGroupController to\n                    // point to its parent MAASFormController. This is done in\n                    // pre-link so the controller has the formController before\n                    // registerField is called.\n                    controllers[1].formController = controllers[0];\n\n                    // Set ngDisabled on this scope from the form controller.\n                    scope.ngDisabled = controllers[0].scope.ngDisabled;\n\n                    // Set the object to always be the same on the scope.\n                    controllers[0].scope.$watch(\"obj\", function(obj) {\n                        scope.obj = obj;\n                    });\n                }\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasObjField', ['$compile',\n    function($compile) {\n        return {\n            restrict: \"E\",\n            require: [\"^^maasObjForm\", \"?^^maasObjFieldGroup\"],\n            scope: {\n                onChange: \"=\",\n                subtleText: \"@\"\n            },\n            transclude: true,\n            template: (\n                '<div data-ng-transclude></div>'),\n            link: function(scope, element, attrs, controllers) {\n                // Select the controller based on which is available.\n                var controller = controllers[1];\n                if(!angular.isObject(controller)) {\n                    controller = controllers[0];\n                }\n\n                // Set ngDisabled from the parent controller.\n                scope.ngDisabled = controller.scope.ngDisabled;\n\n                element.addClass(\"p-form__group\");\n                if(attrs.subtle !== \"false\") {\n                    element.addClass(\"form__group--subtle\");\n                }\n\n                // type and key required.\n                var missingAttrs = [];\n                if(!angular.isString(attrs.type) && attrs.type.length === 0) {\n                    missingAttrs.push(\"type\");\n                }\n                if(!angular.isString(attrs.key) && attrs.key.length === 0) {\n                    missingAttrs.push(\"key\");\n                }\n                if(missingAttrs.length > 0) {\n                    throw new Error(\n                        missingAttrs.join(\", \") +\n                        \" are required on maas-obj-field.\");\n                }\n\n                // Remove transcluded element.\n                element.find(\"div\").remove();\n\n                // Render the label.\n                var label = attrs.label || attrs.key;\n\n                if(attrs.disableLabel !== \"true\") {\n                    var labelElement = angular.element('<label/>');\n                    labelElement.attr('for', attrs.key);\n                    labelElement.text(label);\n                    labelElement.addClass('p-form__label');\n                    if(attrs.labelWidth) {\n                        labelElement.addClass(\"col-\" + attrs.labelWidth);\n                    } else {\n                        labelElement.addClass(\"u-margin--right\");\n                    }\n                    if(attrs.labelLeft === \"true\") {\n                        labelElement.addClass('u-padding--left');\n                        labelElement.addClass('u-position--relative');\n                    }\n                    element.append(labelElement);\n\n                    // Add a label info icon with tooltip.\n                    if(angular.isString(attrs.labelInfo)\n                            && attrs.labelInfo.length > 0) {\n                        var infoWrapper = angular.element(\n                            '<span>&nbsp;</span>');\n                        infoWrapper.addClass('p-tooltip p-tooltip--btm-right');\n\n                        var infoIcon = angular.element('<i/>');\n                        infoIcon.addClass('p-icon--information');\n                        infoIcon.attr(\n                            'aria-describedby', attrs.key + '-tooptip');\n\n                        var infoTooltip = angular.element('<p></p>');\n                        infoTooltip.addClass('p-tooltip__message');\n                        infoTooltip.text(attrs.labelInfo);\n                        infoTooltip.attr('id', attrs.key + '-tooptip');\n\n                        infoWrapper.append(infoIcon);\n                        infoWrapper.append(infoTooltip);\n\n                        labelElement.append(infoWrapper);\n\n                        // prevents the icon from being clickable\n                        infoIcon.bind('click', function (evt) {\n                            evt.preventDefault();\n                        });\n                    }\n                }\n\n                // Add the wrapper for the input.\n                var inputWrapper = angular.element('<div></div>');\n                inputWrapper.addClass(\"p-form__control\");\n\n                if(attrs.inputWidth) {\n                    inputWrapper.addClass(\"col-\" + attrs.inputWidth);\n                }\n\n                // Render the input based on the type.\n                var placeholder = attrs.placeholder || label;\n                var inputElement = null;\n                if(attrs.type === \"text\" || attrs.type === \"textarea\" ||\n                   attrs.type === \"password\") {\n                    if(attrs.type === \"text\") {\n                        inputElement = $compile(\n                            '<input type=\"text\" id=\"' + attrs.key +\n                            '\" placeholder=\"' + placeholder + '\"' +\n                            'data-ng-disabled=\"ngDisabled()\">')(scope);\n                    } else if(attrs.type === \"textarea\") {\n                        inputElement = $compile(\n                            '<textarea id=\"' + attrs.key +\n                            '\" placeholder=\"' + placeholder + '\"' +\n                            'data-ng-disabled=\"ngDisabled()\">' +\n                                '</textarea>')(scope);\n                    } else if(attrs.type === \"password\") {\n                        inputElement = $compile(\n                            '<input type=\"password\" id=\"' + attrs.key +\n                            '\" placeholder=\"' + placeholder + '\"' +\n                            'data-ng-disabled=\"ngDisabled()\">')(scope);\n                    }\n\n                    // Allow enter on blur, by default.\n                    if(attrs.blurOnEnter) {\n                        inputElement.bind(\"keydown keypress\", function(evt) {\n                            if(evt.which === 13) {\n                                inputElement.blur();\n                                evt.preventDefault();\n                            }\n                        });\n                    }\n\n                    // Revert value on esc.\n                    var self = this;\n                    inputElement.bind(\"keydown keypress\", function(evt) {\n                        if(evt.which === 27) {\n                            inputElement.val(controller.scope.obj[attrs.key]);\n                            inputElement.blur();\n                            evt.preventDefault();\n                        }\n                    });\n\n                    // Register the field with the controller and set the\n                    // current value for the field.\n                    var currentValue = controller.registerField(\n                        attrs.key, scope);\n                    inputElement.val(currentValue);\n\n                    // When element is in focus then editing is on.\n                    inputElement.on(\"focus\", function() {\n                        scope.$apply(function() {\n                            controller.startEditingField(attrs.key);\n                        });\n                    });\n\n                    // When element is not in focus then editing is done.\n                    inputElement.on(\"blur\", function() {\n                        scope.$apply(function() {\n                            controller.stopEditingField(\n                                attrs.key, inputElement.val());\n                        });\n                    });\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        inputElement.val(newValue);\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return inputElement.val();\n                    };\n                } else if(attrs.type === \"options\") {\n                    // Requires the options attribute on the element. This\n                    // is copied directly into the ngOptions directive on\n                    // the select.\n                    var options = attrs.options;\n                    if(!angular.isString(options) || options.length === 0) {\n                        throw new Error(\n                            \"options attribute is required on type \" +\n                            \"'options' on maas-obj-field.\");\n                    }\n\n                    // Placeholder by default is disabled, allow it to be\n                    // enabled.\n                    var disabled = \"disabled\";\n                    if(attrs.placeholderEnabled === \"true\") {\n                        disabled = \"\";\n                    }\n\n                    // Create a child scope of the parent scope for this\n                    // directive. Since this directive is created with an\n                    // isolated scope we need the child to use the parent so\n                    // ngOptions can use properties defined in that scope.\n                    var childScope = scope.$parent.$new();\n                    childScope._ngDisabled = scope.ngDisabled;\n                    childScope._selectValue = controller.registerField(\n                        attrs.key, scope);\n                    childScope._selectNgChange = function() {\n                        scope._change();\n                        controller.stopEditingField(\n                            attrs.key, childScope._selectValue);\n                    };\n\n                    // Construct the select.\n                    inputElement = $compile(\n                        '<select id=\"' + attrs.key + '\" ' +\n                        'data-ng-model=\"_selectValue\" ' +\n                        'data-ng-options=\"' + options + '\"' +\n                        'data-ng-change=\"_selectNgChange()\"' +\n                        'data-ng-disabled=\"_ngDisabled()\">' +\n                        '<option value=\"\" ' + disabled + '>' + placeholder +\n                        '</option></select>')(childScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        childScope._selectValue = newValue;\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return childScope._selectValue;\n                    };\n                } else if(attrs.type === \"checkboxes\") {\n                    // Requires the values attribute on the element.\n                    var values = attrs.values;\n                    if(!angular.isString(values) || values.length === 0) {\n                        throw new Error(\n                            \"values attribute is required on type \" +\n                            \"'checkboxes' on maas-obj-field.\");\n                    }\n\n                    // Create a child scope of the parent scope for this\n                    // directive. Since this directive is created with an\n                    // isolated scope we need the child to use the parent so\n                    // values can come from the parent scope.\n                    var checkScope = scope.$parent.$new();\n                    checkScope._selectedValues = controller.registerField(\n                        attrs.key, scope);\n                    checkScope._checked = function(val) {\n                        return checkScope._selectedValues.indexOf(val) > -1;\n                    };\n                    checkScope._toggleChecked = function(val) {\n                        var idx = checkScope._selectedValues.indexOf(val);\n                        if(idx > -1) {\n                            // Uncheck.\n                            checkScope._selectedValues.splice(idx, 1);\n                        } else {\n                            // Check.\n                            checkScope._selectedValues.push(val);\n                        }\n                    };\n\n                    // Construct the checkbox list.\n                    inputElement = angular.element([\n                        '<div class=\"width--full\" ',\n                            'data-ng-repeat=\"val in ' + values +'\">',\n                            '<input id=\"' + attrs.key + '_' + '{$ val $}',\n                                '\" type=\"checkbox\" value=\"{$ val $}\" ',\n                                'class=\"checkbox\" ',\n                                'data-ng-checked=\"_checked(val)\" ',\n                                'data-ng-click=\"_toggleChecked(val)\">',\n                            '<label for=\"' + attrs.key + '_',\n                                '{$ val $}' + '\" ',\n                                'class=\"checkbox-label\">{$ val $}</label>',\n                        '</div>'\n                    ].join(''));\n                    inputElement = $compile(inputElement)(checkScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        checkScope._selectedValues = newValue;\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return checkScope._selectedValues;\n                    };\n                } else if(attrs.type === \"tags\") {\n                    var tagsScope = scope.$new();\n                    var tags = controller.registerField(\n                        attrs.key, scope);\n                    tagsScope._tags = tags.map(function(val) {\n                        return {text: val};\n                    });\n\n                    // Construct the tags input.\n                    inputElement = angular.element([\n                        '<tags-input id=\"' + attrs.key + '\" ',\n                            'data-ng-model=\"_tags\" ',\n                            'placeholder=\"' + placeholder + '\" ',\n                            'data-ng-change=\"_change()\" ',\n                            'allow-tags-pattern=\"[\\\\w-]+\"></tags-input>'\n                    ].join(''));\n                    inputElement = $compile(inputElement)(tagsScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        tagsScope._tags = newValue.map(\n                            function(val) {\n                                return {text: val};\n                            });\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return tagsScope._tags.map(\n                            function(val) {\n                                return val.text;\n                            });\n                    };\n                } else if(attrs.type === \"onoffswitch\") {\n                    var switchScope = scope.$new();\n                    switchScope._toggle = controller.registerField(\n                        attrs.key, scope);\n                    switchScope._changed = function() {\n                        scope._change();\n                        controller.startEditingField(attrs.key);\n                        controller.stopEditingField(\n                            attrs.key, switchScope.getValue());\n                    };\n\n                    // Construct the on and off toggle.\n                    inputElement = angular.element([\n                      '<div class=\"maas-p-switch\">',\n                        '<input type=\"checkbox\" name=\"' + attrs.key + '\" ',\n                          'class=\"maas-p-switch--input\" ',\n                          'id=\"' + attrs.key + '\" ',\n                          'data-ng-model=\"_toggle\" ',\n                          'data-ng-change=\"_changed()\">',\n                        '<div class=\"maas-p-switch--mask\"></div>',\n                      '</div>'\n                    ].join(''));\n                    inputElement = $compile(inputElement)(switchScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        // WARNING: This code is difficult to unit test, since\n                        // we could not figure out how to get the\n                        // isolateScope() from the transcluded element. Be sure\n                        // to manually test versions of this toggle with and\n                        // without the on-value and off-value attributes, such\n                        // as by verifying that both the on/off toggle on both\n                        // the discovery page and the subnet details page work.\n                        if(attrs.onValue && attrs.onValue === newValue) {\n                            switchScope._toggle = true;\n                        } else if(attrs.offValue &&\n                                attrs.offValue === newValue) {\n                            switchScope._toggle = false;\n                        } else {\n                            switchScope._toggle = newValue;\n                        }\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        // WARNING: This code is difficult to unit test, since\n                        // we could not figure out how to get the\n                        // isolateScope() from the transcluded element. Be sure\n                        // to manually test versions of this toggle with and\n                        // without the on-value and off-value attributes, such\n                        // as by verifying that both the on/off toggle on both\n                        // the discovery page and the subnet details page work.\n                        if(switchScope._toggle) {\n                            if(attrs.onValue) {\n                                return attrs.onValue;\n                            } else {\n                                return true;\n                            }\n                        } else {\n                            if(attrs.offValue) {\n                                return attrs.offValue;\n                            } else {\n                                return false;\n                            }\n                        }\n                    };\n                } else {\n                    throw new Error(\n                        \"Unknown type on maas-obj-field: \" + attrs.type);\n                }\n\n                // Called on change.\n                scope._change = function() {\n                    if(angular.isFunction(scope.onChange)) {\n                        scope.onChange(\n                            attrs.key,\n                            controller.getValue(attrs.key),\n                            controller);\n                    }\n                };\n\n                // Copy input class to the input element.\n                if(attrs.inputClass) {\n                    inputElement.addClass(attrs.inputClass);\n                }\n                inputWrapper.append(inputElement);\n\n                // Errors element.\n                var errorsElement = angular.element(\n                    '<ul class=\"p-list u-no-margin--top\"></ul>');\n                if(!controller.isTableForm()) {\n                    errorsElement.addClass(\"form__error\");\n                }\n                inputWrapper.append(errorsElement);\n\n                // Help text elements\n                if (attrs.helpText) {\n                    var helpTextElement = angular.element(\n                        '<p>' + attrs.helpText + '</p>');\n                    helpTextElement.addClass(\"p-form-help-text\");\n                    inputWrapper.append(helpTextElement);\n                }\n\n                // Called by controller to clear all errors.\n                scope.clearErrors = function() {\n                    inputElement.removeClass(\"ng-dirty\");\n                    inputElement.removeClass(\"p-form-validation__input\");\n                    inputWrapper.removeClass(\"p-form-validation\");\n                    inputWrapper.removeClass(\"is-error\");\n                    inputWrapper.removeClass(\"u-no-margin--top\");\n                    errorsElement.empty();\n                };\n\n                // Called by controller to set errors.\n                scope.setErrors = function(errors) {\n                    if(errors.length > 0) {\n                        inputWrapper.addClass(\"p-form-validation\");\n                        inputWrapper.addClass(\"is-error\");\n                        inputWrapper.addClass(\"u-no-margin--top\");\n                        inputElement.addClass(\"ng-dirty\");\n                        inputElement.addClass(\"p-form-validation__input\");\n                        angular.forEach(errors, function(error) {\n                            errorsElement.append(\n                              '<li class=\"p-form-validation__message\">' +\n                              '<strong>Error:</strong> ' + error + '</li>'\n                            );\n                        });\n                        // Set the input in focus but outside of the current\n                        // digest cycle.\n                        setTimeout(function() {\n                            inputElement.focus();\n                        }, 1);\n                    }\n                };\n\n                // Called by controller to see if error is set on field.\n                scope.hasErrors = function() {\n                    return inputWrapper.hasClass(\"is-error\");\n                };\n\n                // Subtle text element.\n                if(attrs.subtleText) {\n                    var subtleTextElement = $compile(\n                        angular.element(\n                            '<span class=\"p-form-help-text\" ' +\n                            'data-ng-bind=\"subtleText\"></span>'))(scope);\n                    inputWrapper.append(subtleTextElement);\n                }\n                element.append(inputWrapper);\n\n                // Watch the showing of saving spinner. Update the elements\n                // correctly to show the saving.\n                scope.$watch(function() {\n                    return controller.showInputSaving(attrs.key);\n                }, function(value) {\n                    if(value) {\n                        inputWrapper.children(\n                            ':first').addClass('u-border--information');\n                        inputWrapper.append(\n                            '<i class=\"obj-saving icon ' +\n                            'p-icon--spinner u-animation--spin\"></i>');\n                        inputWrapper.addClass('p-tooltip');\n                        inputWrapper.addClass('p-tooltip--bottom');\n                        inputWrapper.attr('aria-label', 'Saving');\n                    } else {\n                      inputWrapper.children(\n                          ':first').removeClass('u-border--information');\n                        inputWrapper.find('i.obj-saving').remove();\n                        inputWrapper.removeClass('p-tooltip');\n                        inputWrapper.removeClass('p-tooltip--right');\n                        inputWrapper.removeAttr('aria-label');\n                    }\n                });\n\n                // Called when the scope is destroyed.\n                scope.$on(\"$destroy\", function() {\n                    controller.unregisterField(attrs.key);\n                });\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasObjSave', function() {\n        return {\n            restrict: \"A\",\n            require: [\"^^maasObjForm\"],\n            scope: {},\n            link: function(scope, element, attrs, controllers) {\n                // Only allow maas-obj-save when saveOnBlur is false.\n                var controller = controllers[0];\n                if(controller.saveOnBlur()) {\n                    throw new Error(\n                        \"maas-obj-save is only allowed when save-on-blur is \" +\n                        \"set to false.\");\n                }\n\n                element.on(\"click\", function() {\n                    scope.$apply(function() {\n                        controller.saveForm();\n                    });\n                });\n            }\n        };\n    });\n\nangular.module('MAAS').directive('maasObjErrors', function() {\n        return {\n            restrict: \"E\",\n            require: [\"^^maasObjForm\"],\n            scope: {},\n            template: '<ul class=\"p-list u-no-margin--top\"></ul>',\n            link: function(scope, element, attrs, controllers) {\n                // Set on the controller the global error handler.\n                controllers[0].errorScope = scope;\n                var ul = element.find(\"ul\");\n\n                // Called by controller to clear all errors.\n                scope.clearErrors = function() {\n                    ul.empty();\n                };\n\n                // Called by controller to set errors.\n                scope.setErrors = function(errors) {\n                    if(errors.length > 0) {\n                        angular.forEach(errors, function(error) {\n                            ul.append(\n                              '<li class=\"p-list__item\">' +\n                              '<i class=\"p-icon--error\"></i> ' +\n                              error + '</li>'\n                            );\n                        });\n                    }\n                };\n\n                // Called by controller to see if error is set on field.\n                scope.hasErrors = function() {\n                    return ul.children().length > 0;\n                };\n            }\n        };\n    });\n\n\nangular.module('MAAS').directive('maasObjSaving', function() {\n        return {\n            restrict: \"E\",\n            require: \"^^maasObjForm\",\n            scope: {},\n            transclude: true,\n            template: [\n              '<span data-ng-if=\"saving\">',\n                '<i class=\"p-icon--loading u-animation--spin\"></i>',\n                '<span data-ng-transclude></span>',\n              '</span>'].join(''),\n            link: function(scope, element, attrs, controller) {\n                scope.saving = false;\n                scope.$watch(function() {\n                    return controller.scope.saving;\n                }, function(value) {\n                    scope.saving = value;\n                });\n            }\n        };\n    });\n\n\nangular.module('MAAS').directive('maasObjShowSaving', function() {\n        return {\n            restrict: \"A\",\n            require: \"^^maasObjForm\",\n            link: function(scope, element, attrs, controller) {\n                scope.$watch(function() {\n                    return controller.scope.saving;\n                }, function(value) {\n                    if(value) {\n                        element.removeClass(\"ng-hide\");\n                    } else {\n                        element.addClass(\"ng-hide\");\n                    }\n                });\n            }\n        };\n    });\n\n\nangular.module('MAAS').directive('maasObjHideSaving', function() {\n        return {\n            restrict: \"A\",\n            require: \"^^maasObjForm\",\n            link: function(scope, element, attrs, controller) {\n                scope.$watch(function() {\n                    return controller.scope.saving;\n                }, function(value) {\n                    if(value) {\n                        element.addClass(\"ng-hide\");\n                    } else {\n                        element.removeClass(\"ng-hide\");\n                    }\n                });\n            }\n        };\n    });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Creates the auto-formatting for MAC address inputs.\n */\n\nangular.module('MAAS').directive('macAddress', function () {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        link: function (scope, ele, attr, ngModelCtrl, ngModel) {\n            if (!ngModelCtrl) {\n              return;\n            }\n\n            var macAddressParse = function (value) {\n                return value.toUpperCase();\n            };\n\n            var macAddressFormat = function (value) {\n\n                if (!value) {\n                  return undefined;\n                }\n\n                var numbers = value.replace(/:/g, \"\");\n\n                if (value.length % 3 === 0) {\n\n                    return numbers.replace(/([0-9A-Za-z]{2})/g, \"$1:\");\n                }\n            };\n\n            ngModelCtrl.$parsers.push(macAddressParse);\n            ngModelCtrl.$formatters.push(macAddressFormat);\n\n            ele.on('input', function () {\n                var value = macAddressFormat(ele.val());\n\n                if (value !== undefined) {\n                    ngModelCtrl.$setViewValue(value);\n                    ngModelCtrl.$render();\n                }\n                scope.$apply();\n            });\n        }\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n* GNU Affero General Public License version 3 (see the file LICENSE).\n*\n* Machines listing directive.\n*\n* Renders the machines listing.\n*/\n// testing\n\n\n\nangular.module('MAAS').directive('maasMachinesTable', [\n  'MachinesManager', 'GeneralManager', 'ManagerHelperService',\n  function (MachinesManager, GeneralManager, ManagerHelperService) {\n    return {\n      restrict: \"E\",\n      scope: {\n        search: \"=\",\n        ngDisabled: \"&\",\n        machineHasError: \"&\",\n        hideCheckboxes: \"=?\",\n        onListingChange: \"&\",\n        onCheckAll: \"&\",\n        onCheck: \"&\"\n      },\n      templateUrl: (\n        'static/partials/machines-table.html?v=' + (\n          MAAS_config.files_version)),\n      link: function(scope, element, attrs) {\n        // Statuses that should show spinner.\n        var SPINNER_STATUSES = [\n          1,   // commissioning\n          9,   // deploying\n          12,  // releasing\n          14,  // disk erasing\n          17,  // entering rescue mode\n          19,  // exiting rescue mode\n          21   // testing\n        ];\n\n        // Scope variables.\n        scope.table = {\n          column: 'fqdn',\n          predicate: 'fqdn',\n          reverse: false,\n          allViewableChecked: false,\n          machines: MachinesManager.getItems(),\n          filteredMachines: [],\n          osinfo: GeneralManager.getData(\"osinfo\")\n        };\n\n        // Ensures that the checkbox for select all is the correct value.\n        scope.updateAllChecked = function() {\n          // Not checked when the filtered machines are empty.\n          if(scope.table.filteredMachines.length === 0) {\n              scope.table.allViewableChecked = false;\n              return;\n          }\n\n          // Loop through all filtered machines and see if all are checked.\n          var i;\n          for(i = 0; i < scope.table.filteredMachines.length; i++) {\n              if(!scope.table.filteredMachines[i].$selected) {\n                  scope.table.allViewableChecked = false;\n                  return;\n              }\n          }\n          scope.table.allViewableChecked = true;\n        };\n\n        // Selects and deselects visible machines.\n        scope.toggleCheckAll = function() {\n          if(scope.table.allViewableChecked) {\n            angular.forEach(\n              scope.table.filteredMachines, function(machine) {\n                MachinesManager.unselectItem(machine.system_id);\n              });\n          } else {\n            angular.forEach(\n              scope.table.filteredMachines, function(machine) {\n                MachinesManager.selectItem(machine.system_id);\n              });\n          }\n          scope.updateAllChecked();\n          scope.onCheckAll();\n        };\n\n        // Selects and unselects machine.\n        scope.toggleChecked = function(machine) {\n          if(MachinesManager.isSelected(machine.system_id)) {\n            MachinesManager.unselectItem(machine.system_id);\n          } else {\n            MachinesManager.selectItem(machine.system_id);\n          }\n          scope.updateAllChecked();\n          scope.onCheck({$machine: machine});\n        };\n\n        // Sorts the table by predicate.\n        scope.sortTable = function(predicate) {\n            scope.table.predicate = predicate;\n            scope.table.reverse = !scope.table.reverse;\n        };\n\n        // Sets the viewable column or sorts.\n        scope.selectColumnOrSort = function(predicate) {\n            if(scope.table.column !== predicate) {\n                scope.table.column = predicate;\n            } else {\n                scope.sortTable(predicate);\n            }\n        };\n\n        // Return true if spinner should be shown.\n        scope.showSpinner = function(machine) {\n            return SPINNER_STATUSES.indexOf(machine.status_code) > -1;\n        };\n\n        scope.showFailedTestWarning = function(machine) {\n            if(scope.showSpinner(machine)) {\n                return false;\n            }\n            switch(machine.status_code) {\n                // NEW\n                case 0:\n                // COMMISSIONING\n                case 1:\n                // FAILED_COMMISSIONING\n                case 2:\n                // TESTING\n                case 21:\n                // FAILED_TESTING\n                case 22:\n                    return false;\n            }\n            switch(machine.testing_status) {\n                // Tests havn't been run\n                case -1:\n                // Tests have passed\n                case 2:\n                    return false;\n            }\n            return true;\n        };\n\n        // Return true if the other node status should be shown.\n        scope.showNodeStatus = function(machine) {\n            // -1 means tests havn't been run, 2 means tests have passed.\n            if(!scope.showSpinner(machine) &&\n               !scope.showFailedTestWarning(machine) &&\n               machine.other_test_status !== -1 &&\n               machine.other_test_status !== 2) {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Returns the release title from osinfo.\n        scope.getReleaseTitle = function(os_release) {\n          if(angular.isArray(scope.table.osinfo.releases)) {\n            for(i = 0; i < scope.table.osinfo.releases.length; i++) {\n              var release = scope.table.osinfo.releases[i];\n              if(release[0] === os_release) {\n                return release[1];\n              }\n            }\n          }\n          return os_release;\n        };\n\n        // Returns the status text to show.\n        scope.getStatusText = function(machine) {\n          var showRelease = ['Deploying', 'Deployed'];\n          if(showRelease.indexOf(machine.status) === -1) {\n            return machine.status;\n          } else {\n            var releaseTitle = scope.getReleaseTitle(\n              machine.osystem + '/' + machine.distro_series);\n            if(machine.osystem === \"ubuntu\") {\n              releaseTitle = releaseTitle.split('\"')[0].trim();\n            }\n            if(machine.status === \"Deployed\") {\n              return releaseTitle;\n            }\n            if(machine.status === \"Deploying\") {\n              return machine.status + ' ' + releaseTitle;\n            }\n          }\n        };\n\n        // When the list of filtered machines change update the all checkbox.\n        scope.$watchCollection(\"table.filteredMachines\", function() {\n          scope.updateAllChecked();\n          scope.onListingChange({$machines: scope.table.filteredMachines});\n        });\n\n        // Load the required managers and start polling for osinfo.\n        ManagerHelperService.loadManagers(\n          scope, [MachinesManager, GeneralManager]).then(function() {\n            GeneralManager.startPolling(scope, \"osinfo\");\n          });\n\n        // Stop polling when the scope is destroyed.\n        scope.$on(\"$destroy\", function() {\n          GeneralManager.stopPolling(scope, \"osinfo\");\n        });\n      }\n    };\n}]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Notifications.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject notifications.html into the template cache.\n    $templateCache.put('directive/templates/notifications.html', [\n      '<div class=\"u-no-margin--top\" data-ng-repeat=\"category in categories\"',\n        ' data-ng-init=\"notifications = categoryNotifications[category]\">',\n        // 1 notification.\n        '<span class=\"row\" data-ng-if=\"notifications.length == 1\">',\n          '<ul class=\"p-list\" data-ng-class=\"{\\'is-open\\': shown}\">',\n            '<li data-ng-repeat=\"notification in notifications\"',\n            ' class=\"p-notification\"',\n            ' data-ng-class=\"categoryClasses[notification.category]\">',\n              '<p class=\"p-notification__response\">',\n                '<span data-ng-bind-html=\"notification.message\"></span> ',\n                '<a class=\"p-notification__action\"',\n                ' data-ng-click=\"dismiss(notification)\">Dismiss</a>',\n              '</p>',\n            '</li>',\n          '</ul>',\n        '</span>',\n        // 2 or more notifications.\n        '<div class=\"row p-notification--group\" ',\n             'data-ng-if=\"notifications.length >= 2\"',\n        ' data-ng-init=\"shown = false\">',\n            '<div data-ng-class=\"categoryClasses[notifications[0].category]\">',\n                '<a aria-label=\"{$ notifications.length $} ',\n                    '{$ categoryTitles[category] $}, click to open messages.\"',\n                    ' maas-enter=\"shown = !shown\"',\n                    ' class=\"p-notification__toggle\"',\n                    ' data-ng-click=\"shown = !shown\">',\n                    '<p class=\"p-notification__response\">',\n                        '<span class=\"p-notification__status\"',\n                        ' data-count=\"{$ notifications.length $}\"',\n                        ' data-ng-bind=\"notifications.length + \\' \\' + ',\n                                       'categoryTitles[category]\"></span>',\n                        '<small>',\n                        '<i data-ng-class=\"{ \\'p-icon--expand\\': !shown,',\n                        ' \\'p-icon--collapse\\': shown }\"></i></small>',\n                    '</p>',\n                '</a>',\n                '<ul class=\"p-list--divided\" ',\n                    'data-ng-class=\"{\\'u-hide\\': !shown}\">',\n                    '<li data-ng-repeat=\"notification in notifications\"',\n                    ' class=\"p-list__item\">',\n                    '<p class=\"p-notification__response\">',\n                        '<span data-ng-bind-html=\"notification.message\">',\n                        '</span> ',\n                        '<a class=\"p-notification__action\"',\n                        ' data-ng-click=\"dismiss(notification)\">Dismiss</a>',\n                    '</p>',\n                    '</li>',\n                '</ul>',\n            '</div>',\n        '</div>',\n      '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasNotifications', [\n    \"NotificationsManager\", \"ManagerHelperService\",\n    function(NotificationsManager, ManagerHelperService) {\n        return {\n            restrict: \"E\",\n            templateUrl: 'directive/templates/notifications.html',\n            link: function($scope, element, attrs) {\n                ManagerHelperService.loadManager($scope, NotificationsManager);\n                $scope.notifications = NotificationsManager.getItems();\n                $scope.dismiss = angular.bind(\n                    NotificationsManager, NotificationsManager.dismiss);\n\n                $scope.categories = [\n                    \"error\",\n                    \"warning\",\n                    \"success\",\n                    \"info\"\n                ];\n                $scope.categoryTitles = {\n                    error: \"Errors\",\n                    warning: \"Warnings\",\n                    success: \"Successes\",\n                    info: \"Other messages\"\n                };\n                $scope.categoryClasses = {\n                    error: \"p-notification--negative\",\n                    warning: \"p-notification--caution\",\n                    success: \"p-notification--positive\",\n                    info: \"p-notification\"  // No suffix.\n                };\n                $scope.categoryNotifications = {\n                    error: [],\n                    warning: [],\n                    success: [],\n                    info: []\n                };\n\n                $scope.$watchCollection(\n                    \"notifications\", function() {\n                        var cns = $scope.categoryNotifications;\n                        angular.forEach(\n                            $scope.categories, function(category) {\n                                cns[category].length = 0;\n                            }\n                        );\n                        angular.forEach(\n                            $scope.notifications, function(notification) {\n                                cns[notification.category].push(notification);\n                            }\n                        );\n                    }\n                );\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * OS/Release select directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the os-select.html into the template cache.\n    $templateCache.put('directive/templates/os-select.html', [\n        '<div class=\"form__group-input\"> ',\n            '<select name=\"os\" class=\"u-margin--right\" ',\n                'data-ng-model=\"ngModel.osystem\" ',\n                'data-ng-change=\"selectedOSChanged()\" ',\n                'data-ng-options=\"',\n                'os[0] as os[1] for os in maasOsSelect.osystems\">',\n            '</select>',\n        '</div>',\n        '<div class=\"form__group-input\"> ',\n            '<select name=\"release\" class=\"u-margin--right\" ',\n                'data-ng-model=\"ngModel.release\" ',\n                'data-ng-change=\"selectedReleaseChanged()\" ',\n                'data-ng-options=\"',\n                'release[0] as release[1] for release in releases\">',\n            '</select>',\n        '</div>',\n        '<div class=\"form__group-input\"> ',\n            '<select name=\"hwe_kernel\" data-ng-model=\"ngModel.hwe_kernel\" ',\n                'data-ng-show=\"hwe_kernels.length\"',\n                'data-ng-options=\"',\n                'hwe_kernel[0] as hwe_kernel[1] for hwe_kernel ',\n                'in hwe_kernels\">',\n                '<option value=\"\">Default kernel</option>',\n            '</select>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasOsSelect', function() {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            maasOsSelect: '=',\n            ngModel: '='\n        },\n        templateUrl: 'directive/templates/os-select.html',\n        controller: function($scope) {\n\n            // Return only the selectable releases based on the selected os.\n            function getSelectableReleases() {\n                if(angular.isObject($scope.maasOsSelect) &&\n                    angular.isArray($scope.maasOsSelect.releases)) {\n                    var i, allChoices = $scope.maasOsSelect.releases;\n                    var choice, choices = [];\n                    for(i = 0; i < allChoices.length; i++) {\n                        choice = allChoices[i];\n                        if(choice[0].indexOf($scope.ngModel.osystem + '/') > -1)\n                        {\n                            choices.push(choice);\n                        }\n                    }\n                    return choices;\n                }\n                return [];\n            }\n\n            // Return only the selectable kernels based on the selected os.\n            function getSelectableKernels() {\n                if(angular.isObject($scope.maasOsSelect) &&\n                    angular.isObject($scope.maasOsSelect.kernels) &&\n                    angular.isString($scope.ngModel.osystem) &&\n                    angular.isString($scope.ngModel.release)) {\n                    var os = $scope.ngModel.osystem;\n                    var release = $scope.ngModel.release.split('/')[1];\n                    var osKernels = $scope.maasOsSelect.kernels[os];\n                    if(angular.isObject(osKernels)) {\n                        return osKernels[release];\n                    }\n                }\n                return [];\n            }\n\n            // Returns the defaultValue if its in the choices array. Otherwise\n            // it returns the weighted choice if present, followed by the\n            // first choice.\n            function getDefaultOrFirst(array, defaultValue, weightValue) {\n                var i, first, weightedPresent = false;\n                for(i = 0; i < array.length; i++) {\n                    if(angular.isUndefined(first)) {\n                        first = array[i][0];\n                    }\n                    if(array[i][0] === defaultValue) {\n                        return defaultValue;\n                    }\n                    if(angular.isString(weightValue) &&\n                        array[i][0] === weightValue) {\n                        weightedPresent = true;\n                    }\n                }\n                if(weightedPresent) {\n                    return weightValue;\n                }\n                if(angular.isUndefined(first)) {\n                    return null;\n                }\n                return first;\n            }\n\n            // Sets the default selected values for the ngModel. Only sets the\n            // values once the maasOsSelect is populated. Sets the selected\n            // osystem to default_osystem if present, followed by 'ubuntu' if\n            // present, followed by the first available. Sets the selected\n            // release to the default_release if present, followed by the first\n            // available.\n            function setDefault() {\n                // Do nothing if model is already set.\n                if(angular.isString($scope.ngModel.osystem) &&\n                    angular.isString($scope.ngModel.release)) {\n                    return;\n                }\n                // Do nothing if the default is not set.\n                if(angular.isUndefined($scope.maasOsSelect.default_osystem) ||\n                    angular.isUndefined($scope.maasOsSelect.default_release)) {\n                    return;\n                }\n\n                // Set the intial defaults.\n                $scope.ngModel.osystem = getDefaultOrFirst(\n                    $scope.maasOsSelect.osystems,\n                    $scope.maasOsSelect.default_osystem, \"ubuntu\");\n                $scope.releases = getSelectableReleases();\n                $scope.ngModel.release = getDefaultOrFirst(\n                    $scope.releases,\n                    $scope.ngModel.osystem + \"/\" +\n                    $scope.maasOsSelect.default_release);\n                $scope.ngModel.kernel = \"\";\n            }\n\n            // Defaults\n            if(!angular.isObject($scope.ngModel)) {\n                $scope.ngModel = {\n                    osystem: null,\n                    release: null,\n                    hwe_kernel: null\n                };\n            }\n            $scope.releases = getSelectableReleases();\n            $scope.hwe_kernels = getSelectableKernels();\n\n            // Add the reset function to ngModel, allowing users to call\n            // this function to reset the defauls.\n            $scope.ngModel.$reset = function() {\n                $scope.ngModel.osystem = null;\n                $scope.ngModel.release = null;\n                $scope.ngModel.hwe_kernel = null;\n                setDefault();\n            };\n\n            // If the available os change update the available releases and\n            // set the default.\n            $scope.$watch(\"maasOsSelect.releases\", function() {\n                $scope.releases = getSelectableReleases();\n                setDefault();\n            });\n\n            // If the available release change update the available kernels and\n            // set the default.\n            $scope.$watch(\"maasOsSelect.kernels\", function() {\n                $scope.hwe_kernels = getSelectableKernels();\n                setDefault();\n            });\n\n            // Updates the default and selectable releases.\n            $scope.selectedOSChanged = function() {\n                $scope.releases = getSelectableReleases();\n                $scope.hwe_kernels = getSelectableKernels();\n                $scope.ngModel.release = null;\n                $scope.ngModel.hwe_kernel = null;\n                if($scope.releases.length > 0) {\n                    $scope.ngModel.release = $scope.releases[0][0];\n                }\n            };\n\n            // Updates the default and selectable kernels.\n            $scope.selectedReleaseChanged = function() {\n                $scope.hwe_kernels = getSelectableKernels();\n                $scope.ngModel.hwe_kernel = null;\n            };\n        }\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Placeholder directive.\n *\n * Allows the placeholder attribute on an element to be dynamic.\n */\n\n\nangular.module('MAAS').directive('ngPlaceholder', function() {\n    return {\n        restrict: \"A\",\n        scope: {\n            ngPlaceholder: \"=\"\n        },\n        link: function(scope, element, attrs) {\n            scope.$watch('ngPlaceholder', function() {\n                element[0].placeholder = scope.ngPlaceholder;\n            });\n        }\n    };\n});\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Pod parameters directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the power-parameters.html into the template cache.\n    $templateCache.put('directive/templates/pod-parameters.html', [\n        '<maas-obj-field type=\"options\" key=\"type\" label=\"Pod type\" ',\n          'label-width=\"2\" input-width=\"5\" ',\n          'placeholder=\"Select the pod type\" ',\n          'options=\"type.name as type.description for type in podTypes\" ',\n          'ng-if=\"!hideType\">',\n        '</maas-obj-field>',\n        '<div pod-fields></div>'\n    ].join(''));\n}]);\n\n\nangular.module('MAAS').directive(\n    'maasPodParameters', [\n        '$compile', 'GeneralManager', 'ManagerHelperService', function(\n        $compile, GeneralManager, ManagerHelperService) {\n    return {\n        restrict: \"E\",\n        require: \"^^maasObjForm\",\n        scope: {\n          hideType: '='\n        },\n        templateUrl: 'directive/templates/pod-parameters.html',\n        link: function(scope, element, attrs, controller) {\n            scope.powerTypes = GeneralManager.getData('power_types');\n            scope.podTypes = [];\n            scope.type = null;\n\n            var childScope, fieldsElement = angular.element(\n                element.find('div[pod-fields]'));\n\n            // Function to update the editable fields.\n            var updateFields = function(podType) {\n                var type = null;\n                var i;\n                for(i = 0; i < scope.podTypes.length; i++) {\n                    if(scope.podTypes[i].name === podType) {\n                      type = scope.podTypes[i];\n                    }\n                }\n\n                fieldsElement.empty();\n                if(childScope) {\n                  childScope.$destroy();\n                }\n                if(angular.isObject(type)) {\n                  var html = '<maas-obj-field-group>';\n                  angular.forEach(type.fields, function(field) {\n                      if(field.scope === 'bmc') {\n                          if(field.name === 'power_pass') {\n                              html += (\n                                  '<maas-obj-field type=\"password\" key=\"');\n                          } else {\n                              html += (\n                                  '<maas-obj-field type=\"text\" key=\"');\n                          }\n                          html += (field.name + '\" label=\"' + field.label +\n                            '\" ' + 'label-width=\"2\" input-width=\"5\">' +\n                            '</maas-obj-field>');\n                      }\n                  });\n                  html += '</maas-obj-field-group>';\n                  childScope = scope.$new();\n                  var ele = angular.element(html);\n                  fieldsElement.append(ele);\n                  $compile(ele)(\n                      childScope, undefined, {maasObjForm: controller});\n                }\n            };\n\n            // Return the selected type.\n            var getType = function() {\n                if(scope.hideType) {\n                    return controller.obj.type;\n                } else {\n                    return controller.getValue('type');\n                }\n            };\n\n            // Update the fields when the type changes.\n            scope.$watch(getType, updateFields);\n\n            // Update the pod types when the power types is updated.\n            scope.$watchCollection(\"powerTypes\", function() {\n                scope.podTypes.length = 0;\n                angular.forEach(scope.powerTypes, function(type) {\n                    if(type.driver_type === \"pod\") {\n                        scope.podTypes.push(type);\n                    }\n                });\n                updateFields(getType());\n            });\n\n            // Load the general manager.\n            ManagerHelperService.loadManager(scope, GeneralManager);\n        }\n    };\n}]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Power parameters directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the power-parameters.html into the template cache.\n    $templateCache.put('directive/templates/power-parameters.html', [\n        '<div class=\"p-form__group\">',\n            '<label for=\"power-type\" ',\n                    'class=\"form__group-label col-2\">Power type</label>',\n            '<div class=\"form__group-input col-3\">',\n                '<select name=\"power-type\" id=\"power-type\" ',\n                    'data-ng-disabled=\"ngDisabled\" ',\n                    'data-ng-class=\"{ invalid: !ngModel.type }\" ',\n                    'data-ng-model=\"ngModel.type\" ',\n                    'data-ng-options=\"',\n                    'type as type.description ',\n                    'for type in maasPowerParameters track by type.name\">',\n                    '<option value=\"\" disabled selected>',\n                        'Select your power type',\n                    '</option>',\n                '</select>',\n            '</div>',\n        '</div>',\n        '<div class=\"p-form__group\" ',\n            'data-ng-repeat=\"field in ngModel.type.fields\">',\n            '<label for=\"{$ field.name $}\" class=\"form__group-label col-2\">',\n                '{$ field.label $}',\n            '</label>',\n            '<div class=\"form__group-input col-3\">',\n                '<maas-power-input field=\"field\" ',\n                    'data-ng-disabled=\"ngDisabled\" ',\n                    'data-ng-model=\"ngModel.parameters[field.name]\">',\n            '</div>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasPowerInput', ['$compile',\n    function($compile) {\n        return {\n            restrict: \"E\",\n            require: \"ngModel\",\n            scope: {\n                field: '=',\n                ngModel: '='\n            },\n            link: function(scope, element, attrs) {\n                var type = scope.field.field_type;\n                var req = scope.field.required ? 'required=\"required\" ' : '';\n                var html = \"\";\n                if(type === \"string\" || type === \"mac_address\" ||\n                   type === \"password\") {\n                    // Build an input element with the correct attributes.\n                    var input_type = 'type=\"text\"';\n                    if(type === \"password\") {\n                        // If the input field is a password field, display it\n                        // as text or password depending on if we're editing\n                        // the fields.\n                        input_type = \"data-ng-type=\\\"ngModel.editing && \" +\n                            \"'text' || 'password'\\\"\";\n                    }\n                    html =\n                        '<input ' + input_type + ' ' +\n                        'name=\"' + scope.field.name + '\" ' +\n                        req + 'data-ng-model=\"' + attrs.ngModel + '\" ' +\n                        'data-ng-disabled=\"' + attrs.ngDisabled + '\" ';\n\n                    // Add mac address validation.\n                    if(type === \"mac_address\") {\n                        html +=\n                            'data-ng-pattern=\"' +\n                            '/^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$/\"';\n                    }\n                    html += '>';\n\n                    // Set the default value for the input on the model.\n                    if(angular.isUndefined(scope.ngModel)) {\n                        scope.ngModel = scope.field[\"default\"];\n                    }\n                } else if(type === \"choice\") {\n                    // Build a select element with the correct attributes.\n                    html =\n                        '<select name=\"' + scope.field.name + '\"' +\n                        req + 'data-ng-model=\"' + attrs.ngModel + '\" ' +\n                        'data-ng-disabled=\"' + attrs.ngDisabled + '\" ' +\n                        'data-ng-options=\"' +\n                        'choice[0] as choice[1] for choice in field.choices' +\n                        '\">';\n                    html += '</select>';\n\n                    // Set the default choice on the model.\n                    if(angular.isUndefined(scope.ngModel)) {\n                        var i;\n                        for(i = 0; i < scope.field.choices.length; i++) {\n                            var choice = scope.field.choices[i];\n                            if(scope.field[\"default\"] === choice[0]) {\n                                scope.ngModel = choice;\n                                break;\n                            }\n                        }\n                    }\n                } else {\n                    throw new Error(\"Unknown power_type: \"+ type);\n                }\n\n                // Replace the element with the compiled html using the parents\n                // scope. The parent scope is used because we want to build the\n                // element as if it was in the parent scope, not the scope that\n                // is defined in this directive.\n                element.replaceWith($compile(html)(scope.$parent));\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasPowerParameters', function() {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            maasPowerParameters: '=',\n            ngModel: '=',\n            ngDisabled: '='\n        },\n        templateUrl: 'directive/templates/power-parameters.html'\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Proxy settings directive.\n*/\n\nangular.module('MAAS').directive('maasProxySettings', [\n    '$sce', 'ConfigsManager', 'ManagerHelperService', 'JSONService',\n    function($sce, ConfigsManager, ManagerHelperService, JSONService) {\n        return {\n            restrict: \"E\",\n            scope: {},\n            templateUrl: 'static/partials/proxy-settings.html',\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                ManagerHelperService.loadManager(\n                    $scope, ConfigsManager).then(function() {\n                    $scope.loading = false;\n                    $scope.httpProxy = ConfigsManager.getItemFromList(\n                        \"http_proxy\");\n                    $scope.enableHttpProxy = ConfigsManager.getItemFromList(\n                        \"enable_http_proxy\");\n                    $scope.usePeerProxy = ConfigsManager.getItemFromList(\n                        \"use_peer_proxy\");\n                    if ($scope.enableHttpProxy.value) {\n                        if ($scope.httpProxy.value) {\n                            if ($scope.usePeerProxy.value) {\n                                $scope.proxy_type = \"peer-proxy\";\n                            } else {\n                                $scope.proxy_type = \"external-proxy\";\n                            }\n                        } else {\n                            $scope.proxy_type = \"builtin-proxy\";\n                        }\n                    } else {\n                        $scope.proxy_type = \"no-proxy\";\n                    }\n                });\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Release name.\n *\n * Converts the provided release name into the release title.\n */\n\n\nangular.module('MAAS').directive('maasReleaseName', [\n    'GeneralManager', 'ManagerHelperService',\n    function(GeneralManager, ManagerHelperService) {\n    return {\n        restrict: \"A\",\n        scope: {\n          releaseName: \"=maasReleaseName\"\n        },\n        link: function(scope, element, attrs) {\n            scope.osinfo = GeneralManager.getData(\"osinfo\");\n\n            // Gets the release name.\n            var getName = function() {\n                if(angular.isArray(scope.osinfo.releases)) {\n                  for(i = 0; i < scope.osinfo.releases.length; i++) {\n                      var release = scope.osinfo.releases[i];\n                      if(release[0] === scope.releaseName) {\n                          return release[1];\n                      }\n                  }\n                }\n                return scope.releaseName;\n            };\n\n            // Sets the text inside the element.\n            var setText = function() {\n                element.text(getName());\n            };\n\n            // Update the text when the release name or osinfo changes.\n            scope.$watch('releaseName', function() {\n              setText();\n            });\n            scope.$watchCollection('osinfo.releases', function() {\n              setText();\n            });\n\n            // Load the manager and start polling.\n            ManagerHelperService.loadManager(scope, GeneralManager).then(\n                function() {\n                    GeneralManager.startPolling(scope, 'osinfo');\n                });\n\n            // Stop polling when the scope is destroyed.\n            scope.$on('$destroy', function() {\n              GeneralManager.stopPolling(scope, 'osinfo');\n            });\n        }\n    };\n}]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Release options directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the release-options.html into the template cache.\n    $templateCache.put('directive/templates/release-options.html', [\n        '<div class=\"form__group u-margin--right u-margin--top-tiny\">',\n            '<input class=\"checkbox margin-right\" id=\"diskErase\" ',\n                'type=\"checkbox\" data-ng-model=\"maasReleaseOptions.erase\" ',\n                'data-ng-disabled=\"globalOptions.erase\" ',\n                'data-ng-change=\"onEraseChange()\">',\n            '<label class=\"checkbox-label\" for=\"diskErase\">',\n                'Erase disks before releasing',\n            '</label>',\n        '</div>',\n        '<div class=\"form__group u-margin--right u-margin--top-tiny\">',\n            '<input class=\"checkbox margin-right\" id=\"secureErase\" ',\n                'type=\"checkbox\" ',\n                'data-ng-model=\"maasReleaseOptions.secureErase\" ',\n                'data-ng-disabled=\"!maasReleaseOptions.erase\">',\n            '<label class=\"checkbox-label\" for=\"secureErase\">',\n                'Use secure erase',\n            '</label>',\n        '</div>',\n        '<div class=\"form__group u-margin--top-tiny\">',\n            '<input class=\"checkbox\" id=\"quickErase\" type=\"checkbox\" ',\n                'data-ng-model=\"maasReleaseOptions.quickErase\" ',\n                'data-ng-disabled=\"!maasReleaseOptions.erase\">',\n            '<label class=\"checkbox-label\" for=\"quickErase\">',\n                'Use quick erase (not secure)',\n            '</label>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasReleaseOptions', [\n    'GeneralManager', function(GeneralManager) {\n        return {\n            restrict: \"A\",\n            scope: {\n                maasReleaseOptions: '='\n            },\n            templateUrl: 'directive/templates/release-options.html',\n            link: function(scope, element, attrs) {\n                // On click of enabling erasing set the others to the\n                // global default value.\n                scope.onEraseChange = function() {\n                    if(scope.maasReleaseOptions.erase) {\n                        scope.maasReleaseOptions.secureErase = (\n                            scope.globalOptions.secure_erase);\n                        scope.maasReleaseOptions.quickErase = (\n                            scope.globalOptions.quick_erase);\n                    } else {\n                        scope.maasReleaseOptions.secureErase = false;\n                        scope.maasReleaseOptions.quickErase = false;\n                    }\n                };\n\n                // Watch the global options. Once set update the defaults\n                // of maasReleaseOptions.\n                scope.globalOptions = GeneralManager.getData(\n                    \"release_options\");\n                scope.$watch('globalOptions', function() {\n                    if(angular.isDefined(scope.globalOptions.erase)) {\n                        // Set the initial defauls for the release options.\n                        scope.maasReleaseOptions.erase = (\n                            scope.globalOptions.erase);\n                        scope.onEraseChange();\n                    }\n                }, true);\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n* GNU Affero General Public License version 3 (see the file LICENSE).\n*\n* Script results listing directive.\n*\n*/\n\nangular.module('MAAS').directive('maasScriptResultsList', function() {\n    return {\n        templateUrl: (\n        'static/partials/script-results-list.html?v=' + (\n            MAAS_config.files_version))\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Script runtime counter directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the script_runtime.html into the template cache.\n    $templateCache.put('directive/templates/script_runtime.html', [\n        '<span data-ng-if=\"(scriptStatus === 1 || scriptStatus === 7) &&',\n        \" estimatedRunTime !== 'Unknown'\" + '\">{{counter}} of ',\n        '~{{estimatedRunTime}}</span>',\n        '<span data-ng-if=\"(scriptStatus === 1 || scriptStatus === 7) &&',\n        \" estimatedRunTime == 'Unknown'\" + '\">{{counter}}</span>',\n        '<span data-ng-if=\"scriptStatus === 0 && estimatedRunTime !== ',\n        \"'Unknown'\" + '\">~{{estimatedRunTime}}</span>',\n        '<span data-ng-if=\"scriptStatus !== 0 && scriptStatus !== 1 ',\n        '&& scriptStatus !== 7\">{{runTime}}</span>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasScriptRunTime', function() {\n    return {\n        restrict: \"A\",\n        require: [\"startTime\", \"runTime\", \"estimatedRunTime\", \"scriptStatus\"],\n        scope: {\n            startTime: '=',\n            runTime: '@',\n            estimatedRunTime: '@',\n            scriptStatus: '='\n        },\n        templateUrl: 'directive/templates/script_runtime.html',\n        controller: function($scope, $interval) {\n            $scope.counter = \"0:00:00\";\n\n            function incrementCounter() {\n                if(($scope.scriptStatus === 1 || $scope.scriptStatus === 7) &&\n                    $scope.startTime) {\n                    var start_date = new Date(null);\n                    start_date.setSeconds($scope.startTime);\n                    var seconds = Math.floor((Date.now() - start_date) / 1000);\n                    var minutes = Math.floor(seconds / 60);\n                    var hours = Math.floor(minutes / 60);\n                    var days = Math.floor(hours / 24);\n                    hours = hours - (days * 24);\n                    minutes = minutes - (days * 24 * 60) - (hours * 60);\n                    seconds = seconds - (days * 24 * 60 * 60) -\n                        (hours * 60 * 60) - (minutes * 60);\n                    var new_counter = \"\";\n                    // This outputs the same format used by Python. It is\n                    // import to use the same format as when scripts are not\n                    // running runtime is taken from the region using Python's\n                    // format.\n                    if(days === 1) {\n                        new_counter = days + \" day, \";\n                    }else if(days > 1) {\n                        new_counter = days + \" days, \";\n                    }\n                    new_counter += hours + \":\";\n                    if(minutes < 10) {\n                        new_counter += \"0\" + minutes + \":\";\n                    } else {\n                        new_counter += minutes + \":\";\n                    }\n                    if(seconds < 10) {\n                        new_counter += \"0\" + seconds;\n                    } else {\n                        new_counter += seconds;\n                    }\n                    $scope.counter = new_counter;\n                }\n            }\n\n            // Update the counter on init, start the interval and stop it when\n            // the directive is destroyed.\n            incrementCounter();\n            var promise = $interval(incrementCounter, 1000);\n            $scope.$on('$destroy', function() {\n              $interval.cancel(promise);\n            });\n        }\n    };\n});\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Script select directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the script-select.html into the template cache.\n    $templateCache.put('directive/templates/script-select.html', [\n        '<tags-input data-ng-model=\"ngModel\" placeholder=\"Select scripts\" ',\n                'key-property=\"id\" display-property=\"name\" min-length=1',\n                'on-tag-adding=\"onTagAdding($tag)\" spellcheck=\"false\"',\n                'add-from-autocomplete-only=\"true\" on-tag-removed=\"refocus()\"',\n                'on-tag-adding=\"onTagAdding($tag)\" on-tag-added=\"refocus()\">',\n            '<auto-complete source=\"getScripts($query)\" min-length=\"0\" ',\n                    'load-on-down-arrow=\"true\" load-on-focus=\"true\" ',\n                    'load-on-empty=\"true\" template=\"script-template\" ',\n                    'max-results-to-show=\"1000\">',\n            '</auto-complete>',\n        '</tags-input>',\n        '<script type=\"text/ng-template\" id=\"script-template\">',\n            '<div>',\n                '<p>',\n                    '{{data.name}} {{data.tags_string}}',\n                '</p>',\n                '<span class=\"p-form-help-text\">',\n                    '{{data.description}}',\n                '</span>',\n            '</div>',\n        '</script>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive(\n        'maasScriptSelect',\n        ['$q', 'ScriptsManager', 'ManagerHelperService',\n        function($q, ScriptsManager, ManagerHelperService) {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            ngModel: '=',\n            scriptType: '='\n        },\n        templateUrl: 'directive/templates/script-select.html',\n        link: function($scope, element, attrs, ngModelCtrl) {\n\n            $scope.allScripts = ScriptsManager.getItems();\n            $scope.scripts = [];\n            $scope.getScripts = function(query) {\n                $scope.scripts.length = 0;\n                angular.forEach($scope.allScripts, function(script) {\n                    if(script.script_type === $scope.scriptType &&\n                            script.name.indexOf(query) >= 0) {\n                        script.tags_string = '';\n                        angular.forEach(script.tags, function (tag) {\n                            if(script.tags_string === '') {\n                                script.tags_string = '(' + tag;\n                            } else {\n                                script.tags_string += ', ' + tag;\n                            }\n                        });\n                        if(script.tags_string !== '') {\n                            script.tags_string += ')';\n                        }\n                        $scope.scripts.push(script);\n                    }\n                });\n                return {\n                    data: $scope.scripts\n                };\n            };\n            $scope.onTagAdding = function(tag) {\n                return tag.id !== undefined;\n            };\n\n            $scope.refocus = function() {\n                var tagsInput = element.find('tags-input');\n                var tagsInputScope = tagsInput.isolateScope();\n                tagsInputScope.eventHandlers.input.change('');\n                tagsInputScope.eventHandlers.input.focus();\n                tagsInput.find('input').focus();\n            };\n\n            if(!angular.isArray($scope.ngModel)) {\n                $scope.ngModel = [];\n            }\n            ManagerHelperService.loadManager($scope, ScriptsManager).then(\n                function() {\n                    $scope.ngModel.length = 0;\n                    angular.forEach($scope.allScripts, function(script) {\n                        if(script.script_type === $scope.scriptType &&\n                           script.for_hardware.length === 0) {\n                            if($scope.scriptType === 0) {\n                                // By default MAAS runs all custom\n                                // commissioning scripts in addition to all\n                                // builtin commissioning scripts.\n                                $scope.ngModel.push(script);\n                            } else if($scope.scriptType === 2 &&\n                                    script.tags.indexOf('commissioning') >= 0) {\n                                // By default MAAS runs testing scripts which\n                                // have been tagged 'commissioning'\n                                $scope.ngModel.push(script);\n                            }\n                        }\n                    });\n                }\n            );\n        }\n    };\n}]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Script status icon select directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the script_status.html into the template cache.\n    $templateCache.put('directive/templates/script_status.html', [\n        '<span data-ng-class=\"icon\" data-ng-show=\"show\"></span>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasScriptStatus', function() {\n    return {\n        restrict: \"A\",\n        require: \"scriptStatus\",\n        scope: {\n            scriptStatus: '='\n        },\n        templateUrl: 'directive/templates/script_status.html',\n        controller: function($scope) {\n            function getIcon() {\n                $scope.show = true;\n                switch($scope.scriptStatus) {\n                    // SCRIPT_STATUS.PENDING\n                    case 0:\n                        $scope.icon = 'p-icon--pending';\n                        break;\n                    // SCRIPT_STATUS.RUNNING\n                    case 1:\n                    // SCRIPT_STATUS.INSTALLING\n                    case 7:\n                        $scope.icon = 'p-icon--running';\n                        break;\n                    // SCRIPT_STATUS.PASSED\n                    case 2:\n                        $scope.icon = 'p-icon--pass';\n                        break;\n                    // SCRIPT_STATUS.FAILED\n                    case 3:\n                    // SCRIPT_STATUS.ABORTED\n                    case 5:\n                    // SCRIPT_STATUS.DEGRADED\n                    case 6:\n                    // SCRIPT_STATUS.FAILED_INSTALLING\n                    case 8:\n                        $scope.icon = 'p-icon--power-error';\n                        break;\n                    // SCRIPT_STATUS.TIMEDOUT\n                    case 4:\n                        $scope.icon = 'p-icon--timed-out';\n                        break;\n                    case -1:\n                        // No scripts have been run.\n                        $scope.show = false;\n                        break;\n                    default:\n                        $scope.icon = 'p-icon--help';\n                        break;\n                }\n            }\n\n            getIcon();\n\n            $scope.$watch(\"scriptStatus\", function() {\n                getIcon();\n            });\n        }\n    };\n});\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * SSH keys directive.\n*/\n\nangular.module('MAAS').directive('maasSshKeys', [\n    '$sce', 'SSHKeysManager', 'ManagerHelperService', 'JSONService',\n    function($sce, SSHKeysManager, ManagerHelperService, JSONService) {\n        return {\n            restrict: \"E\",\n            scope: {},\n            templateUrl: (\n                'static/partials/ssh-keys.html?v=' + (\n                    MAAS_config.files_version)),\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                $scope.keys = SSHKeysManager.getItems();\n                $scope.groupedKeys = [];\n                $scope.add = {\n                    source: 'lp',\n                    authId: '',\n                    key: '',\n                    error: null,\n                    saving: false\n                };\n                $scope.sourceTitles = {\n                    'lp': 'Launchpad',\n                    'gh': 'Github',\n                    'upload': 'Upload'\n                };\n                $scope.openRow = null;\n                $scope.rowMode = null;\n\n                // Expose trustAsHtml on the scope for the view to use.\n                $scope.trustAsHtml = $sce.trustAsHtml;\n\n                // Open a row.\n                $scope.open = function(obj, mode) {\n                    $scope.openRow = obj.id;\n                    $scope.rowMode = mode;\n                };\n\n                // Close the open row.\n                $scope.close = function() {\n                    $scope.openRow = null;\n                };\n\n                // Returns true if the key can be imported.\n                $scope.canImportKeys = function() {\n                    if($scope.add.saving) {\n                        return false;\n                    } else if ($scope.add.source === 'lp' ||\n                        $scope.add.source === 'gh') {\n                        return $scope.add.authId.length > 0;\n                    } else {\n                        return $scope.add.key.length > 0;\n                    }\n                };\n\n                // Called to import the key.\n                $scope.importKeys = function() {\n                    if(!$scope.canImportKeys()) {\n                        return;\n                    }\n                    $scope.add.error = null;\n                    $scope.add.saving = true;\n                    if($scope.add.source === 'lp' ||\n                        $scope.add.source === 'gh') {\n                        SSHKeysManager.importKeys({\n                            'protocol': $scope.add.source,\n                            'auth_id': $scope.add.authId\n                        }).then(function() {\n                            $scope.add.saving = false;\n                            $scope.add.source = 'lp';\n                            $scope.add.authId = '';\n                            $scope.add.key = '';\n                        }, function(error) {\n                            $scope.add.saving = false;\n                            var errorJson = JSONService.tryParse(error);\n                            if(angular.isObject(errorJson)) {\n                                if(angular.isArray(errorJson.__all__)) {\n                                    $scope.add.error = errorJson.__all__[0];\n                                } else {\n                                    $scope.add.error = error;\n                                }\n                            } else {\n                                $scope.add.error = error;\n                            }\n                        });\n                    } else {\n                        SSHKeysManager.createItem({\n                            'key': $scope.add.key\n                        }).then(function() {\n                            $scope.add.saving = false;\n                            $scope.add.source = 'lp';\n                            $scope.add.authId = '';\n                            $scope.add.key = '';\n                        }, function(error) {\n                            $scope.add.saving = false;\n                            var errorJson = JSONService.tryParse(error);\n                            if(angular.isObject(errorJson)) {\n                                if(angular.isArray(errorJson.key)) {\n                                    $scope.add.error = errorJson.key[0];\n                                } else if(angular.isArray(errorJson.__all__)) {\n                                    $scope.add.error = errorJson.__all__[0];\n                                } else {\n                                    $scope.add.error = error;\n                                }\n                            } else {\n                                $scope.add.error = error;\n                            }\n                        });\n                    }\n                };\n\n                // Called to delete the selected group of keys.\n                $scope.confirmDelete = function(obj) {\n                    angular.forEach(obj.keys, function(key) {\n                        SSHKeysManager.deleteItem(key);\n                    });\n                };\n\n                // Updates the groupedKeys that is used to render the table.\n                $scope.$watchCollection(\"keys\", function() {\n                    $scope.groupedKeys = [];\n                    var keyMap = {};\n                    angular.forEach($scope.keys, function(key) {\n                        var groupObj, keysource = key.keysource;\n                        if(angular.isObject(keysource)) {\n                            var keysourceKey = (\n                                keysource.protocol + '/' + keysource.auth_id);\n                            groupObj = keyMap[keysourceKey];\n                            if(angular.isObject(groupObj)) {\n                                groupObj.keys.push(key);\n                            } else {\n                                groupObj = {\n                                    id: keysourceKey,\n                                    source: keysource.protocol,\n                                    authId: keysource.auth_id,\n                                    keys: [key]\n                                };\n                                keyMap[keysourceKey] = groupObj;\n                                $scope.groupedKeys.push(groupObj);\n                            }\n                        } else {\n                            groupObj = {\n                                id: 'upload/' + key.id,\n                                source: 'upload',\n                                authId: '',\n                                keys: [key]\n                            };\n                            $scope.groupedKeys.push(groupObj);\n                        }\n                    });\n                });\n\n                ManagerHelperService.loadManager($scope, SSHKeysManager).then(\n                    function() {\n                        $scope.loading = false;\n                    });\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n* GNU Affero General Public License version 3 (see the file LICENSE).\n*\n* Switches listing directive.\n*\n* Renders the switches listing.\n*/\n\n\nangular.module('MAAS').directive('maasSwitchesTable', [\n  'SwitchesManager', 'GeneralManager', 'ManagerHelperService',\n  function (SwitchesManager, GeneralManager, ManagerHelperService) {\n    return {\n      restrict: \"E\",\n      scope: {\n        search: \"=\",\n        ngDisabled: \"&\",\n        switchHasError: \"&\",\n        hideCheckboxes: \"=?\",\n        onListingChange: \"&\",\n        onCheckAll: \"&\",\n        onCheck: \"&\"\n      },\n      templateUrl: (\n        'static/partials/switches-table.html?v=' + (\n          MAAS_config.files_version)),\n      link: function(scope, element, attrs) {\n        // Statuses that should show spinner.\n        var SPINNER_STATUSES = [\n          1,   // commissioning\n          9,   // deploying\n          12,  // releasing\n          14,  // disk erasing\n          17,  // entering rescue mode\n          19,  // exiting rescue mode\n          21   // testing\n        ];\n\n        // Scope variables.\n        scope.table = {\n          column: 'fqdn',\n          predicate: 'fqdn',\n          reverse: false,\n          allViewableChecked: false,\n          switches: SwitchesManager.getItems(),\n          filteredSwitches: [],\n          osinfo: GeneralManager.getData(\"osinfo\")\n        };\n\n        // Ensures that the checkbox for select all is the correct value.\n        scope.updateAllChecked = function() {\n          // Not checked when the filtered switches are empty.\n          if(scope.table.filteredSwitches.length === 0) {\n              scope.table.allViewableChecked = false;\n              return;\n          }\n\n          // Loop through all filtered switches and see if all are checked.\n          var i;\n          for(i = 0; i < scope.table.filteredSwitches.length; i++) {\n              if(!scope.table.filteredSwitches[i].$selected) {\n                  scope.table.allViewableChecked = false;\n                  return;\n              }\n          }\n          scope.table.allViewableChecked = true;\n        };\n\n        // Selects and deselects visible switches.\n        scope.toggleCheckAll = function() {\n          if(scope.table.allViewableChecked) {\n            angular.forEach(\n              scope.table.filteredSwitches, function(switch_) {\n                SwitchesManager.unselectItem(switch_.system_id);\n              });\n          } else {\n            angular.forEach(\n              scope.table.filteredSwitches, function(switch_) {\n                SwitchesManager.selectItem(switch_.system_id);\n              });\n          }\n          scope.updateAllChecked();\n          scope.onCheckAll();\n        };\n\n        // Selects and unselects switch.\n        scope.toggleChecked = function(switch_) {\n          if(SwitchesManager.isSelected(switch_.system_id)) {\n            SwitchesManager.unselectItem(switch_.system_id);\n          } else {\n            SwitchesManager.selectItem(switch_.system_id);\n          }\n          scope.updateAllChecked();\n          scope.onCheck({$switch_: switch_});\n        };\n\n        // Sorts the table by predicate.\n        scope.sortTable = function(predicate) {\n            scope.table.predicate = predicate;\n            scope.table.reverse = !scope.table.reverse;\n        };\n\n        // Sets the viewable column or sorts.\n        scope.selectColumnOrSort = function(predicate) {\n            if(scope.table.column !== predicate) {\n                scope.table.column = predicate;\n            } else {\n                scope.sortTable(predicate);\n            }\n        };\n\n        // Return true if spinner should be shown.\n        scope.showSpinner = function(switch_) {\n          return SPINNER_STATUSES.indexOf(switch_.status_code) > -1;\n        };\n\n        // Returns the release title from osinfo.\n        scope.getReleaseTitle = function(os_release) {\n          if(angular.isArray(scope.table.osinfo.releases)) {\n            for(i = 0; i < scope.table.osinfo.releases.length; i++) {\n              var release = scope.table.osinfo.releases[i];\n              if(release[0] === os_release) {\n                return release[1];\n              }\n            }\n          }\n          return os_release;\n        };\n\n        // Returns the status text to show.\n        scope.getStatusText = function(switch_) {\n          var showRelease = ['Deploying', 'Deployed'];\n          if(showRelease.indexOf(switch_.status) === -1) {\n            return switch_.status;\n          } else {\n            var releaseTitle = scope.getReleaseTitle(\n              switch_.osystem + '/' + switch_.distro_series);\n            if(switch_.osystem === \"ubuntu\") {\n              releaseTitle = releaseTitle.split('\"')[0].trim();\n            }\n            if(switch_.status === \"Deployed\") {\n              return releaseTitle;\n            }\n            if(switch_.status === \"Deploying\") {\n              return switch_.status + ' ' + releaseTitle;\n            }\n          }\n        };\n\n        // When the list of filtered switches change update the all checkbox.\n        scope.$watchCollection(\"table.filteredSwitches\", function() {\n          scope.updateAllChecked();\n          scope.onListingChange({$switches: scope.table.filteredSwitches});\n        });\n\n        // Load the required managers and start polling for osinfo.\n        ManagerHelperService.loadManagers(\n          scope, [SwitchesManager, GeneralManager]).then(function() {\n            GeneralManager.startPolling(scope, \"osinfo\");\n          });\n\n        // Stop polling when the scope is destroyed.\n        scope.$on(\"$destroy\", function() {\n          GeneralManager.stopPolling(scope, \"osinfo\");\n        });\n      }\n    };\n}]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Toggle control.\n */\n\nangular.module('MAAS').directive('toggleCtrl',[\n    '$document',\n    function($document) {\n        return {\n            restrict: 'A',\n            link: function($scope, $element, $attr){\n\n                $scope.isToggled = false;\n                $scope.toggleMenu = function() {\n                  $scope.isToggled = !$scope.isToggled;\n                };\n\n                var clickHandler = function(event) {\n                    if ($element.find(event.target).length > 0) {\n                        return;\n                    }\n                    $scope.$apply(function() {\n                        $scope.isToggled = false;\n                    });\n                };\n\n                $document.on('click', clickHandler);\n                $scope.$on('$destroy', function() {\n                    $document.off('click', clickHandler);\n                });\n            }\n        };\n}]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Type directive.\n */\n\nangular.module('MAAS').directive('ngType', function() {\n    return {\n        restrict: \"A\",\n        scope: {\n            ngType: \"=\"\n        },\n        link: function(scope, element, attrs) {\n            scope.$watch('ngType', function() {\n                valid_types = [\n                    'button',\n                    'checkbox',\n                    'color',\n                    'date ',\n                    'datetime ',\n                    'datetime-local ',\n                    'email ',\n                    'file',\n                    'hidden',\n                    'image',\n                    'month ',\n                    'number ',\n                    'password',\n                    'radio',\n                    'range ',\n                    'reset',\n                    'search',\n                    'submit',\n                    'tel',\n                    'text',\n                    'time ',\n                    'url',\n                    'week'\n                ];\n                if(valid_types.indexOf(scope.ngType) !== -1) {\n                    element[0].type = scope.ngType;\n                }\n                else {\n                    throw new Error(\"Invalid input type: \" + scope.ngType);\n                }\n\n            });\n        }\n    };\n});","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Version reloader.\n *\n * Watches the version reported by the GeneralManager if it changes then\n * the entire page is reloaded by-passing the local browser cache.\n */\n\n\nangular.module('MAAS').directive('maasVersionReloader', [\n    '$window', 'GeneralManager', 'ManagerHelperService', 'LogService',\n    function($window, GeneralManager, ManagerHelperService, LogService) {\n        return {\n            restrict: \"A\",\n            controller: function($scope) {\n                $scope.version = GeneralManager.getData(\"version\");\n\n                // Reload the page by-passing the browser cache.\n                $scope.reloadPage = function() {\n                    // Force cache reload by passing true.\n                    $window.location.reload(true);\n                };\n\n                ManagerHelperService.loadManager($scope, GeneralManager).then(\n                    function() {\n                        GeneralManager.enableAutoReload(true);\n                        LogService.info(\n                            'Version reloader: Monitoring MAAS \"' +\n                            $scope.site + '\"; version', $scope.version.text,\n                            \"via\", $window.location.href);\n                        $scope.$watch(\"version.text\",\n                            function(newValue, oldValue) {\n                                if(newValue !== oldValue) {\n                                    LogService.info(\n                                        \"MAAS version changed from '\" +\n                                        oldValue + \"' to '\" + newValue +\n                                        \"'; forcing reload.\");\n                                    $scope.reloadPage();\n                                }\n                            });\n                    });\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Window Width.\n *\n * Watches the window width and calculates what the inner width of the window.\n * Applying the attribute window-wdith on the parent element and calling\n * data-ng-if=\"width > 768\" you can use this to hide / show elements for mobile\n * development.\n *\n */\n\n\nangular.module('MAAS').directive('windowWidth', [\n    '$window',\n    function ($window) {\n        return {\n            restrict: 'A',\n            link: function($scope, element, attrs){\n                $scope.windowWidth = $window.innerWidth;\n                function onResize(){\n                    // uncomment for only fire when $window.innerWidth change\n                    if ($scope.windowWidth !== $window.innerWidth) {\n                        $scope.windowWidth = $window.innerWidth;\n                        $scope.$apply(function () {\n                            $scope.message = \"Timeout called!\";\n                        });\n                    }\n                }\n\n                function cleanUp() {\n                    angular.element($window).off('resize', onResize);\n                }\n\n                angular.element($window).on('resize', onResize);\n                $scope.$on('$destroy', cleanUp);\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS BootResource Manager\n *\n * Manager for the boot resources. This manager is unique from all the other\n * managers because it uses polling instead of having the region push the\n * information.\n *\n * Why is it polling?\n * The boot resource information is split between the region controller and\n * all rack controllers. The region controller does not cache any information\n * about a rack controllers images it contacts the rack as its source of truth.\n * This means that the client needs to use polling so the region controller\n * can ask each rack controller what is the status of your images.\n */\n\nangular.module('MAAS').factory(\n    'BootResourcesManager',\n    ['$q', '$timeout', 'RegionConnection', 'ErrorService',\n    function($q, $timeout, RegionConnection, ErrorService) {\n\n        // Constructor\n        function BootResourcesManager() {\n            // Set true once been loaded the first time.\n            this._loaded = false;\n\n            // Holds the data recieved from polling.\n            this._data = {};\n\n            // Set to true when polling has been enabled.\n            this._polling = false;\n\n            // The next promise for the polling interval.\n            this._nextPromise = null;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data.\n            this._pollTimeout = 10000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when an error occurs.\n            this._pollErrorTimeout = 500;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when the retrieved data is empty.\n            this._pollEmptyTimeout = 3000;\n        }\n\n        // Return the data.\n        BootResourcesManager.prototype.getData = function() {\n            return this._data;\n        };\n\n        // Return true when data has been loaded.\n        BootResourcesManager.prototype.isLoaded = function() {\n            return this._loaded;\n        };\n\n        // Returns true when currently polling.\n        BootResourcesManager.prototype.isPolling = function() {\n            return this._polling;\n        };\n\n        // Starts the polling for data.\n        BootResourcesManager.prototype.startPolling = function() {\n            if(!this._polling) {\n                this._polling = true;\n                return this._poll();\n            } else {\n                return this._nextPromise;\n            }\n        };\n\n        // Stops the polling for data.\n        BootResourcesManager.prototype.stopPolling = function() {\n            this._polling = false;\n            if(angular.isObject(this._nextPromise)) {\n                $timeout.cancel(this._nextPromise);\n                this._nextPromise = null;\n            }\n        };\n\n        // Load the data from the region.\n        BootResourcesManager.prototype._loadData = function(raiseError) {\n            raiseError = raiseError || false;\n            var self = this;\n            return RegionConnection.callMethod(\"bootresource.poll\").then(\n                function(newData) {\n                    angular.copy(angular.fromJson(newData), self._data);\n                    self._loaded = true;\n                    return self._data;\n                }, function(error) {\n                    if(raiseError) {\n                        ErrorService.raiseError(error);\n                    }\n                });\n        };\n\n        // Registers the next polling attempt.\n        BootResourcesManager.prototype._pollAgain = function(timeout) {\n            var self = this;\n            this._nextPromise = $timeout(function() {\n                self._poll();\n            }, timeout);\n            return this._nextPromise;\n        };\n\n        // Polls for the data from the region.\n        BootResourcesManager.prototype._poll = function() {\n            var self = this;\n\n            // Can only poll if connected.\n            if(!RegionConnection.isConnected()) {\n                return this._pollAgain(this._pollErrorTimeout);\n            }\n\n            return this._loadData(false).then(function(newData) {\n                var pollTimeout = self._pollTimeout;\n                if(!angular.isObject(newData) ||\n                    newData.connection_error ||\n                    !angular.isArray(newData.resources) ||\n                    newData.resources.length === 0) {\n                    pollTimeout = self._pollEmptyTimeout;\n                }\n                self._pollAgain(pollTimeout);\n                return newData;\n            }, function(error) {\n                // Don't raise the error, just log it and try again.\n                console.log(error);\n                self._pollAgain(self._pollErrorTimeout);\n            });\n        };\n\n        // Loads the resources. This implemented so the ManagerHelperService\n        // can work on this manager just like all the rest.\n        BootResourcesManager.prototype.loadItems = function() {\n            var defer = $q.defer();\n            this._loadData(true).then(function() {\n                defer.resolve();\n            });\n            return defer.promise;\n        };\n\n        // Does nothing. This implemented so the ManagerHelperService\n        // can work on this manager just like all the rest.\n        BootResourcesManager.prototype.enableAutoReload = function() { };\n\n        // Stop the running image import process.\n        BootResourcesManager.prototype.stopImport = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.stop_import\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Save the ubuntu options and start the import process.\n        BootResourcesManager.prototype.saveUbuntu = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.save_ubuntu\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Save the Ubuntu Core images and start the import process.\n        BootResourcesManager.prototype.saveUbuntuCore = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.save_ubuntu_core\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Save the other images and start the import process.\n        BootResourcesManager.prototype.saveOther = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.save_other\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Fetch the releases and arches from the provided source.\n        BootResourcesManager.prototype.fetch = function(source) {\n            return RegionConnection.callMethod(\"bootresource.fetch\", source);\n        };\n\n        // Delete an image.\n        BootResourcesManager.prototype.deleteImage = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.delete_image\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        return new BootResourcesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Configs Manager\n *\n * Manages all of the config values in the browser. This manager is used for\n * the first-user journey and the settings page.\n */\n\n angular.module('MAAS').factory(\n     'ConfigsManager',\n     ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n             $q, $rootScope, RegionConnection, Manager) {\n\n         function ConfigsManager() {\n             Manager.call(this);\n\n             this._pk = \"name\";\n             this._handler = \"config\";\n\n             // Listen for notify events for the config object.\n             var self = this;\n             RegionConnection.registerNotifier(\"config\",\n                 function(action, data) {\n                     self.onNotify(action, data);\n                 });\n         }\n\n         ConfigsManager.prototype = new Manager();\n\n         return new ConfigsManager();\n     }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Controllers Manager\n *\n * Manages all of the controllers in the browser. This manager is used for the\n * controller listing and view pages. The manager is a subclass of\n * NodesManager.\n */\n\nangular.module('MAAS').factory(\n    'ControllersManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', 'ServicesManager',\n            function($q, $rootScope, RegionConnection, NodesManager,\n            ServicesManager) {\n\n        function ControllersManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"controller\";\n\n            // Listen for notify events for the controller object.\n            var self = this;\n            RegionConnection.registerNotifier(\"controller\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n        ControllersManager.prototype = new NodesManager();\n\n        ControllersManager.prototype.getServices = function(controller) {\n            var services = [];\n            angular.forEach(controller.service_ids, function(service_id) {\n                var service = ServicesManager.getItemFromList(service_id);\n                if(angular.isObject(service)) {\n                    services.push(service);\n                }\n            });\n            return services;\n        };\n\n        // Check the boot image import status.\n        ControllersManager.prototype.checkImageStates = function(controllers) {\n            return RegionConnection.callMethod(\n                this._handler + \".check_images\", controllers);\n        };\n\n        return new ControllersManager();\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Devices Manager\n *\n * Manages all of the devices in the browser. This manager is used for the\n * device listing and the device view page. The manager uses the\n * RegionConnection to load the devices, update the devices, and listen for\n * notification events about devices.\n */\n\nangular.module('MAAS').factory(\n    'DevicesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', function(\n            $q, $rootScope, RegionConnection, NodesManager) {\n\n        function DevicesManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"device\";\n            this._metadataAttributes = {\n                \"owner\": null,\n                \"subnets\": null,\n                \"tags\": null,\n                \"zone\": function(device) {\n                    return device.zone.name;\n                }\n            };\n\n            // Listen for notify events for the device object.\n            var self = this;\n            RegionConnection.registerNotifier(\"device\", function(action, data) {\n                self.onNotify(action, data);\n            });\n        }\n\n        DevicesManager.prototype = new NodesManager();\n\n        // Create a device.\n        DevicesManager.prototype.create = function(node) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the device to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"device.create\", node);\n        };\n\n        // Create an interface on device.\n        DevicesManager.prototype.createInterface = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"device.create_interface\", params).then(function(device) {\n                    self._replaceItem(device);\n                    return device;\n                });\n        };\n\n        // Perform the action on the device.\n        DevicesManager.prototype.performAction = function(\n            device, action, extra) {\n\n            if(!angular.isObject(extra)) {\n                extra = {};\n            }\n            return RegionConnection.callMethod(\"device.action\", {\n                \"system_id\": device.system_id,\n                \"action\": action,\n                \"extra\": extra\n                });\n        };\n\n        return new DevicesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS DHCPSnippet Manager\n *\n * Manages all of the DHCPSnippets in the browser. The manager uses the\n * RegionConnection to load the DHCPSnippets, update the DHCPSnippets, and\n * listen for notification events about DHCPSnippets.\n */\n\nangular.module('MAAS').factory(\n    'DHCPSnippetsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function DHCPSnippetsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"dhcpsnippet\";\n\n            // Listen for notify events for the DHCPSnippet object.\n            var self = this;\n            RegionConnection.registerNotifier(\"dhcpsnippet\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        DHCPSnippetsManager.prototype = new Manager();\n\n        // Create the snippet.\n        DHCPSnippetsManager.prototype.create = function(snippet) {\n            return RegionConnection.callMethod(\n                this._handler + \".create\", snippet, true);\n        };\n\n        return new DHCPSnippetsManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Discovery Manager\n *\n * A Discovery is a MAC, IP binding with an optional hostname that MAAS\n * believes it has discovered. It is associated with a particular fabric and\n * VLAN, and is aware of which rack or region interface most recently\n * discovered it.\n *\n * This class manages all of the discoveries in the browser. It uses the\n * RegionConnection to load the discoveries and listen for notification events\n * about discoveries.\n */\n\nangular.module('MAAS').factory(\n    'DiscoveriesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'PollingManager',\n    function($q, $rootScope, RegionConnection, PollingManager) {\n\n        function DiscoveriesManager() {\n            PollingManager.call(this);\n\n            this._pk = \"first_seen\";\n            this._batchKey = \"first_seen\";\n            this._handler = \"discovery\";\n\n            // Poll every 10 seconds when its empty as its okay for\n            // this to be empty.\n            this._pollEmptyTimeout = 5000;\n        }\n\n        DiscoveriesManager.prototype = new PollingManager();\n\n        return new DiscoveriesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Domain Manager\n *\n * Manages all of the domains in the browser. The manager uses the\n * RegionConnection to load the domains, update the domains, and listen for\n * notification events about domains.\n */\n\nangular.module('MAAS').factory(\n    'DomainsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function DomainsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"domain\";\n\n            // Listen for notify events for the domain object.\n            var self = this;\n            RegionConnection.registerNotifier(\"domain\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        DomainsManager.prototype = new Manager();\n\n        // Create a domain.\n        DomainsManager.prototype.create = function(domain) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"domain.create\", domain);\n        };\n\n        // Delete the domain.\n        DomainsManager.prototype.deleteDomain = function(domain) {\n            return RegionConnection.callMethod(\"domain.delete\", domain);\n        };\n\n        DomainsManager.prototype.getDefaultDomain = function() {\n            if(this._items.length === 0) {\n                return null;\n            } else {\n                var i;\n                for(i=0;i<this._items.length;i++) {\n                    if(this._items[i].id === 0) {\n                        return this._items[i];\n                    }\n                }\n            }\n            return this._items[0];\n        };\n\n        DomainsManager.prototype.getDomainByName = function(name) {\n            if(this._items.length > 0) {\n                var i;\n                for(i=0;i<this._items.length;i++) {\n                    if(this._items[i].name === name) {\n                        return this._items[i];\n                    }\n                }\n            }\n            return null;\n        };\n\n        return new DomainsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Event Manager Factory\n *\n * Manages all of the events for a node in the browser. The manager uses the\n * RegionConnection to load the events and listen for event notifications.\n */\n\nangular.module('MAAS').factory(\n    'EventsManagerFactory',\n    ['RegionConnection', 'Manager', 'ErrorService',\n    function(RegionConnection, Manager, ErrorService) {\n\n        function EventsManager(nodeId, factory) {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"event\";\n            this._nodeId = nodeId;\n            this._factory = factory;\n            this._maxDays = 1;\n        }\n\n        EventsManager.prototype = new Manager();\n\n        // Return the initial batch parameters with the id of the node\n        // and the maximum number of days to load.\n        EventsManager.prototype._initBatchLoadParameters = function() {\n            return {\n                \"node_id\": this._nodeId,\n                \"max_days\": this._maxDays\n            };\n        };\n\n        // Destroys its self. Removes self from the EventsManagerFactory.\n        EventsManager.prototype.destroy = function(){\n            this._factory.destroyManager(this);\n\n            // If this manager has ever loaded then the region is sending\n            // events about this node. Tell the RegionConnection not to\n            // stop sending notification for events from this node.\n            if(this.isLoaded()) {\n                RegionConnection.callMethod(\"event.clear\", {\n                    node_id: this._nodeId\n                });\n            }\n        };\n\n        // Get the maximum number of days the manager will load.\n        EventsManager.prototype.getMaximumDays = function() {\n            return this._maxDays;\n        };\n\n        // Changes the maximum number of days to load and loads the items.\n        EventsManager.prototype.loadMaximumDays = function(days) {\n            var self = this;\n            var setMaximumDays = function() {\n                self._maxDays = days;\n                self.loadItems();\n            };\n\n            if(this.isLoading()) {\n                // Call loadItems to get an extra defer to know when\n                // the loading is done.\n                this.loadItems().then(function() {\n                    setMaximumDays();\n                });\n            } else {\n                setMaximumDays();\n            }\n        };\n\n        // Factory that holds all created EventsManagers.\n        function EventsManagerFactory() {\n            // Holds a list of all EventsManager that have been created.\n            this._managers = [];\n\n            // Listen for notify events for the event object.\n            var self = this;\n            RegionConnection.registerNotifier(\"event\", function(action, data) {\n                self.onNotify(action, data);\n            });\n        }\n\n        // Gets the EventManager for the nodes with node_id.\n        EventsManagerFactory.prototype._getManager = function(nodeId) {\n            var i;\n            for(i = 0; i < this._managers.length; i++) {\n                if(this._managers[i]._nodeId === nodeId) {\n                    return this._managers[i];\n                }\n            }\n            return null;\n        };\n\n        // Gets the EventManager for the nodes node_id. Creates a new manager\n        // if one does not exist.\n        EventsManagerFactory.prototype.getManager = function(nodeId) {\n            var manager = this._getManager(nodeId);\n            if(!angular.isObject(manager)) {\n                // Not created so create it.\n                manager = new EventsManager(nodeId, this);\n                this._managers.push(manager);\n                return manager;\n            }\n            return manager;\n        };\n\n        // Destroy the EventManager.\n        EventsManagerFactory.prototype.destroyManager = function(manager) {\n            var idx = this._managers.indexOf(manager);\n            if(idx >= 0) {\n                this._managers.splice(idx, 1);\n            }\n        };\n\n        // Called when the RegionConnection gets a notification for an event.\n        EventsManagerFactory.prototype.onNotify = function(action, data) {\n            if(action === \"delete\") {\n                // Send all delete actions to all managers. Only one will\n                // remove the event with the given id.\n                angular.forEach(this._managers, function(manager) {\n                    manager.onNotify(action, data);\n                });\n            } else if (action === \"create\" || action === \"update\") {\n                // Get the manager based on the node_id in data, and send\n                // it the notification.\n                var manager = this._getManager(data.node_id);\n                if(angular.isObject(manager)) {\n                    manager.onNotify(action, data);\n                }\n            }\n        };\n\n        return new EventsManagerFactory();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Fabric Manager\n *\n * Manages all of the fabrics in the browser. The manager uses the\n * RegionConnection to load the fabrics, update the fabrics, and listen for\n * notification events about fabrics.\n */\n\nangular.module('MAAS').factory(\n    'FabricsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', 'VLANsManager',\n    function(\n    $q, $rootScope, RegionConnection, Manager, VLANsManager) {\n\n        function FabricsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"fabric\";\n\n            // Listen for notify events for the fabric object.\n            var self = this;\n            RegionConnection.registerNotifier(\"fabric\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        FabricsManager.prototype = new Manager();\n\n        // Given a Fabric object, returns its display name.\n        FabricsManager.prototype.getName = function(fabric) {\n            if(!angular.isObject(fabric)) {\n                return;\n            }\n            if(angular.isString(fabric.name)) {\n                return fabric.name;\n            } else {\n                return this._handler + \"-\" + fabric[this._pk];\n            }\n        };\n\n        // Delete the Fabric.\n        FabricsManager.prototype.deleteFabric = function(fabric) {\n            return RegionConnection.callMethod(\n                \"fabric.delete\", { \"id\": fabric.id }, true);\n        };\n\n        // Create a Fabric.\n        FabricsManager.prototype.create = function(fabric) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"fabric.create\", fabric);\n        };\n\n\n        return new FabricsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS General Manager\n *\n * Manager for general information from the region. The general handler on the\n * region side does not push information to the client. This manager uses\n * polling to grab this data periodically from the region.\n *\n * This manage provides different pieces of data and is structure differently\n * than extending the Manager service. It still provides the Manager service\n * interface allowing the ManagerHelperService to load this manager.\n */\n\nangular.module('MAAS').factory(\n    'GeneralManager',\n    ['$q', '$timeout', 'RegionConnection', 'ErrorService',\n    function($q, $timeout, RegionConnection, ErrorService) {\n\n        // Constructor\n        function GeneralManager() {\n            // Holds the available endpoints and its data.\n            this._data = {\n                machine_actions: {\n                    method: \"general.machine_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                device_actions: {\n                    method: \"general.device_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                region_controller_actions: {\n                    method: \"general.region_controller_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                rack_controller_actions: {\n                    method: \"general.rack_controller_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                region_and_rack_controller_actions: {\n                    method: \"general.region_and_rack_controller_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                architectures: {\n                    method: \"general.architectures\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                known_architectures: {\n                    method: \"general.known_architectures\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                pockets_to_disable: {\n                    method: \"general.pockets_to_disable\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                components_to_disable: {\n                    method: \"general.components_to_disable\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                hwe_kernels: {\n                    method: \"general.hwe_kernels\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                min_hwe_kernels: {\n                    method: \"general.min_hwe_kernels\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                default_min_hwe_kernel: {\n                    method: \"general.default_min_hwe_kernel\",\n                    data: { text: '' },\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        oldData.text = newData;\n                    }\n                },\n                osinfo: {\n                    method: \"general.osinfo\",\n                    data: {},\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    isEmpty: function(data) {\n                        var osystems = data.osystems;\n                        return (angular.isUndefined(osystems) ||\n                            osystems.length === 0);\n                    },\n                    replaceData: function(oldData, newData) {\n                        angular.copy(newData, oldData);\n                    }\n                },\n                bond_options: {\n                    method: \"general.bond_options\",\n                    data: {},\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        angular.copy(newData, oldData);\n                    }\n                },\n                version: {\n                    method: \"general.version\",\n                    data: { text: null },\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        oldData.text = newData;\n                    }\n                },\n                power_types: {\n                    method: \"general.power_types\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        // Add new power types.\n                        var i, j, newPowerType, oldPowerType;\n                        for(i = 0; i < newData.length; i++) {\n                            newPowerType = newData[i];\n                            var newItem = true;\n                            for(j = 0; j < oldData.length; j++) {\n                                oldPowerType = oldData[j];\n                                if(newPowerType.name === oldPowerType.name) {\n                                    newItem = false;\n                                    break;\n                                }\n                            }\n\n                            // Item was previously not in the list so it is\n                            // inserted into the array.\n                            if(newItem) {\n                                oldData.push(newPowerType);\n                            }\n                        }\n\n                        // Remove any power types that are not included in\n                        // the newData.\n                        for(i = oldData.length - 1; i >= 0; i--) {\n                            oldPowerType = oldData[i];\n                            var found = false;\n                            for(j = 0; j < newData.length; j++) {\n                                newPowerType = newData[j];\n                                if(newPowerType.name === oldPowerType.name) {\n                                    found = true;\n                                    break;\n                                }\n                            }\n\n                            // Item was previously not in the list so it is\n                            // inserted into the array.\n                            if(!found) {\n                                oldData.splice(i, 1);\n                            }\n                        }\n                    }\n                },\n                release_options: {\n                    method: \"general.release_options\",\n                    data: {},\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        angular.copy(newData, oldData);\n                    }\n                }\n            };\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data.\n            this._pollTimeout = 10000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when an error occurs.\n            this._pollErrorTimeout = 3000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when the retrieved data is empty.\n            this._pollEmptyTimeout = 3000;\n\n            // Set to true when the items list should reload upon re-connection\n            // to the region.\n            this._autoReload = false;\n\n            // Use the same notify type as a default manager.\n            this._type = 'notify';\n\n            // The scopes that have loaded this manager.\n            this._scopes = [];\n        }\n\n        GeneralManager.prototype._getInternalData = function(name) {\n            var data = this._data[name];\n            if(angular.isUndefined(data)) {\n                throw new Error(\"Unknown data: \" + name);\n            }\n            return data;\n        };\n\n        // Return loaded data.\n        GeneralManager.prototype.getData = function(name) {\n            return this._getInternalData(name).data;\n        };\n\n        // Return true when all data has been loaded.\n        GeneralManager.prototype.isLoaded = function() {\n            var loaded = true;\n            angular.forEach(this._data, function(data) {\n                if(!data.loaded) {\n                    loaded = false;\n                }\n            });\n            return loaded;\n        };\n\n        // Return true when data has been loaded.\n        GeneralManager.prototype.isDataLoaded = function(name) {\n            return this._getInternalData(name).loaded;\n        };\n\n        // Returns true when the manager is currently polling.\n        GeneralManager.prototype.isPolling = function() {\n            var polling = false;\n            angular.forEach(this._data, function(data) {\n                if(data.polling.length > 0) {\n                    polling = true;\n                }\n            });\n            return polling;\n        };\n\n        // Returns true when the manager is currently polling for that data.\n        GeneralManager.prototype.isDataPolling = function(name) {\n            return this._getInternalData(name).polling;\n        };\n\n        // Starts the manager polling for data.\n        GeneralManager.prototype.startPolling = function(scope, name) {\n            var data = this._getInternalData(name);\n            var idx = data.polling.indexOf(scope);\n            if(idx === -1) {\n                data.polling.push(scope);\n                if(data.polling.length === 1) {\n                    // Polling needs to be started. This is the first scope\n                    // that is requesting for polling to be performed.\n                    this._poll(data);\n                }\n            }\n        };\n\n        // Stops the manager polling for data.\n        GeneralManager.prototype.stopPolling = function(scope, name) {\n            var data = this._getInternalData(name);\n            var idx = data.polling.indexOf(scope);\n            if(idx >= 0) {\n                data.polling.splice(idx, 1);\n            }\n            if(data.polling.length === 0 &&\n                angular.isObject(data.nextPromise)) {\n                $timeout.cancel(data.nextPromise);\n                data.nextPromise = null;\n            }\n        };\n\n        // Load the data from the region.\n        GeneralManager.prototype._loadData = function(data, raiseError) {\n            var replaceData = data.replaceData;\n            raiseError = raiseError || false;\n\n            // Set default replaceData function if data doesn't provide its\n            // own function.\n            if(angular.isUndefined(replaceData)) {\n                replaceData = function(oldData, newData) {\n                    oldData.length = 0;\n                    oldData.push.apply(oldData, newData);\n                };\n            }\n\n            return RegionConnection.callMethod(data.method).then(\n                function(newData) {\n                    replaceData(data.data, newData);\n                    data.loaded = true;\n                    return data.data;\n                }, function(error) {\n                    if(raiseError) {\n                        ErrorService.raiseError(error);\n                    }\n                    return error;\n                });\n        };\n\n        GeneralManager.prototype._pollAgain = function(data, timeout) {\n            var self = this;\n            data.nextPromise = $timeout(function() {\n                self._poll(data);\n            }, timeout);\n        };\n\n        // Polls for the data from the region.\n        GeneralManager.prototype._poll = function(data) {\n            var self = this;\n            var isEmpty = data.isEmpty;\n\n            // Set default isEmpty function if data doesn't provide its\n            // own function.\n            if(angular.isUndefined(isEmpty)) {\n                isEmpty = function(data) {\n                    return data.length === 0;\n                };\n            }\n\n            // Can only poll if connected.\n            if(!RegionConnection.isConnected()) {\n                this._pollAgain(data, this._pollErrorTimeout);\n                return;\n            }\n\n            return this._loadData(data, false).then(function(newData) {\n                var pollTimeout = self._pollTimeout;\n                if(isEmpty(data.data)) {\n                    pollTimeout = self._pollEmptyTimeout;\n                }\n                self._pollAgain(data, pollTimeout);\n                return newData;\n            }, function(error) {\n                // Don't raise the error, just log it and try again.\n                console.log(error);\n                self._pollAgain(data, self._pollErrorTimeout);\n            });\n        };\n\n        // Loads all the items. This implemented so the ManagerHelperService\n        // can work on this manager just like all the rest.\n        GeneralManager.prototype.loadItems = function() {\n            var self = this;\n            var defer = $q.defer();\n            var waitingCount = Object.keys(this._data).length;\n            var done = function() {\n                waitingCount -= 1;\n                if(waitingCount === 0) {\n                    defer.resolve();\n                }\n            };\n\n            angular.forEach(this._data, function(data) {\n                self._loadData(data, true).then(function() {\n                    done();\n                });\n            });\n\n            return defer.promise;\n        };\n\n        // Enables auto reloading of the item list on connection to region.\n        GeneralManager.prototype.enableAutoReload = function() {\n            if(!this._autoReload) {\n                this._autoReload = true;\n                var self = this;\n                this._reloadFunc = function() {\n                    self.loadItems();\n                };\n                RegionConnection.registerHandler(\"open\", this._reloadFunc);\n            }\n        };\n\n        // Disable auto reloading of the item list on connection to region.\n        GeneralManager.prototype.disableAutoReload = function() {\n            if(this._autoReload) {\n                RegionConnection.unregisterHandler(\"open\", this._reloadFunc);\n                this._reloadFunc = null;\n                this._autoReload = false;\n            }\n        };\n\n        return new GeneralManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS IPRange Manager\n *\n * Manages all of the IPRanges in the browser. The manager uses the\n * RegionConnection to load the IPRanges, update the IPRanges, and listen for\n * notification events about IPRanges.\n */\n\nangular.module('MAAS').factory(\n    'IPRangesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function IPRangesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"iprange\";\n\n            // Listen for notify events for the iprange object.\n            var self = this;\n            RegionConnection.registerNotifier(\"iprange\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        IPRangesManager.prototype = new Manager();\n\n        return new IPRangesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Machines Manager\n *\n * Manages all of the machines in the browser. This manager is used for the\n * machine listing and view pages. The manager is a subclass of NodesManager.\n */\n\nangular.module('MAAS').factory(\n    'MachinesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', function(\n            $q, $rootScope, RegionConnection, NodesManager) {\n\n        function MachinesManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"machine\";\n\n            this._metadataAttributes = {\n                \"architecture\": null,\n                \"status\": null,\n                \"owner\": null,\n                \"tags\": null,\n                \"pod\": function(machine) {\n                    return (machine.pod === undefined) ? '' :machine.pod.name;\n                },\n                \"zone\": function(machine) {\n                    return machine.zone.name;\n                },\n                \"subnets\": null,\n                \"fabrics\": null,\n                \"spaces\": null,\n                \"storage_tags\": null,\n                \"release\": function(machine) {\n                    if(machine.status_code === 6 || machine.status_code === 9) {\n                        return machine.osystem + \"/\" + machine.distro_series;\n                    } else {\n                        return '';\n                    }\n                }\n            };\n\n            // Listen for notify events for the machine object.\n            var self = this;\n            RegionConnection.registerNotifier(\"machine\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n\n        }\n        MachinesManager.prototype = new NodesManager();\n\n        MachinesManager.prototype.mountSpecialFilesystem =\n            function(machine, fstype, mount_point, mount_options) {\n                var method = this._handler + \".mount_special\";\n                var params = {\n                    system_id: machine.system_id,\n                    fstype: fstype,\n                    mount_point: mount_point,\n                    mount_options: mount_options\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        MachinesManager.prototype.unmountSpecialFilesystem =\n            function(machine, mount_point) {\n                var method = this._handler + \".unmount_special\";\n                var params = {\n                    system_id: machine.system_id,\n                    mount_point: mount_point\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        return new MachinesManager();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS NodeResultsManager Manager\n *\n * Manages all of the NodeResults in the browser. The manager uses the\n * RegionConnection to load the NodeResults, and listen for\n * notification events about NodeResults.\n */\n\nangular.module('MAAS').factory(\n    'NodeResultsManagerFactory', ['RegionConnection', 'Manager',\n    function(RegionConnection, Manager) {\n\n        function NodeResultsManager(node, factory) {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"noderesult\";\n            this._node = node;\n            this._factory = factory;\n\n            // Store as an array to preserve order.\n            this.commissioning_results = [\n                {\n                    title: null,\n                    hardware_type: 0,\n                    results: {}\n                },\n                {\n                    title: \"CPU\",\n                    hardware_type: 1,\n                    results: {}\n                },\n                {\n                    title: \"Memory\",\n                    hardware_type: 2,\n                    results: {}\n                },\n                {\n                    title: \"Storage\",\n                    hardware_type: 3,\n                    results: {}\n                }\n            ];\n            this.testing_results = [\n                {\n                    title: \"CPU\",\n                    hardware_type: 1,\n                    results: {}\n                },\n                {\n                    title: \"Memory\",\n                    hardware_type: 2,\n                    results: {}\n                },\n                {\n                    title: \"Storage\",\n                    hardware_type: 3,\n                    results: {}\n                },\n                {\n                    title: \"Other Results\",\n                    hardware_type: 0,\n                    results: {}\n                }\n            ];\n            this.installation_results = [];\n\n            // Listen for notify events for the ScriptResult object.\n            // This is noderesult instead of scriptresult because the\n            // class name is NodeResultHandler.\n            var self = this;\n            RegionConnection.registerNotifier(\"noderesult\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        NodeResultsManager.prototype = new Manager();\n\n        NodeResultsManager.prototype._getStorageSubtext = function(disk) {\n            var deviceinfo = '';\n            if(disk.model !== '') {\n                deviceinfo += \"Model: \" + disk.model;\n            }\n            if(disk.serial !== '') {\n                if(deviceinfo !== '') {\n                    deviceinfo += ', ';\n                }\n                deviceinfo += \"Serial: \" + disk.serial;\n            }\n            if(deviceinfo !== '') {\n                return '/dev/' + disk.name + ' (' + deviceinfo + ')';\n            }else{\n                return '/dev/' + disk.name;\n            }\n        };\n\n        NodeResultsManager.prototype._updateObject = function(\n            existing, updated) {\n            angular.forEach(updated, function(value, key) {\n                if(existing[key] !== value && key !== 'showing_results' &&\n                   key !== 'showing_history' && key !== 'showing_menu' &&\n                   key !== '$selected') {\n                    existing[key] = value;\n                }\n            });\n        };\n\n        NodeResultsManager.prototype._addOrReplace = function(results, result) {\n            var i;\n            for(i = 0; i < results.length; i++) {\n                if(results[i].name === result.name) {\n                    // Object already exists, update fields.\n                    result.$selected = results[i].$selected;\n                    result.showing_results = results[i].showing_results;\n                    result.showing_history = results[i].showing_history;\n                    result.showing_menu = results[i].showing_menu;\n                    angular.copy(result, results[i]);\n                    return;\n                }\n            }\n            // No result with the same name exists, add it to the sorted list.\n            for(i = 0; i < results.length; i++) {\n                if(results[i].name > result.name) {\n                    results.splice(i, 0, result);\n                    return;\n                }\n            }\n            results.push(result);\n        };\n\n        NodeResultsManager.prototype._processItem = function(result) {\n            var results;\n            result.showing_results = false;\n            result.showing_history = false;\n            result.showing_menu = false;\n            result.result_section = \"scripts\";\n\n            if(result.result_type === 0) {\n                results = this.commissioning_results;\n            } else if(result.result_type === 1) {\n                // Installation results are not split into hardware types or\n                // have subtext labels.\n                this._addOrReplace(this.installation_results, result);\n                return;\n            } else {\n                // Store all remaining result types as test results in case\n                // another result type is ever added.\n                results = this.testing_results;\n                result.result_section = \"tests\";\n            }\n            var i;\n            // Fallback to storing results in other results incase a new type\n            // is added\n            var hardware_type_results = results[3];\n            for(i = 0; i < results.length; i++) {\n                if(results[i].hardware_type === result.hardware_type) {\n                    hardware_type_results = results[i].results;\n                    break;\n                }\n            }\n\n            if(result.hardware_type === 3 &&\n               result.physical_blockdevice !== null) {\n                // Storage results are split into individual components.\n                var disk, subtext;\n                // If the storage result is associated with a specific\n                // component generate subtext for that component.\n                for(i = 0; i < this._node.disks.length; i++) {\n                    disk = this._node.disks[i];\n                    if(disk.id === result.physical_blockdevice) {\n                        subtext = this._getStorageSubtext(disk);\n                        if(!angular.isArray(\n                            hardware_type_results[subtext])) {\n                                hardware_type_results[subtext] = [];\n                        }\n                        this._addOrReplace(\n                            hardware_type_results[subtext], result);\n                        break;\n                    }\n                }\n            } else {\n                // Other hardware types are not split into individual\n                // components.\n                if(!angular.isArray(hardware_type_results[null])) {\n                    hardware_type_results[null] = [];\n                }\n                this._addOrReplace(hardware_type_results[null], result);\n            }\n        };\n\n        NodeResultsManager.prototype._removeItem = function(result) {\n            var idx = this._getIndexOfItem(this._items, result.id);\n            if(idx >= 0) {\n                this._updateMetadata(this._items[idx], \"delete\");\n            }\n            this._removeItemByIdFromArray(this._items, result.id);\n            this._removeItemByIdFromArray(this._selectedItems, result.id);\n\n            var self = this;\n            angular.forEach(this.commissioning_results, function(hw_type) {\n                angular.forEach(hw_type.results, function(results, subtext) {\n                    self._removeItemByIdFromArray(results, result.id);\n                    if(results.length === 0)\n                    {\n                        delete hw_type.results[subtext];\n                    }\n                });\n            });\n            angular.forEach(this.testing_results, function(hw_type) {\n                angular.forEach(hw_type.results, function(results, subtext) {\n                    self._removeItemByIdFromArray(results, result.id);\n                    if(results.length === 0)\n                    {\n                        delete hw_type.results[subtext];\n                    }\n                });\n            });\n            this._removeItemByIdFromArray(this.installation_results, result.id);\n        };\n\n        // Return the list of ScriptResults for the given node when retrieving\n        // the initial list.\n        NodeResultsManager.prototype._initBatchLoadParameters = function() {\n            var ret = {\n                \"system_id\": this._node.system_id\n            };\n            // Limit the results returned to what can be viewed.\n            if(this._area === \"summary\") {\n                ret.has_surfaced = true;\n                ret.result_type = 2;\n            }else if(this._area === \"testing\") {\n                ret.result_type = 2;\n            }else if(this._area === \"commissioning\") {\n                ret.result_type = 0;\n            }else if(this._area === \"logs\") {\n                ret.result_type = 1;\n            }\n            return ret;\n        };\n\n        // Destroys itself. Removes self from the NodeResultsManagerFactory.\n        NodeResultsManager.prototype.destroy = function() {\n            this._factory.destroyManager(this);\n\n            // If this manager has ever loaded then the region is sending\n            // results from this node. Tell the RegionConnection to stop.\n            if(this.isLoaded()) {\n                var method = this._handler + \".clear\";\n                RegionConnection.callMethod(method, {\n                    system_id: this._node.system_id\n                });\n            }\n        };\n\n        // Get result data.\n        NodeResultsManager.prototype.get_result_data = function(\n            script_id, data_type) {\n            var method = this._handler + \".get_result_data\";\n            var params = {\n                id: script_id,\n                data_type: data_type\n            };\n            return RegionConnection.callMethod(method, params);\n        };\n\n        // Factory that holds all created NodeResultsManagers.\n        function NodeResultsManagerFactory() {\n            // Holds a list of all NodeResultsManagers that have been created.\n            this._managers = [];\n        }\n\n        // Gets the NodeResultsManager for the nodes with node_system_id.\n        NodeResultsManagerFactory.prototype._getManager = function(node) {\n            var i;\n            for(i = 0; i < this._managers.length; i++) {\n                if(this._managers[i]._node.system_id === node.system_id) {\n                    return this._managers[i];\n                }\n            }\n            return null;\n        };\n\n        // Gets the NodeResultsManager for the nodes system_id. Creates a new\n        // manager if one does not exist.\n        NodeResultsManagerFactory.prototype.getManager = function(\n            node, area) {\n            var manager = this._getManager(node);\n            if(!angular.isObject(manager)) {\n                // Not created so create it.\n                manager = new NodeResultsManager(node, this);\n                this._managers.push(manager);\n            }\n            manager._area = area;\n            if(area === \"commissioning\") {\n                manager.results = manager.commissioning_results;\n            }else if(area === \"logs\") {\n                manager.results = manager.installation_results;\n            }else{\n                manager.results = manager.testing_results;\n            }\n            return manager;\n        };\n\n        // Destroy the NodeResultsManager.\n        NodeResultsManagerFactory.prototype.destroyManager = function(manager) {\n            var idx = this._managers.indexOf(manager);\n            if(idx >= 0) {\n                this._managers.splice(idx, 1);\n            }\n        };\n\n        return new NodeResultsManagerFactory();\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes Manager\n *\n * Manages all of the nodes in the browser. This manager is used for the\n * machine and controller listing and view pages (as machines and controllers\n * are both Nodes).  The manager uses the RegionConnection to load the nodes,\n * update the nodes, and listen for notification events about nodes.\n */\n\nangular.module('MAAS').service(\n    'NodesManager',\n    ['$q', '$rootScope', '$timeout', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, $timeout, RegionConnection, Manager) {\n\n        function NodesManager() {\n            Manager.call(this);\n        }\n\n        NodesManager.prototype = new Manager();\n\n        // Create a node.\n        NodesManager.prototype.create = function(node) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the node to the list. Adding it here will cause angular\n            // to complain because the same object exist in the list.\n            return RegionConnection.callMethod(\n                this._handler + \".create\", node);\n        };\n\n        // Perform the action on the node.\n        NodesManager.prototype.performAction = function(\n            node, action, extra) {\n            if(!angular.isObject(extra)) {\n                extra = {};\n            }\n            return RegionConnection.callMethod(this._handler + \".action\", {\n                \"system_id\": node.system_id,\n                \"action\": action,\n                \"extra\": extra\n                });\n        };\n\n        // Check the power state for the node.\n        NodesManager.prototype.checkPowerState = function(node) {\n            return RegionConnection.callMethod(this._handler + \".check_power\", {\n                \"system_id\": node.system_id\n                }).then(function(state) {\n                    node.power_state = state;\n                    return state;\n                }, function(error) {\n                    node.power_state = \"error\";\n\n                    // Already been logged server side, but log it client\n                    // side so if they really care they can see why.\n                    console.log(error);\n\n                    // Return the state as error to the remaining callbacks.\n                    return \"error\";\n                });\n        };\n\n        // Create the physical interface on the node.\n        NodesManager.prototype.createPhysicalInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_physical\", params);\n            };\n\n        // Create the VLAN interface on the node.\n        NodesManager.prototype.createVLANInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_vlan\", params);\n            };\n\n        // Create the bond interface on the node.\n        NodesManager.prototype.createBondInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_bond\", params);\n            };\n\n        // Create the bridge interface on the node.\n        NodesManager.prototype.createBridgeInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_bridge\", params);\n            };\n\n        // Update the interface for the node.\n        NodesManager.prototype.updateInterface = function(\n            node, interface_id, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                params.interface_id = interface_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".update_interface\", params);\n            };\n\n        // Update an interface from a maas-obj-form.\n        NodesManager.prototype.updateInterfaceForm = function(\n            params) {\n                return RegionConnection.callMethod(\n                    this._handler + \".update_interface\", params);\n            };\n\n        // Delete the interface for the node.\n        NodesManager.prototype.deleteInterface = function(\n            node, interface_id) {\n                var params = {\n                    system_id: node.system_id,\n                    interface_id: interface_id\n                };\n                return RegionConnection.callMethod(\n                    this._handler + \".delete_interface\", params);\n            };\n\n        // Create or update the link to the subnet for the interface.\n        NodesManager.prototype.linkSubnet = function(\n            node, interface_id, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                params.interface_id = interface_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".link_subnet\", params);\n            };\n\n        // Remove the link to the subnet for the interface.\n        NodesManager.prototype.unlinkSubnet = function(\n            node, interface_id, link_id) {\n                var params = {\n                    system_id: node.system_id,\n                    interface_id: interface_id,\n                    link_id: link_id\n                };\n                return RegionConnection.callMethod(\n                    this._handler + \".unlink_subnet\", params);\n            };\n\n        // Send the update information to the region.\n        NodesManager.prototype.updateFilesystem = function(\n            node, block_id, partition_id, fstype, mount_point, mount_options,\n            tags) {\n                var self = this;\n                var method = this._handler + \".update_filesystem\";\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id,\n                    partition_id: partition_id,\n                    fstype: fstype,\n                    mount_point: mount_point,\n                    mount_options: mount_options,\n                    tags: tags\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete the disk.\n        NodesManager.prototype.deleteDisk = function(\n            node, block_id) {\n                var self = this;\n                var method = this._handler + \".delete_disk\";\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete the partition.\n        NodesManager.prototype.deletePartition = function(\n            node, partition_id) {\n                var self = this;\n                var method = this._handler + \".delete_partition\";\n                var params = {\n                    system_id: node.system_id,\n                    partition_id: partition_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete the disk or partition.\n        NodesManager.prototype.deleteVolumeGroup = function(\n            node, volume_group_id) {\n                var self = this;\n                var method = this._handler + \".delete_volume_group\";\n                var params = {\n                    system_id: node.system_id,\n                    volume_group_id: volume_group_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete a cache set.\n        NodesManager.prototype.deleteCacheSet = function(\n            node, cache_set_id) {\n                var self = this;\n                var method = this._handler + \".delete_cache_set\";\n                var params = {\n                    system_id: node.system_id,\n                    cache_set_id: cache_set_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete a filesystem.\n        NodesManager.prototype.deleteFilesystem = function(\n            node, blockdevice_id, partition_id, filesystem_id) {\n                var self = this;\n                var method = this._handler + \".delete_filesystem\";\n                var params = {\n                    system_id: node.system_id,\n                    blockdevice_id: blockdevice_id,\n                    partition_id: partition_id,\n                    filesystem_id: filesystem_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Create a new partition.\n        NodesManager.prototype.createPartition = function(\n            node, block_id, size, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                var self = this;\n                var method = this._handler + \".create_partition\";\n                params.system_id = node.system_id;\n                params.block_id = block_id;\n                params.partition_size = size;\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Create a new cache set.\n        NodesManager.prototype.createCacheSet = function(\n            node, block_id, partition_id) {\n                var self = this;\n                var method = this._handler + \".create_cache_set\";\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id,\n                    partition_id: partition_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Create a new bcache device.\n        NodesManager.prototype.createBcache = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_bcache\", params);\n            };\n\n        // Create a new RAID device.\n        NodesManager.prototype.createRAID = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_raid\", params);\n            };\n\n        // Create a new volume group.\n        NodesManager.prototype.createVolumeGroup = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_volume_group\", params);\n            };\n\n        // Create a new logical volume.\n        NodesManager.prototype.createLogicalVolume = function(\n            node, volume_group_id, name, size, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                var self = this;\n                var method = this._handler + \".create_logical_volume\";\n                params.system_id = node.system_id;\n                params.volume_group_id = volume_group_id;\n                params.name = name;\n                params.size = size;\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Update a disk.\n        NodesManager.prototype.updateDisk = function(\n            node, block_id, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                params.block_id = block_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".update_disk\", params);\n            };\n\n        // Set disk as the boot disk.\n        NodesManager.prototype.setBootDisk = function(\n            node, block_id) {\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id\n                };\n                return RegionConnection.callMethod(\n                    this._handler + \".set_boot_disk\", params);\n            };\n\n        NodesManager.prototype.getSummaryXML = function(node) {\n            return RegionConnection.callMethod(\n                this._handler + \".get_summary_xml\",\n                {\"system_id\": node.system_id});\n        };\n\n        NodesManager.prototype.getSummaryYAML = function(node) {\n            return RegionConnection.callMethod(\n                this._handler + \".get_summary_yaml\",\n                {\"system_id\": node.system_id});\n        };\n\n        return NodesManager;\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Notifications Manager.\n *\n * Manages notifications in the browser. Uses RegionConnection to load\n * notifications, await new, updated, and deleted notifications, and to\n * dismiss them.\n */\n\nangular.module('MAAS').factory(\n    'NotificationsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n     function($q, $rootScope, RegionConnection, Manager) {\n\n        function NotificationsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"notification\";\n\n            // Listen for notify events for the notification object.\n            RegionConnection.registerNotifier(\n                \"notification\", angular.bind(this, this.onNotify));\n        }\n\n        NotificationsManager.prototype = new Manager();\n        NotificationsManager.prototype.dismiss = function(notification) {\n            return RegionConnection.callMethod(\n                \"notification.dismiss\", {id: notification.id});\n        };\n\n        return new NotificationsManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS PackageRepositories Manager\n *\n * Manages all of the PackageRepositories in the browser. The manager uses the\n * RegionConnection to load the PackageRepositories, update them, and listen\n * for notification events about them.\n */\n\nangular.module('MAAS').factory(\n    'PackageRepositoriesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function PackageRepositoriesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"packagerepository\";\n\n            // Listen for notify events for the PackageRepository object.\n            var self = this;\n            RegionConnection.registerNotifier(\"packagerepository\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        PackageRepositoriesManager.prototype = new Manager();\n\n        // Create the repository.\n        PackageRepositoriesManager.prototype.create = function(repository) {\n            return RegionConnection.callMethod(\n                this._handler + \".create\", repository, true);\n        };\n\n        return new PackageRepositoriesManager();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Pods Manager\n *\n * Manages all of the pods in the browser. The manager uses the\n * RegionConnection to load the pods, update the pods, and listen for\n * notification events about pods.\n */\n\nangular.module('MAAS').service(\n    'PodsManager',\n    ['$q', '$rootScope', '$timeout', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, $timeout, RegionConnection, Manager) {\n\n        function PodsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"pod\";\n\n            // Listen for notify events for the pod object.\n            var self = this;\n            RegionConnection.registerNotifier(\"pod\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        PodsManager.prototype = new Manager();\n\n        // Refresh the pod information\n        PodsManager.prototype.refresh = function(pod) {\n            var self = this;\n            return RegionConnection.callMethod(\"pod.refresh\", pod).then(\n                function(pod) {\n                    self._replaceItem(pod);\n                    return pod;\n                });\n        };\n\n        // Compose a machine in the pod.\n        PodsManager.prototype.compose = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\"pod.compose\", params).then(\n                function(pod) {\n                    self._replaceItem(pod);\n                    return pod;\n                });\n        };\n\n        return new PodsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Region Connection\n *\n * Provides the websocket connection between the client and the MAAS regiond\n * service.\n */\n\nangular.module('MAAS').factory(\n    'RegionConnection',\n    ['$q', '$rootScope', '$timeout', '$window', '$cookies', function(\n        $q, $rootScope, $timeout, $window, $cookies) {\n\n        // Message types\n        var MSG_TYPE = {\n            REQUEST: 0,\n            RESPONSE: 1,\n            NOTIFY: 2\n        };\n\n        // Response types\n        var RESPONSE_TYPE = {\n            SUCCESS: 0,\n            ERROR: 1\n        };\n\n        // Constructor\n        function RegionConnection() {\n            this.callbacks = {};\n            this.requests = {};\n            this.requestId = 0;\n            this.url = null;\n            this.websocket = null;\n            this.connected = false;\n            this.autoReconnect = true;\n            this.retryTimeout = 5000;\n            this.error = null;\n\n            // Defer used for defaultConnect. If defaultConnect is called\n            // quickly only the first one will start the connection. The\n            // remaining will recieve this defer.\n            this.defaultConnectDefer = null;\n\n            // List of functions to call when a WebSocket event occurs. Each\n            // function will get the WebSocket event passed to it.\n            this.handlers = {\n                open: [],\n                error: [],\n                close: []\n            };\n\n            // Object containing a fields with list of functions. When\n            // a NOTIFY message is received it will match the name to a field\n            // in this object. If the field exists in the object the list\n            // of functions will be called with the action and obj_id.\n            this.notifiers = {};\n        }\n\n        // Return a new request id.\n        RegionConnection.prototype.newRequestId = function() {\n            this.requestId += 1;\n            return this.requestId;\n        };\n\n        // Register event handler.\n        RegionConnection.prototype.registerHandler = function (name, func) {\n            if(!angular.isDefined(this.handlers[name])) {\n                throw new Error(\"Invalid handler: \" + name);\n            }\n            if(!angular.isFunction(func)) {\n                throw new Error(\"Requires a function to register a handler.\");\n            }\n            this.handlers[name].push(func);\n        };\n\n        // Unregister event handler.\n        RegionConnection.prototype.unregisterHandler = function (name, func) {\n            if(!angular.isDefined(this.handlers[name])) {\n                throw new Error(\"Invalid handler: \" + name);\n            }\n            var idx = this.handlers[name].indexOf(func);\n            if(idx >= 0) {\n                this.handlers[name].splice(idx, 1);\n            }\n        };\n\n        // Register notification handler.\n        RegionConnection.prototype.registerNotifier = function(name, func) {\n            if(!angular.isFunction(func)) {\n                throw new Error(\"Requires a function to register a notifier.\");\n            }\n            if(angular.isUndefined(this.notifiers[name])) {\n                this.notifiers[name] = [];\n            }\n            this.notifiers[name].push(func);\n        };\n\n        // Unregister notification handler.\n        RegionConnection.prototype.unregisterNotifier = function(name, func) {\n            if(angular.isUndefined(this.notifiers[name])) {\n                return;\n            }\n            var idx = this.notifiers[name].indexOf(func);\n            if(idx >= 0) {\n                this.notifiers[name].splice(idx, 1);\n            }\n        };\n\n        // Return True if currently connected to region.\n        RegionConnection.prototype.isConnected = function() {\n            return this.connected;\n        };\n\n        // Builds the websocket connection.\n        RegionConnection.prototype.buildSocket = function(url) {\n            return new WebSocket(url);\n        };\n\n        // Opens the websocket connection.\n        RegionConnection.prototype.connect = function() {\n            this.url = this._buildUrl();\n            this.autoReconnect = true;\n            this.websocket = this.buildSocket(this.url);\n\n            var self = this;\n            this.websocket.onopen = function(evt) {\n                self.connected = true;\n                angular.forEach(self.handlers.open, function(func) {\n                    func(evt);\n                });\n            };\n            this.websocket.onerror = function(evt) {\n                angular.forEach(self.handlers.error, function(func) {\n                    func(evt);\n                });\n            };\n            this.websocket.onclose = function(evt) {\n                self.connected = false;\n                self.error = \"Unable to connect to: \" + self.url.split(\"?\")[0];\n                angular.forEach(self.handlers.close, function(func) {\n                    func(evt);\n                });\n                if(self.autoReconnect) {\n                    $timeout(function() {\n                        self.connect();\n                    }, self.retryTimeout);\n                }\n            };\n            this.websocket.onmessage = function(evt) {\n                self.onMessage(angular.fromJson(evt.data));\n            };\n        };\n\n        // Closes the websocket connection.\n        RegionConnection.prototype.close = function() {\n            this.autoReconnect = false;\n            this.websocket.close();\n            this.websocket = null;\n        };\n\n        // Return the protocol used for the websocket connection.\n        RegionConnection.prototype._getProtocol = function() {\n            return $window.location.protocol;\n        };\n\n        // Return connection url to websocket from current location and\n        // html options.\n        RegionConnection.prototype._buildUrl = function() {\n            var host = $window.location.hostname;\n            var port = $window.location.port;\n            var path = $window.location.pathname;\n            var proto = 'ws';\n            if (this._getProtocol() === 'https:') {\n                proto = 'wss';\n            }\n\n            // Path and port can be overridden by href and data-websocket-port\n            // in the base element respectively.\n            var base = angular.element(\"base\");\n            if(angular.isDefined(base)) {\n                var newPath = base.attr(\"href\");\n                if(angular.isDefined(newPath)) {\n                    path = newPath;\n                }\n                var newPort = base.data(\"websocket-port\");\n                if(angular.isDefined(newPort)) {\n                    port = newPort;\n                }\n            }\n\n            // Append final '/' if missing from end of path.\n            if(path[path.length - 1] !== '/') {\n                path += '/';\n            }\n\n            // Build the URL. Include the :port only if it has a value.\n            url = proto + \"://\" + host;\n            if(angular.isString(port) && port.length > 0){\n                url += \":\" + port;\n            }\n            url += path + \"ws\";\n\n            // Include the csrftoken in the URL if it's defined.\n            var csrftoken;\n            if(angular.isFunction($cookies.get)) {\n                csrftoken = $cookies.get('csrftoken');\n            } else {\n                csrftoken = $cookies.csrftoken;\n            }\n            if(angular.isDefined(csrftoken)) {\n                url += '?csrftoken=' + encodeURIComponent(csrftoken);\n            }\n\n            return url;\n        };\n\n        // Opens the default websocket connection.\n        RegionConnection.prototype.defaultConnect = function() {\n            // Already been called but the connection has not been completed.\n            if(angular.isObject(this.defaultConnectDefer)) {\n                return this.defaultConnectDefer.promise;\n            }\n\n            // Already connected.\n            var defer;\n            if(this.isConnected()) {\n                // Create a new defer as the defaultConnectDefer would\n                // have already been resolved.\n                defer = $q.defer();\n\n                // Cannot resolve the defer inline as it hasn't been given\n                // back to the caller. It will be called in the next loop.\n                $timeout(defer.resolve);\n                return defer.promise;\n            }\n\n            // Start the connection.\n            var self = this, opened, errored;\n            defer = this.defaultConnectDefer = $q.defer();\n            opened = function(evt) {\n                this.defaultConnectDefer = null;\n                self.unregisterHandler(\"open\", opened);\n                self.unregisterHandler(\"error\", errored);\n                $rootScope.$apply(defer.resolve(evt));\n            };\n            errored = function(evt) {\n                this.defaultConnectDefer = null;\n                self.unregisterHandler(\"open\", opened);\n                self.unregisterHandler(\"error\", errored);\n                $rootScope.$apply(defer.reject(evt));\n            };\n            this.registerHandler(\"open\", opened);\n            this.registerHandler(\"error\", errored);\n            this.connect();\n            return defer.promise;\n        };\n\n        // Called when a message is received.\n        RegionConnection.prototype.onMessage = function(msg) {\n            // Response\n            if(msg.type === MSG_TYPE.RESPONSE) {\n                this.onResponse(msg);\n            // Notify\n            } else if(msg.type === MSG_TYPE.NOTIFY) {\n                this.onNotify(msg);\n            }\n        };\n\n        // Called when a response message is recieved.\n        RegionConnection.prototype.onResponse = function(msg) {\n            // Grab the registered defer from the callbacks list.\n            var defer = this.callbacks[msg.request_id];\n            var remembered_request = this.requests[msg.request_id];\n            if(angular.isDefined(defer)) {\n                if(msg.rtype === RESPONSE_TYPE.SUCCESS) {\n                    // Resolve the defer inside of the digest cycle, so any\n                    // update to an object or collection will trigger a\n                    // watcher.\n                    $rootScope.$apply(defer.resolve(msg.result));\n                } else if(msg.rtype === RESPONSE_TYPE.ERROR) {\n                    // Reject the defer since an error occurred.\n                    if(angular.isObject(remembered_request)) {\n                        $rootScope.$apply(defer.reject({\n                            \"error\": msg.error,\n                            \"request\": remembered_request\n                        }));\n                    } else {\n                        $rootScope.$apply(defer.reject(msg.error));\n                    }\n                }\n                // Remove the defer from the callback list.\n                delete this.callbacks[msg.request_id];\n                delete this.requests[msg.request_id];\n            }\n        };\n\n        // Called when a notify response is recieved.\n        RegionConnection.prototype.onNotify = function(msg) {\n            var handlers = this.notifiers[msg.name];\n            if(angular.isArray(handlers)) {\n                angular.forEach(handlers, function(handler) {\n                    handler(msg.action, msg.data);\n                });\n            }\n        };\n\n        // Call method on the region.\n        RegionConnection.prototype.callMethod = function(\n                method, params, remember) {\n            var defer = $q.defer();\n            var request_id = this.newRequestId();\n            var request = {\n                type: MSG_TYPE.REQUEST,\n                request_id: request_id,\n                method: method,\n                params: params\n            };\n            this.callbacks[request_id] = defer;\n            // If requested, remember what the details of the request were,\n            // so that the controller can refresh its memory.\n            if (remember) {\n                this.requests[request_id] = request;\n            }\n            this.websocket.send(angular.toJson(request));\n            return defer.promise;\n        };\n\n        return new RegionConnection();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS ScriptsManager Manager\n *\n * Manages all of the Scripts in the browser. The manager uses the\n * RegionConnection to load the Scripts, and listen for notification\n * events about Scripts.\n */\n\nangular.module('MAAS').factory(\n    'ScriptsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function ScriptsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"script\";\n\n            // Listen for notify events for the Script object.\n            var self = this;\n            RegionConnection.registerNotifier(\"script\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        ScriptsManager.prototype = new Manager();\n\n        return new ScriptsManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Service Manager\n *\n * Manages all of the services for a node in the browser. The manager uses the\n * RegionConnection to load the services and listen for service notifications.\n */\n\nangular.module('MAAS').factory(\n    'ServicesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function ServicesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"service\";\n\n            // Listen for notify events for the service object.\n            var self = this;\n            RegionConnection.registerNotifier(\"service\",\n                function(action, data) {\n                    self.onNotify(action, data);\n            });\n        }\n\n        ServicesManager.prototype = new Manager();\n\n        return new ServicesManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Space Manager\n *\n * Manages all of the spaces in the browser. The manager uses the\n * RegionConnection to load the spaces, update the spaces, and listen for\n * notification events about spaces.\n */\n\nangular.module('MAAS').factory(\n    'SpacesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', 'SubnetsManager',\n    function($q, $rootScope, RegionConnection, Manager, SubnetsManager) {\n\n        function SpacesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"space\";\n\n            // Listen for notify events for the space object.\n            var self = this;\n            RegionConnection.registerNotifier(\"space\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        SpacesManager.prototype = new Manager();\n\n        // Create a space.\n        SpacesManager.prototype.create = function(space) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"space.create\", space);\n        };\n\n\n        // Delete the space.\n        SpacesManager.prototype.deleteSpace = function(space) {\n            return RegionConnection.callMethod(\"space.delete\", space);\n        };\n\n        return new SpacesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS SSHKey Manager\n *\n * Manages all of the SSHKeys in the browser. The manager uses the\n * RegionConnection to load the SSHKeys, update the SSHKeys, and\n * listen for notification events about SSHKeys.\n */\n\nangular.module('MAAS').factory(\n    'SSHKeysManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function SSHKeysManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"sshkey\";\n\n            // Listen for notify events for the sshkey object.\n            var self = this;\n            RegionConnection.registerNotifier(\"sshkey\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        SSHKeysManager.prototype = new Manager();\n\n        // Imports SSH keys from a launchpad and github.\n        SSHKeysManager.prototype.importKeys = function(params) {\n            // We don't add the results to the list because a NOTIFY event will\n            // add the ssh key to the list. Adding it here will cause angular\n            // to complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"sshkey.import_keys\", params);\n        };\n\n        return new SSHKeysManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS StaticRoute Manager\n *\n * Manages all of the StaticRoutes in the browser. The manager uses the\n * RegionConnection to load the StaticRoutes, update the StaticRoutes, and\n * listen for notification events about StaticRoutes.\n */\n\nangular.module('MAAS').factory(\n    'StaticRoutesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function StaticRoutesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"staticroute\";\n\n            // Listen for notify events for the staticroute object.\n            var self = this;\n            RegionConnection.registerNotifier(\"staticroute\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        StaticRoutesManager.prototype = new Manager();\n\n        return new StaticRoutesManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Subnet Manager\n *\n * Manages all of the subnets in the browser. The manager uses the\n * RegionConnection to load the subnets, update the subnets, and listen for\n * notification events about subnets.\n */\n\nangular.module('MAAS').factory(\n    'SubnetsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function SubnetsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"subnet\";\n\n            // Listen for notify events for the subnet object.\n            var self = this;\n            RegionConnection.registerNotifier(\"subnet\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        SubnetsManager.prototype = new Manager();\n\n        // Return the name of the subnet. Will include the name of the subnet\n        // in '(', ')' if it exists and not the same as the cidr.\n        SubnetsManager.prototype.getName = function(subnet) {\n            if(!angular.isObject(subnet)) {\n                return \"\";\n            }\n\n            var name = subnet.cidr;\n            if(angular.isString(subnet.name) &&\n                subnet.name !== \"\" &&\n                subnet.name !== subnet.cidr) {\n                name += \" (\" + subnet.name + \")\";\n            }\n            return name;\n        };\n\n        SubnetsManager.prototype.getLargestRange = function(subnet) {\n            var largest_range = {num_addresses: 0, start: \"\", end: \"\"};\n            angular.forEach(subnet.statistics.ranges, function(iprange) {\n                if(angular.equals(iprange.purpose, [\"unused\"]) &&\n                        iprange.num_addresses > largest_range.num_addresses) {\n                    largest_range = iprange;\n                }\n            });\n            return largest_range;\n        };\n\n        SubnetsManager.prototype.hasDynamicRange = function(subnet) {\n            var i;\n            for(i = 0; i < subnet.statistics.ranges.length ; i++) {\n                var iprange = subnet.statistics.ranges[i];\n                if(iprange.purpose.indexOf(\"dynamic\") !== -1) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Create a subnet.\n        SubnetsManager.prototype.create = function(subnet) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"subnet.create\", subnet);\n        };\n\n        // Delete the subnet.\n        SubnetsManager.prototype.deleteSubnet = function(subnet) {\n            return RegionConnection.callMethod(\"subnet.delete\", {\n                \"id\": subnet.id\n            });\n        };\n\n        // Perform a neighbour discovery scan on the subnet.\n        SubnetsManager.prototype.scanSubnet = function(subnet) {\n            return RegionConnection.callMethod(\"subnet.scan\", {\n                \"id\": subnet.id\n            });\n        };\n\n        return new SubnetsManager();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Switches Manager\n *\n * Manages all of the switches in the browser. This manager is used for the\n * switches listing and the switches view page. The manager uses the\n * RegionConnection to load the switches, update the switches, and listen for\n * notification events about switches.\n */\n\nangular.module('MAAS').factory(\n    'SwitchesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', function(\n            $q, $rootScope, RegionConnection, NodesManager) {\n\n        function SwitchesManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"switch\";\n            this._metadataAttributes = {\n                \"owner\": null,\n                \"subnets\": null,\n                \"tags\": null,\n                \"zone\": function(device) {\n                    return device.zone.name;\n                }\n            };\n\n            // Listen for notify events for the switch object.\n            var self = this;\n            RegionConnection.registerNotifier(\"switch\", function(action, data) {\n                self.onNotify(action, data);\n            });\n        }\n\n        SwitchesManager.prototype = new NodesManager();\n\n        // Create a switch.\n        SwitchesManager.prototype.create = function(node) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the device to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"switch.create\", node);\n        };\n\n        // Perform the action on the switch.\n        SwitchesManager.prototype.performAction = function(\n            device, action, extra) {\n\n            if(!angular.isObject(extra)) {\n                extra = {};\n            }\n            return RegionConnection.callMethod(\"switch.action\", {\n                \"system_id\": device.system_id,\n                \"action\": action,\n                \"extra\": extra\n                });\n        };\n\n        return new SwitchesManager();\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Tag Manager\n *\n * Manages all of the tags in the browser. The manager uses the\n * RegionConnection to load the tags, update the tags, and listen for\n * notification events about tags.\n */\n\nangular.module('MAAS').factory(\n    'TagsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function TagsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"tag\";\n\n            // Listen for notify events for the tag object.\n            var self = this;\n            RegionConnection.registerNotifier(\"tag\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        TagsManager.prototype = new Manager();\n\n        // Helper for autocomplete that will return a string of tags that\n        // contain the query text.\n        TagsManager.prototype.autocomplete = function(query) {\n            var matching = [];\n            angular.forEach(this._items, function(item) {\n                if(item.name.indexOf(query) > -1) {\n                    matching.push(item.name);\n                }\n            });\n            return matching;\n        };\n\n        return new TagsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS User Manager\n *\n * Manages all of the users in the browser. The manager uses the\n * RegionConnection to load the users, update the users, and listen for\n * notification events about users.\n */\n\nangular.module('MAAS').factory(\n    'UsersManager',\n    ['RegionConnection', 'Manager', 'ErrorService',\n    function(RegionConnection, Manager, ErrorService) {\n\n        function UsersManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"user\";\n\n            // Holds the authenticated user for the connection.\n            this._authUser = null;\n\n            // Listen for notify events for the user object.\n            var self = this;\n            RegionConnection.registerNotifier(\"user\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        UsersManager.prototype = new Manager();\n\n        // Get the authenticated user for the connection.\n        UsersManager.prototype.getAuthUser = function() {\n            return this._authUser;\n        };\n\n        // Return true if the authenticated user is super user.\n        UsersManager.prototype.isSuperUser = function() {\n            var authUser = this.getAuthUser();\n            if(!angular.isObject(authUser)) {\n                return false;\n            }\n            return authUser.is_superuser;\n        };\n\n        // Return true if the authenticated user has uploaded at\n        // least one SSH key.\n        UsersManager.prototype.getSSHKeyCount = function() {\n            authuser = this._authUser;\n            if(!angular.isObject(authuser)) {\n                return 0;\n            }\n            return authuser.sshkeys_count;\n        };\n\n        // Load the authenticated user.\n        UsersManager.prototype._loadAuthUser = function() {\n            var self = this;\n            return RegionConnection.callMethod(\"user.auth_user\", {}).then(\n                function(user) {\n                    if(angular.isObject(self._authUser)) {\n                        // Copy the user into the authUser. This keeps the\n                        // reference the same, not requiring another call to\n                        // getAuthUser.\n                        angular.copy(user, self._authUser);\n                    } else {\n                        self._authUser = user;\n                    }\n                    return self._authUser;\n                }, function(error) {\n                    ErrorService.raiseError(error);\n                });\n        };\n\n        UsersManager.prototype._replaceItem = function(item) {\n            Manager.prototype._replaceItem.call(this, item);\n\n            // Update the authenticated user if updated item has the\n            // same primary key.\n            if(angular.isObject(this._authUser) &&\n                this._authUser[this._pk] === item[this._pk]) {\n                // Copy the item into the authUser. This keeps the reference\n                // the same, not requiring another call to getAuthUser.\n                angular.copy(item, this._authUser);\n            }\n        };\n\n        UsersManager.prototype.loadItems = function() {\n            // Load the auth user when all the items are loaded as well.\n            this._loadAuthUser();\n            return Manager.prototype.loadItems.call(this);\n        };\n\n        UsersManager.prototype.reloadItems = function() {\n            // Load the auth user when all the items are reloaded as well.\n            this._loadAuthUser();\n            return Manager.prototype.reloadItems.call(this);\n        };\n\n        // Mark the user as completed the intro.\n        UsersManager.prototype.markIntroComplete = function() {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"user.mark_intro_complete\", {}).then(\n                    function(user) {\n                        if(angular.isObject(self._authUser)) {\n                            // Copy the user into the authUser. This keeps the\n                            // reference the same, not requiring another call\n                            // to getAuthUser.\n                            angular.copy(user, self._authUser);\n                        } else {\n                            self._authUser = user;\n                        }\n                        return self._authUser;\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n        };\n\n        return new UsersManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS VLAN Manager\n *\n * Manages all of the VLANs in the browser. The manager uses the\n * RegionConnection to load the VLANs, update the VLANs, and listen for\n * notification events about VLANs.\n */\n\nangular.module('MAAS').factory(\n    'VLANsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', 'SubnetsManager',\n    function($q, $rootScope, RegionConnection, Manager, SubnetsManager) {\n\n        function VLANsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"vlan\";\n\n            // Listen for notify events for the vlan object.\n            var self = this;\n            RegionConnection.registerNotifier(\"vlan\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        VLANsManager.prototype = new Manager();\n\n        VLANsManager.prototype.getName = function(vlan) {\n            var name = vlan.vid;\n            if(vlan.vid === 0) {\n                name = \"untagged\";\n            } else if(angular.isString(vlan.name) && vlan.name !== \"\") {\n                name += \" (\" + vlan.name + \")\";\n            }\n            return name;\n        };\n\n        // Delete the VLAN.\n        VLANsManager.prototype.deleteVLAN = function(vlan) {\n            return RegionConnection.callMethod(\n                \"vlan.delete\", { \"id\": vlan.id }, true);\n        };\n\n        // This is needed for testing: in the normal course of things,\n        // rack_sids is generated entirely by the websocket handler.\n        VLANsManager.prototype.addRackController = function(vlan, rack) {\n            vlan.rack_sids.push(rack.system_id);\n        };\n\n        // Configure DHCP on the VLAN\n        VLANsManager.prototype.configureDHCP = function(\n           vlan, controllers, extra, relay_vlan) {\n           var params = {\n               \"id\": vlan.id,\n               \"controllers\": controllers,\n               \"extra\": extra\n           };\n           if(relay_vlan === null || angular.isNumber(relay_vlan)) {\n              params.relay_vlan = relay_vlan;\n           }\n           return RegionConnection.callMethod(\n                \"vlan.configure_dhcp\", params, true);\n        };\n\n        // Disable DHCP on the VLAN\n        VLANsManager.prototype.disableDHCP = function(vlan) {\n            return RegionConnection.callMethod(\n                \"vlan.configure_dhcp\", {\n                    \"id\": vlan.id,\n                    \"controllers\": [],\n                    \"relay_vlan\": null\n                }, true);\n        };\n\n        // Create a VLAN.\n        VLANsManager.prototype.create = function(vlan) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"vlan.create\", vlan);\n        };\n\n        return new VLANsManager();\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Zone Manager\n *\n * Manages all of the zones in the browser. The manager uses the\n * RegionConnection to load the zones, update the zones, and listen for\n * notification events about zones.\n */\n\nangular.module('MAAS').factory(\n    'ZonesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function ZonesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"zone\";\n\n            // Listen for notify events for the zone object.\n            var self = this;\n            RegionConnection.registerNotifier(\"zone\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        ZonesManager.prototype = new Manager();\n\n        // Return the default zone.\n        ZonesManager.prototype.getDefaultZone = function() {\n            if(this._items.length === 0) {\n                return null;\n            } else {\n                var i;\n                for(i=0;i<this._items.length;i++) {\n                    if(this._items[i].id === 0) {\n                        return this._items[i];\n                    }\n                }\n            }\n            return this._items[0];\n        };\n\n        return new ZonesManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter VLANs by Fabric.\n */\n\nangular.module('MAAS').filter('filterByFabric', function() {\n    return function(vlans, fabric) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(fabric)) {\n            id = fabric.id;\n        } else if(angular.isNumber(fabric)) {\n            id = fabric;\n        } else {\n            return filtered;\n        }\n        angular.forEach(vlans, function(vlan) {\n            if(vlan.fabric === id) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter Subnets by Space.\n */\n\nangular.module('MAAS').filter('filterBySpace', function() {\n    return function(objects, space) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(space)) {\n            id = space.id;\n        } else if(angular.isNumber(space)) {\n            id = space;\n        } else {\n            return filtered;\n        }\n        angular.forEach(objects, function(object) {\n            if(object.space === id) {\n                filtered.push(object);\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').filter('filterByNullSpace', function() {\n    return function(objects) {\n        var filtered = [];\n        angular.forEach(objects, function(object) {\n            if(object.space === null) {\n                filtered.push(object);\n            }\n        });\n        return filtered;\n    };\n});","/* Copyright 2016-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Filter objects with subnet foreign key references by a particular subnet.\n */\n\nangular.module('MAAS').filter('filterBySubnet', function() {\n    return function(foreign_objects, subnet, key) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(subnet)) {\n            id = subnet.id;\n        } else if(angular.isNumber(subnet)) {\n            id = subnet;\n        } else {\n            return filtered;\n        }\n        if(angular.isUndefined(key)) {\n            key = 'subnet';\n        }\n        angular.forEach(foreign_objects, function(obj) {\n            if(obj[key] === id) {\n                filtered.push(obj);\n            }\n        });\n        return filtered;\n    };\n});\n\n// Filters by subnet, unless the subnet is not defined. If the subnet is not\n// defined, filters by VLAN.\nangular.module('MAAS').filter('filterBySubnetOrVlan', function() {\n    return function(foreign_objects, subnet, vlan) {\n        var filtered = [];\n        var id;\n        var key = null;\n        if(angular.isDefined(subnet) && subnet !== null) {\n            key = 'subnet';\n            if(angular.isObject(subnet)) {\n                id = subnet.id;\n            } else if(angular.isNumber(subnet)) {\n                id = subnet;\n            }\n        } else if(angular.isDefined(vlan) && vlan !== null) {\n            key = 'vlan';\n            if(angular.isObject(vlan)) {\n                id = vlan.id;\n            } else if(angular.isNumber(vlan)) {\n                id = vlan;\n            }\n        } else {\n            return filtered;\n        }\n        angular.forEach(foreign_objects, function(obj) {\n            if(obj[key] === id) {\n                filtered.push(obj);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter Subnets by VLAN.\n */\n\nangular.module('MAAS').filter('filterByVLAN', function() {\n    return function(subnets, vlan) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(vlan)) {\n            id = vlan.id;\n        } else if(angular.isNumber(vlan)) {\n            id = vlan;\n        } else {\n            return filtered;\n        }\n        angular.forEach(subnets, function(subnet) {\n            if(subnet.vlan === id) {\n                filtered.push(subnet);\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').filter('filterControllersByVLAN', function() {\n    return function(controllers, vlan) {\n        var filtered = [];\n        if(!angular.isObject(vlan)) {\n            return filtered;\n        }\n        angular.forEach(controllers, function(controller) {\n            // XXX mpontillo disable VLAN check until VLAN is populated\n            // on the rack controller's interfaces.\n            // if(controller.vlan_ids.indexOf(vlan.id) != -1) {\n\n            // XXX mpontillo 2016-02-22 this is a hack to prevent too many\n            // nodes from being sent through the filter; we have a bug which\n            // sends nodes in which are not controllers.\n            if(controller.node_type === 2 || controller.node_type === 4) {\n                filtered.push(controller);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes Filter\n */\n\nangular.module('MAAS').filter('nodesFilter', ['$filter', 'SearchService',\n    function($filter, SearchService) {\n\n        // Default filter built-in angular. Used on all extra filters that do\n        // not specify a specific type.\n        var standardFilter = $filter('filter');\n\n        // Helpers that convert the pseudo field on node to an actual\n        // value from the node.\n        var mappings = {\n            cpu: function(node) {\n                return node.cpu_count;\n            },\n            cores: function(node) {\n                return node.cpu_count;\n            },\n            ram: function(node) {\n                return node.memory;\n            },\n            mac: function(node) {\n                macs = [];\n                macs.push(node.pxe_mac);\n                macs.push.apply(macs, node.extra_macs);\n                return macs;\n            },\n            zone: function(node) {\n                return node.zone.name;\n            },\n            pod: function(node) {\n                return (node.pod === undefined) ? undefined : node.pod.name;\n            },\n            'pod-id': function(node) {\n                return (node.pod === undefined) ? undefined : node.pod.id;\n            },\n            power: function(node) {\n                return node.power_state;\n            },\n            release: function(node) {\n                if(node.status_code === 6 || node.status_code === 9) {\n                    return node.osystem + \"/\" + node.distro_series;\n                } else {\n                    return '';\n                }\n            }\n        };\n\n        // Return true when value is an integer.\n        function isInteger(value) {\n            // +1 done to silence js-lint.\n            return value % +1 === 0;\n        }\n\n        // Return true when lowercase value contains the already\n        // lowercased lowerTerm.\n        function _matches(value, lowerTerm, exact) {\n            if(angular.isNumber(value)) {\n                if(exact) {\n                    if(isInteger(value)) {\n                        return value === parseInt(lowerTerm, 10);\n                    } else {\n                        return value === parseFloat(lowerTerm);\n                    }\n                } else {\n                    if(isInteger(value)) {\n                        return value >= parseInt(lowerTerm, 10);\n                    } else {\n                        return value >= parseFloat(lowerTerm);\n                    }\n                }\n            } else if(angular.isString(value)) {\n                if(exact) {\n                    return value.toLowerCase() === lowerTerm;\n                } else {\n                    return value.toLowerCase().indexOf(lowerTerm) >= 0;\n                }\n            } else {\n                return value === lowerTerm;\n            }\n        }\n\n        // Return true if value matches lowerTerm, unless negate is true then\n        // return false if matches.\n        function matches(value, lowerTerm, exact, negate) {\n            var match = _matches(value, lowerTerm, exact);\n            if(negate) {\n                return !match;\n            }\n            return match;\n        }\n\n        return function(nodes, search) {\n            if(angular.isUndefined(nodes) ||\n                angular.isUndefined(search) ||\n                nodes.length === 0) {\n                return nodes;\n            }\n\n            var filtered = nodes;\n            var filters = SearchService.getCurrentFilters(search);\n            angular.forEach(filters, function(terms, attr) {\n                if(attr === '_') {\n                    // Use the standard filter on terms that do not specify\n                    // an attribute.\n                    angular.forEach(terms, function(term) {\n                        filtered = standardFilter(filtered, term);\n                    });\n                } else if(attr === 'in') {\n                    // \"in:\" is used to filter the nodes by those that are\n                    // currently selected.\n                    angular.forEach(terms, function(term) {\n                        var matched = [];\n                        angular.forEach(filtered, function(node) {\n                            if(node.$selected &&\n                                term.toLowerCase() === \"selected\") {\n                                matched.push(node);\n                            } else if(!node.$selected &&\n                                term.toLowerCase() === \"!selected\") {\n                                matched.push(node);\n                            }\n                        });\n                        filtered = matched;\n                    });\n                } else {\n                    // Mapping function for the attribute.\n                    var mapFunc = mappings[attr];\n\n                    // Loop through each item and only select the matching.\n                    var matched = [];\n                    angular.forEach(filtered, function(node) {\n                        var value;\n                        if(angular.isFunction(mapFunc)) {\n                            value = mapFunc(node);\n                        } else if(node.hasOwnProperty(attr)) {\n                            value = node[attr];\n                        }\n\n                        // Unable to get value for this node. So skip it.\n                        if(angular.isUndefined(value)) {\n                            return;\n                        }\n\n                        var i, j;\n                        for(i = 0; i < terms.length; i++) {\n                            var term = terms[i].toLowerCase();\n                            var exact = false, negate = false;\n\n                            // '!' at the beginning means the term is negated.\n                            while(term.indexOf('!') === 0) {\n                                negate = !negate;\n                                term = term.substring(1);\n                            }\n\n                            // '=' at the beginning means to match exactly.\n                            if(term.indexOf('=') === 0) {\n                                exact = true;\n                                term = term.substring(1);\n                            }\n\n                            // Allow '!' after the '=' as well.\n                            while(term.indexOf('!') === 0) {\n                                negate = !negate;\n                                term = term.substring(1);\n                            }\n\n                            if(angular.isArray(value)) {\n                                // If value is an array check if the\n                                // term matches any value in the\n                                // array. If negated, check whether no\n                                // value in the array matches.\n                                if(negate) {\n                                    // Push to matched only if no value in\n                                    // the array matches term.\n                                    var no_match = true;\n                                    for(j = 0; j < value.length; j++) {\n                                        if(matches(\n                                            value[j], term, exact, false)) {\n                                            no_match = false;\n                                            break; // Skip remaining tests.\n                                        }\n                                    }\n                                    if(no_match) {\n                                        matched.push(node);\n                                        return;\n                                    }\n                                } else {\n                                    for(j = 0; j < value.length; j++) {\n                                        if(matches(\n                                            value[j], term, exact, false)) {\n                                            matched.push(node);\n                                            return;\n                                        }\n                                    }\n                                }\n                            } else {\n                                // Standard value check that it matches the\n                                // term.\n                                if(matches(value, term, exact, negate)) {\n                                    matched.push(node);\n                                    return;\n                                }\n                            }\n                        }\n                    });\n                    filtered = matched;\n                }\n            });\n            return filtered;\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter Subnets by VLAN.\n */\n\nangular.module('MAAS').filter('orderByDate', function() {\n    return function(items, field, field2) {\n        var sorted = items.slice();\n        sorted.sort(function(a, b) {\n            aDate = new Date(a[field]);\n            bDate = new Date(b[field]);\n\n            // Sort by ID as well if equal.\n            if(angular.isString(field2) &&\n                aDate.getTime() === bDate.getTime()) {\n                return (\n                    a[field2] > b[field2] ? -1 : a[field2] < b[field2] ? 1 : 0);\n            } else {\n              return aDate > bDate ? -1 : aDate < bDate ? 1 : 0;\n            }\n        });\n        return sorted;\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter to remove the default VLAN as an option.\n */\n\nangular.module('MAAS').filter('removeDefaultVLAN', function() {\n    return function(vlans) {\n        var filtered = [];\n        angular.forEach(vlans, function(vlan) {\n            if(vlan.vid !== 0) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Module\n *\n * Initializes the MAAS module with its required dependencies and sets up\n * the interpolater to use '{$' and '$}' instead of '{{' and '}}' as this\n * conflicts with Django templates.\n */\n\nangular.module('MAAS',\n    ['ngRoute', 'ngCookies', 'ngSanitize', 'ngTagsInput', 'sticky',\n    'vs-repeat']).config(\n    function($interpolateProvider, $routeProvider, $httpProvider) {\n        $interpolateProvider.startSymbol('{$');\n        $interpolateProvider.endSymbol('$}');\n\n        // Set the $httpProvider to send the csrftoken in the header of any\n        // http request.\n        $httpProvider.defaults.xsrfCookieName = 'csrftoken';\n        $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';\n\n        // Helper that wrappers the templateUrl to append the files version\n        // to the path. Used to override client cache.\n        function versionedPath(path) {\n            return path + \"?v=\" + MAAS_config.files_version;\n        }\n\n        // Setup routes only for the index page, all remaining pages should\n        // not use routes. Once all pages are converted to using Angular this\n        // will go away. Causing the page to never have to reload.\n        var href = angular.element(\"base\").attr('href');\n        var path = document.location.pathname;\n        if(path[path.length - 1] !== '/') {\n            path += '/';\n        }\n        if(path === href) {\n            var routes = $routeProvider.\n                when('/intro', {\n                    templateUrl: versionedPath(\n                        'static/partials/intro.html'),\n                    controller: 'IntroController'\n                }).\n                when('/intro/user', {\n                    templateUrl: versionedPath(\n                        'static/partials/intro-user.html'),\n                    controller: 'IntroUserController'\n                }).\n                when('/nodes', {\n                    templateUrl: versionedPath(\n                        'static/partials/nodes-list.html'),\n                    controller: 'NodesListController'\n                }).\n                when('/node/:type/:system_id/:result_type/:id', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-result.html'),\n                    controller: 'NodeResultController'\n                }).\n                when('/node/:type/:system_id/events', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-events.html'),\n                    controller: 'NodeEventsController'\n                }).\n                when('/node/:system_id/events', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-events.html'),\n                    controller: 'NodeEventsController'\n                }).\n                when('/node/:type/:system_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-details.html'),\n                    controller: 'NodeDetailsController'\n                }).\n                when('/node/:system_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-details.html'),\n                    controller: 'NodeDetailsController'\n                }).\n                when('/pods', {\n                    templateUrl: versionedPath(\n                        'static/partials/pods-list.html'),\n                    controller: 'PodsListController'\n                }).\n                when('/pod/:id', {\n                    templateUrl: versionedPath(\n                        'static/partials/pod-details.html'),\n                    controller: 'PodDetailsController'\n                }).\n                when('/images', {\n                    templateUrl: versionedPath(\n                        'static/partials/images.html'),\n                    controller: 'ImagesController'\n                }).\n                when('/domains', {\n                    templateUrl: versionedPath(\n                        'static/partials/domains-list.html'),\n                    controller: 'DomainsListController'\n                }).\n                when('/domain/:domain_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/domain-details.html'),\n                    controller: 'DomainDetailsController'\n                }).\n                when('/space/:space_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/space-details.html'),\n                    controller: 'SpaceDetailsController'\n                }).\n                when('/fabric/:fabric_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/fabric-details.html'),\n                    controller: 'FabricDetailsController'\n                }).\n                when('/subnets', {\n                    redirectTo: '/networks?by=fabric'\n                }).\n                when('/networks', {\n                    templateUrl: versionedPath(\n                        'static/partials/networks-list.html'),\n                    controller: 'NetworksListController',\n                    reloadOnSearch: false\n                }).\n                when('/subnet/:subnet_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/subnet-details.html'),\n                    controller: 'SubnetDetailsController'\n                }).\n                when('/vlan/:vlan_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/vlan-details.html'),\n                    controller: 'VLANDetailsController',\n                    controllerAs: 'vlanDetails'\n                }).\n                when('/settings/:section', {\n                    templateUrl: versionedPath(\n                        'static/partials/settings.html'),\n                    controller: 'SettingsController'\n                }).\n                when('/zone/:zone_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/zone-details.html'),\n                    controller: 'ZoneDetailsController'\n                }).\n                when('/zones', {\n                    templateUrl: versionedPath(\n                        'static/partials/zones-list.html'),\n                    controller: 'ZonesListController',\n                    reloadOnSearch: false\n                });\n            if(MAAS_config.superuser) {\n                // Only superuser's can access the dashboard at the moment.\n                routes = routes.when('/dashboard', {\n                    templateUrl: versionedPath(\n                        'static/partials/dashboard.html'),\n                    controller: 'DashboardController'\n                }).\n                otherwise({\n                    redirectTo: '/dashboard'\n                });\n            } else {\n                routes = routes.otherwise({\n                    redirectTo: '/nodes'\n                });\n            }\n        }\n    });\n\n// Force users to #/intro when it has not been completed.\nangular.module('MAAS').run(['$rootScope', '$location',\n    function ($rootScope, $location) {\n        $rootScope.$on('$routeChangeStart', function(event, next, current) {\n            if(!MAAS_config.completed_intro) {\n                if(next.controller !== 'IntroController') {\n                    $location.path('/intro');\n                }\n            } else if (!MAAS_config.user_completed_intro) {\n                if(next.controller !== 'IntroUserController') {\n                    $location.path('/intro/user');\n                }\n            }\n        });\n    }]);\n\n// Send pageview to Google Anayltics when the route has changed.\nangular.module('MAAS').run(['$rootScope',\n    function ($rootScope) {\n        window.ga = window.ga || function() {\n            (window.ga.q = window.ga.q || []).push(arguments);\n        };\n        window.ga.l = +new Date();\n        window.ga('create', 'UA-1018242-63', 'auto', {\n          userId: MAAS_config.analytics_user_id\n        });\n        window.ga('set', 'dimension1', MAAS_config.version);\n        window.ga('set', 'dimension2', MAAS_config.uuid);\n        $rootScope.$on('$routeChangeSuccess', function() {\n            var path = window.location.pathname + window.location.hash;\n            window.ga('send', 'pageview', path);\n        });\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Browser Service\n *\n * Detects the browser used by the client. This is very simple case, because\n * at the moment we really only care about if the browser is Firefox. This\n * could be improved for other browsers, but this should only be used as a\n * last resort to prevent something bad happening on a misbehaving browser.\n */\n\nangular.module('MAAS').service('BrowserService', ['$window',\n    function($window) {\n\n        // The first items in the array will be matched first. So if the user\n        // agent for the browser contains both you need to make the more\n        // specific one first. E.g. Chrome contains both \"Chrome\" and \"Safari\"\n        // in its user-agent string. Since \"Safari\" does not chrome comes first\n        // so it matches that browser more specifically.\n        var BROWSERS = [\n            {\n                name: \"chrome\",\n                regex: /chrome/i\n            },\n            {\n                name: \"safari\",\n                regex: /safari/i\n            },\n            {\n                name: \"firefox\",\n                regex: /firefox/i\n            },\n            {\n                name: \"ie\",\n                regex: /MSIE/\n            }\n        ];\n\n        this.browser = \"other\";\n\n        // Set the browser if a regex matches. The first to match wins.\n        var self = this;\n        angular.forEach(BROWSERS, function(matcher) {\n            if(matcher.regex.test($window.navigator.userAgent) &&\n                self.browser === \"other\") {\n                self.browser = matcher.name;\n            }\n        });\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Converter Service\n *\n * Used by controllers to convert user inputs.\n */\n\nangular.module('MAAS').service('ConverterService', function() {\n\n        // Case is important: 1kB is 1000 bytes, whereas 1KB is 1024 bytes.\n        // See https://en.wikipedia.org/wiki/Byte#Unit_symbol\n        var UNITS = ['bytes', 'kB', 'MB', 'GB', 'TB'];\n\n        var KILOBYTE = 1000.0;\n        var MEGABYTE = 1000.0 * 1000.0;\n        var GIGABYTE = 1000.0 * 1000.0 * 1000.0;\n        var TERABYTE = 1000.0 * 1000.0 * 1000.0 * 1000.0;\n\n        // Convert the bytes to a unit.\n        this.bytesToUnits = function(bytes) {\n            // Support string being passed.\n            if(angular.isString(bytes)) {\n                bytes = parseInt(bytes, 10);\n            }\n\n            var i, unit, converted = bytes;\n            for(i = 0; i < UNITS.length; i++) {\n                unit = UNITS[i];\n                if(Math.abs(converted) < 1000.0 || unit === 'TB') {\n                    var string = converted.toFixed(1) + \" \" + unit;\n                    if(unit === 'bytes') {\n                        string = converted + \" \" + unit;\n                    }\n                    return {\n                        original: bytes,\n                        converted: converted,\n                        units: unit,\n                        string: string\n                    };\n                }\n                converted /= 1000.0;\n            }\n        };\n\n        // Convert the data based on the unit to bytes.\n        this.unitsToBytes = function(data, unit) {\n            // Support string being passed.\n            if(angular.isString(data)) {\n                data = parseFloat(data);\n            }\n            if(unit === 'bytes') {\n                return Math.floor(data);\n            } else if(unit === 'kB') {\n                return Math.floor(data * KILOBYTE);\n            } else if(unit === 'MB') {\n                return Math.floor(data * MEGABYTE);\n            } else if(unit === 'GB') {\n                return Math.floor(data * GIGABYTE);\n            } else if(unit === 'TB') {\n                return Math.floor(data * TERABYTE);\n            }\n        };\n\n        // Convert the data based on unit down to the lowest tolerance to still\n        // be the same value in that unit.\n        this.roundUnits = function(data, unit) {\n            // Support string being passed.\n            if(angular.isString(data)) {\n                data = parseFloat(data);\n            }\n            if(unit === 'bytes') {\n                return Math.floor(data);\n            } else if(unit === 'kB') {\n                return Math.floor(data * KILOBYTE) - (0.05 * KILOBYTE);\n            } else if(unit === 'MB') {\n                return Math.floor(data * MEGABYTE) - (0.05 * MEGABYTE);\n            } else if(unit === 'GB') {\n                return Math.floor(data * GIGABYTE) - (0.05 * GIGABYTE);\n            } else if(unit === 'TB') {\n                return Math.floor(data * TERABYTE) - (0.05 * TERABYTE);\n            }\n        };\n\n        // Round the bytes down to size based on the block size.\n        this.roundByBlockSize = function(bytes, block_size) {\n            return block_size * Math.floor(bytes / block_size);\n        };\n\n        // Convert string ipv4 address into octets array.\n        this.ipv4ToOctets = function(ipAddress) {\n            var parts = ipAddress.split('.');\n            var octets = [];\n            angular.forEach(parts, function(part) {\n                octets.push(parseInt(part, 10));\n            });\n            return octets;\n        };\n\n        // Convert string ipv4 address into integer.\n        this.ipv4ToInteger = function(ipAddress) {\n            var octets = this.ipv4ToOctets(ipAddress);\n            return (\n                (octets[0] * Math.pow(256,3)) +\n                (octets[1] * Math.pow(256,2)) +\n                (octets[2] * 256) + octets[3]);\n        };\n\n        // Convert ipv6 address to a full ipv6 address, removing the\n        // '::' shortcut and padding each group with zeros.\n        this.ipv6Expand = function(ipAddress) {\n            var i, expandedAddress = ipAddress;\n            if(expandedAddress.indexOf(\"::\") !== -1) {\n                // '::' is present so replace it with the required\n                // number of '0000:' based on its location in the string.\n                var split = ipAddress.split(\"::\");\n                var groups = 0;\n                for(i = 0; i < split.length; i++) {\n                    groups += split[i].split(\":\").length;\n                }\n                expandedAddress = split[0] + \":\";\n                for(i = 0; i < 8 - groups; i++) {\n                    expandedAddress += \"0000:\";\n                }\n                expandedAddress += split[1];\n            }\n            // Pad the output of each part with zeros.\n            var output = [], parts = expandedAddress.split(\":\");\n            angular.forEach(parts, function(part) {\n                output.push(\"0000\".substr(part.length) + part);\n            });\n            return output.join(\":\");\n        };\n\n        // Convert string ipv6 into groups array.\n        this.ipv6ToGroups = function(ipAddress) {\n            var groups = [];\n            var parts = this.ipv6Expand(ipAddress).split(\":\");\n            angular.forEach(parts, function(part) {\n                groups.push(parseInt(part, 16));\n            });\n            return groups;\n        };\n    });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Error Service\n */\n\nangular.module('MAAS').service('ErrorService', function() {\n\n        // Holds the client error.\n        this._error = null;\n\n        // Raise this error in the UI.\n        this.raiseError = function(error) {\n            // Possible that this method is called more than once.\n            // Only take the first error.\n            if(!angular.isString(this._error)) {\n                this._error = error;\n            }\n        };\n    });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS JSON Service\n *\n * Used by controllers to parse JSON.\n */\n\nangular.module('MAAS').service('JSONService', function() {\n\n    // Return the JSON for the string or null if it cannot be parsed.\n    this.tryParse = function(jsonString) {\n        try {\n            var obj = JSON.parse(jsonString);\n            // JSON.parse(false) or JSON.parse(1234) will throw errors, but\n            // JSON.parse(null) returns 'null', and typeof null === \"object\".\n            if (obj && typeof obj === \"object\" && obj !== null) {\n                return obj;\n            }\n        }\n        catch (e) { }\n        return null;\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Log Service\n *\n * Allows logging to be enabled or disabled, and allows a particular log level\n * to be set, which will allow logs of a specified importance (or more) to be\n * seen.\n *\n * Also appends a time index (in seconds, accurate to milliseconds) to the\n * beginning of the log string.\n */\n\nangular.module('MAAS').service('LogService', [\n    '$window', function($window) {\n        var self = this;\n\n        // Global enable/disable for MAAS logging. If set to `false`, this\n        // value takes precedence over the logLevel.\n        self.logging = true;\n\n        // Specifies the log level.\n        // Level 1: error() logging\n        // Level 2: error() and warn() logging\n        // Level 3: all of the above, plus info()\n        // Level 4: all of the above, plus log()\n        // Level 5: all of the above, plus debug()\n        self.logLevel = 5;\n\n        // Returns a monotonic time (in milliseconds) since page load.\n        self.now = function() {\n            return $window.performance ? $window.performance.now() : 0;\n        };\n\n        // Standard logging functions.\n        self._debug = console.debug;\n        self._log = console.log;\n        self._info = console.info;\n        self._warn = console.warn;\n        self._error = console.error;\n\n        // Formats the specified time (in milliseconds) in seconds.\n        this.formatMilliseconds = function(milliseconds) {\n            return parseFloat(milliseconds / 1000.0).toFixed(3);\n        };\n\n        // Internal function to log using the specified destination, with the\n        // specified list of arguments.\n        this.__log = function(destination, args) {\n            if(self.logging === true) {\n                // Add time index to the beginning of the log.\n                Array.prototype.unshift.call(args,\n                    \"[\" + self.formatMilliseconds(self.now()) + \"]\");\n                destination.apply(self, args);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._debug().\n        this.debug = function() {\n            if(self.logLevel >= 5) {\n                self.__log(self._debug, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._log().\n        this.log = function() {\n            if(self.logLevel >= 4) {\n                self.__log(self._log, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._info().\n        this.info = function() {\n            if(self.logLevel >= 3) {\n                self.__log(self._info, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._warn().\n        this.warn = function() {\n            if(self.logLevel >= 2) {\n                self.__log(self._warn, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._err().\n        this.error = function() {\n            if(self.logLevel >= 1) {\n                self.__log(self._error, arguments);\n            }\n        };\n    }\n]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Base Manager\n *\n * Manages a collection of items from the websocket in the browser. The manager\n * uses the RegionConnection to load the items, update the items, and listen\n * for notification events about the items.\n */\n\nangular.module('MAAS').service(\n    'Manager',\n    ['$q', '$rootScope', '$timeout', 'RegionConnection', function(\n            $q, $rootScope, $timeout, RegionConnection) {\n\n        // Actions that are used to update the statuses metadata.\n        var METADATA_ACTIONS = {\n            CREATE: \"create\",\n            UPDATE: \"update\",\n            DELETE: \"delete\"\n        };\n\n        // Constructor\n        function Manager() {\n            // Primary key on the items in the list. Used to match items.\n            this._pk = \"id\";\n\n            // Key used when loading batches. Typically the same as _pk\n            // but not always.\n            this._batchKey = \"id\";\n\n            // The field from which to get a human-readable name.\n            this._name_field = \"name\";\n\n            // Handler on the region to call to list, create, update, delete,\n            // and listen for notifications. Must be set by overriding manager.\n            this._handler = null;\n\n            // Holds all items in the system. This list must always be the same\n            // object.\n            this._items = [];\n\n            // The way this manager recieves its updated information. 'notify'\n            // means this manager recieved notify messages from the websocket.\n            // See PollingManager for the other possible type. This is only\n            // used by the `ManagerHelperService` to identify how updating\n            // the data should be handled.\n            this._type = 'notify';\n\n            // Holds list of scopes that currently have this manager loaded.\n            this._scopes = [];\n\n            // True when all of the items have been loaded. This is done on\n            // intial connection to the region.\n            this._loaded = false;\n\n            // True when the items list is currently being loaded or reloaded.\n            // Actions will not be processed while this is false.\n            this._isLoading = false;\n\n            // Holds list of defers that need to be called once the loading of\n            // items has finished. This is used when a caller calls loadItems\n            // when its already loading.\n            this._extraLoadDefers = [];\n\n            // Holds list of defers that need to be called once the reloading\n            // of items has finished. This is used when a caller calls\n            // reloadItems when its already reloading.\n            this._extraReloadDefers = [];\n\n            // Holds all of the notify actions that need to be processed. This\n            // is used to hold the actions while the items are being loaded.\n            // Once all of the items are loaded the queue will be processed.\n            this._actionQueue = [];\n\n            // Holds list of all of the currently selected items. This is held\n            // in a seperate list to remove the need to loop through the full\n            // listing to grab the selected items.\n            this._selectedItems = [];\n\n            // Set to true when the items list should reload upon re-connection\n            // to the region.\n            this._autoReload = false;\n\n            // Holds the item that is currenly being viewed. This object will\n            // be updated if any notify events are recieved for it. This allows\n            // the ability of not having to keep pulling the item out of the\n            // items list.\n            this._activeItem = null;\n\n            // Holds metadata information that is used to helper filtering.\n            this._metadata = {};\n\n            // List of attributes to track on the loaded items. Each attribute\n            // in this list will be placed in _metadata to track its currect\n            // values and the number of items with that value.\n            this._metadataAttributes = [];\n        }\n\n        // Return index of the item in the given array.\n        Manager.prototype._getIndexOfItem = function(array, pk_value) {\n            var i;\n            for(i = 0, len = array.length; i < len; i++) {\n                if(array[i][this._pk] === pk_value) {\n                    return i;\n                }\n            }\n            return -1;\n        };\n\n        // Replace the item in the array at the same index.\n        Manager.prototype._replaceItemInArray = function(array, item) {\n            var idx = this._getIndexOfItem(array, item[this._pk]);\n            if(idx >= 0) {\n                // Keep the current selection on the item.\n                item.$selected = array[idx].$selected;\n                angular.copy(item, array[idx]);\n            }\n        };\n\n        // Remove the item from the array.\n        Manager.prototype._removeItemByIdFromArray = function(\n            array, pk_value) {\n            var idx = this._getIndexOfItem(array, pk_value);\n            if(idx >= 0) {\n                array.splice(idx, 1);\n            }\n        };\n\n        // Return the parameters that should be used for the batch load\n        // request. Should be used by subclass that want to add extra\n        // parameters to the batch request. By default it returns an empty\n        // object.\n        Manager.prototype._initBatchLoadParameters = function() {\n            return {};\n        };\n\n        // Batch load items from the region in groups of 50.\n        Manager.prototype._batchLoadItems = function(array, extra_func) {\n            var self = this;\n            var defer = $q.defer();\n            var method = this._handler + \".list\";\n            function callLoad() {\n                var params = self._initBatchLoadParameters();\n                params.limit = 50;\n\n                // Get the last batchKey in the list so the region knows to\n                // start at that offset.\n                if(array.length > 0) {\n                    params.start = array[array.length-1][self._batchKey];\n                }\n                RegionConnection.callMethod(\n                    method, params).then(function(items) {\n                        // Pass each item to extra_func function if given.\n                        if(angular.isFunction(extra_func)) {\n                            angular.forEach(items, function(item) {\n                                extra_func(item);\n                            });\n                        }\n\n                        array.push.apply(array, items);\n                        if(items.length === 50) {\n                            // Could be more items, request the next 50.\n                            callLoad(array);\n                        } else {\n                            defer.resolve(array);\n                        }\n                    }, defer.reject);\n            }\n            callLoad();\n            return defer.promise;\n        };\n\n        // Resolves array of defers with item.\n        Manager.prototype._resolveDefers = function(defersArray, item) {\n            angular.forEach(defersArray, function(defer) {\n                defer.resolve(item);\n            });\n        };\n\n        // Rejects array of defers with error.\n        Manager.prototype._rejectDefers = function(defersArray, error) {\n            angular.forEach(defersArray, function(defer) {\n                defer.reject(error);\n            });\n        };\n\n        // Return list of items.\n        Manager.prototype.getItems = function() {\n            return this._items;\n        };\n\n        // Clears the currect state of the manager.\n        Manager.prototype.clear = function() {\n            this._loaded = false;\n            this._items.length = 0;\n            this._actionQueue.length = 0;\n            this._selectedItems.length = 0;\n            this._activeItem = null;\n            this._metadata = {};\n            this._metadataAttributes.length = 0;\n        };\n\n        // Load all the items.\n        Manager.prototype.loadItems = function() {\n            // If the items have already been loaded then, we need to\n            // reload the items list not load the initial list.\n            if(this._loaded) {\n                return this.reloadItems();\n            }\n\n            // If its already loading then the caller just needs to be informed\n            // of when it has finished loading.\n            if(this._isLoading) {\n                var defer = $q.defer();\n                this._extraLoadDefers.push(defer);\n                return defer.promise;\n            }\n\n            var self = this;\n            this._isLoading = true;\n            return this._batchLoadItems(this._items, function(item) {\n                item.$selected = false;\n                self._updateMetadata(item, METADATA_ACTIONS.CREATE);\n                self._processItem(item);\n            }).then(function() {\n                self._loaded = true;\n                self._isLoading = false;\n                self.processActions();\n                self._resolveDefers(self._extraLoadDefers, self._items);\n                self._extraLoadDefers = [];\n                return self._items;\n            }, function(error) {\n                self._rejectDefers(self._extraLoadDefers, error);\n                self._extraLoadDefers = [];\n                return $q.reject(error);\n            });\n        };\n\n        // Reload the items list.\n        Manager.prototype.reloadItems = function() {\n            // If the items have not been loaded then, we need to\n            // load the initial list.\n            if(!this._loaded) {\n                return this.loadItems();\n            }\n\n            // If its already reloading then the caller just needs to be\n            // informed of when it has refinished loading.\n            if(this._isLoading) {\n                var defer = $q.defer();\n                this._extraReloadDefers.push(defer);\n                return defer.promise;\n            }\n\n            // Updates the items list with the reloaded items.\n            var self = this;\n            function updateItems(items) {\n                // Iterate in reverse so we can remove items inline, without\n                // having to adjust the index.\n                var i = self._items.length;\n                while(i--) {\n                    var item = self._items[i];\n                    var updatedIdx = self._getIndexOfItem(\n                        items, item[self._pk]);\n                    if(updatedIdx === -1) {\n                        self._updateMetadata(item, METADATA_ACTIONS.DELETE);\n                        self._items.splice(i, 1);\n                        self._removeItemByIdFromArray(\n                            self._selectedItems, item[self._pk]);\n                    } else {\n                        var updatedItem = items[updatedIdx];\n                        self._updateMetadata(\n                            updatedItem, METADATA_ACTIONS.UPDATE);\n                        updatedItem.$selected = item.$selected;\n                        angular.copy(items[updatedIdx], item);\n                        items.splice(updatedIdx, 1);\n                    }\n                }\n\n                // The remain items in items array are the new items.\n                angular.forEach(items, function(item) {\n                    self._items.push(item);\n                    self._processItem(item);\n                });\n            }\n\n            // The reload action loads all of the items into this list\n            // instead of the items list. This list will then be used to\n            // update the items list.\n            var currentItems = [];\n\n            // Start the reload process and once complete call updateItems.\n            self._isLoading = true;\n            return this._batchLoadItems(currentItems).then(function(items) {\n                updateItems(items);\n                self._isLoading = false;\n                self.processActions();\n\n                // Set the activeItem again so the region knows that its\n                // the active item.\n                if(angular.isObject(self._activeItem)) {\n                    self.setActiveItem(self._activeItem[self._pk]);\n                }\n\n                self._resolveDefers(self._extraReloadDefers, self._items);\n                self._extraReloadDefers = [];\n                return self._items;\n            }, function(error) {\n                self._rejectDefers(self._extraReloadDefers, error);\n                self._extraReloadDefers = [];\n                return $q.reject(error);\n            });\n        };\n\n        // Enables auto reloading of the item list on connection to region.\n        Manager.prototype.enableAutoReload = function() {\n            if(!this._autoReload) {\n                this._autoReload = true;\n                var self = this;\n                this._reloadFunc = function() {\n                    self.reloadItems();\n                };\n                RegionConnection.registerHandler(\"open\", this._reloadFunc);\n            }\n        };\n\n        // Disable auto reloading of the item list on connection to region.\n        Manager.prototype.disableAutoReload = function() {\n            if(this._autoReload) {\n                RegionConnection.unregisterHandler(\"open\", this._reloadFunc);\n                this._reloadFunc = null;\n                this._autoReload = false;\n            }\n        };\n\n        // True when the initial item list has finished loading.\n        Manager.prototype.isLoaded = function() {\n            return this._loaded;\n        };\n\n        // True when the item list is currently being loaded or reloaded.\n        Manager.prototype.isLoading = function() {\n            return this._isLoading;\n        };\n\n        // Allow for extra processing of items as they are added or updated.\n        Manager.prototype._processItem = function(item) {\n        };\n\n        // Replace item in the items and selectedItems list.\n        Manager.prototype._replaceItem = function(item) {\n            this._updateMetadata(item, METADATA_ACTIONS.UPDATE);\n            this._replaceItemInArray(this._items, item);\n        };\n\n        // Remove item in the items and selectedItems list.\n        Manager.prototype._removeItem = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx >= 0) {\n                this._updateMetadata(this._items[idx], METADATA_ACTIONS.DELETE);\n            }\n            this._removeItemByIdFromArray(this._items, pk_value);\n            this._removeItemByIdFromArray(this._selectedItems, pk_value);\n        };\n\n        // Get the item from the list. Does not make a get request to the\n        // region to load more data.\n        Manager.prototype.getItemFromList = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx >= 0) {\n                return this._items[idx];\n            } else {\n                return null;\n            }\n        };\n\n        // Get the item from the region.\n        Manager.prototype.getItem = function(pk_value) {\n            var self = this;\n            var method = this._handler + \".get\";\n            var params = {};\n            params[this._pk] = pk_value;\n            return RegionConnection.callMethod(\n                method, params).then(function(item) {\n                    self._replaceItem(item);\n                    return item;\n                });\n        };\n\n        // Send the create information to the region.\n        Manager.prototype.createItem = function(item) {\n            var self = this;\n            var method = this._handler + \".create\";\n            item = angular.copy(item);\n            delete item.$selected;\n            return RegionConnection.callMethod(\n                method, item).then(function(item) {\n                    self._replaceItem(item);\n                    return item;\n                });\n        };\n\n        // Send the update information to the region.\n        Manager.prototype.updateItem = function(item) {\n            var self = this;\n            var method = this._handler + \".update\";\n            item = angular.copy(item);\n            delete item.$selected;\n            return RegionConnection.callMethod(\n                method, item).then(function(item) {\n                    self._replaceItem(item);\n                    return item;\n                });\n        };\n\n        // Send the delete call for item to the region.\n        Manager.prototype.deleteItem = function(item) {\n            var self = this;\n            var method = this._handler + \".delete\";\n            var params = {};\n            params[this._pk] = item[this._pk];\n            return RegionConnection.callMethod(\n                method, params).then(function() {\n                    self._removeItem(item[self._pk]);\n                });\n        };\n\n        // Return the active item.\n        Manager.prototype.getActiveItem = function() {\n            return this._activeItem;\n        };\n\n        // Set the active item.\n        Manager.prototype.setActiveItem = function(pk_value) {\n            if(!this._loaded) {\n                throw new Error(\n                    \"Cannot set active item unless the manager is loaded.\");\n            }\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                this._activeItem = null;\n                // Item with pk_value does not exists. Reject the returned\n                // deferred.\n                var defer = $q.defer();\n                $timeout(function() {\n                    defer.reject(\"No item with pk: \" + pk_value);\n                });\n                return defer.promise;\n            } else {\n                this._activeItem = this._items[idx];\n                // Data that is loaded from the list call is limited and\n                // doesn't contain all of the needed data for an activeItem.\n                // Call set_active on the handler for the region to know\n                // this item needs all information when updated.\n                var self = this;\n                var method = this._handler + \".set_active\";\n                var params = {};\n                params[this._pk] = pk_value;\n                return RegionConnection.callMethod(\n                    method, params).then(function(item) {\n                        self._replaceItem(item);\n                        return self._activeItem;\n                    });\n            }\n        };\n\n        // Clears the active item.\n        Manager.prototype.clearActiveItem = function() {\n            this._activeItem = null;\n        };\n\n        // True when the item list is stable and not being loaded or reloaded.\n        Manager.prototype.canProcessActions = function() {\n            return !this._isLoading;\n        };\n\n        // Handle notify from RegionConnection about an item.\n        Manager.prototype.onNotify = function(action, data) {\n            // Place the notification in the action queue.\n            this._actionQueue.push({\n                action: action,\n                data: data\n            });\n            // Processing incoming actions is enabled. Otherwise they\n            // will be queued until processActions is called.\n            if(this.canProcessActions()) {\n               $rootScope.$apply(this.processActions());\n            }\n        };\n\n        // Process all actions to keep the item information up-to-date.\n        Manager.prototype.processActions = function() {\n            while(this._actionQueue.length > 0) {\n                var action = this._actionQueue.shift();\n                if(action.action === \"create\") {\n                    // Check that the received data doesn't already exists\n                    // in the _items list. If it does then this is actually\n                    // an update action not a create action.\n                    var idx = this._getIndexOfItem(\n                        this._items, action.data[this._pk]);\n                    if(idx >= 0) {\n                        // Actually this is an update action not a create\n                        // action. So replace the item instead of adding it.\n                        this._replaceItem(action.data);\n                    } else {\n                        action.data.$selected = false;\n                        this._updateMetadata(\n                            action.data, METADATA_ACTIONS.CREATE);\n                        this._items.push(action.data);\n                    }\n                    this._processItem(action.data);\n                } else if(action.action === \"update\") {\n                    this._replaceItem(action.data);\n                    this._processItem(action.data);\n                } else if(action.action === \"delete\") {\n                    this._removeItem(action.data);\n                }\n            }\n        };\n\n        // Return list of selected items.\n        Manager.prototype.getSelectedItems = function() {\n            return this._selectedItems;\n        };\n\n        // Mark the given item as selected.\n        Manager.prototype.selectItem = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                console.log(\n                    \"WARN: selection of \" + this._handler + \"(\" + pk_value +\n                    \") failed because its missing in the items list.\");\n                return;\n            }\n\n            var item = this._items[idx];\n            item.$selected = true;\n\n            idx = this._selectedItems.indexOf(item);\n            if(idx === -1) {\n                this._selectedItems.push(item);\n            }\n        };\n\n        // Mark the given item as unselected.\n        Manager.prototype.unselectItem = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                console.log(\n                    \"WARN: de-selection of \" + this._handler + \"(\" +\n                    pk_value + \") failed because its missing in the \" +\n                    \"nodes list.\");\n                return;\n            }\n\n            var item = this._items[idx];\n            item.$selected = false;\n\n            idx = this._selectedItems.indexOf(item);\n            if(idx >= 0) {\n                this._selectedItems.splice(idx, 1);\n            }\n        };\n\n        // Determine if a item is selected.\n        Manager.prototype.isSelected = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                console.log(\n                    \"WARN: unable to determine if \" + this._handler + \"(\" +\n                    pk_value + \") is selected because its missing in the \" +\n                    \"nodes list.\");\n                return false;\n            }\n\n            return this._items[idx].$selected === true;\n        };\n\n        // Return the metadata object value from `metadatas` matching `name`.\n        Manager.prototype._getMetadataValue = function(metadatas, name) {\n            var i;\n            for(i = 0; i < metadatas.length; i++) {\n                if(metadatas[i].name === name) {\n                    return metadatas[i];\n                }\n            }\n            return null;\n        };\n\n        // Add new value to metadatas if it doesnt exists or increment the\n        // count if it already does.\n        Manager.prototype._addMetadataValue = function(metadatas, value) {\n            var metadata = this._getMetadataValue(metadatas, value);\n            if(metadata) {\n                metadata.count += 1;\n            } else {\n                metadata = {\n                    name: value,\n                    count: 1\n                };\n                metadatas.push(metadata);\n            }\n        };\n\n        // Remove value from metadatas.\n        Manager.prototype._removeMetadataValue = function(metadatas, value) {\n            var metadata = this._getMetadataValue(metadatas, value);\n            if(metadata) {\n                metadata.count -= 1;\n                if(metadata.count <= 0) {\n                    metadatas.splice(metadatas.indexOf(metadata), 1);\n                }\n            }\n        };\n\n        // Update the metadata entry in `metadatas` for the array value and\n        // based on the action.\n        Manager.prototype._updateMetadataArrayEntry = function(\n                metadatas, newValue, action, oldValue) {\n            var self = this;\n\n            if(action === METADATA_ACTIONS.CREATE) {\n                angular.forEach(newValue, function(value) {\n                    // On create ignore empty values.\n                    if(value === '') {\n                        return;\n                    }\n                    self._addMetadataValue(metadatas, value);\n                });\n            } else if(action === METADATA_ACTIONS.DELETE) {\n                angular.forEach(newValue, function(value) {\n                    self._removeMetadataValue(metadatas, value);\n                });\n            } else if(action === METADATA_ACTIONS.UPDATE &&\n                angular.isDefined(oldValue)) {\n                // Any values in added are new on the item, and any values left\n                // in oldArray have been removed.\n                var added = [];\n                var oldArray = angular.copy(oldValue);\n                angular.forEach(newValue, function(value) {\n                    var idx = oldArray.indexOf(value);\n                    if(idx === -1) {\n                        // Value not in oldArray so it has been added.\n                        added.push(value);\n                    } else {\n                        // Value already in oldArray so its already tracked.\n                        oldArray.splice(idx, 1);\n                    }\n                });\n\n                // Add the new values.\n                angular.forEach(added, function(value) {\n                    self._addMetadataValue(metadatas, value);\n                });\n\n                // Remove the old values.\n                angular.forEach(oldArray, function(value) {\n                    self._removeMetadataValue(metadatas, value);\n                });\n            }\n        };\n\n        // Update the metadata entry in `metadatas` for the newValue and based\n        // on the action. Method does not work with array values, use\n        // _updateMetadataArrayEntry for values that are arrays.\n        Manager.prototype._updateMetadataValueEntry = function(\n                metadatas, newValue, action, oldValue) {\n            if(action === METADATA_ACTIONS.CREATE) {\n                // On create ignore empty values.\n                if(newValue === '') {\n                    return;\n                }\n                this._addMetadataValue(metadatas, newValue);\n            } else if(action === METADATA_ACTIONS.DELETE) {\n                this._removeMetadataValue(metadatas, newValue);\n            } else if(action === METADATA_ACTIONS.UPDATE &&\n                angular.isDefined(oldValue)) {\n                if(oldValue !== newValue) {\n                    if(oldValue !== \"\") {\n                        // Decrement the old value\n                        this._removeMetadataValue(metadatas, oldValue);\n                    }\n\n                    // Increment the new value with the \"create\"\n                    // operation.\n                    this._updateMetadataEntry(\n                        metadatas, newValue, METADATA_ACTIONS.CREATE, oldValue);\n                }\n            }\n        };\n\n        // Update the metadata entry in `metadatas` with the newValue and based\n        // on the action. Update action will use the oldValue to remove it from\n        // the metadata.\n        Manager.prototype._updateMetadataEntry = function(\n                metadatas, newValue, action, oldValue) {\n            if(angular.isArray(newValue)) {\n                this._updateMetadataArrayEntry(\n                    metadatas, newValue, action, oldValue);\n            } else {\n                this._updateMetadataValueEntry(\n                    metadatas, newValue, action, oldValue);\n            }\n        };\n\n        // Return the metadata object.\n        Manager.prototype.getMetadata = function() {\n            return this._metadata;\n        };\n\n        // Update the metadata objects based on the given item and action.\n        Manager.prototype._updateMetadata = function(item, action) {\n            var self = this;\n            var oldItem, idx;\n            if(action === METADATA_ACTIONS.UPDATE) {\n                // Update actions require the oldItem if it exist in the\n                // current item listing.\n                idx = this._getIndexOfItem(this._items, item[this._pk]);\n                if(idx >= 0) {\n                    oldItem = this._items[idx];\n                }\n            }\n            angular.forEach(this._metadataAttributes, function(func, attr) {\n                if(angular.isUndefined(self._metadata[attr])) {\n                    self._metadata[attr] = [];\n                }\n                var newValue, oldValue;\n                if(angular.isFunction(func)) {\n                    newValue = func(item);\n                    if(angular.isObject(oldItem)) {\n                        oldValue = func(oldItem);\n                    }\n                } else {\n                    newValue = item[attr];\n                    if(angular.isObject(oldItem)) {\n                        oldValue = oldItem[attr];\n                    }\n                }\n                self._updateMetadataEntry(\n                    self._metadata[attr], newValue, action, oldValue);\n            });\n        };\n\n        // Default implementation of getName(): returns the default name for\n        // this object, if it exists.\n        Manager.prototype.getName = function(obj) {\n            if(!angular.isObject(obj)) {\n                return;\n            }\n            if(angular.isString(obj[this._name_field])) {\n                return obj[this._name_field];\n            }\n        };\n\n        return Manager;\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Manager Helper Service\n *\n * Used by controllers to load managers. It helps the initialization of\n * managers and makes sure that all items in the manager are loaded\n * before resolving the defer.\n */\n\nangular.module('MAAS').service('ManagerHelperService', [\n    '$q', '$timeout', 'ErrorService', 'RegionConnection',\n    function($q, $timeout, ErrorService, RegionConnection) {\n\n        // Loads the manager.\n        this.loadManager = function(scope, manager) {\n            var defer = $q.defer();\n\n            // If the manager already has this scope loaded then nothing needs\n            // to be done.\n            if(manager._scopes.indexOf(scope) > -1) {\n                $timeout(function() {\n                    defer.resolve(manager);\n                });\n                return defer.promise;\n            }\n\n            // Do this entire operation with in the context of the region\n            // connection is connected.\n            RegionConnection.defaultConnect().then(function() {\n                if(manager._type === 'notify') {\n                    if(manager.isLoaded()) {\n                        $timeout(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        });\n                    } else {\n                        manager.loadItems().then(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                    }\n                    // Always enable auto reload. This will make sure the items\n                    // are reloaded if the connection goes down.\n                    manager.enableAutoReload();\n\n                    // Remove the scope for the loaded scopes for the manager.\n                    scope.$on(\"$destroy\", function() {\n                        var idx = manager._scopes.indexOf(scope);\n                        if(idx > -1) {\n                            manager._scopes.splice(idx, 1);\n                        }\n                    });\n                } else if(manager._type === 'poll') {\n                    if(manager.isPolling()) {\n                        $timeout(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        });\n                    } else {\n                        manager.startPolling().then(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                    }\n\n                    // Stop the polling when the scope is destroyed and its\n                    // not in use by any other scopes.\n                    scope.$on(\"$destroy\", function() {\n                        var idx = manager._scopes.indexOf(scope);\n                        if(idx > -1) {\n                            manager._scopes.splice(idx, 1);\n                        }\n                        if(manager._scopes.length === 0) {\n                            manager.stopPolling();\n                        }\n                    });\n                } else {\n                    throw new Error(\"Unknown manager type: \" + manager._type);\n                }\n            });\n            return defer.promise;\n        };\n\n        // Gets the list of managers.\n        this.loadManagers = function(scope, managers) {\n            var defer = $q.defer();\n            var loadedManagers = [];\n\n            // Resolves the defer if all managers are loaded.\n            var resolveAllLoaded = function() {\n                if(loadedManagers.length === managers.length) {\n                    defer.resolve(managers);\n                }\n            };\n\n            var self = this;\n            angular.forEach(managers, function(manager) {\n                self.loadManager(scope, manager).then(function(loadedManager) {\n                    loadedManagers.push(loadedManager);\n                    resolveAllLoaded();\n                });\n            });\n            return defer.promise;\n        };\n\n        // Tries to parse the specified string as JSON. If parsing fails,\n        // returns the original string. (This is useful since some manager\n        // calls return an error that could be either plain text, or JSON.)\n        this.tryParsingJSON = function(string) {\n            var error;\n            try {\n                error = JSON.parse(string);\n            } catch(e) {\n                if (e instanceof SyntaxError) {\n                    return string;\n                } else {\n                    throw e;\n                }\n            }\n            return error;\n        };\n\n        // Returns a printable version of the specified dictionary (useful\n        // for displaying an error to the user).\n        this.getPrintableString = function(dict, showNames) {\n            var result = '';\n            angular.forEach(dict, function(value, key) {\n                var error = dict[key];\n                if(showNames === true) {\n                    result += key + \": \";\n                }\n                if(angular.isString(error) || angular.isNumber(error)) {\n                    result += error + \"  \";\n                } else if(angular.isObject(error)) {\n                    angular.forEach(error, function(error) {\n                        result += error + \"  \";\n                    });\n                }\n                result = result.trim() + \"\\n\";\n            });\n            return result.trim();\n        };\n\n        // Convert the Python dict error message to displayed message.\n        // We know it's probably a form ValidationError dictionary, so just use\n        // it as such, and recover if that doesn't parse as JSON.\n        this.parseValidationError = function(error, showNames) {\n            error = this.tryParsingJSON(error);\n            if(!angular.isObject(error)) {\n                return error;\n            } else {\n                return this.getPrintableString(error, showNames);\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Space Manager\n *\n * Manages all of the spaces in the browser. The manager uses the\n * RegionConnection to load the spaces, update the spaces, and listen for\n * notification events about spaces.\n */\n\nangular.module('MAAS').factory(\n    'PollingManager',\n    ['$q', '$timeout', 'RegionConnection', 'Manager',\n    function($q, $timeout, RegionConnection, Manager) {\n\n        function PollingManager() {\n            Manager.call(this);\n\n            // The way this manager recieves its updated information. 'poll'\n            // means this manager periodicly polls for new data from the\n            // websocket.\n            this._type = 'poll';\n\n            // Set to true when polling has been enabled.\n            this._polling = false;\n\n            // The next promise for the polling interval.\n            this._nextPromise = null;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data.\n            this._pollTimeout = 10000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when an error occurs.\n            this._pollErrorTimeout = 3000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when the retrieved data is empty.\n            this._pollEmptyTimeout = 3000;\n        }\n\n        PollingManager.prototype = new Manager();\n\n        // Returns true when currently polling.\n        PollingManager.prototype.isPolling = function() {\n            return this._polling;\n        };\n\n        // Starts the polling.\n        PollingManager.prototype.startPolling = function() {\n            if(!this._polling) {\n                this._polling = true;\n                return this._poll();\n            } else {\n                return this._nextPromise;\n            }\n        };\n\n        // Stops the polling.\n        PollingManager.prototype.stopPolling = function() {\n            this._polling = false;\n            if(angular.isObject(this._nextPromise)) {\n                $timeout.cancel(this._nextPromise);\n                this._nextPromise = null;\n            }\n        };\n\n        // Registers the next polling attempt.\n        PollingManager.prototype._pollAgain = function(timeout) {\n            var self = this;\n            this._nextPromise = $timeout(function() {\n                self._poll();\n            }, timeout);\n            return this._nextPromise;\n        };\n\n        // Polls for the data from the region.\n        PollingManager.prototype._poll = function() {\n            var self = this;\n            return this.reloadItems().then(function(items) {\n                var pollTimeout = self._pollTimeout;\n                if(items.length === 0) {\n                    pollTimeout = self._pollEmptyTimeout;\n                }\n                self._pollAgain(pollTimeout);\n                return items;\n            }, function(error) {\n                self._pollAgain(self._pollErrorTimeout);\n                return $q.reject(error);\n            });\n        };\n\n        return PollingManager;\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes Search Services\n */\n\nangular.module('MAAS').service('SearchService', function() {\n\n    // Holds an empty filter object.\n    var emptyFilter = { _: [] };\n\n    // Return a new empty filter;\n    this.getEmptyFilter = function() {\n        return angular.copy(emptyFilter);\n    };\n\n    // Splits the search string into different terms based on white space.\n    // This handles the ability for whitespace to be inside of '(', ')'.\n    //\n    // XXX blake_r 28-01-15: This could be improved with a regex, but was\n    // unable to come up with one that would allow me to validate the end\n    // ')' in the string.\n    this.getSplitSearch = function(search) {\n        var terms = search.split(' ');\n        var fixedTerms = [];\n        var spanningParentheses = false;\n        angular.forEach(terms, function(term, idx) {\n            if(spanningParentheses) {\n                // Previous term had an opening '(' but not a ')'. This\n                // term should join that previous term.\n                fixedTerms[fixedTerms.length - 1] += ' ' + term;\n\n                // If the term contains the ending ')' then its the last\n                // in the group.\n                if(term.indexOf(')') !== -1) {\n                    spanningParentheses = false;\n                }\n            } else {\n                // Term is not part of a previous '(' span.\n                fixedTerms.push(term);\n\n                var startIdx = term.indexOf('(');\n                if(startIdx !== -1) {\n                    if(term.indexOf(')', startIdx) === -1) {\n                        // Contains a starting '(' but not a ending ')'.\n                        spanningParentheses = true;\n                    }\n                }\n            }\n        });\n\n        if(spanningParentheses) {\n            // Missing ending parentheses so error with terms.\n            return null;\n        }\n        return fixedTerms;\n    };\n\n    // Return all of the currently active filters for the given search.\n    this.getCurrentFilters = function(search) {\n        var filters = this.getEmptyFilter();\n        if(search.length === 0) {\n            return filters;\n        }\n        var searchTerms = this.getSplitSearch(search);\n        if(!searchTerms) {\n            return null;\n        }\n        angular.forEach(searchTerms, function(terms) {\n            terms = terms.split(':');\n            if(terms.length === 1) {\n                // Search term is not specifing a specific field. Gets\n                // add to the '_' section of the filters.\n                if(filters._.indexOf(terms[0]) === -1) {\n                    filters._.push(terms[0]);\n                }\n            } else {\n                var field = terms.shift();\n                var values = terms.join(\":\");\n\n                // Remove the starting '(' and ending ')'.\n                values = values.replace('(', '');\n                values = values.replace(')', '');\n\n                // If empty values then do nothing.\n                if(values.length === 0) {\n                    return;\n                }\n\n                // Split the values based on comma.\n                values = values.split(',');\n\n                // Add the values to filters.\n                if(angular.isUndefined(filters[field])) {\n                    filters[field] = [];\n                }\n                angular.forEach(values, function(value) {\n                    if(filters[field].indexOf(value) === -1) {\n                        filters[field].push(value);\n                    }\n                });\n            }\n        });\n        return filters;\n    };\n\n    // Convert \"filters\" into a search string.\n    this.filtersToString = function(filters) {\n        var search = \"\";\n        angular.forEach(filters, function(terms, type) {\n            // Skip empty and skip \"_\" as it gets appended at the\n            // beginning of the search.\n            if(terms.length === 0 || type === \"_\") {\n                return;\n            }\n            search += type + \":(\" + terms.join(\",\") + \") \";\n        });\n        if(filters._.length > 0) {\n            search = filters._.join(\" \") + \" \" + search;\n        }\n        return search.trim();\n    };\n\n    // Return the index of the value in the type for the filter.\n    this._getFilterValueIndex = function(filters, type, value) {\n        var values = filters[type];\n        if(angular.isUndefined(values)) {\n            return -1;\n        }\n        var lowerValues = values.map(function(value) {\n            return value.toLowerCase();\n        });\n        return lowerValues.indexOf(value.toLowerCase());\n    };\n\n    // Return true if the type and value are in the filters.\n    this.isFilterActive = function(filters, type, value, exact) {\n        var values = filters[type];\n        if(angular.isUndefined(values)) {\n            return false;\n        }\n        if(angular.isUndefined(exact)) {\n            exact = false;\n        }\n        if(exact) {\n            value = \"=\" + value;\n        }\n        return this._getFilterValueIndex(filters, type, value) !== -1;\n    };\n\n    // Toggles a filter on or off based on type and value.\n    this.toggleFilter = function(filters, type, value, exact) {\n        if(angular.isUndefined(filters[type])) {\n            filters[type] = [];\n        }\n        if(exact) {\n            value = \"=\" + value;\n        }\n        var idx = this._getFilterValueIndex(filters, type, value);\n        if(idx === -1) {\n            filters[type].push(value);\n        } else {\n            filters[type].splice(idx, 1);\n        }\n        return filters;\n    };\n\n    // Holds all stored filters.\n    var storedFilters = {};\n\n    // Store a filter for later.\n    this.storeFilters = function(name, filters) {\n        storedFilters[name] = filters;\n    };\n\n    // Retrieve a stored fitler.\n    this.retrieveFilters = function(name) {\n        return storedFilters[name];\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Validation Service\n *\n * Used by controllers to validate user inputs.\n */\n\nangular.module('MAAS').service('ValidationService', [\n    'ConverterService', function(ConverterService) {\n\n        // Pattern that matches a domainname.\n        // XXX 2016-02-24 lamont: This also matches \"example.com.\",\n        // which is wrong.\n        var domainnamePattern =\n            /^([a-z\\d]|[a-z\\d][a-z\\d-.]*[a-z\\d])*$/i;\n\n        // Pattern that matches a hostname.\n        var hostnamePattern =\n            /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])*$/;\n\n        // Pattern that matches a MAC.\n        var macPattern = /^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$/;\n\n        // Pattern used to match IPv4.\n        var ipv4Pattern = new RegExp([\n            '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.',\n            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.',\n            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.',\n            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'\n            ].join(''));\n\n        // Returns true if the octets in one equal two with the cidr mask in\n        // bits applied to both.\n        function cidrMatcher(one, two, size, bits) {\n            var part = 0;\n            while(bits > 0) {\n                var shift = size - bits;\n                if(shift < 0) {\n                    shift = 0;\n                }\n\n                var oneShift = one[part] >> shift;\n                var twoShift = two[part] >> shift;\n                if(oneShift !== twoShift) {\n                    return false;\n                }\n                bits -= size;\n                part += 1;\n            }\n            return true;\n        }\n\n        // Return true if the domainname is valid, false otherwise.\n        this.validateDomainName = function(domainname) {\n            // Invalid if the domain is not a string, empty, or more than\n            // 253 characters.\n            if(!angular.isString(domainname) ||\n                domainname.length === 0 || domainname.length > 253) {\n                return false;\n            }\n            return domainnamePattern.test(domainname);\n        };\n\n        // Return true if the hostname is valid, false otherwise.\n        this.validateHostname = function(hostname) {\n            // Invalid if the hostname is not a string, empty, or more than\n            // 63 characters.\n            if(!angular.isString(hostname) ||\n                hostname.length === 0 || hostname.length > 63) {\n                return false;\n            }\n            return hostnamePattern.test(hostname);\n        };\n\n        // Return true if the MAC is valid, false otherwise.\n        this.validateMAC = function(macAddress) {\n            // Invalid if the macAddress is not a string.\n            if(!angular.isString(macAddress)) {\n                return false;\n            }\n            return macPattern.test(macAddress.trim());\n        };\n\n        // Return true if the IP is valid IPv4 address, false otherwise.\n        this.validateIPv4 = function(ipAddress) {\n            // Invalid if the ipAddress is not a string or empty.\n            if(!angular.isString(ipAddress) || ipAddress.length === 0) {\n                return false;\n            }\n            return ipv4Pattern.test(ipAddress);\n        };\n\n        // Return true if the IP is valid IPv6 address, false otherwise.\n        this.validateIPv6 = function(ipAddress) {\n            // Invalid if the ipAddress is not a string, empty, or missing\n            // at least one ':'.\n            if(!angular.isString(ipAddress) ||\n                ipAddress.length === 0 ||\n                ipAddress.indexOf(':') === -1) {\n                return false;\n            }\n            var expandedAddress = ConverterService.ipv6Expand(ipAddress);\n            var octets = ConverterService.ipv6ToGroups(expandedAddress);\n            if(octets.length !== 8) {\n                return false;\n            }\n\n            // Make sure all octets are in range.\n            var i;\n            for(i = 0; i < 8; i++) {\n                if(isNaN(octets[i]) || octets[i] < 0 || octets[i] > 0xffff) {\n                    // Out of range.\n                    return false;\n                }\n            }\n\n            // Don't allow unspecified, loopback, multicast, link-local\n            // unicast, or anything out of range.\n            if(octets[0] < 1 ||\n                octets[0] === 0xff00 ||\n                octets[0] === 0xfe80) {\n                return false;\n            }\n            return true;\n        };\n\n        // Return true if the IP is valid, false otherwise.\n        this.validateIP = function(ipAddress) {\n            return (\n                this.validateIPv4(ipAddress) || this.validateIPv6(ipAddress));\n        };\n\n        // Return true if the ipAddress is in the network.\n        this.validateIPInNetwork = function(ipAddress, network) {\n            var networkSplit = network.split('/');\n            var networkAddress = networkSplit[0];\n            var cidrBits = parseInt(networkSplit[1], 10);\n\n            if(this.validateIPv4(ipAddress) &&\n                this.validateIPv4(networkAddress)) {\n                return cidrMatcher(\n                    ConverterService.ipv4ToOctets(ipAddress),\n                    ConverterService.ipv4ToOctets(networkAddress),\n                    8, cidrBits);\n            } else if(this.validateIPv6(ipAddress) &&\n                this.validateIPv6(networkAddress)) {\n                return cidrMatcher(\n                    ConverterService.ipv6ToGroups(ipAddress),\n                    ConverterService.ipv6ToGroups(networkAddress),\n                    16, cidrBits);\n            }\n            return false;\n        };\n\n        // Return true if the ipAddress is in the network and between the\n        // lowAddress and highAddress inclusive.\n        this.validateIPInRange = function(\n            ipAddress, network, lowAddress, highAddress) {\n            // If the ip address is not even in the network then its\n            // not in the range.\n            if(!this.validateIPInNetwork(ipAddress, network)) {\n                return false;\n            }\n\n            var i, ipOctets, lowOctets, highOctets;\n            if(this.validateIPv4(ipAddress) &&\n                this.validateIPv4(lowAddress) &&\n                this.validateIPv4(highAddress)) {\n\n                // Check that each octet is of the ip address is more or equal\n                // to the low address and less or equal to the high address.\n                ipOctets = ConverterService.ipv4ToOctets(ipAddress);\n                lowOctets = ConverterService.ipv4ToOctets(lowAddress);\n                highOctets = ConverterService.ipv4ToOctets(highAddress);\n                for(i = 0; i < 4; i++) {\n                    if(ipOctets[i] > highOctets[i] ||\n                        ipOctets[i] < lowOctets[i]) {\n                        return false;\n                    }\n                }\n                return true;\n            } else if(this.validateIPv6(ipAddress) &&\n                this.validateIPv6(lowAddress) &&\n                this.validateIPv6(highAddress)) {\n\n                // Check that each octet is of the ip address is more or equal\n                // to the low address and less or equal to the high address.\n                ipOctets = ConverterService.ipv6ToGroups(ipAddress);\n                lowOctets = ConverterService.ipv6ToGroups(lowAddress);\n                highOctets = ConverterService.ipv6ToGroups(highAddress);\n                for(i = 0; i < 8; i++) {\n                    if(ipOctets[i] > highOctets[i] ||\n                        ipOctets[i] < lowOctets[i]) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return false;\n        };\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * IO module.\n *\n */\n\nYUI.add('maas.io', function(Y) {\n\nY.log('loading maas.io');\n\nvar module = Y.namespace('maas.io');\n\n/**\n * Return a Y.IO object to talk to the MAAS website.\n *\n * @method getIO\n */\nmodule.getIO = function() {\n    var io = new Y.IO();\n    // Populate the header used by Django for CSRF protection.\n    Y.io.header('X-CSRFTOKEN', Y.Cookie.get(\"csrftoken\"));\n    return io;\n};\n\n}, '0.1', {'requires': ['cookie', 'io-base']}\n);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * OS/Release seletion utilities.\n *\n * @module Y.maas.power_parameter\n */\n\nYUI.add('maas.os_distro_select', function(Y) {\n\nY.log('loading maas.os_distro_select');\nvar module = Y.namespace('maas.os_distro_select');\n\n// Only used to mockup io in tests.\nmodule._io = new Y.maas.io.getIO();\n\nvar OSReleaseWidget;\n\n/**\n * A widget class that modifies the viewable options of the release\n * field, based on the selected operating system field.\n *\n */\nOSReleaseWidget = function() {\n    OSReleaseWidget.superclass.constructor.apply(this, arguments);\n};\n\nOSReleaseWidget.NAME = 'os-release-widget';\n\nY.extend(OSReleaseWidget, Y.Widget, {\n\n   /**\n    * Initialize the widget.\n    * - cfg.srcNode is the node which will be updated when the selected\n    *   value of the 'os node' will change.\n    * - cfg.osNode is the node containing a 'select' element.  When\n    *   the selected element will change, the srcNode HTML will be\n    *   updated.\n    *\n    * @method initializer\n    */\n    initializer: function(cfg) {\n        this.initialSkip = true;\n    },\n\n   /**\n    * Bind the widget to events (to name 'event_name') generated by the given\n    * 'osNode'.\n    *\n    * @method bindTo\n    */\n    bindTo: function(osNode, event_name) {\n        var self = this;\n        if (!osNode) {\n            return;\n        }\n        Y.one(osNode).on(event_name, function(e) {\n            var osValue = e.currentTarget.get('value');\n            self.switchTo(osValue);\n        });\n        var osValue = Y.one(osNode).get('value');\n        self.switchTo(osValue);\n    },\n\n   /**\n    * React to a new value of the os node: update the HTML of\n    * 'srcNode'.\n    *\n    * @method switchTo\n    */\n    switchTo: function(newOSValue) {\n        var srcNode = this.get('srcNode');\n        var options = srcNode.all('option');\n        var selected = false;\n        options.each(function(option) {\n            var sel = this.modifyOption(option, newOSValue);\n            if (selected === false) {\n                selected = sel;\n            }\n        }, this);\n\n        // We skip selection on first load, as Django will already\n        // provide the users, current selection. Without this the\n        // current selection will be clobered.\n        if (this.initialSkip === true) {\n            this.initialSkip = false;\n            return;\n        }\n\n        // See if a selection was made, if not then we need\n        // to select the first visible as a default is not\n        // present.\n        if(!selected) {\n            this.selectVisableOption(options);\n        }\n    },\n\n   /**\n    * Modify an option to make it visible or hidden. Returns true\n    * if the method also make the selection active.\n    *\n    * @method modifyOption\n    */\n    modifyOption: function(option, newOSValue) {\n        var selected = false;\n        var value = option.get('value');\n        var split_value = value.split(\"/\");\n\n        // If \"Default OS\" is selected, then\n        // only show \"Default OS Release\".\n        if(newOSValue === '') {\n            if(value === '') {\n                option.removeClass('hidden');\n                option.set('selected', 'selected');\n            }\n            else {\n                option.addClass('hidden');\n            }\n        }\n        else {\n            if(split_value[0] === newOSValue) {\n                option.removeClass('hidden');\n                if(split_value[1] === '' && !this.initialSkip) {\n                    selected = true;\n                    option.set('selected', 'selected');\n                }\n            }\n            else {\n                option.addClass('hidden');\n            }\n        }\n        return selected;\n    },\n\n   /**\n    * Selected the first option that is not hidden.\n    *\n    * @method selectVisableOption\n    */\n    selectVisableOption: function(options) {\n        var first_option = null;\n        Y.Array.each(options, function(option) {\n            if(!option.hasClass('hidden')) {\n                if(first_option === null) {\n                    first_option = option;\n                }\n            }\n        });\n        if(first_option !== null) {\n            first_option.set('selected', 'selected');\n        }\n    }\n});\n\nmodule.OSReleaseWidget = OSReleaseWidget;\n\n}, '0.1', {'requires': ['widget', 'maas.io']}\n);\n\nYUI().use(\n  'maas.os_distro_select',\n  function (Y) {\n  Y.on('load', function() {\n    // Create OSDistroWidget so that the release field will be\n    // updated each time the value of the os field changes.\n    var releaseWidget = new Y.maas.os_distro_select.OSReleaseWidget({\n        srcNode: '#id_deploy-default_distro_series'\n        });\n    releaseWidget.bindTo(Y.one('#id_deploy-default_osystem'), 'change');\n    releaseWidget.render();\n  });\n});\n","/* Copyright 2012-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Utilities for the user preferences page.\n *\n * @module Y.maas.prefs\n */\n\nYUI.add('maas.prefs', function(Y) {\n\nY.log('loading maas.prefs');\nvar module = Y.namespace('maas.prefs');\n\n// Only used to mockup io in tests.\nmodule._io = new Y.maas.io.getIO();\n\nvar TokenWidget;\n\nTokenWidget = function() {\n    TokenWidget.superclass.constructor.apply(this, arguments);\n};\n\nTokenWidget.NAME = 'profile-widget';\n\nTokenWidget.ATTRS = {\n    // The number of tokens displayed.\n    nb_tokens: {\n        readOnly: true,\n        getter: function() {\n            return this.get('srcNode').all('.js-bundle').size();\n        }\n    }\n};\n\nY.extend(TokenWidget, Y.Widget, {\n\n    displayError: function(message) {\n        this.status_node.set('text', message);\n    },\n\n    initializer: function(cfg) {\n        this.create_link = Y.Node.create('<a />')\n            .set('href', '#')\n            .set('id','create_token')\n            .addClass('p-button--neutral')\n            .addClass('u-float--right')\n            .set('text', \"Generate MAAS key\");\n        this.status_node = Y.Node.create('<div />')\n            .set('id','create_error');\n        this.spinnerNode = Y.Node.create('<img />')\n            .addClass('u-animation--spin')\n            .addClass('icon')\n            .addClass('icon--loading');\n        this.get('srcNode').one('#token_creation_placeholder')\n            .append(this.create_link)\n            .append(this.status_node);\n    },\n\n    confirm: function(message) {\n        return confirm(message);\n    },\n\n    bindDeleteRow: function(row) {\n        var self = this;\n        var delete_link = row.one('a.js-delete-link');\n        delete_link.on('click', function(e) {\n            e.preventDefault();\n            if (self.confirm(\"Are you sure you want to delete this key?\")) {\n                self.deleteToken(row);\n            }\n        });\n    },\n\n    bindUI: function() {\n        var self = this;\n        this.create_link.on('click', function(e) {\n            e.preventDefault();\n            self.requestKeys();\n        });\n        Y.each(this.get('srcNode').all('.js-bundle'), function(row) {\n            self.bindDeleteRow(row);\n        });\n    },\n\n   /**\n    * Delete the token contained in the provided row.\n    * Call the API to delete the token and then remove the table row.\n    *\n    * @method deleteToken\n    */\n    deleteToken: function(row) {\n        var token_key = row.one('input').get('id');\n        var self = this;\n        var cfg = {\n            method: 'POST',\n            data: Y.QueryString.stringify({\n                op: 'delete_authorisation_token',\n                token_key: token_key\n                }),\n            sync: false,\n            on: {\n                start: Y.bind(self.showSpinner, self),\n                end: Y.bind(self.hideSpinner, self),\n                success: function(id, out) {\n                    row.remove();\n                 },\n                failure: function(id, out) {\n                    Y.log(out);\n                    if (out.status === 404) {\n                        self.displayError(\"The key has already been deleted.\");\n                    }\n                    else {\n                        self.displayError(\"Unable to delete the key.\");\n                    }\n                }\n            }\n        };\n        var request = module._io.send(\n            MAAS_config.uris.account_handler, cfg);\n    },\n\n    showSpinner: function() {\n        this.displayError('');\n        this.status_node.insert(this.spinnerNode, 'after');\n    },\n\n    hideSpinner: function() {\n        this.spinnerNode.remove();\n    },\n\n   /**\n    * Create a single string token from a key set.\n    *\n    * A key set is composed of 3 keys: consumer_key, token_key, token_secret.\n    * For an easy copy and paste experience, the string handed over to the\n    * user is a colon separated concatenation of these keys called 'token'.\n    *\n    * @method createTokenFromKeys\n    */\n    createTokenFromKeys: function(consumer_key, token_key, token_secret) {\n        return consumer_key + ':' + token_key + ':' + token_secret;\n    },\n\n   /**\n    * Add a token to the list of tokens.\n    *\n    * @method addToken\n    */\n    addToken: function(token, token_key) {\n        var list = this.get('srcNode').one('ul');\n        var row = Y.Node.create('<li />')\n            .addClass('js-bundle')\n            .addClass('u-equal-height')\n            .append(Y.Node.create('<div />')\n                .addClass('col-8')\n                .addClass('p-code-snippet')\n                    .append(Y.Node.create('<input />')\n                        .set('type', 'text')\n                        .addClass('p-code-snippet__input')\n                        .set('id', token_key)\n                        .set('value', token)))\n            .append(Y.Node.create(\n                '<div class=\"col-1 u-vertically-center\">' +\n                '<a class=\"p-tooltip p-tooltip--top-center js-delete-link\">' +\n                '<i class=\"p-icon--delete\"></i>' +\n                '<span class=\"p-tooltip__message\" role=\"tooltip\">' +\n                'Delete API key</span></a></div>'))\n       list.append(row);\n       this.bindDeleteRow(row);\n    },\n\n   /**\n    * Request a new OAuth key set from the API.\n    *\n    * @method requestKeys\n    */\n    requestKeys: function() {\n        var self = this;\n        var cfg = {\n            method: 'POST',\n            data: 'op=create_authorisation_token',\n            sync: false,\n            on: {\n                start: Y.bind(self.showSpinner, self),\n                end: Y.bind(self.hideSpinner, self),\n                success: function(id, out) {\n                    var keys;\n                    try {\n                        keys = JSON.parse(out.response);\n                    }\n                    catch(e) {\n                        // Parsing error.\n                        self.displayError('Unable to create a new token.');\n                    }\n                    // Generate a token from the keys.\n                    var token = self.createTokenFromKeys(\n                        keys.consumer_key, keys.token_key,\n                        keys.token_secret);\n                    // Add the new token to the list of tokens.\n                    self.addToken(token, keys.token_key);\n                 },\n                failure: function(id, out) {\n                    self.displayError('Unable to create a new token.');\n                }\n            }\n        };\n        var request = module._io.send(\n            MAAS_config.uris.account_handler, cfg);\n    }\n});\n\nmodule.TokenWidget = TokenWidget;\n\n}, '0.1', {'requires': ['widget', 'maas.io']}\n);\n","/* Copyright 2012-2014 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Widget to expand (make visible) or fold (make invisible) a content div,\n * in response to clicks on a button link.\n *\n * Write your initial HTML for the visible state.  If the client does not\n * execute the script, the content div will be visible.  Upon initialization,\n * the widget immediately goes into its \"hidden\" state.\n *\n * Once the widget is set up, its reveal() method will toggle it between its\n * visible and invisible states.  The transition is animated with a sliding\n * effect.\n *\n * The widget fires a \"hiding\" event before hiding, and \"hidden\" after.\n * Similarly, it fires \"revealing\" before revealing and \"revealed\" after.\n *\n * Synonyms: expander, collapsible, foldable.\n *\n * @module Y.maas.reveal\n */\n\nYUI.add('maas.reveal', function(Y) {\n\nY.log('loading maas.reveal');\n\nvar module = Y.namespace('maas.reveal');\n\nvar Reveal;\n\nReveal = function(config) {\n    Reveal.superclass.constructor.apply(this, arguments);\n};\n\nReveal.NAME = 'reveal';\n\nReveal.ATTRS = {\n    /**\n     * DOM node for the content div.  This is the div that will be hidden\n     * or revealed.  It must contain exactly one tag.\n     *\n     * The widget will add the \"slider\" class to this node, and the \"content\"\n     * class to its child node.\n     *\n     * Hiding the content is done by setting the target node's height to zero;\n     * it's child node keeps its original size but becomes invisible.\n     *\n     * @attribute targetNode\n     * @type node\n     */\n    targetNode: {\n        value: null\n    },\n\n    /**\n     * DOM node for the button link that triggers the reveal.\n     *\n     * @attribute linkNode\n     * @type node\n     */\n    linkNode: {\n        value: null\n    },\n\n    /**\n     * The text the button link should contain when the content div is\n     * visible.\n     *\n     * @attribute hideText\n     * @type string\n     */\n    hideText: {\n        value: null\n    },\n\n    /**\n     * The text the button link should contain when the content div is hidden.\n     *\n     * @attribute showText\n     * @type string\n     */\n    showText: {\n        value: null\n    },\n\n    /**\n     * Skip animations?\n     *\n     * Use this when testing, to avoid wasting time on delays.\n     *\n     * @attribute quick\n     * @type bool\n     */\n    quick: {\n        value: false\n    }\n};\n\n\n// Return a style attribute for a node, as an int.\n// Any suffix to the number, such as the typical \"px,\" is ignored.\nfunction get_style_int(node, attribute) {\n    return parseInt(node.getStyle(attribute), 10);\n}\n\n\nY.extend(Reveal, Y.Widget, {\n    /**\n     * Standard YUI hook: prepare the DOM for the widget.\n     *\n     * @method renderUI\n     */\n    renderUI: function() {\n        var target = this.get('targetNode');\n        target.addClass('slider');\n        target.get('children').addClass('content');\n    },\n\n    /**\n     * Standard YUI hook: install event listeners for the widget.\n     *\n     * @method bindUI\n     */\n    bindUI: function() {\n        var self = this;\n        this.get('linkNode').on('click', function(e) {\n            e.preventDefault();\n            self.reveal();\n        });\n    },\n\n    /**\n     * Standard YUI hook: update UI to match the widget's state at the time\n     * it is rendered.\n     *\n     * The HTML is written in an expanded state, but during rendering, the\n     * widget immediately (and without animation) goes into its hidden state.\n     *\n     * @method syncUI\n     */\n    syncUI: function() {\n        this.fire(\"hiding\");\n        this.get('targetNode').setStyle('height', 0);\n        this.set_hidden_link(this.get('linkNode'));\n        this.fire(\"hidden\");\n    },\n\n    /**\n     * Is this widget currently in its visible state?\n     *\n     * @method is_visible\n     */\n    is_visible: function() {\n        return get_style_int(this.get('targetNode'), 'height') > 0;\n    },\n\n    /**\n     * Set link to its \"hidden\" state.\n     *\n     * @method set_hidden_link\n     */\n    set_hidden_link: function(link) {\n        var new_text = this.get('showText');\n        if (new_text !== null && new_text !== undefined) {\n            link.set('text', new_text);\n        }\n    },\n\n    /**\n     * Set link to its \"visible\" state.\n     *\n     * @method set_visible_link\n     */\n    set_visible_link: function(link) {\n        var new_text = this.get('hideText');\n        if (new_text !== null && new_text !== undefined) {\n            link.set('text', new_text);\n        }\n    },\n\n    /**\n     * Get the desired duration for an animation.\n     *\n     * Returns the suggested duration, unless the \"quick\" attribute is set\n     * in which case it returns a very brief duration.\n     *\n     * @method get_animation_duration\n     */\n    get_animation_duration: function(suggested_duration) {\n        if (this.get('quick')) {\n            return 0.01;\n        }\n        else {\n            return suggested_duration;\n        }\n    },\n\n    /**\n     * Create the animation for sliding in the content div.\n     *\n     * @method create_slide_in\n     */\n    create_slide_in: function(node, publisher) {\n        var anim = new Y.Anim({\n            node: node,\n            duration: this.get_animation_duration(0.3),\n            to: {height: 0}\n        });\n        anim.on('end', function() {\n            publisher.fire('hidden');\n        });\n        return anim;\n    },\n\n    /**\n     * Create the animation for sliding out the content div.\n     *\n     * @method create_slide_out\n     */\n    create_slide_out: function(node, publisher) {\n        // The target node contains exactly one node of content.  Its height\n        // is constant.  We calculate the appropriate expanded height for the\n        // target node from the height of the content node, plus marings and\n        // padding.\n        var content_node = node.one('.content');\n        var new_height = (\n            get_style_int(content_node, 'height') +\n            get_style_int(content_node, 'paddingTop') +\n            get_style_int(content_node, 'paddingBottom') +\n            get_style_int(content_node, 'marginTop') +\n            get_style_int(content_node, 'marginBottom'));\n        var anim = new Y.Anim({\n            node: node,\n            duration: this.get_animation_duration(0.2),\n            to: {height: new_height}\n        });\n        anim.on('end', function() {\n            publisher.fire('revealed');\n        });\n        return anim;\n    },\n\n    /**\n     * Toggle between the hidden and revealed states.\n     *\n     * @method reveal\n     */\n    reveal: function() {\n        var target = this.get('targetNode');\n        var link = this.get('linkNode');\n        if (this.is_visible()) {\n            this.fire('hiding');\n            this.create_slide_in(target, this).run();\n            this.set_hidden_link(link);\n        }\n        else {\n            this.fire('revealing');\n            this.create_slide_out(target, this).run();\n            this.set_visible_link(link);\n        }\n    }\n});\n\nmodule.Reveal = Reveal;\n\n}, '0.1', {'requires': ['widget', 'node', 'event', 'anim']});\n\nYUI().use('maas.reveal', function (Y) {\n  Y.on('domready', function() {\n    Y.all('.p-script-expander').each(function (script_entry) {\n      var script_expander = new Y.maas.reveal.Reveal({\n        targetNode: script_entry.one('.p-script-expander__content'),\n        linkNode: script_entry.one('.p-script-expander__trigger')\n        });\n      script_expander.render();\n    });\n  });\n});\n","/* Copyright 2014-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * The shortpoll module provides the functionality to deal with updating\n * in-browser data by polling the server.\n *\n * @module shortpoll\n */\nYUI.add('maas.shortpoll', function(Y) {\n\nvar namespace = Y.namespace('maas.shortpoll');\n\n// Event fired when the short-polling request starts.\nnamespace.shortpoll_start_event = 'maas.shortpoll.start';\n\n// Event fired each time the short-polling request fails (to connect or\n// to parse the returned result).\nnamespace.shortpoll_fail_event = 'maas.shortpoll.failure';\n\n// After MAX_SHORT_DELAY_FAILED_ATTEMPTS failed connections (real failed\n// connections or connection getting an invalid return) separated\n// by SHORT_DELAY (millisec), wait LONG_DELAY (millisec) between\n// each failed connection.\nnamespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS = 5;\nnamespace.SHORT_DELAY = 15 * 1000;  // 15 seconds.\nnamespace.LONG_DELAY = 3 * 60 * 1000;  // 3 minutes.\n\n// Ugly hack for tests, to prevent repolling.\nnamespace._repoll = true;\n\n// Overridden by tests.\nnamespace._io = new Y.maas.io.getIO();\n\n/**\n *\n * A ShortPollManager creates and manages a polling connection to the server\n * to fetch objects.\n *\n * @class ShortPollManager\n */\nfunction ShortPollManager(config) {\n    ShortPollManager.superclass.constructor.apply(this, arguments);\n}\n\nShortPollManager.NAME = \"shortPollManager\";\n\nShortPollManager.ATTRS = {\n    /**\n     * The URI to poll.\n     *\n     * @attribute uri\n     * @type string\n     */\n    uri: {\n        value: \"\"\n    },\n\n    /**\n     * The key with which to publish polled responses.\n     *\n     * @attribute eventKey\n     * @type string\n     */\n    eventKey: {\n        valueFn: function() {\n            return Y.guid(\"shortpoll_\");\n        }\n    },\n\n    /**\n     * The IO instance used.\n     *\n     * @attribute io\n     * @type Y.IO\n     */\n    io: {\n        readOnly: true,\n        getter: function() {\n            return namespace._io;\n        }\n    }\n};\n\nY.extend(ShortPollManager, Y.Base, {\n    initializer : function(cfg) {\n        this._started = false;\n        this._failed_attempts = 0;\n        this._sequence = 0;\n    },\n\n    successPoll : function (id, response) {\n        try {\n            var eventKey = this.get(\"eventKey\");\n            var data = Y.JSON.parse(response.responseText);\n            Y.fire(eventKey, data);\n            return true;\n        }\n        catch (e) {\n            Y.fire(namespace.shortpoll_fail_event, e);\n            return false;\n        }\n    },\n\n    failurePoll : function () {\n        Y.fire(namespace.shortpoll_fail_event);\n    },\n\n    /**\n     * Return the delay (milliseconds) to wait before trying to reconnect\n     * again after a failed connection.\n     *\n     * The rationale here is that:\n     * 1. We should not try to reconnect instantaneously after a failed\n     *    connection.\n     * 2. After a certain number of failed connections, we should set the\n     *    delay between two failed connection to a bigger number because the\n     *    server may be having problems.\n     *\n     * @method _pollDelay\n     */\n    _pollDelay : function() {\n        if (this._failed_attempts >=\n                namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS) {\n            return namespace.LONG_DELAY;\n        }\n        else {\n            return namespace.SHORT_DELAY;\n        }\n    },\n\n    /**\n     * Relaunch a connection to the server after a successful or\n     * a failed connection.\n     *\n     * @method repoll\n     * @param {Boolean} failed: whether or not the previous connection\n     *     has failed.\n     */\n    repoll : function(failed) {\n        if (failed) {\n            this._failed_attempts += 1;\n        }\n        else {\n            this._failed_attempts = 0;\n        }\n        if (namespace._repoll) {\n            var delay = this._pollDelay();\n            Y.later(delay, this, this.poll);\n            return delay;\n        }\n        else {\n            return this._pollDelay();\n        }\n    },\n\n    poll : function() {\n        var that = this;\n        var config = {\n            method: \"GET\",\n            sync: false,\n            on: {\n                failure: function(id, response) {\n                    if (Y.Lang.isValue(response) &&\n                        Y.Lang.isValue(response.status) &&\n                        (response.status === 408 ||\n                         response.status === 504)) {\n                        // If the error code is:\n                        // - 408 Request timeout\n                        // - 504 Gateway timeout\n                        // Then ignore the error and start\n                        // polling again.\n                        that.repoll(false);\n                    }\n                    else {\n                        that.failurePoll();\n                        that.repoll(true);\n                    }\n                },\n                success: function(id, response) {\n                    var success = that.successPoll(id, response);\n                    that.repoll(!success);\n                }\n            }\n        };\n        this._sequence = this._sequence + 1;\n        var poll_uri = this.get(\"uri\");\n        if (poll_uri.indexOf(\"?\") >= 0) {\n            poll_uri += \"&sequence=\" + this._sequence;\n        }\n        else {\n            poll_uri += \"?sequence=\" + this._sequence;\n        }\n        if (!this._started) {\n            Y.fire(namespace.shortpoll_start_event);\n            this._started = true;\n        }\n        this.get(\"io\").send(poll_uri, config);\n    }\n});\n\nnamespace.ShortPollManager = ShortPollManager;\n\n}, \"0.1\", {\"requires\":[\"base\", \"event\", \"json\", \"maas.io\"]});\n","var MAASUI = MAASUI || {};\n\n/**\n * A set of framework-agnostic JavaScript utilities for the MAAS UI\n * @namespace MAASUI.utils\n * @return {Object} public methods\n */\nMAASUI.utils = (function() {\n  /**\n   * Run the supplied function when page content is loaded\n   * @namespace MAASUI.utils\n   * @method ready\n   * @param {Object} fn - the function to run\n   */\n  var ready = function(fn) {\n    if (document.attachEvent ? document.readyState === \"complete\" :\n        document.readyState !== \"loading\") {\n      fn();\n    } else {\n      document.addEventListener('DOMContentLoaded', fn);\n    }\n  };\n\n  /**\n   * Toggle a specified class on the provided element\n   * @namespace MAASUI.utils\n   * @method toggleClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to toggle\n   * @return {bool} true for success or false if incorrect params are given\n   */\n  var toggleClass = function(el, className) {\n    if (typeof(el) != 'undefined' && el != null) {\n      if (el.classList) {\n        el.classList.toggle(className);\n      } else {\n        var classes = el.className.split(' ');\n        var existingIndex = classes.indexOf(className);\n        if (existingIndex >= 0) {\n          classes.splice(existingIndex, 1);\n        } else {\n          classes.push(className);\n        }\n        el.className = classes.join(' ');\n      }\n    } else {\n      return false;\n    }\n    return true;\n  };\n\n  /**\n   * Remove a specified class from the provided element\n   * @namespace MAASUI.utils\n   * @method removeClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to remove\n   * @return {bool} true for success or false if incorrect params are given\n   */\n  var removeClass = function(el, className) {\n    if (typeof(el) != 'undefined' && el != null) {\n      if (el.classList) {\n        el.classList.remove(className);\n      } else {\n        el.className = el.className.replace(new RegExp(\n          '(^|\\\\b)' + className.split(' ').join('|') + '(\\\\b|$)', 'gi'), ' ');\n      }\n    } else {\n      return false;\n    }\n    return true;\n  };\n\n  /**\n   * Check if a DOM element has a class\n   * @namespace MAASUI.utils\n   * @method hasClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to check\n   * @return {bool} is the class present\n   */\n  var hasClass = function(el, className) {\n    var hasClass = false;\n\n    if (el.classList) {\n      hasClass = el.classList.contains(className);\n    } else {\n      hasClass = new RegExp(\n        '(^| )' + className + '( |$)', 'gi').test(el.className);\n    }\n\n    return hasClass;\n  };\n\n  /**\n   * Remove a specified class from the provided element\n   * @namespace MAASUI.utils\n   * @method addClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to add\n   */\n  var addClass = function(el, className) {\n    if (!hasClass(el, className)) {\n      if (el.classList) {\n        el.classList.add(className);\n      } else {\n        el.className += ' ' + className;\n      }\n    }\n  };\n\n  return {\n    ready: ready,\n    toggleClass: toggleClass,\n    removeClass: removeClass,\n    hasClass: hasClass,\n    addClass: addClass\n  };\n})();\n\n/**\n * A handler for toggleable menus\n * @namespace MAASUI.dropdown\n */\nMAASUI.dropdown = (function() {\n  var wrapperClassname = \"p-dropdown\";\n  var toggleClassName = \"p-dropdown__toggle\";\n  var menuClassName = \"p-dropdown__menu\";\n  var menuItemClassName =\"p-dropdown__item\";\n  var activeClassName = \"active\"\n  var dropdowns;\n\n  /**\n   * Initialise the menu and toggle events\n   * @namespace MAASUI.dropdown\n   * @method init\n   */\n  var init = function() {\n    dropdowns = document.querySelectorAll('.' + wrapperClassname);\n\n    Array.prototype.forEach.call(dropdowns, function(dropdown, i) {\n      // Add click event for dropdown toggling.\n      dropdown.addEventListener(\"click\", click);\n\n      // Add click event to all dropdown links to close menus.\n      var sublinks = dropdown.querySelectorAll('.' + menuItemClassName);\n      Array.prototype.forEach.call(sublinks, function(link, i) {\n        link.addEventListener(\"click\", closeAllMenus);\n      });\n\n      // Add click event for whole document to close all menus when\n      // anything else is clicked.\n      document.addEventListener('click', function(event) {\n        var isClickInside = dropdown.contains(event.target);\n        if (!isClickInside) {\n          closeAllMenus();\n        }\n      });\n    });\n\n    return true;\n  }\n\n  /**\n   * A handler for a toggle menu click (intended for use on click events)\n   * @namespace MAASUI.dropdown\n   * @method click\n   * @param {Object} event - a click event\n   */\n  var click = function(event) {\n    if (MAASUI.utils.hasClass(this, activeClassName)) {\n      closeAllMenus();\n    } else {\n      openMenu(this);\n    }\n    event.stopPropagation();\n  }\n\n  /**\n   * Opens the menu for the provided dropdown element\n   * @namespace MAASUI.dropdown\n   * @method openMenu\n   * @param {Object} el - the dropdown element\n   */\n  var openMenu = function(el) {\n    closeAllMenus();\n    MAASUI.utils.addClass(el, activeClassName);\n  }\n\n  /**\n   * Closes all open menus and deactivates all toggles\n   * @namespace MAASUI.dropdown\n   * @method closeAllMenus\n   * @param {Object} event - a click event (optional)\n   */\n  var closeAllMenus = function(event) {\n    Array.prototype.forEach.call(dropdowns, function(dropdown, i) {\n      //Deactive all toggle buttons\n      MAASUI.utils.removeClass(dropdown, activeClassName);\n    });\n\n    if (typeof event != 'undefined') {\n      event.stopPropagation();\n    }\n  }\n\n  return {\n    init: init\n  };\n})();\n\nMAASUI.utils.ready(MAASUI.dropdown.init);\n"],"sourceRoot":""}
 
 
b'\\ No newline at end of file'
 
1
{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/maasserver/static/js/angular/controllers/add_device.js","webpack:///./src/maasserver/static/js/angular/controllers/add_domain.js","webpack:///./src/maasserver/static/js/angular/controllers/add_hardware.js","webpack:///./src/maasserver/static/js/angular/controllers/dashboard.js","webpack:///./src/maasserver/static/js/angular/controllers/domain_details.js","webpack:///./src/maasserver/static/js/angular/controllers/domains_list.js","webpack:///./src/maasserver/static/js/angular/controllers/fabric_details.js","webpack:///./src/maasserver/static/js/angular/controllers/images.js","webpack:///./src/maasserver/static/js/angular/controllers/intro.js","webpack:///./src/maasserver/static/js/angular/controllers/intro_user.js","webpack:///./src/maasserver/static/js/angular/controllers/networks_list.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details_networking.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details_storage.js","webpack:///./src/maasserver/static/js/angular/controllers/node_details_storage_filesystems.js","webpack:///./src/maasserver/static/js/angular/controllers/node_events.js","webpack:///./src/maasserver/static/js/angular/controllers/node_result.js","webpack:///./src/maasserver/static/js/angular/controllers/node_results.js","webpack:///./src/maasserver/static/js/angular/controllers/nodes_list.js","webpack:///./src/maasserver/static/js/angular/controllers/pod_details.js","webpack:///./src/maasserver/static/js/angular/controllers/pods_list.js","webpack:///./src/maasserver/static/js/angular/controllers/prefs.js","webpack:///./src/maasserver/static/js/angular/controllers/settings.js","webpack:///./src/maasserver/static/js/angular/controllers/space_details.js","webpack:///./src/maasserver/static/js/angular/controllers/subnet_details.js","webpack:///./src/maasserver/static/js/angular/controllers/vlan_details.js","webpack:///./src/maasserver/static/js/angular/controllers/zone_details.js","webpack:///./src/maasserver/static/js/angular/controllers/zones_list.js","webpack:///./src/maasserver/static/js/angular/directives/accordion.js","webpack:///./src/maasserver/static/js/angular/directives/boot_images.js","webpack:///./src/maasserver/static/js/angular/directives/call_to_action.js","webpack:///./src/maasserver/static/js/angular/directives/card_loader.js","webpack:///./src/maasserver/static/js/angular/directives/code_lines.js","webpack:///./src/maasserver/static/js/angular/directives/contenteditable.js","webpack:///./src/maasserver/static/js/angular/directives/controller_image_status.js","webpack:///./src/maasserver/static/js/angular/directives/controller_status.js","webpack:///./src/maasserver/static/js/angular/directives/dbl_click_overlay.js","webpack:///./src/maasserver/static/js/angular/directives/enter.js","webpack:///./src/maasserver/static/js/angular/directives/enter_blur.js","webpack:///./src/maasserver/static/js/angular/directives/error_overlay.js","webpack:///./src/maasserver/static/js/angular/directives/error_toggle.js","webpack:///./src/maasserver/static/js/angular/directives/ipranges.js","webpack:///./src/maasserver/static/js/angular/directives/maas_obj_form.js","webpack:///./src/maasserver/static/js/angular/directives/mac_address.js","webpack:///./src/maasserver/static/js/angular/directives/machines_table.js","webpack:///./src/maasserver/static/js/angular/directives/notifications.js","webpack:///./src/maasserver/static/js/angular/directives/os_select.js","webpack:///./src/maasserver/static/js/angular/directives/placeholder.js","webpack:///./src/maasserver/static/js/angular/directives/pod_parameters.js","webpack:///./src/maasserver/static/js/angular/directives/power_parameters.js","webpack:///./src/maasserver/static/js/angular/directives/proxy_settings.js","webpack:///./src/maasserver/static/js/angular/directives/release_name.js","webpack:///./src/maasserver/static/js/angular/directives/release_options.js","webpack:///./src/maasserver/static/js/angular/directives/script_results_list.js","webpack:///./src/maasserver/static/js/angular/directives/script_runtime.js","webpack:///./src/maasserver/static/js/angular/directives/script_select.js","webpack:///./src/maasserver/static/js/angular/directives/script_status.js","webpack:///./src/maasserver/static/js/angular/directives/ssh_keys.js","webpack:///./src/maasserver/static/js/angular/directives/switches_table.js","webpack:///./src/maasserver/static/js/angular/directives/toggle_control.js","webpack:///./src/maasserver/static/js/angular/directives/type.js","webpack:///./src/maasserver/static/js/angular/directives/version_reloader.js","webpack:///./src/maasserver/static/js/angular/directives/window_width.js","webpack:///./src/maasserver/static/js/angular/factories/bootresources.js","webpack:///./src/maasserver/static/js/angular/factories/configs.js","webpack:///./src/maasserver/static/js/angular/factories/controllers.js","webpack:///./src/maasserver/static/js/angular/factories/devices.js","webpack:///./src/maasserver/static/js/angular/factories/dhcpsnippets.js","webpack:///./src/maasserver/static/js/angular/factories/discoveries.js","webpack:///./src/maasserver/static/js/angular/factories/domains.js","webpack:///./src/maasserver/static/js/angular/factories/events.js","webpack:///./src/maasserver/static/js/angular/factories/fabrics.js","webpack:///./src/maasserver/static/js/angular/factories/general.js","webpack:///./src/maasserver/static/js/angular/factories/ipranges.js","webpack:///./src/maasserver/static/js/angular/factories/machines.js","webpack:///./src/maasserver/static/js/angular/factories/node_results.js","webpack:///./src/maasserver/static/js/angular/factories/nodes.js","webpack:///./src/maasserver/static/js/angular/factories/notifications.js","webpack:///./src/maasserver/static/js/angular/factories/packagerepositories.js","webpack:///./src/maasserver/static/js/angular/factories/pods.js","webpack:///./src/maasserver/static/js/angular/factories/region.js","webpack:///./src/maasserver/static/js/angular/factories/scripts.js","webpack:///./src/maasserver/static/js/angular/factories/services.js","webpack:///./src/maasserver/static/js/angular/factories/spaces.js","webpack:///./src/maasserver/static/js/angular/factories/sshkeys.js","webpack:///./src/maasserver/static/js/angular/factories/staticroutes.js","webpack:///./src/maasserver/static/js/angular/factories/subnets.js","webpack:///./src/maasserver/static/js/angular/factories/switches.js","webpack:///./src/maasserver/static/js/angular/factories/tags.js","webpack:///./src/maasserver/static/js/angular/factories/users.js","webpack:///./src/maasserver/static/js/angular/factories/vlans.js","webpack:///./src/maasserver/static/js/angular/factories/zones.js","webpack:///./src/maasserver/static/js/angular/filters/by_fabric.js","webpack:///./src/maasserver/static/js/angular/filters/by_space.js","webpack:///./src/maasserver/static/js/angular/filters/by_subnet.js","webpack:///./src/maasserver/static/js/angular/filters/by_vlan.js","webpack:///./src/maasserver/static/js/angular/filters/nodes.js","webpack:///./src/maasserver/static/js/angular/filters/order_by_date.js","webpack:///./src/maasserver/static/js/angular/filters/remove_default_vlan.js","webpack:///./src/maasserver/static/js/angular/maas.js","webpack:///./src/maasserver/static/js/angular/services/browser.js","webpack:///./src/maasserver/static/js/angular/services/converter.js","webpack:///./src/maasserver/static/js/angular/services/error.js","webpack:///./src/maasserver/static/js/angular/services/json.js","webpack:///./src/maasserver/static/js/angular/services/log.js","webpack:///./src/maasserver/static/js/angular/services/manager.js","webpack:///./src/maasserver/static/js/angular/services/managerhelper.js","webpack:///./src/maasserver/static/js/angular/services/pollingmanager.js","webpack:///./src/maasserver/static/js/angular/services/search.js","webpack:///./src/maasserver/static/js/angular/services/validation.js","webpack:///./src/maasserver/static/js/io.js","webpack:///./src/maasserver/static/js/os_distro_select.js","webpack:///./src/maasserver/static/js/prefs.js","webpack:///./src/maasserver/static/js/reveal.js","webpack:///./src/maasserver/static/js/shortpoll.js","webpack:///./src/maasserver/static/js/ui/maas-ui.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","r","value","n","__esModule","object","property","prototype","hasOwnProperty","p","s","angular","controller","$scope","DevicesManager","SubnetsManager","DomainsManager","ManagerHelperService","ValidationService","newDevice","cloneDevice","isObject","domain","interfaces","mac","ipAssignment","subnetId","ipAddress","getDefaultDomain","$parent","addDeviceScope","subnets","getItems","domains","viewable","error","ipAssignments","title","device","show","hide","$emit","nameHasError","length","validateHostname","macHasError","deviceInterface","validateMAC","ipHasError","validateIP","validateIPInNetwork","cidr","isNumber","subnet","getItemFromList","deviceHasError","externalIpError","staticIpError","addInterface","push","isPrimaryInterface","indexOf","deleteInterface","splice","cancel","save","addAnother","convertedDevice","hostname","primary_mac","extra_macs","forEach","nic","ip_assignment","ip_address","convertDeviceToProtocol","create","then","parseValidationError","loadManagers","addDomainScope","authoritative","validateDomainName","domainHasError","copy","convertDomainToProtocol","$http","ZonesManager","MachinesManager","GeneralManager","RegionConnection","addHardwareScope","model","zones","architectures","getData","hwe_kernels","default_min_hwe_kernel","power_types","macAddressRegex","machine","chassis","virshFields","label","field_type","default","choices","required","defaultArchitecture","newMachine","cloneMachine","macs","zone","architecture","min_hwe_kernel","power","type","parameters","text","newChassis","cloneChassis","chassisPowerTypes","description","fields","mode","startPolling","stopPolling","showMachine","showChassis","addMac","removeMac","idx","invalidName","validateMac","machineHasError","in_error","chassisHasErrors","power_type","field","isUndefined","powerParametersHasError","saveMachine","pxe_mac","shift","map","power_parameters","id","saveChassis","params","chassis_type","username","method","url","data","$","param","headers","Content-Type","loadManager","$on","$window","$rootScope","$routeParams","$location","DiscoveriesManager","VLANsManager","ConfigsManager","deviceIPOptions","page","loaded","discoveredDevices","machines","devices","configManager","networkDiscovery","column","selectedDevice","convertTo","predicate","last_seen","sortTable","reverse","proxyManager","updateItem","createItem","createInterface","Error","getDiscoveryName","discovery","getSubnetName","getName","getVLANName","vlanId","vlan","toggleSelected","deviceId","discovered","getDomainByName","slice","split","parent","goTo","saved","filter","option","preProcess","item","mac_address","ip","afterSave","obj","_removeItem","isString","path","search","tab","UsersManager","ErrorService","domainLoaded","displayname","isSuperUser","isDefaultDomain","canBeDeleted","rrsets","deleteButton","confirmingDelete","cancelDeleteButton","deleteConfirmButton","deleteDomain","activeDomain","getActiveItem","requestedDomain","parseInt","domain_id","isNaN","raiseError","setActiveItem","$filter","currentpage","loading","addDomain","cancelAddDomain","FabricsManager","SpacesManager","ControllersManager","fabricLoaded","fabric","$watch","updateVLANs","rows","racks","vlans","space","space_name","row","vlan_name","subnet_name","rack_sids","rack_sid","rack","system_id","keys","key","fabricManager","editSummary","controllers","enterEditSummary","exitEditSummary","isDefaultFabric","deleteFabric","reply","activeFabric","requestedFabric","fabric_id","BootResourcesManager","bootResources","autoImport","isArray","resources","PackageRepositoriesManager","repoManager","hasImages","maasName","upstreamDNS","mainArchive","portsArchive","httpProxy","skip","clickContinue","welcomeInError","form","$maasForm","hasErrors","networkInError","inError","objs","canContinue","force","location","reload","MAAS_config","completed_intro","managers","repo","user","sshkeys_count","markIntroComplete","user_completed_intro","getAuthUser","filterByVLAN","filterByFabric","filterBySpace","filterByNullSpace","getURLParameters","by","groupBy","ADD_FABRIC_ACTION","selectedTitle","objectName","ADD_VLAN_ACTION","ADD_SPACE_ACTION","ADD_SUBNET_ACTION","subnetManager","fabrics","spaceManager","spaces","vlanManager","group","orphanVLANs","actionObjectInitializers","vlan_ids","updateGroupBy","previous_space","index","updateOrphanVLANs","previous_fabric","previous_vlan","fabric_name","updateFabricsGroupBy","updateActions","actionOptions","actionChanged","newObject","actionOption","cancelAction","getFabricNameById","fabricId","actionSubnetPreSave","$interval","TagsManager","ServicesManager","ScriptsManager","DEVICE_IP_ASSIGNMENT","external","dynamic","static","updateTitle","node","fqdn","updateHeader","header","editing","editing_domain","options","selected","updateAvailableActionOptions","action","availableOptions","allOptions","getAllActionOptions","node_type","actions","updatePower","bmc_node_count","power_bmc_node_count","canEdit","updateSummary","summary","tags","hasUsableArchitectures","hasInvalidArchitecture","updateServices","isController","services","getServices","service","updateDevices","child","nicIdx","deviceWithMAC","links","link","lIdx","deviceWithLink","nodeLoaded","$watchCollection","storageController","networkingController","showing_confirmation","osinfo","section","area","osSelection","osystem","release","hwe_kernel","commissionOptions","enableSSH","skipNetworking","skipStorage","updateFirmware","configureHBA","commissioningSelection","testSelection","releaseOptions","checkingPower","scripts","getDeviceIPAssignment","events","limit","0","1","2","3","4","updateNode","queryPower","nodesManager","checkPowerState","console","log","tagsAutocomplete","query","autocomplete","getPowerStateClass","power_state","getPowerStateText","canCheckPowerState","isUbuntuOS","isUbuntuCoreOS","isCustomOS","isActionError","isDeployError","missing_osinfo","osystems","isSSHKeyError","getSSHKeyCount","optionChanged","actionCancel","actionGo","extra","distro_series","enable_ssh","skip_networking","skip_storage","commissioning_scripts","testing_scripts","status_code","erase","secure_erase","secureErase","quick_erase","quickErase","performAction","$reset","getArchitecturePlaceholder","isDevice","invalidArchitecture","isRackControllerConnected","isLocked","locked","editHeaderDomain","editHeader","editHeaderInvalid","cancelEditHeader","saveEditHeader","cancelEditSummary","saveEditSummary","tag","invalidPowerType","editPower","cancelEditPower","saveEditPower","allowShowMoreEvents","showMoreEvents","getEventText","event","getPowerEventError","level","hasPowerEventError","getPowerEventErrorText","hasActionPowerError","actionName","hasPowerError","missing_packages","getPowerErrors","result","packages","sort","getServiceClass","status","hasCustomCommissioningScripts","script_type","controllerLoaded","scope","showFailedTestWarning","testing_status","getCPUSubtext","cpu_count","cpu_speed","type_name","type_name_title","activeNode","originalInterfaces","filtered","usedVLANs","inter","parents","vlan_id","childInterface","found","link_id","interfaceType","vid","modes","isFunction","getValue","this","nicType","allowLinkUp","JSONService","INTERFACE_TYPE","PHYSICAL","BOND","BRIDGE","VLAN","ALIAS","INTERFACE_TYPE_TEXTS","physical","bond","bridge","alias","LINK_MODE","AUTO","STATIC","DHCP","LINK_UP","LINK_MODE_TEXTS","auto","dhcp","link_up","SELECTION_MODE","NONE","SINGLE","MULTI","DELETE","ADD","CREATE_BOND","CREATE_BRIDGE","CREATE_PHYSICAL","EDIT","IP_ASSIGNMENT","updateLoaded","nodeHasLoaded","managersHaveLoaded","updateInterfaces","vlanTable","addedVlans","children","editInterface","selectedMode","formatted","members","vlanRecord","primary_rack","secondary_rack","sort_key","getVLANText","a","b","localeCompare","nic_copy","subnet_id","interfaceLinksMap","linkMaps","newInterface","parentId","linkId","newParent","iType","isAlias","isVLAN","canAddAlias","canAddVLAN","addTypeChanged","leaveSingleSelectionMode","updateNewInterface","mapNICToOriginalLink","nic_id","originalInteface","getDefaultVLAN","default_vlan_id","getUnusedVLANs","ignoreVLANs","getSelectedInterfaces","selectedInterfaces","splitKey","getNextName","prefix","tableInfo","interfaceErrorsByLinkId","newBondInterface","newBridgeInterface","bondOptions","isLimitedEditingAllowed","isAllNetworkingDisabled","isBootInterface","is_boot","getInterfaceTypeText","isDefined","getLinkModeText","getSubnetText","getSubnet","isInterfaceNameInvalid","otherNic","isLinkModeDisabled","getInterfaceError","isIPAddressInvalid","getUniqueKey","toggleInterfaceSelect","isInterfaceSelected","cannotEditInterface","isEditing","edit","undefined","defaultSubnet","fabricChanged","vlanChanged","fabricChangedForm","updateValue","vlanChangedForm","subnetChanged","subnetChangedForm","modeChanged","modeChangedForm","originalLink","editCancel","preProcessInterface","interface_id","saveInterface","updateInterface","saveInterfaceLink","linkSubnet","editSave","isShowingDeleteConfirm","isShowingAdd","canAddAliasOrVLAN","canAddAnotherVLAN","getRemoveTypeText","canBeRemoved","remove","quickRemove","confirmRemove","unlinkSubnet","add","defaultVLAN","defaultMode","quickAdd","getAddName","aliasIdx","createVLANInterface","isDisabled","canCreateBond","isShowingCreateBond","showCreateBond","primary","lacpRate","xmitHashPolicy","hasBootInterface","getInterfacePlaceholderMACAddress","isMACAddressInvalid","invalidEmpty","showLACPRate","showXMITHashPolicy","cannotAddBond","addBond","bond_mode","bond_lacp_rate","bond_xmit_hash_policy","createBondInterface","canCreateBridge","isShowingCreateBridge","showCreateBridge","bridge_stp","bridge_fd","cannotAddBridge","addBridge","createBridgeInterface","isShowingCreatePhysical","showCreatePhysical","macError","errorMsg","cannotAddPhysicalInterface","addPhysicalInterface","createPhysicalInterface","errorStr","tryParse","disks","availableNew","single","disk","ConverterService","MIN_PARTITION_SIZE","MUTLI","UNMOUNT","UNFORMAT","FORMAT_AND_MOUNT","PARTITION","BCACHE","RAID","VOLUME_GROUP","LOGICAL_VOLUME","RAID_MODES","min_disks","allows_spares","calculateSize","minSize","numDisks","hasMountedFilesystem","filesystem","mount_point","hasFormattedUnmountedFilesystem","fstype","isInUse","is_format_fstype","available_size","getTags","cache_set_id","block_id","partition_id","updateDisks","used","cachesets","filesystems","has_disks","size_human","mount_options","filesystem_id","original_type","original","parent_type","partitions","partition","special_filesystems","oldFilesystem","filesystemsMap","$selected","updateFilesystemSelection","used_by","used_for","cacheset","oldCacheSet","cachesetsMap","updateCacheSetsSelection","available","has_partitions","available_size_human","used_size_human","serial","test_status","firmware_version","oldDisk","availableMap","$options","newDevices","updateAvailableSelection","updateAvailable","filesystemMode","filesystemAllSelected","cachesetsMode","cachesetsAllSelected","availableMode","availableAllSelected","deselectAll","items","capitalizeFirstLetter","string","charAt","toUpperCase","getIndexFromName","match","RegExp","exec","dIdx","Math","max","isNameAlreadyInUse","exclude_disk","j","isLogicalVolume","showMembers","isBootDiskDisabled","setAsBootDisk","setBootDisk","getSelectedFilesystems","toggleFilesystemSelect","toggleFilesystemAllSelect","isFilesystemsDisabled","isAllStorageDisabled","filesystemCancel","filesystemUnmount","quickFilesystemUnmount","filesystemConfirmUnmount","updateFilesystem","filesystemDelete","quickFilesystemDelete","filesystemConfirmDelete","unmountSpecialFilesystem","deletePartition","deleteFilesystem","hasUnmountedFilesystem","showFreeSpace","getDeviceType","getSelectedAvailable","toggleAvailableSelect","toggleAvailableAllSelect","isAvailableDisabled","canFormatAndMount","getPartitionButtonText","availablePartitionSpace","space_to_reserve","partition_table_type","INITIAL_PARTITION_OFFSET","roundByBlockSize","canAddPartition","isNameInvalid","nameHasChanged","parentName","availableCancel","usesMountPoint","usesStorage","isMountPointInvalid","mountPoint","canDelete","used_size","availableDelete","availableQuickDelete","availableEdit","editingTags","editingFilesystem","availableQuickEdit","availableConfirmEdit","mountOptions","updateDisk","availableConfirmDelete","deleteVolumeGroup","deleteDisk","availablePartition","size_and_units","size","sizeUnits","availableQuickPartition","getAddPartitionName","isAddPartitionSizeInvalid","test","bytes","unitsToBytes","roundUnits","availableConfirmPartition","removeDisk","available_space","createPartition","getSelectedCacheSets","toggleCacheSetSelect","toggleCacheSetAllSelect","isCacheSetsDisabled","cacheSetCancel","canDeleteCacheSet","cacheSetDelete","quickCacheSetDelete","cacheSetConfirmDelete","deleteCacheSet","canCreateCacheSet","createCacheSet","getCannotCreateBcacheMsg","canCreateBcache","createBcache","cacheMode","fstypeChanged","isNewDiskNameInvalid","createBcacheCanSave","availableConfirmCreateBcache","cache_set","cache_mode","canCreateRAID","createRAID","spares","getAvailableRAIDModes","getTotalNumberOfAvailableSpares","diff","getNumberOfRemainingSpares","allowed","showSparesColumn","RAIDModeChanged","isActiveRAIDMember","isSpareRAIDMember","setAsActiveRAIDMember","setAsSpareRAIDMember","getNewRAIDSize","Number","MAX_VALUE","deviceSize","min","bytesToUnits","createRAIDCanSave","availableConfirmCreateRAID","block_devices","spare_devices","spare_partitions","canCreateVolumeGroup","createVolumeGroup","getNewVolumeGroupSize","total","createVolumeGroupCanSave","availableConfirmCreateVolumeGroup","canAddLogicalVolume","availableLogicalVolume","namePrefix","isLogicalVolumeNameInvalid","newLogicalVolumeNameChanged","isAddLogicalVolumeSizeInvalid","availableConfirmLogicalVolume","createLogicalVolume","authUser","is_superuser","owner","hasStorageLayoutIssues","storage_layout_issues","SpecialFilesystem","isValid","startsWith","describe","parts","join","dropdown","addSpecialFilesystem","addSpecialFilesystemFinished","canMount","mount","mountSpecialFilesystem","EventsManagerFactory","eventsManager","getManager","days","getMaximumDays","loadItems","eventsLoaded","loadMore","loadMaximumDays","destroy","NodeResultsManagerFactory","nodeResultsManager","requestedResult","getItem","get_result_data","output","resultLoaded","updateLogs","had_installation","logs","installation_results","selectedLog","commissioning_results","testing_results","results","updateLogOutput","resultsLoaded","logOutput","getSummaryXML","getSummaryYAML","hlist","history_list","SearchService","SwitchesManager","isViewingSelected","tabs","toLowerCase","enterViewSelected","previous_search","leaveViewSelected","updateFilters","updateAllViewableChecked","filtered_items","allViewableChecked","clearAction","resetActionProgress","zoneSelection","shouldClearAction","selectedItems","removeEmptyFilter","updateActionErrorCount","actionErrorCount","supportsAction","action_failed","progress","actionProgress","completed","errors","affected_nodes","updateSelectedItems","hasActionsFailed","manager","unselectItem","hasActionsInProgress","nodes","switches","showswitches","pagetitle","searchValid","getSelectedItems","metadata","getMetadata","filters","getEmptyFilter","takeActionOptions","syncStatuses","addController","registerUrl","register_url","registerSecret","register_secret","addHardwareOption","addHardwareOptions","toggleTab","clearSearch","toggleChecked","isSelected","selectItem","toggleCheckAll","onNodeListingChanged","showSelected","toggleFilter","filtersToString","isFilterActive","getCurrentFilters","selectColumnOrSort","actionOptionSelected","zone_id","addErrorToActionProgress","addHardwareOptionChanged","addDevice","cancelAddDevice","statusPoll","storeFilters","nodesFilter","retrieveFilters","devicesFilter","controllersFilter","switchesFilter","PodsManager","pod","podManager","sentence","operation","bind","refresh","deleteItem","inProgress","compose","storage","boot","machinesSearch","editPodConfiguration","exitEditPodConfiguration","actionOptionChanged","getPodTypeTitle","canCompose","capabilities","composeMachine","composePreProcess","sorted","constraint","cancelCompose","composeAddStorage","composeSetBootDisk","composeRemoveDisk","startWatching","now","getDefaultZone","activePod","pods","filteredItems","open","powerTypes","action_error","addPod","cancelAddPod","getPowerTypeTitle","powerType","DHCPSnippetsManager","snippetsManager","snippets","known_architectures","pockets_to_disable","components_to_disable","packageRepositoriesManager","repositories","newSnippet","editSnippet","deleteSnippet","snippetTypes","newRepository","editRepository","deleteRepository","repositoryEnabledToggle","repository","repositoryEnterRemove","repositoryExitRemove","repositoryConfirmRemove","isPPA","isMirror","repositoryEnterEdit","repositoryExitEdit","repositoryAdd","enabled","arches","distributions","components","repositoryAddCancel","getSnippetTypeText","snippet","getSnippetAppliesToObject","getSnippetAppliesToText","snippetEnterRemove","snippetExitRemove","snippetConfirmRemove","snippetEnterEdit","snippetExitEdit","snippetToggle","snippetAdd","snippetAddCancel","spaceLoaded","updateSubnets","isDefaultSpace","subnet_ids","deleteSpace","activeSpace","requestedSpace","space_id","source","version","StaticRoutesManager","active_discovery_data","active_discovery_interval","staticRoutes","staticRoutesManager","actionError","newStaticRoute","editStaticRoute","deleteStaticRoute","MAP_SUBNET_ACTION","DELETE_ACTION","ALLOC_TYPES","5","6","NODE_TYPES","updateIPVersion","ipVersion","subnetLoaded","updateFabric","ipSort","ipv4ToInteger","ipv6Expand","getAllocType","allocType","str","getSubnetCIDR","destId","allocTypeSort","alloc_type","getUsageForIP","node_summary","nodeType","bmcs","dns_records","nodeTypeSort","ownerSort","sortIPTable","actionRetry","scanSubnet","scan_started_on","deleteSubnet","subnetPreSave","changedFields","addStaticRoute","gateway_ip","destination","metric","cancelAddStaticRoute","isStaticRouteInEditMode","route","staticRouteToggleEditMode","isStaticRouteInDeleteMode","staticRouteEnterDeleteMode","staticRouteCancelDelete","staticRouteConfirmDelete","choice","activeSubnet","requestedSubnet","objects","self","vm","updateManagementRacks","primaryRack","secondaryRack","updateRelatedControllers","relatedControllers","updateRelatedSubnets","relatedSubnets","updatePossibleActions","relay_vlan","RELAY_DHCP_ACTION","DISABLE_DHCP_ACTION","dhcp_on","PROVIDE_DHCP_ACTION","isFabricDefault","vlanLoaded","provideDHCPAction","getSpaceName","getActionByName","initProvideDHCP","forRelay","relayVLAN","maxIPs","startIP","endIP","gatewayIP","needsDynamicRange","iprange","statistics","suggested_dynamic_range","needsGatewayIP","subnetMissingGatewayIP","updatePrimaryRack","updateSecondaryRack","updateSubnet","filterPrimaryRack","suggested_gateway","num_addresses","startPlaceholder","start","endPlaceholder","end","gatewayPlaceholder","canPerformAction","gateway","configureDHCP","extraDHCP","relay","disableDHCP","deleteVLAN","getFullVLANName","getDHCPStatus","activeVLAN","requestedVLAN","zoneLoaded","zoneManager","isDefaultZone","activeZone","requestedZone","addZone","closeZone","directive","restrict","element","attrs","clickHandler","evt","toggleClass","find","on","off","template","$element","$document","design","templateUrl","files_version","saving","stopping","ubuntuImages","isNew","tooMany","showingAdvanced","connecting","errorMessage","source_type","keyring_filename","keyring_data","releases","selections","changed","ubuntuCoreImages","ubuntu_core","images","otherImages","other","generatedImages","customImages","ubuntuDeleteId","removingImage","getTitleIcon","showMirrorPath","isShowingAdvancedOptions","toggleAdvancedOptions","bothKeyringOptionsSet","showConnectButton","sourceChanged","currentSources","ubuntu","sources","prevNew","updateSource","regenerateUbuntuImages","connect","isConnectButtonDisabled","getSourceParams","selectDefaults","arch","fetch","fromJson","showConnectBlock","showSelections","getUbuntuLTSReleases","deleted","getUbuntuNonLTSReleases","getArchitectures","toggleSelection","showImagesTable","getResource","resource","resource_os","rtype","image","icon","beingDeleted","resourceId","downloading","name_split","regenerateUbuntuCoreImages","ubuntuCoreImage","checked","regenerateOtherImages","otherImage","_regenerateImages","image_id","regenerateGeneratedImages","regenerateCustomImages","ltsIsSelected","commissioningSeriesSelected","commissioning_series","cancelRemove","deleteImage","showStopImportButton","region_import_running","showSaveSelection","canSaveSelection","commissioning_series_being_deleted","commissioning_series_arches","getSaveSelectionText","canStopImport","getStopImportText","stopImport","saveSelection","saveUbuntu","getNewSelections","newObjs","oldSelections","newSelections","selection","source_len","toggleUbuntuCoreSelection","saveUbuntuCoreSelection","saveUbuntuCore","toggleOtherSelection","saveOtherSelection","saveOther","confirmDeleteImage","ready","ubuntu_core_images","other_images","run","$templateCache","put","replace","require","maasCta","ngModel","ngModelCtrl","defaultTitle","select","shown","$setViewValue","getTitle","$modelValue","secondary","getOptionTitle","$viewChangeListeners","$eval","ngChange","stopPropagation","$apply","$compile","include","maasCardLoader","html","contents","maasCodeLines","attributes","empty","lines","newLine","insert","each","ngDisabled","maasEditing","focusHandler","blur","changeHandler","$render","$viewValue","unbind","$timeout","statuses","updateStatuses","controllerIds","checkImageStates","register","known","runningInterval","startTimeout","CHECK_INTERVAL","unregister","showSpinner","getImageStatus","ControllerImageStatusService","systemId","unwatch","registered","textOnly","getClass","countClass","classes","class_name","counter","updateStatusClass","serviceClass","serviceText","styleElement","document","createElement","innerHTML","getElementsByTagName","appendChild","BrowserService","transclude","maasDblClickOverlay","clickElement","overlay","tagName","createEvent","initMouseEvent","window","dispatchEvent","css","cursor","triggerHandler","overlayClick","preventDefault","overlayDblClick","browser","addClass","which","maasEnter","jasmine","Image","src","markDisconnected","connected","showDisconnected","clientError","wasConnected","watchConnection","isConnected","_error","disconnectedPromise","cancelTimeout","watchConnectionAndError","removeClass","IPRangesManager","ipranges","iprangeManager","newRange","editIPRange","deleteIPRange","addRange","start_ip","end_ip","comment","cancelAddRange","ipRangeCanBeModified","range","isIPRangeInEditMode","ipRangeToggleEditMode","ipRangeClearEditMode","isIPRangeInDeleteMode","ipRangeEnterDeleteMode","ipRangeCancelDelete","ipRangeConfirmDelete","ipRangeSort","MAASFormController","savingKeys","managerMethod","cloneObject","clonedObj","isTableForm","tableForm","saveOnBlur","isSaving","showInputSaving","errorScope","registerField","unregisterField","startEditingField","stopEditingField","clearErrors","updatedObj","newObj","errorJson","errorField","setErrors","v","saveForm","newValue","inline","MAASGroupController","timeout","formController","keyIdx","pre","onChange","subtleText","subtle","missingAttrs","disableLabel","labelElement","attr","labelWidth","labelLeft","append","labelInfo","infoWrapper","infoIcon","infoTooltip","inputWrapper","inputWidth","placeholder","inputElement","blurOnEnter","val","currentValue","disabled","placeholderEnabled","childScope","$new","_ngDisabled","_selectValue","_selectNgChange","_change","values","checkScope","_selectedValues","_checked","_toggleChecked","tagsScope","_tags","switchScope","_toggle","_changed","onValue","offValue","inputClass","errorsElement","helpText","helpTextElement","setTimeout","focus","hasClass","subtleTextElement","removeAttr","ul","ele","macAddressFormat","numbers","$parsers","$formatters","hideCheckboxes","onListingChange","onCheckAll","onCheck","SPINNER_STATUSES","table","filteredMachines","updateAllChecked","$machine","showNodeStatus","other_test_status","getReleaseTitle","os_release","getStatusText","releaseTitle","trim","$machines","NotificationsManager","notifications","dismiss","categories","categoryTitles","warning","success","info","categoryClasses","categoryNotifications","cns","category","notification","maasOsSelect","getSelectableReleases","allChoices","getSelectableKernels","kernels","os","osKernels","getDefaultOrFirst","array","defaultValue","weightValue","first","weightedPresent","setDefault","default_osystem","default_release","kernel","selectedOSChanged","selectedReleaseChanged","ngPlaceholder","hideType","podTypes","fieldsElement","updateFields","podType","$destroy","maasObjForm","getType","driver_type","req","input_type","replaceWith","maasPowerParameters","$sce","enableHttpProxy","usePeerProxy","proxy_type","releaseName","setText","maasReleaseOptions","onEraseChange","globalOptions","startTime","runTime","estimatedRunTime","scriptStatus","incrementCounter","start_date","Date","setSeconds","seconds","floor","minutes","hours","new_counter","promise","$q","scriptType","allScripts","getScripts","script","tags_string","onTagAdding","refocus","tagsInput","tagsInputScope","isolateScope","eventHandlers","input","change","for_hardware","getIcon","SSHKeysManager","groupedKeys","authId","sourceTitles","lp","gh","upload","openRow","rowMode","trustAsHtml","close","canImportKeys","importKeys","protocol","auth_id","__all__","confirmDelete","keyMap","groupObj","keysource","keysourceKey","switchHasError","filteredSwitches","switch_","$switch_","$switches","$attr","isToggled","toggleMenu","target","ngType","valid_types","LogService","reloadPage","enableAutoReload","site","href","oldValue","onResize","windowWidth","innerWidth","message","factory","_loaded","_data","_polling","_nextPromise","_pollTimeout","_pollErrorTimeout","_pollEmptyTimeout","isLoaded","isPolling","_poll","_loadData","callMethod","newData","_pollAgain","pollTimeout","connection_error","defer","resolve","Manager","_pk","_handler","registerNotifier","onNotify","NodesManager","service_ids","service_id","_metadataAttributes","_replaceItem","PollingManager","_batchKey","_items","EventsManager","nodeId","_nodeId","_factory","_maxDays","_managers","_initBatchLoadParameters","node_id","max_days","destroyManager","setMaximumDays","isLoading","_getManager","machine_actions","polling","nextPromise","device_actions","region_controller_actions","rack_controller_actions","region_and_rack_controller_actions","min_hwe_kernels","replaceData","oldData","isEmpty","bond_options","newPowerType","oldPowerType","newItem","release_options","_autoReload","_type","_scopes","_getInternalData","isDataLoaded","isDataPolling","apply","waitingCount","_reloadFunc","registerHandler","disableAutoReload","unregisterHandler","storage_tags","NodeResultsManager","_node","hardware_type","_getStorageSubtext","deviceinfo","_updateObject","existing","updated","_addOrReplace","showing_results","showing_history","showing_menu","_processItem","result_section","result_type","subtext","hardware_type_results","physical_blockdevice","_getIndexOfItem","_updateMetadata","_removeItemByIdFromArray","_selectedItems","hw_type","ret","_area","has_surfaced","script_id","data_type","state","updateInterfaceForm","volume_group_id","blockdevice_id","partition_size","$cookies","MSG_TYPE","RESPONSE_TYPE","callbacks","requests","requestId","websocket","autoReconnect","retryTimeout","defaultConnectDefer","handlers","notifiers","newRequestId","func","unregisterNotifier","buildSocket","WebSocket","_buildUrl","onopen","onerror","onclose","onmessage","onMessage","_getProtocol","host","port","pathname","proto","csrftoken","base","newPath","newPort","encodeURIComponent","defaultConnect","opened","errored","reject","msg","onResponse","request_id","remembered_request","request","handler","remember","send","toJson","getLargestRange","largest_range","ranges","equals","purpose","hasDynamicRange","matching","_authUser","authuser","_loadAuthUser","reloadItems","addRackController","foreign_objects","standardFilter","mappings","cpu","cores","ram","memory","pod-id","isInteger","matches","lowerTerm","exact","negate","parseFloat","_matches","terms","term","matched","mapFunc","substring","no_match","field2","aDate","bDate","getTime","config","$interpolateProvider","$routeProvider","$httpProvider","versionedPath","startSymbol","endSymbol","defaults","xsrfCookieName","xsrfHeaderName","routes","when","redirectTo","reloadOnSearch","controllerAs","superuser","otherwise","next","current","ga","q","arguments","userId","analytics_user_id","uuid","hash","regex","matcher","navigator","userAgent","UNITS","unit","converted","abs","toFixed","units","block_size","ipv4ToOctets","octets","part","pow","expandedAddress","groups","substr","ipv6ToGroups","jsonString","JSON","parse","_typeof","e","logging","logLevel","performance","_debug","debug","_log","_info","_warn","warn","formatMilliseconds","milliseconds","__log","args","Array","unshift","METADATA_ACTIONS","CREATE","UPDATE","_name_field","_isLoading","_extraLoadDefers","_extraReloadDefers","_actionQueue","_activeItem","_metadata","pk_value","len","_replaceItemInArray","_batchLoadItems","extra_func","callLoad","_resolveDefers","defersArray","_rejectDefers","clear","processActions","updatedIdx","updatedItem","updateItems","clearActiveItem","canProcessActions","_getMetadataValue","metadatas","_addMetadataValue","count","_removeMetadataValue","_updateMetadataArrayEntry","added","oldArray","_updateMetadataValueEntry","_updateMetadataEntry","oldItem","loadedManagers","loadedManager","tryParsingJSON","SyntaxError","getPrintableString","dict","showNames","emptyFilter","_","getSplitSearch","fixedTerms","spanningParentheses","startIdx","searchTerms","_getFilterValueIndex","storedFilters","domainnamePattern","hostnamePattern","macPattern","ipv4Pattern","cidrMatcher","one","two","bits","domainname","macAddress","validateIPv4","validateIPv6","network","networkSplit","networkAddress","cidrBits","validateIPInRange","lowAddress","highAddress","ipOctets","lowOctets","highOctets","YUI","Y","namespace","getIO","io","IO","Cookie","requires","OSReleaseWidget","_io","maas","superclass","constructor","NAME","extend","Widget","initializer","cfg","initialSkip","bindTo","osNode","event_name","osValue","currentTarget","switchTo","newOSValue","all","sel","modifyOption","selectVisableOption","split_value","set","first_option","use","releaseWidget","os_distro_select","srcNode","render","TokenWidget","ATTRS","nb_tokens","readOnly","displayError","status_node","create_link","Node","spinnerNode","confirm","_x","_confirm","toString","bindDeleteRow","deleteToken","bindUI","requestKeys","token_key","QueryString","stringify","op","sync","hideSpinner","out","failure","uris","account_handler","createTokenFromKeys","consumer_key","token_secret","addToken","token","list","response","Reveal","get_style_int","attribute","getStyle","targetNode","linkNode","hideText","showText","quick","renderUI","reveal","syncUI","fire","setStyle","set_hidden_link","is_visible","new_text","set_visible_link","get_animation_duration","suggested_duration","create_slide_in","publisher","anim","Anim","duration","to","height","create_slide_out","content_node","new_height","script_entry","ShortPollManager","shortpoll_start_event","shortpoll_fail_event","MAX_SHORT_DELAY_FAILED_ATTEMPTS","SHORT_DELAY","LONG_DELAY","_repoll","uri","eventKey","valueFn","guid","Base","_started","_failed_attempts","_sequence","successPoll","responseText","failurePoll","_pollDelay","repoll","failed","delay","later","poll","that","Lang","isValue","poll_uri","dropdowns","click","openMenu","closeAllMenus","MAASUI","utils","fn","attachEvent","readyState","addEventListener","el","className","classList","toggle","existingIndex","contains","init","querySelectorAll","sublinks"],"mappings":"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","file":"maas-min.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Add Device Controller\n */\n\nangular.module('MAAS').controller('AddDeviceController', [\n    '$scope', 'DevicesManager', 'SubnetsManager', 'DomainsManager',\n    'ManagerHelperService', 'ValidationService', function(\n        $scope, DevicesManager, SubnetsManager, DomainsManager,\n        ManagerHelperService, ValidationService) {\n\n        // Set the addDeviceScope in the parent, so it can call functions\n        // in this controller.\n        var parentScope = $scope.$parent;\n        parentScope.addDeviceScope = $scope;\n\n        // Set initial values.\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.domains = DomainsManager.getItems();\n        $scope.viewable = false;\n        $scope.error = null;\n\n        // Device ip assignment options.\n        $scope.ipAssignments = [\n            {\n                name: \"external\",\n                title: \"External\"\n            },\n            {\n                name: \"dynamic\",\n                title: \"Dynamic\"\n            },\n            {\n                name: \"static\",\n                title: \"Static\"\n            }\n        ];\n\n        // Makes a new interface.\n        function makeInterface() {\n            return {\n                mac: \"\",\n                ipAssignment: null,\n                subnetId: null,\n                ipAddress: \"\"\n            };\n        }\n\n        // Makes a new device.\n        function newDevice(cloneDevice) {\n            if(angular.isObject(cloneDevice)) {\n                return {\n                    name: \"\",\n                    domain: cloneDevice.domain,\n                    interfaces: [makeInterface()]\n                };\n            } else {\n                return {\n                    name: \"\",\n                    domain: DomainsManager.getDefaultDomain(),\n                    interfaces: [makeInterface()]\n                };\n            }\n        }\n\n        // Input values.\n        $scope.device = null;\n\n        // Converts the device information from how it is held in the UI to\n        // how it is handled over the websocket.\n        function convertDeviceToProtocol(device) {\n            // Return the new object.\n            var convertedDevice = {\n                hostname: device.name,\n                domain: device.domain,\n                primary_mac: device.interfaces[0].mac,\n                extra_macs: [],\n                interfaces: []\n            };\n            var i;\n            for(i = 1; i < device.interfaces.length; i++) {\n                convertedDevice.extra_macs.push(device.interfaces[i].mac);\n            }\n            angular.forEach(device.interfaces, function(nic) {\n                convertedDevice.interfaces.push({\n                    mac: nic.mac,\n                    ip_assignment: nic.ipAssignment.name,\n                    ip_address: nic.ipAddress,\n                    \"subnet\": nic.subnetId\n                });\n            });\n            return convertedDevice;\n        }\n\n        // Called by the parent scope when this controller is viewable.\n        $scope.show = function() {\n            // Exit early if already viewable.\n            if($scope.viewable) {\n                return;\n            }\n            $scope.device = newDevice();\n            $scope.viewable = true;\n        };\n\n        // Called by the parent scope when this controller is hidden.\n        $scope.hide = function() {\n            $scope.viewable = false;\n\n            // Emit the hidden event.\n            $scope.$emit('addDeviceHidden');\n        };\n\n        // Returns true if the name is in error.\n        $scope.nameHasError = function() {\n            // If the name is empty don't show error.\n            if($scope.device === null || $scope.device.name.length === 0) {\n                return false;\n            }\n            return !ValidationService.validateHostname($scope.device.name);\n        };\n\n        // Returns true if the MAC is in error.\n        $scope.macHasError = function(deviceInterface) {\n            // If the MAC is empty don't show error.\n            if(deviceInterface.mac.length === 0) {\n                return false;\n            }\n            // If the MAC is invalid show error.\n            if(!ValidationService.validateMAC(deviceInterface.mac)) {\n                return true;\n            }\n            // If the MAC is the same as another MAC show error.\n            var i;\n            for(i = 0; i < $scope.device.interfaces.length; i++) {\n                var isSelf = $scope.device.interfaces[i] === deviceInterface;\n                if(!isSelf &&\n                    $scope.device.interfaces[i].mac === deviceInterface.mac) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Returns true if the IP address is in error.\n        $scope.ipHasError = function(deviceInterface) {\n            // If the IP is empty don't show error.\n            if(deviceInterface.ipAddress.length === 0) {\n                return false;\n            }\n            // If ip address is invalid, then exit early.\n            if(!ValidationService.validateIP(deviceInterface.ipAddress)) {\n                return true;\n            }\n            var i, inNetwork;\n            if(angular.isObject(deviceInterface.ipAssignment)){\n                if(deviceInterface.ipAssignment.name === \"external\") {\n                    // External IP address cannot be within a known subnet.\n                    for(i = 0; i < $scope.subnets.length; i++) {\n                        inNetwork = ValidationService.validateIPInNetwork(\n                            deviceInterface.ipAddress,\n                            $scope.subnets[i].cidr);\n                        if(inNetwork) {\n                            return true;\n                        }\n                    }\n                } else if(deviceInterface.ipAssignment.name === \"static\" &&\n                    angular.isNumber(deviceInterface.subnetId)) {\n                    // Static IP address must be within a subnet.\n                    var subnet = SubnetsManager.getItemFromList(\n                        deviceInterface.subnetId);\n                    inNetwork = ValidationService.validateIPInNetwork(\n                        deviceInterface.ipAddress, subnet.cidr);\n                    if(!inNetwork) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Return true when the device is missing information or invalid\n        // information.\n        $scope.deviceHasError = function() {\n            if($scope.device === null || $scope.device.name === '' ||\n                    $scope.nameHasError()) {\n                return true;\n            }\n\n            var i;\n            for(i = 0; i < $scope.device.interfaces.length; i++) {\n                var deviceInterface = $scope.device.interfaces[i];\n                if(deviceInterface.mac === '' ||\n                    $scope.macHasError(deviceInterface) ||\n                    !angular.isObject(deviceInterface.ipAssignment)) {\n                    return true;\n                }\n                var externalIpError = (\n                    deviceInterface.ipAssignment.name === \"external\" && (\n                        deviceInterface.ipAddress === '' ||\n                        $scope.ipHasError(deviceInterface)));\n                var staticIpError = (\n                    deviceInterface.ipAssignment.name === \"static\" && (\n                        !angular.isNumber(deviceInterface.subnetId) ||\n                        $scope.ipHasError(deviceInterface)));\n                if(externalIpError || staticIpError) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Adds new interface to device.\n        $scope.addInterface = function() {\n            $scope.device.interfaces.push(makeInterface());\n        };\n\n        // Returns true if the first interface in the device interfaces array.\n        $scope.isPrimaryInterface = function(deviceInterface) {\n            return $scope.device.interfaces.indexOf(deviceInterface) === 0;\n        };\n\n        // Removes the interface from the devices interfaces array.\n        $scope.deleteInterface = function(deviceInterface) {\n            // Don't remove the primary.\n            if($scope.isPrimaryInterface(deviceInterface)) {\n                return;\n            }\n            $scope.device.interfaces.splice(\n                $scope.device.interfaces.indexOf(deviceInterface), 1);\n        };\n\n        // Called when cancel clicked.\n        $scope.cancel = function() {\n            $scope.error = null;\n            $scope.device = newDevice();\n            $scope.hide();\n        };\n\n        // Called when save is clicked.\n        $scope.save = function(addAnother) {\n            // Do nothing if device in error.\n            if($scope.deviceHasError()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the device.\n            $scope.error = null;\n\n            // Create the device.\n            var device = convertDeviceToProtocol($scope.device);\n            DevicesManager.create(device).then(function(device) {\n                if(addAnother) {\n                    $scope.device = newDevice($scope.device);\n                } else {\n                    $scope.device = newDevice();\n                    // Hide the scope if not adding another.\n                    $scope.hide();\n                }\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load subnets to get the available subnets.\n        ManagerHelperService.loadManagers(\n            $scope, [SubnetsManager, DomainsManager]).then(function() {\n                // Initial device.\n                $scope.device = newDevice();\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Add Domain Controller\n */\n\nangular.module('MAAS').controller('AddDomainController', [\n    '$scope', 'DomainsManager', 'ManagerHelperService',\n    'ValidationService', function($scope, DomainsManager,\n        ManagerHelperService, ValidationService) {\n\n        // Set the addDomainScope in the parent, so it can call functions\n        // in this controller.\n        var parentScope = $scope.$parent;\n        parentScope.addDomainScope = $scope;\n\n        // Set initial values.\n        $scope.viewable = false;\n        $scope.error = null;\n\n        // Makes a new domain.\n        function makeDomain() {\n            return {\n                name: \"\",\n                authoritative: true\n            };\n        }\n\n        // Initial domain.\n        $scope.domain = makeDomain();\n\n        // Converts the domain information from how it is held in the UI to\n        // how it is handled over the websocket.  Since they're identical, we\n        // just return a copy: some day, they might be different, so we retain\n        // the function against that day.\n        function convertDomainToProtocol(domain) {\n            return angular.copy(domain);\n        }\n\n        // Called by the parent scope when this controller is viewable.\n        $scope.show = function() {\n            // Exit early if already viewable.\n            if($scope.viewable) {\n                return;\n            }\n            $scope.domain = makeDomain();\n            $scope.viewable = true;\n        };\n\n        // Called by the parent scope when this controller is hidden.\n        $scope.hide = function() {\n            $scope.viewable = false;\n\n            // Emit the hidden event.\n            $scope.$emit('addDomainHidden');\n        };\n\n        // Returns true if the name is in error.\n        $scope.nameHasError = function() {\n            // If the name is empty don't show error.\n            if($scope.domain.name.length === 0) {\n                return false;\n            }\n            return !ValidationService.validateDomainName($scope.domain.name);\n        };\n\n        // Return true when the domain is missing information or invalid\n        // information.\n        $scope.domainHasError = function() {\n            if($scope.domain.name === '' || $scope.nameHasError()) {\n                return true;\n            }\n\n            return false;\n        };\n\n        // Called when cancel clicked.\n        $scope.cancel = function() {\n            $scope.error = null;\n            $scope.domain = makeDomain();\n            $scope.hide();\n        };\n\n        // Called when save is clicked.\n        $scope.save = function(addAnother) {\n            // Do nothing if domain in error.\n            if($scope.domainHasError()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the domain.\n            $scope.error = null;\n\n            // Create the domain.\n            var domain = convertDomainToProtocol($scope.domain);\n            DomainsManager.create(domain).then(function() {\n                $scope.domain = makeDomain();\n                if(!addAnother) {\n                    // Hide the scope if not adding another.\n                    $scope.hide();\n                }\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n    }]);\n","/* Copyright 2015-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Add Hardware Controller\n */\n\nangular.module('MAAS').controller('AddHardwareController', [\n    '$scope', '$http', 'ZonesManager', 'MachinesManager',\n    'GeneralManager', 'DomainsManager', 'RegionConnection',\n    'ManagerHelperService', 'ValidationService', function(\n        $scope, $http, ZonesManager, MachinesManager,\n        GeneralManager, DomainsManager, RegionConnection,\n        ManagerHelperService, ValidationService) {\n\n        // Set the addHardwareScope in the parent, so it can call functions\n        // in this controller.\n        var parentScope = $scope.$parent;\n        parentScope.addHardwareScope = $scope;\n\n        // Set initial values.\n        $scope.viewable = false;\n        $scope.model = 'machine';\n        $scope.zones = ZonesManager.getItems();\n        $scope.domains = DomainsManager.getItems();\n        $scope.architectures = GeneralManager.getData(\"architectures\");\n        $scope.hwe_kernels = GeneralManager.getData(\"hwe_kernels\");\n        $scope.default_min_hwe_kernel = GeneralManager.getData(\n            \"default_min_hwe_kernel\");\n        $scope.power_types = GeneralManager.getData(\"power_types\");\n        $scope.error = null;\n        $scope.macAddressRegex = /^([0-9A-F]{2}[::]){5}([0-9A-F]{2})$/gmi;\n\n        // Input values.\n        $scope.machine = null;\n        $scope.chassis = null;\n\n        // Hard coded chassis types. This is because there is no method in\n        // MAAS to get a full list of supported chassis. This needs to be\n        // fixed ASAP.\n        var virshFields = [\n            {\n                name: 'hostname',\n                label: 'Address',\n                field_type: 'string',\n                \"default\": '',  // Using \"default\" to make lint happy.\n                choices: [],\n                required: true\n            },\n            {\n                name: 'password',\n                label: 'Password',\n                field_type: 'string',\n                \"default\": '',\n                choices: [],\n                required: false\n            },\n            {\n                name: 'prefix_filter',\n                label: 'Prefix filter',\n                field_type: 'string',\n                \"default\": '',\n                choices: [],\n                required: false\n            }\n        ];\n        $scope.chassisPowerTypes = [\n            {\n                name: 'mscm',\n                description: 'Moonshot Chassis Manager',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Host',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'powerkvm',\n                description: 'PowerKVM',\n                fields: virshFields\n            },\n            {\n                name: 'recs_box',\n                description: 'Christmann RECS|Box',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Hostname',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'port',\n                        label: 'Port',\n                        field_type: 'string',\n                        \"default\": '80',\n                        choices: [],\n                        required: false\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'seamicro15k',\n                description: 'SeaMicro 15000',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Hostname',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'power_control',\n                        label: 'Power Control',\n                        field_type: 'choice',\n                        \"default\": 'restapi2',\n                        choices: [\n                            ['restapi2', 'REST API V2.0'],\n                            ['restapi', 'REST API V0.9'],\n                            ['ipmi', 'IPMI']\n                        ],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'ucsm',\n                description: 'UCS Chassis Manager',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'URL',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    }\n                ]\n            },\n            {\n                name: 'virsh',\n                description: 'Virsh (virtual systems)',\n                fields: virshFields\n            },\n            {\n                name: 'vmware',\n                description: 'VMware',\n                fields: [\n                    {\n                        name: 'hostname',\n                        label: 'Host',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'username',\n                        label: 'Username',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'password',\n                        label: 'Password',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: true\n                    },\n                    {\n                        name: 'prefix_filter',\n                        label: 'Prefix filter',\n                        field_type: 'string',\n                        \"default\": '',\n                        choices: [],\n                        required: false\n                    }\n                ]\n            }\n        ];\n\n        // Get the default zone from the loaded zones.\n        function defaultZone() {\n            if($scope.zones.length === 0) {\n                return null;\n            } else {\n                return $scope.zones[0];\n            }\n        }\n\n        // Get the default architecture from the loaded architectures.\n        function defaultArchitecture() {\n            if($scope.architectures.length === 0) {\n                return '';\n            } else {\n                // Return amd64/generic first if available.\n                var i;\n                for(i = 0; i < $scope.architectures.length; i++) {\n                    if($scope.architectures[i] === \"amd64/generic\") {\n                        return $scope.architectures[i];\n                    }\n                }\n                return $scope.architectures[0];\n            }\n        }\n\n        // Return a new MAC address object.\n        function newMAC() {\n            return {\n                mac: '',\n                error: false\n            };\n        }\n\n        // Return a new machine object.\n        function newMachine(cloneMachine) {\n            // Clone the machine instead of just creating a new one.\n            // This helps the user by already having the previous selected\n            // items selected for the new machine.\n            if(angular.isObject(cloneMachine)) {\n                return {\n                    name: '',\n                    domain: cloneMachine.domain,\n                    macs: [newMAC()],\n                    zone: cloneMachine.zone,\n                    architecture: cloneMachine.architecture,\n                    min_hwe_kernel: cloneMachine.min_hwe_kernel,\n                    power: {\n                        type: cloneMachine.power.type,\n                        parameters: {}\n                    }\n                };\n            }\n\n            // No clone machine. So create a new blank machine.\n            return {\n                name: '',\n                domain: DomainsManager.getDefaultDomain(),\n                macs: [newMAC()],\n                zone: defaultZone(),\n                architecture: defaultArchitecture(),\n                min_hwe_kernel: $scope.default_min_hwe_kernel.text,\n                power: {\n                    type: null,\n                    parameters: {}\n                }\n            };\n        }\n\n        // Return a new chassis object.\n        function newChassis(cloneChassis) {\n            // Clone the chassis instead of just creating a new one.\n            // This helps the user by already having the previous selected\n            // items selected for the new machine.\n            if(angular.isObject(cloneChassis)) {\n                return {\n                    domain: cloneChassis.domain,\n                    power: {\n                        type: null,\n                        parameters: {}\n                    }\n                };\n            } else {\n                return {\n                    domain: DomainsManager.getDefaultDomain(),\n                    power: {\n                        type: null,\n                        parameters: {}\n                    }\n                };\n            }\n        }\n\n        // Converts the machine information from how it is held in the UI to\n        // how it is handled over the websocket.\n        function convertMachineToProtocol(machine) {\n            // Convert the mac addresses.\n            var macs = angular.copy(machine.macs);\n            var pxe_mac = macs.shift().mac;\n            var extra_macs = macs.map(function(mac) { return mac.mac; });\n\n            // Return the new object.\n            return {\n                hostname: machine.name,\n                domain: machine.domain,\n                architecture: machine.architecture,\n                min_hwe_kernel: machine.min_hwe_kernel,\n                pxe_mac: pxe_mac,\n                extra_macs: extra_macs,\n                power_type: machine.power.type.name,\n                power_parameters: angular.copy(machine.power.parameters),\n                zone: {\n                    id: machine.zone.id,\n                    name: machine.zone.name\n                }\n            };\n        }\n\n        // Validate that all the parameters are there for the given power type.\n        function powerParametersHasError(power_type, parameters) {\n            var i;\n            for(i = 0; i < power_type.fields.length; i++) {\n                var field = power_type.fields[i];\n                var value = parameters[field.name];\n                if(field.required) {\n                    if(angular.isUndefined(value) || value === '') {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        }\n\n        // Called by the parent scope when this controller is viewable.\n        $scope.show = function(mode) {\n            // Change the mode.\n            if($scope.mode !== mode) {\n                if($scope.mode === \"machine\") {\n                    $scope.machine = newMachine();\n                } else if($scope.mode === \"chassis\") {\n                    $scope.chassis = newChassis();\n                }\n                $scope.error = null;\n                $scope.mode = mode;\n            }\n\n            // Exit early if alreayd viewable.\n            if($scope.viewable) {\n                return;\n            }\n            $scope.viewable = true;\n\n            // Start the polling of architectures.\n            GeneralManager.startPolling($scope, \"architectures\");\n\n            // Start the polling of hwe_kernels.\n            GeneralManager.startPolling($scope, \"hwe_kernels\");\n        };\n\n        // Called by the parent scope when this controller is hidden.\n        $scope.hide = function() {\n            $scope.viewable = false;\n\n            // Stop the polling of architectures.\n            GeneralManager.stopPolling($scope, \"architectures\");\n\n            // Stop the polling of hwe_kernels.\n            GeneralManager.stopPolling($scope, \"hwe_kernels\");\n\n            // Emit the hidden event.\n            $scope.$emit('addHardwareHidden');\n        };\n\n        // Return True when architectures loaded and in machine mode.\n        $scope.showMachine = function() {\n            if($scope.architectures.length === 0) {\n                return false;\n            }\n            return $scope.mode === \"machine\";\n        };\n\n        // Return True when architectures loaded and in chassis mode.\n        $scope.showChassis = function() {\n            if($scope.architectures.length === 0) {\n                return false;\n            }\n            return $scope.mode === \"chassis\";\n        };\n\n        // Add a new MAC address to the machine.\n        $scope.addMac = function() {\n            $scope.machine.macs.push(newMAC());\n        };\n\n        // Remove a MAC address to the machine.\n        $scope.removeMac = function(mac) {\n            var idx = $scope.machine.macs.indexOf(mac);\n            if(idx > -1) {\n                $scope.machine.macs.splice(idx, 1);\n            }\n        };\n\n        // Return true if the machine name is invalid.\n        $scope.invalidName = function() {\n            // Not invalid if empty.\n            if($scope.machine.name.length === 0) {\n                return false;\n            }\n            return !ValidationService.validateHostname($scope.machine.name);\n        };\n\n        // Validate that the mac address is valid.\n        $scope.validateMac = function(mac) {\n            if(mac.mac === '') {\n                mac.error = false;\n            } else {\n                mac.error = !ValidationService.validateMAC(mac.mac);\n            }\n        };\n\n        // Return true when the machine is missing information or invalid\n        // information.\n        $scope.machineHasError = function() {\n            // Early-out for errors.\n            in_error = (\n                $scope.machine === null ||\n                $scope.machine.zone === null ||\n                $scope.machine.architecture === '' ||\n                $scope.machine.power.type === null ||\n                $scope.invalidName($scope.machine));\n            if(in_error) {\n                return in_error;\n            }\n\n            // Make sure none of the mac addresses are in error. The first one\n            // cannot be blank the remaining are allowed to be empty.\n            if($scope.machine.macs[0].mac === '' ||\n                $scope.machine.macs[0].error) {\n                return true;\n            }\n            var i;\n            for(i = 1; i < $scope.machine.macs.length; i++) {\n                var mac = $scope.machine.macs[i];\n                if(mac.mac !== '' && mac.error) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Return true if the chassis has errors.\n        $scope.chassisHasErrors = function() {\n            // Early-out for errors.\n            in_error = (\n                $scope.chassis === null ||\n                $scope.chassis.power.type === null);\n            if(in_error) {\n                return in_error;\n            }\n            return powerParametersHasError(\n                $scope.chassis.power.type, $scope.chassis.power.parameters);\n        };\n\n        // Called when the cancel button is pressed.\n        $scope.cancel = function() {\n            $scope.error = null;\n            $scope.machine = newMachine();\n            $scope.chassis = newChassis();\n\n            // Hide the controller.\n            $scope.hide();\n        };\n\n        // Called to perform the saving of the machine.\n        $scope.saveMachine = function(addAnother) {\n            // Does nothing if machine has errors.\n            if($scope.machineHasError()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the device.\n            $scope.error = null;\n\n            // Add the machine.\n            MachinesManager.create(\n                convertMachineToProtocol($scope.machine)).then(\n                    function() {\n                        if(addAnother) {\n                            $scope.machine = newMachine($scope.machine);\n                        } else {\n                            $scope.machine = newMachine();\n\n                            // Hide the scope if not adding another.\n                            $scope.hide();\n                        }\n                    }, function(error) {\n                        $scope.error =\n                            ManagerHelperService.parseValidationError(error);\n                    });\n        };\n\n        // Called to perform the saving of the chassis.\n        $scope.saveChassis = function(addAnother) {\n            // Does nothing if error exists.\n            if($scope.chassisHasErrors()) {\n                return;\n            }\n\n            // Clear the error so it can be set again, if it fails to save\n            // the device.\n            $scope.error = null;\n\n            // Create the parameters.\n            var params = angular.copy($scope.chassis.power.parameters);\n            params.chassis_type = $scope.chassis.power.type.name;\n            params.domain = $scope.chassis.domain.name;\n\n            // XXX ltrager 24-02-2016: Something is adding the username field\n            // even though its not defined in virshFields. The API rejects\n            // requests with improper fields so remove it before we send the\n            // request.\n            if(\n                    params.chassis_type === \"powerkvm\" ||\n                    params.chassis_type === \"virsh\") {\n                delete params.username;\n            }\n            // Add the chassis. For now we use the API as the websocket doesn't\n            // support probe and enlist.\n            $http({\n                method: 'POST',\n                url: 'api/2.0/machines/?op=add_chassis',\n                data: $.param(params),\n                headers: {\n                    'Content-Type': 'application/x-www-form-urlencoded'\n                }\n            }).then(function() {\n                if(addAnother) {\n                    $scope.chassis = newChassis($scope.chassis);\n                } else {\n                    $scope.chassis = newChassis();\n                    // Hide the scope if not adding another.\n                    $scope.hide();\n                }\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error.data);\n            });\n        };\n\n        // Load zones and domains. Once loaded create the first machine and\n        // chassis.\n        ManagerHelperService.loadManagers(\n            $scope, [ZonesManager, DomainsManager]).then(function() {\n                // Add the first machine and chassis.\n                $scope.machine = newMachine();\n                $scope.chassis = newChassis();\n            });\n\n        // Load the general manager.\n        ManagerHelperService.loadManager(\n            $scope, GeneralManager).then(function() {\n            if($scope.architectures.length > 0) {\n                // If the machine doesn't have an architecture\n                // set then it was created before all of the\n                // architectures were loaded. Set the default\n                // architecture for that machine.\n                if(angular.isObject($scope.machine) &&\n                    $scope.machine.architecture === '') {\n                    $scope.machine.architecture = defaultArchitecture();\n                }\n            }\n        });\n\n        // Stop polling when the scope is destroyed.\n        $scope.$on(\"$destroy\", function() {\n            GeneralManager.stopPolling($scope, \"architectures\");\n            GeneralManager.stopPolling($scope, \"hwe_kernels\");\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Dashboard Controller\n */\n\nangular.module('MAAS').controller('DashboardController', [\n    '$scope', '$window', '$rootScope', '$routeParams', '$location',\n    'DiscoveriesManager', 'DomainsManager', 'MachinesManager',\n    'DevicesManager', 'SubnetsManager', 'VLANsManager', 'ConfigsManager',\n    'ManagerHelperService',\n    function($scope, $window, $rootScope, $routeParams, $location,\n             DiscoveriesManager, DomainsManager, MachinesManager,\n             DevicesManager, SubnetsManager, VLANsManager, ConfigsManager,\n             ManagerHelperService) {\n\n        // Default device IP options.\n        var deviceIPOptions = [\n            ['static', 'Static'],\n            ['dynamic', 'Dynamic'],\n            ['external', 'External']\n        ];\n\n        // Set title and page.\n        $rootScope.title = \"Dashboard\";\n        $rootScope.page = \"dashboard\";\n\n        // Set initial values.\n        $scope.loaded = false;\n        $scope.discoveredDevices = DiscoveriesManager.getItems();\n        $scope.domains = DomainsManager.getItems();\n        $scope.machines = MachinesManager.getItems();\n        $scope.devices = DevicesManager.getItems();\n        $scope.configManager = ConfigsManager;\n        $scope.networkDiscovery = null;\n        $scope.column = 'mac';\n        $scope.selectedDevice = null;\n        $scope.convertTo = null;\n\n        // Set default predicate to last_seen.\n        $scope.predicate = $scope.last_seen;\n\n        // Sorts the table by predicate.\n        $scope.sortTable = function(predicate) {\n            $scope.predicate = predicate;\n            $scope.reverse = !$scope.reverse;\n        };\n\n        // Proxy manager that the maas-obj-form directive uses to call the\n        // correct method based on current type.\n        $scope.proxyManager = {\n            updateItem: function(params) {\n                if($scope.convertTo.type === 'device') {\n                    return DevicesManager.createItem(params);\n                } else if($scope.convertTo.type === 'interface') {\n                    return DevicesManager.createInterface(params);\n                } else {\n                    throw new Error(\"Unknown type: \" + $scope.convertTo.type);\n                }\n            }\n        };\n\n        // Return the name name for the Discovery.\n        $scope.getDiscoveryName = function(discovery) {\n            if(discovery.hostname === null) {\n                return 'unknown';\n            }\n            else {\n                return discovery.hostname;\n            }\n        };\n\n        // Get the name of the subnet from its ID.\n        $scope.getSubnetName = function(subnetId) {\n            var subnet = SubnetsManager.getItemFromList(subnetId);\n            return SubnetsManager.getName(subnet);\n        };\n\n        // Get the name of the VLAN from its ID.\n        $scope.getVLANName = function(vlanId) {\n            var vlan = VLANsManager.getItemFromList(vlanId);\n            return VLANsManager.getName(vlan);\n        };\n\n        // Sets selected device\n        $scope.toggleSelected = function(deviceId) {\n            if($scope.selectedDevice === deviceId) {\n                $scope.selectedDevice = null;\n            } else {\n                var discovered = DiscoveriesManager.getItemFromList(deviceId);\n                var hostname = $scope.getDiscoveryName(discovered);\n                var domain;\n                if(hostname === 'unknown') {\n                    hostname = '';\n                }\n                if(hostname.indexOf('.') > 0) {\n                    domain = DomainsManager.getDomainByName(\n                        hostname.slice(hostname.indexOf('.') + 1));\n                    hostname = hostname.split(\".\", 1)[0];\n                    if(domain === null) {\n                        domain = DomainsManager.getDefaultDomain();\n                    }\n                } else {\n                    domain = DomainsManager.getDefaultDomain();\n                }\n                $scope.convertTo = {\n                    type: 'device',\n                    hostname: hostname,\n                    domain: domain,\n                    parent: null,\n                    ip_assignment: 'dynamic',\n                    goTo: false,\n                    saved: false,\n                    deviceIPOptions: deviceIPOptions.filter(\n                        function(option) {\n                            // Filter the options to not include static if\n                            // a subnet is not defined for this discovered\n                            // item.\n                            if(option[0] === 'static' &&\n                                !angular.isNumber(discovered.subnet)) {\n                                return false;\n                            } else {\n                                return true;\n                            }\n                        })\n                };\n                $scope.selectedDevice = deviceId;\n            }\n        };\n\n        // Called before the createItem is called to adjust the values\n        // passed over the call.\n        $scope.preProcess = function(item) {\n            var discovered = DiscoveriesManager.getItemFromList(\n                $scope.selectedDevice);\n            item = angular.copy(item);\n            if($scope.convertTo.type === 'device') {\n                item.primary_mac = discovered.mac_address;\n                item.extra_macs = [];\n                item.interfaces = [{\n                    mac: discovered.mac_address,\n                    ip_assignment: item.ip_assignment,\n                    ip_address: discovered.ip,\n                    subnet: discovered.subnet\n                }];\n            } else if($scope.convertTo.type === 'interface') {\n                item.mac_address = discovered.mac_address;\n                item.ip_address = discovered.ip;\n                item.subnet = discovered.subnet;\n            }\n            return item;\n        };\n\n        // Called after the createItem has been successful.\n        $scope.afterSave = function(obj) {\n            DiscoveriesManager._removeItem($scope.selectedDevice);\n            $scope.selectedDevice = null;\n            $scope.convertTo.hostname = obj.hostname;\n            $scope.convertTo.parent = obj.parent;\n            $scope.convertTo.saved = true;\n            if($scope.convertTo.goTo) {\n                if(angular.isString(obj.parent)) {\n                    $location.path('/node/' + obj.parent);\n                } else {\n                    $location.path('/nodes').search({tab: 'devices'});\n                }\n            }\n        };\n\n        // Load all the managers and get the network discovery config item.\n        ManagerHelperService.loadManagers($scope, [\n            DiscoveriesManager, DomainsManager, MachinesManager,\n            DevicesManager, SubnetsManager, VLANsManager, ConfigsManager]).then(\n            function() {\n                $scope.loaded = true;\n                $scope.networkDiscovery = ConfigsManager.getItemFromList(\n                    'network_discovery');\n            });\n    }\n]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Domain Details Controller\n */\n\nangular.module('MAAS').controller('DomainDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$location',\n    'DomainsManager', 'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $location,\n        DomainsManager, UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"domains\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.domain = null;\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.domain.displayname;\n        }\n\n        // Called when the domain has been loaded.\n        function domainLoaded(domain) {\n            $scope.domain = domain;\n            $scope.loaded = true;\n\n            updateTitle();\n        }\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if this is the default domain.\n        $scope.isDefaultDomain = function() {\n            if(angular.isObject($scope.domain)) {\n                return $scope.domain.id === 0;\n            }\n            return false;\n        };\n\n        // Called to check if the space can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.domain)) {\n                return $scope.domain.rrsets.length === 0;\n            }\n            return false;\n        };\n\n        // Called when the delete domain button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete domain button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete domain button is pressed.\n        $scope.deleteConfirmButton = function() {\n            DomainsManager.deleteDomain($scope.domain).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/domains\");\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers(\n            $scope, [DomainsManager, UsersManager]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this domain set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeDomain = DomainsManager.getActiveItem();\n            var requestedDomain = parseInt($routeParams.domain_id, 10);\n            if(isNaN(requestedDomain)) {\n                ErrorService.raiseError(\"Invalid domain identifier.\");\n            } else if(angular.isObject(activeDomain) &&\n                activeDomain.id === requestedDomain) {\n                domainLoaded(activeDomain);\n            } else {\n                DomainsManager.setActiveItem(\n                    requestedDomain).then(function(domain) {\n                        domainLoaded(domain);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Domains List Controller\n */\n\nangular.module('MAAS').controller('DomainsListController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', 'DomainsManager',\n    'UsersManager', 'ManagerHelperService',\n    function($scope, $rootScope, $routeParams, $filter, DomainsManager,\n        UsersManager, ManagerHelperService) {\n\n        // Load the filters that are used inside the controller.\n\n        // Set title and page.\n        $rootScope.title = \"DNS\";\n        $rootScope.page = \"domains\";\n\n        // Set initial values.\n        $scope.domains = DomainsManager.getItems();\n        $scope.currentpage = \"domains\";\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n        $scope.loading = true;\n\n        // This will hold the AddDomainController once it's initialized.  The\n        // controller will set this variable as it's always a child of this\n        // scope.\n        $scope.addDomainScope = null;\n\n        // Called when the add domain button is pressed.\n        $scope.addDomain = function() {\n            $scope.addDomainScope.show();\n        };\n\n        // Called when the cancel add domain button is pressed.\n        $scope.cancelAddDomain = function() {\n            $scope.addDomainScope.cancel();\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        ManagerHelperService.loadManagers(\n            $scope, [DomainsManager, UsersManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n        }\n    ]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Fabric Details Controller\n */\n\nangular.module('MAAS').controller('FabricDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'FabricsManager', 'VLANsManager', 'SubnetsManager', 'SpacesManager',\n    'ControllersManager',\n    'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $filter, $location,\n        FabricsManager, VLANsManager, SubnetsManager, SpacesManager,\n        ControllersManager,\n        UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        // Initial values.\n        $scope.fabric = null;\n        $scope.fabricManager = FabricsManager;\n        $scope.editSummary = false;\n        $scope.vlans = VLANsManager.getItems();\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.controllers = ControllersManager.getItems();\n        $scope.loaded = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.fabric.name;\n        }\n\n        // Called when the \"edit\" button is cliked in the fabric summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the fabric summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Called when the fabric has been loaded.\n        function fabricLoaded(fabric) {\n            if(angular.isObject(fabric)) {\n                $scope.fabric = fabric;\n                updateTitle();\n                $scope.$watch(\"vlans\", updateVLANs, true);\n                $scope.$watch(\"subnets\", updateVLANs, true);\n                $scope.$watch(\"controllers\", updateVLANs, true);\n                $scope.loaded = true;\n                // Initial table sort order.\n                $scope.predicate = \"['vlan_name', 'vlan.id', 'subnet_name']\";\n            }\n        }\n\n        // Generate a table that can easily be rendered in the view.\n        function updateVLANs() {\n            var rows = [];\n            var racks = {};\n            angular.forEach($filter('filter')(\n                    $scope.vlans, {fabric:$scope.fabric.id}, true),\n                    function(vlan) {\n                var subnets =\n                    $filter('filter')($scope.subnets, {vlan:vlan.id}, true);\n                if(subnets.length > 0) {\n                    angular.forEach(subnets, function(subnet) {\n                        var space = SpacesManager.getItemFromList(subnet.space);\n                        var space_name = (space === null) ?\n                            \"(undefined)\" : space.name;\n                        var row = {\n                            vlan: vlan,\n                            vlan_name: VLANsManager.getName(vlan),\n                            subnet: subnet,\n                            subnet_name: SubnetsManager.getName(subnet),\n                            space: space,\n                            space_name: space_name\n                        };\n                        rows.push(row);\n                    });\n                } else {\n                    // If there are no subnets, populate a row based on the\n                    // information we have (just the VLAN).\n                    var row = {\n                        vlan: vlan,\n                        vlan_name: VLANsManager.getName(vlan),\n                        subnet: null,\n                        subnet_name: null,\n                        space: null,\n                        space_name: null\n                    };\n                    rows.push(row);\n                }\n                // Enumerate racks for vlan.\n                angular.forEach(vlan.rack_sids, function(rack_sid) {\n                    var rack = ControllersManager.getItemFromList(rack_sid);\n                    if(angular.isObject(rack)) {\n                        racks[rack.system_id] = rack;\n                    }\n                });\n            });\n            $scope.rows = rows;\n            $scope.racks = Object.keys(racks).map(function(key) {\n                return racks[key];\n            });\n        }\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if this is the default Fabric\n        $scope.isDefaultFabric = function() {\n            if(!angular.isObject($scope.fabric)) {\n                return false;\n            }\n            return $scope.fabric.id === 0;\n        };\n\n        // Called to check if the space can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.fabric)) {\n                return $scope.fabric.id !== 0;\n            }\n            return false;\n        };\n\n        // Called when the delete fabric button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete fabric button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete fabric button is pressed.\n        $scope.deleteConfirmButton = function() {\n            FabricsManager.deleteFabric($scope.fabric).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/networks\");\n                $location.search('by', 'fabric');\n            }, function(reply) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(reply.error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            FabricsManager, VLANsManager, SubnetsManager, SpacesManager,\n            ControllersManager, UsersManager]).then(\n            function() {\n                // Possibly redirected from another controller that already had\n                // this fabric set to active. Only call setActiveItem if not\n                // already the activeItem.\n                var activeFabric = FabricsManager.getActiveItem();\n                var requestedFabric = parseInt($routeParams.fabric_id, 10);\n\n                if(isNaN(requestedFabric)) {\n                    ErrorService.raiseError(\"Invalid fabric identifier.\");\n                } else if(angular.isObject(activeFabric) &&\n                    activeFabric.id === requestedFabric) {\n                    fabricLoaded(activeFabric);\n                } else {\n                    FabricsManager.setActiveItem(\n                        requestedFabric).then(function(fabric) {\n                            fabricLoaded(fabric);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                }\n            });\n    }\n]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Images Controller\n */\n\nangular.module('MAAS').controller('ImagesController', [\n    '$rootScope', '$scope', 'BootResourcesManager',\n    'ConfigsManager', 'UsersManager', 'ManagerHelperService', function(\n        $rootScope, $scope, BootResourcesManager,\n        ConfigsManager, UsersManager, ManagerHelperService) {\n\n            $rootScope.page = \"images\";\n            $rootScope.title = \"Loading...\";\n\n            $scope.loading = true;\n            $scope.bootResources = BootResourcesManager.getData();\n            $scope.configManager = ConfigsManager;\n            $scope.autoImport = null;\n\n            // Return true if the user is a super user.\n            $scope.isSuperUser = function() {\n                return UsersManager.isSuperUser();\n            };\n\n            // Load the required managers.\n            ManagerHelperService.loadManagers(\n                $scope, [ConfigsManager, UsersManager]).then(function() {\n                $scope.autoImport = ConfigsManager.getItemFromList(\n                    \"boot_images_auto_import\");\n            });\n\n            // The boot-images directive will load the bootResources manager,\n            // we just watch until resources is set. That means the page is\n            // loaded.\n            $scope.$watch(\"bootResources.resources\", function() {\n                if(angular.isArray($scope.bootResources.resources)) {\n                    $scope.loading = false;\n                    $rootScope.title = \"Images\";\n                }\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Intro Controller\n */\n\nangular.module('MAAS').controller('IntroController', [\n    '$rootScope', '$scope', '$window', '$location',\n    'ConfigsManager', 'PackageRepositoriesManager', 'BootResourcesManager',\n    'ManagerHelperService',\n    function(\n        $rootScope, $scope, $window, $location,\n        ConfigsManager, PackageRepositoriesManager, BootResourcesManager,\n        ManagerHelperService) {\n\n            $rootScope.page = \"intro\";\n            $rootScope.title = \"Welcome\";\n\n            $scope.loading = true;\n            $scope.configManager = ConfigsManager;\n            $scope.repoManager = PackageRepositoriesManager;\n            $scope.bootResources = BootResourcesManager.getData();\n            $scope.hasImages = false;\n            $scope.maasName = null;\n            $scope.upstreamDNS = null;\n            $scope.mainArchive = null;\n            $scope.portsArchive = null;\n            $scope.httpProxy = null;\n\n            // Set the skip function on the rootScope to allow skipping the\n            // intro view.\n            $rootScope.skip = function() {\n                $scope.clickContinue(true);\n            };\n\n            // Return true if the welcome section is not in error.\n            $scope.welcomeInError = function() {\n                var form = $scope.maasName.$maasForm;\n                if(angular.isObject(form)) {\n                    return form.hasErrors();\n                } else {\n                    return false;\n                }\n            };\n\n            // Return true if the network section is in error.\n            $scope.networkInError = function() {\n                var inError = false;\n                var objs = [\n                    $scope.upstreamDNS,\n                    $scope.mainArchive,\n                    $scope.portsArchive,\n                    $scope.httpProxy];\n                angular.forEach(objs, function(obj) {\n                    var form = obj.$maasForm;\n                    if(angular.isObject(form) && form.hasErrors()) {\n                        inError = true;\n                    }\n                });\n                return inError;\n            };\n\n            // Return true if continue can be clicked.\n            $scope.canContinue = function() {\n                return (\n                    !$scope.welcomeInError() &&\n                    !$scope.networkInError() &&\n                    $scope.hasImages);\n            };\n\n            // Called when continue button is clicked.\n            $scope.clickContinue = function(force) {\n                if(angular.isUndefined(force)) {\n                    force = false;\n                }\n                if(force || $scope.canContinue()) {\n                    ConfigsManager.updateItem({\n                        'name': 'completed_intro',\n                        'value': true\n                    }).then(function() {\n                        // Reload the whole page so that the MAAS_config will be\n                        // set to the new value.\n                        $window.location.reload();\n                    });\n                }\n            };\n\n            // If intro has been completed redirect to '/'.\n            if(MAAS_config.completed_intro) {\n                $location.path('/');\n            } else {\n                // Load the required managers.\n                var managers = [ConfigsManager, PackageRepositoriesManager];\n                ManagerHelperService.loadManagers(\n                    $scope, managers).then(function() {\n                    $scope.loading = false;\n                    $scope.maasName = ConfigsManager.getItemFromList(\n                        \"maas_name\");\n                    $scope.upstreamDNS = ConfigsManager.getItemFromList(\n                        \"upstream_dns\");\n                    $scope.httpProxy = ConfigsManager.getItemFromList(\n                        \"http_proxy\");\n                    $scope.mainArchive = (\n                        PackageRepositoriesManager.getItems().filter(\n                            function(repo) {\n                                return (repo['default'] &&\n                                    repo.name === \"main_archive\");\n                            })[0]);\n                    $scope.portsArchive = (\n                        PackageRepositoriesManager.getItems().filter(\n                            function(repo) {\n                                return (repo['default'] &&\n                                    repo.name === \"ports_archive\");\n                            })[0]);\n                });\n\n                // Don't load the boot resources as the boot-images directive\n                // performs that action. Just watch and make sure that\n                // at least one resource exists before continuing.\n                $scope.$watch(\"bootResources.resources\", function() {\n                    if(angular.isArray($scope.bootResources.resources) &&\n                        $scope.bootResources.resources.length > 0) {\n                        $scope.hasImages = true;\n                    } else {\n                        $scope.hasImages = false;\n                    }\n                });\n            }\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Intro Controller\n */\n\nangular.module('MAAS').controller('IntroUserController', [\n    '$rootScope', '$scope', '$window', '$location',\n    'UsersManager', 'ManagerHelperService',\n    function(\n        $rootScope, $scope, $window, $location,\n        UsersManager, ManagerHelperService) {\n\n            $rootScope.page = \"intro\";\n            $rootScope.title = \"Welcome\";\n\n            $scope.loading = true;\n            $scope.user = null;\n\n            // Set the skip function on the rootScope to allow skipping the\n            // intro view.\n            $rootScope.skip = function() {\n                $scope.clickContinue(true);\n            };\n\n            // Return true if super user.\n            $scope.isSuperUser = function() {\n                return UsersManager.isSuperUser();\n            };\n\n            // Return true if continue can be clicked.\n            $scope.canContinue = function() {\n                return $scope.user.sshkeys_count > 0;\n            };\n\n            // Called when continue button is clicked.\n            $scope.clickContinue = function(force) {\n                if(angular.isUndefined(force)) {\n                    force = false;\n                }\n                if(force || $scope.canContinue()) {\n                    UsersManager.markIntroComplete().then(function() {\n                        // Reload the whole page so that the MAAS_config will\n                        // be set to the new value.\n                        $window.location.reload();\n                    });\n                }\n            };\n\n            // If intro has been completed redirect to '/'.\n            if(MAAS_config.user_completed_intro) {\n                $location.path('/');\n            } else {\n                // Load the required managers.\n                ManagerHelperService.loadManager(\n                    $scope, UsersManager).then(function() {\n                        $scope.loading = false;\n                        $scope.user = UsersManager.getAuthUser();\n                    });\n            }\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Networks List Controller\n */\n\nangular.module('MAAS').controller('NetworksListController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'SubnetsManager', 'FabricsManager', 'SpacesManager', 'VLANsManager',\n    'UsersManager', 'ManagerHelperService',\n    function($scope, $rootScope, $routeParams, $filter, $location,\n             SubnetsManager, FabricsManager, SpacesManager, VLANsManager,\n             UsersManager, ManagerHelperService) {\n\n        // Load the filters that are used inside the controller.\n        var filterByVLAN = $filter('filterByVLAN');\n        var filterByFabric = $filter('filterByFabric');\n        var filterBySpace = $filter('filterBySpace');\n        var filterByNullSpace = $filter('filterByNullSpace');\n\n        // Set title and page.\n        $rootScope.title = \"Subnets\";\n        $rootScope.page = \"networks\";\n\n        // Set the initial value of $scope.groupBy based on the URL\n        // parameters, but default to the 'fabric' groupBy if it's not found.\n        $scope.getURLParameters = function() {\n            if(angular.isString($location.search().by)) {\n                $scope.groupBy = $location.search().by;\n            } else {\n                $scope.groupBy = 'fabric';\n            }\n        };\n\n        $scope.ADD_FABRIC_ACTION = {\n            name: \"add_fabric\",\n            title: \"Fabric\",\n            selectedTitle: \"Add fabric\",\n            objectName: 'fabric'\n        };\n        $scope.ADD_VLAN_ACTION = {\n            name: \"add_vlan\",\n            title: \"VLAN\",\n            selectedTitle: \"Add VLAN\",\n            objectName: 'vlan'\n        };\n        $scope.ADD_SPACE_ACTION = {\n            name: \"add_space\",\n            title: \"Space\",\n            selectedTitle: \"Add space\",\n            objectName: 'space'\n        };\n        $scope.ADD_SUBNET_ACTION = {\n            name: \"add_subnet\",\n            title: \"Subnet\",\n            selectedTitle: \"Add subnet\",\n            objectName: 'subnet'\n        };\n\n        $scope.getURLParameters();\n\n        // Set initial values.\n        $scope.subnetManager = SubnetsManager;\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.fabricManager = FabricsManager;\n        $scope.fabrics = FabricsManager.getItems();\n        $scope.spaceManager = SpacesManager;\n        $scope.spaces = SpacesManager.getItems();\n        $scope.vlanManager = VLANsManager;\n        $scope.vlans = VLANsManager.getItems();\n        $scope.loading = true;\n\n        $scope.group = {};\n        // Used when grouping by fabrics.\n        $scope.group.fabrics = {};\n        // User when grouping by spaces.\n        $scope.group.spaces = {};\n        $scope.group.spaces.orphanVLANs = [];\n\n        // Initializers for action objects.\n        var actionObjectInitializers = {\n            fabric: function() {\n                return {};\n            },\n            vlan: function() {\n                // Set initial fabric.\n                return {\n                    fabric: $scope.fabrics[0].id\n                };\n            },\n            space: function() {\n                return {};\n            },\n            subnet: function() {\n                // Set initial VLAN and space.\n                return {\n                    vlan: $scope.fabrics[0].vlan_ids[0]\n                };\n            }\n        };\n\n        // Return the name of the subnet.\n        function getSubnetName(subnet) {\n            return SubnetsManager.getName(subnet);\n        }\n\n        // Generate a table that can be easily rendered in the view.\n        // Traverses the fabrics and VLANs in-order so that if previous\n        // fabrics and VLANs' names are identical, they can be hidden from\n        // the table cell.\n        function updateFabricsGroupBy() {\n            var rows = [];\n            var previous_fabric = {id:-1};\n            var previous_vlan = {id:-1};\n            var fabrics = $filter('orderBy')($scope.fabrics, ['name']);\n            angular.forEach(fabrics, function(fabric) {\n                var vlans = filterByFabric($scope.vlans, fabric);\n                vlans = $filter('orderBy')(vlans, ['vid']);\n                angular.forEach(vlans, function(vlan) {\n                    var subnets = filterByVLAN($scope.subnets, vlan);\n                    if(subnets.length > 0) {\n                        angular.forEach(subnets, function(subnet) {\n                            var space = SpacesManager.getItemFromList(\n                                subnet.space);\n                            var row = {\n                                fabric: fabric,\n                                fabric_name: \"\",\n                                vlan: vlan,\n                                vlan_name: \"\",\n                                space: space,\n                                subnet: subnet,\n                                subnet_name: getSubnetName(subnet)\n                            };\n                            if(fabric.id !== previous_fabric.id) {\n                                previous_fabric.id = fabric.id;\n                                row.fabric_name = fabric.name;\n                            }\n                            if(vlan.id !== previous_vlan.id) {\n                                previous_vlan.id = vlan.id;\n                                row.vlan_name = $scope.getVLANName(vlan);\n                            }\n                            rows.push(row);\n                        });\n                    } else {\n                        var row = {\n                            fabric: fabric,\n                            fabric_name: \"\",\n                            vlan: vlan,\n                            vlan_name: $scope.getVLANName(vlan)\n                        };\n                        if(fabric.id !== previous_fabric.id) {\n                            previous_fabric.id = fabric.id;\n                            row.fabric_name = fabric.name;\n                        }\n                        rows.push(row);\n                    }\n                });\n            });\n            $scope.group.fabrics.rows = rows;\n        }\n\n        // Generate a table that can be easily rendered in the view.\n        // Traverses the spaces in-order so that if the previous space's name\n        // is identical, it can be hidden from the table cell.\n        // Note that this view only shows items that can be related to a space.\n        // That is, VLANs and fabrics with no corresponding subnets (and\n        // therefore spaces) cannot be shown in this table.\n        function updateSpacesGroupBy() {\n            var rows = [];\n            var spaces = $filter('orderBy')($scope.spaces, ['name']);\n            var previous_space = {id: -1};\n            angular.forEach(spaces, function(space) {\n                var subnets = filterBySpace($scope.subnets, space);\n                subnets = $filter('orderBy')(subnets, ['cidr']);\n                var index = 0;\n                angular.forEach(subnets, function(subnet) {\n                    index++;\n                    var vlan = VLANsManager.getItemFromList(subnet.vlan);\n                    var fabric = FabricsManager.getItemFromList(vlan.fabric);\n                    var row = {\n                        fabric: fabric,\n                        vlan: vlan,\n                        vlan_name: $scope.getVLANName(vlan),\n                        subnet: subnet,\n                        subnet_name: getSubnetName(subnet),\n                        space: space,\n                        space_name: \"\"\n                    };\n                    if(space.id !== previous_space.id) {\n                        previous_space.id = space.id;\n                        row.space_name = space.name;\n                    }\n                    rows.push(row);\n                });\n                if(index === 0) {\n                    rows.push({\n                        space: space,\n                        space_name: space.name\n                    });\n                }\n            });\n            $scope.group.spaces.rows = rows;\n        }\n\n        function updateOrphanVLANs() {\n            var rows = [];\n            var subnets = filterByNullSpace($scope.subnets);\n            subnets = $filter('orderBy')(subnets, ['cidr']);\n            angular.forEach(subnets, function(subnet) {\n                var vlan = VLANsManager.getItemFromList(subnet.vlan);\n                var fabric = FabricsManager.getItemFromList(vlan.fabric);\n                var row = {\n                    fabric: fabric,\n                    vlan: vlan,\n                    vlan_name: $scope.getVLANName(vlan),\n                    subnet: subnet,\n                    subnet_name: getSubnetName(subnet),\n                    space: null\n                };\n                rows.push(row);\n            });\n            $scope.group.spaces.orphanVLANs = rows;\n        }\n\n        // Update the \"Group by\" selection. This is called from a few places:\n        // * When the $watch notices data has changed\n        // * When the URL bar is updated, after the URL is parsed and\n        //   $scope.groupBy is updated\n        // * When the drop-down \"Group by\" selection box changes\n        $scope.updateGroupBy = function() {\n            var groupBy = $scope.groupBy;\n            if(groupBy === 'space') {\n                $location.search('by', 'space');\n                updateSpacesGroupBy();\n                updateOrphanVLANs();\n            } else {\n                // The only other option is 'fabric', but in case the user\n                // made a typo on the URL bar we just assume it was 'fabric'\n                // as a fallback.\n                $location.search('by', 'fabric');\n                updateFabricsGroupBy();\n            }\n        };\n\n        // Called when the managers load to populate the actions the user\n        // is allowed to perform.\n        $scope.updateActions = function() {\n            if(UsersManager.isSuperUser()) {\n                $scope.actionOptions = [\n                    $scope.ADD_FABRIC_ACTION,\n                    $scope.ADD_VLAN_ACTION,\n                    $scope.ADD_SPACE_ACTION,\n                    $scope.ADD_SUBNET_ACTION\n                ];\n            } else {\n                $scope.actionOptions = [];\n            }\n        };\n\n        // Called when a action is selected.\n        $scope.actionChanged = function() {\n            $scope.newObject = (\n                actionObjectInitializers[$scope.actionOption.objectName]());\n        };\n\n        // Called when the \"Cancel\" button is pressed.\n        $scope.cancelAction = function() {\n            $scope.actionOption = null;\n            $scope.newObject = null;\n        };\n\n        // Return the name name for the VLAN.\n        $scope.getVLANName = function(vlan) {\n            return VLANsManager.getName(vlan);\n        };\n\n        // Return the name of the fabric from its given ID.\n        $scope.getFabricNameById = function(fabricId) {\n            return FabricsManager.getName(\n                FabricsManager.getItemFromList(fabricId));\n        };\n\n        // Called before the subnet object is saved. Sets the fabric\n        // field to be the fabric for the selected VLAN.\n        $scope.actionSubnetPreSave = function(obj) {\n            obj.fabric = VLANsManager.getItemFromList(obj.vlan).fabric;\n            return obj;\n        };\n\n        ManagerHelperService.loadManagers($scope, [\n            SubnetsManager, FabricsManager, SpacesManager, VLANsManager,\n            UsersManager]).then(\n            function() {\n                $scope.loading = false;\n\n                $scope.updateActions();\n\n                $scope.$watch(\n                    \"[subnets, fabrics, spaces, vlans]\",\n                    $scope.updateGroupBy, true);\n\n                // If the route has been updated, a new search string must\n                // potentially be rendered.\n                $scope.$on(\"$routeUpdate\", function() {\n                    $scope.getURLParameters();\n                    $scope.updateGroupBy();\n                });\n                $scope.updateGroupBy();\n            });\n    }\n]);\n","/* Copyright 2015-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Details Controller\n */\n\nangular.module('MAAS').controller('NodeDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$location', '$interval',\n    'DevicesManager', 'MachinesManager', 'ControllersManager', 'ZonesManager',\n    'GeneralManager', 'UsersManager', 'TagsManager', 'DomainsManager',\n    'ManagerHelperService', 'ServicesManager', 'ErrorService',\n    'ValidationService', 'ScriptsManager', function(\n        $scope, $rootScope, $routeParams, $location, $interval, DevicesManager,\n        MachinesManager, ControllersManager, ZonesManager, GeneralManager,\n        UsersManager, TagsManager, DomainsManager, ManagerHelperService,\n        ServicesManager, ErrorService, ValidationService, ScriptsManager) {\n\n        // Mapping of device.ip_assignment to viewable text.\n        var DEVICE_IP_ASSIGNMENT = {\n            external: \"External\",\n            dynamic: \"Dynamic\",\n            \"static\": \"Static\"\n        };\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"nodes\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.node = null;\n        $scope.action = {\n          option: null,\n          allOptions: null,\n          availableOptions: [],\n          error: null,\n          showing_confirmation: false\n        };\n        $scope.power_types = GeneralManager.getData(\"power_types\");\n        $scope.osinfo = GeneralManager.getData(\"osinfo\");\n        $scope.section = {\n            area: angular.isString(\n                $routeParams.area) ? $routeParams.area : \"summary\"\n        };\n        $scope.osSelection = {\n            osystem: null,\n            release: null,\n            hwe_kernel: null\n        };\n        $scope.commissionOptions = {\n            enableSSH: false,\n            skipNetworking: false,\n            skipStorage: false,\n            updateFirmware: false,\n            configureHBA: false\n        };\n        $scope.commissioningSelection = [];\n        $scope.testSelection = [];\n        $scope.releaseOptions = {};\n        $scope.checkingPower = false;\n        $scope.devices = [];\n        $scope.scripts = ScriptsManager.getItems();\n\n        // Node header section.\n        $scope.header = {\n            editing: false,\n            editing_domain: false,\n            hostname: {\n                value: \"\"\n            },\n            domain: {\n                selected: null,\n                options: DomainsManager.getItems()\n            }\n        };\n\n        // Summary section.\n        $scope.summary = {\n            editing: false,\n            architecture: {\n                selected: null,\n                options: GeneralManager.getData(\"architectures\")\n            },\n            min_hwe_kernel: {\n                selected: null,\n                options: GeneralManager.getData(\"min_hwe_kernels\")\n            },\n            zone: {\n                selected: null,\n                options: ZonesManager.getItems()\n            },\n            tags: []\n        };\n\n        // Service monitor section (for controllers).\n        $scope.services = {};\n\n        // Power section.\n        $scope.power = {\n            editing: false,\n            type: null,\n            bmc_node_count: 0,\n            parameters: {}\n        };\n\n        // Get the display text for device ip assignment type.\n        $scope.getDeviceIPAssignment = function(ipAssignment) {\n            return DEVICE_IP_ASSIGNMENT[ipAssignment];\n        };\n\n        // Events section.\n        $scope.events = {\n            limit: 10\n        };\n\n        // Updates the page title.\n        function updateTitle() {\n            if($scope.node && $scope.node.fqdn) {\n                $rootScope.title = $scope.node.fqdn;\n            }\n        }\n\n        function updateHeader() {\n            // Don't update the value if in editing mode. As this would\n            // overwrite the users changes.\n            if($scope.header.editing || $scope.header.editing_domain) {\n                return;\n            }\n            $scope.header.hostname.value = $scope.node.fqdn;\n            // DomainsManager gives us all Domain information while the node\n            // only contains the name and id. Because of this we need to loop\n            // through the DomainsManager options and find the option with the\n            // id matching the node id. Otherwise we end up setting our\n            // selected field to an option not from DomainsManager which\n            // doesn't work.\n            var i;\n            for(i=0;i<$scope.header.domain.options.length;i++) {\n                var option = $scope.header.domain.options[i];\n                if(option.id === $scope.node.domain.id) {\n                    $scope.header.domain.selected = option;\n                    break;\n                }\n            }\n        }\n\n        // Update the available action options for the node.\n        function updateAvailableActionOptions() {\n            $scope.action.availableOptions = [];\n            if(!angular.isObject($scope.node)) {\n                return;\n            }\n\n            // Initialize the allowed action list.\n            if($scope.action.allOptions === null) {\n                $scope.action.allOptions =\n                    $scope.getAllActionOptions($scope.node.node_type);\n            }\n\n            // Build the available action options control from the\n            // allowed actions, except set-zone which does not make\n            // sense in this view because the form has this\n            // functionality\n            angular.forEach($scope.action.allOptions, function(option) {\n                if($scope.node.actions.indexOf(option.name) >= 0\n                   && option.name !== \"set-zone\") {\n                    $scope.action.availableOptions.push(option);\n                }\n            });\n        }\n\n        // Updates the currently selected items in the power section.\n        function updatePower() {\n            // Do not update the selected items, when editing this would\n            // cause the users selection to change.\n            if($scope.power.editing) {\n                return;\n            }\n\n            var i;\n            $scope.power.type = null;\n            for(i = 0; i < $scope.power_types.length; i++) {\n                if($scope.node.power_type === $scope.power_types[i].name) {\n                    $scope.power.type = $scope.power_types[i];\n                    break;\n                }\n            }\n\n            $scope.power.bmc_node_count = $scope.node.power_bmc_node_count;\n\n            $scope.power.parameters = angular.copy(\n                $scope.node.power_parameters);\n            if(!angular.isObject($scope.power.parameters)) {\n                $scope.power.parameters = {};\n            }\n\n            // Force editing mode on, if the power_type is missing for a\n            // machine. This is placed at the bottom because we wanted the\n            // selected items to be filled in at least once.\n            if($scope.canEdit() && $scope.node.power_type === \"\" &&\n               $scope.node.node_type === 0) {\n                $scope.power.editing = true;\n            }\n        }\n\n        // Updates the currently selected items in the summary section.\n        function updateSummary() {\n            // Do not update the selected items, when editing this would\n            // cause the users selection to change.\n            if($scope.summary.editing) {\n                return;\n            }\n\n            if(angular.isObject($scope.node.zone)) {\n                $scope.summary.zone.selected = ZonesManager.getItemFromList(\n                    $scope.node.zone.id);\n            }\n            $scope.summary.architecture.selected = $scope.node.architecture;\n            $scope.summary.min_hwe_kernel.selected = $scope.node.min_hwe_kernel;\n            $scope.summary.tags = angular.copy($scope.node.tags);\n\n            // Force editing mode on, if the architecture is invalid. This is\n            // placed at the bottom because we wanted the selected items to\n            // be filled in at least once.\n            if($scope.canEdit() &&\n                $scope.hasUsableArchitectures() &&\n                $scope.hasInvalidArchitecture()) {\n                $scope.summary.editing = true;\n            }\n        }\n\n        // Updates the service monitor section.\n        function updateServices() {\n            if($scope.isController) {\n                $scope.services = {};\n                angular.forEach(ControllersManager.getServices(\n                        $scope.node), function(service) {\n                    $scope.services[service.name] = service;\n                });\n            }\n        }\n\n        // Update the devices array on the scope based on the device children\n        // on the node.\n        function updateDevices() {\n            $scope.devices = [];\n            angular.forEach($scope.node.devices, function(child) {\n                var device = {\n                    name: child.fqdn\n                };\n\n                // Add the interfaces to the device object if any exists.\n                if(angular.isArray(child.interfaces) &&\n                    child.interfaces.length > 0) {\n                    angular.forEach(child.interfaces, function(nic, nicIdx) {\n                        var deviceWithMAC = angular.copy(device);\n                        deviceWithMAC.mac_address = nic.mac_address;\n\n                        // Remove device name so it is not duplicated in the\n                        // table since this is another MAC address on this\n                        // device.\n                        if(nicIdx > 0) {\n                            deviceWithMAC.name = \"\";\n                        }\n\n                        // Add this links to the device object if any exists.\n                        if(angular.isArray(nic.links) &&\n                            nic.links.length > 0) {\n                            angular.forEach(nic.links, function(link, lIdx) {\n                                var deviceWithLink = angular.copy(\n                                    deviceWithMAC);\n                                deviceWithLink.ip_address = link.ip_address;\n\n                                // Remove the MAC address so it is not\n                                // duplicated in the table since this is\n                                // another link on this interface.\n                                if(lIdx > 0) {\n                                    deviceWithLink.mac_address = \"\";\n                                }\n\n                                $scope.devices.push(deviceWithLink);\n                            });\n                        } else {\n                            $scope.devices.push(deviceWithMAC);\n                        }\n                    });\n                } else {\n                    $scope.devices.push(device);\n                }\n            });\n        }\n\n        // Starts the watchers on the scope.\n        function startWatching() {\n            // Update the title and name when the node fqdn changes.\n            $scope.$watch(\"node.fqdn\", function() {\n                updateTitle();\n                updateHeader();\n            });\n\n            // Update the devices on the node.\n            $scope.$watch(\"node.devices\", updateDevices);\n\n            // Update the availableActionOptions when the node actions change.\n            $scope.$watch(\"node.actions\", updateAvailableActionOptions);\n\n            // Update the summary when the node or architectures list is\n            // updated.\n            $scope.$watch(\"node.architecture\", updateSummary);\n            $scope.$watchCollection(\n                $scope.summary.architecture.options, updateSummary);\n\n            // Uppdate the summary when min_hwe_kernel is updated.\n            $scope.$watch(\"node.min_hwe_kernel\", updateSummary);\n            $scope.$watchCollection(\n                $scope.summary.min_hwe_kernel.options, updateSummary);\n\n            // Update the summary when the node or zone list is\n            // updated.\n            $scope.$watch(\"node.zone.id\", updateSummary);\n            $scope.$watchCollection(\n                $scope.summary.zone.options, updateSummary);\n\n            // Update the power when the node power_type or power_parameters\n            // are updated.\n            $scope.$watch(\"node.power_type\", updatePower);\n            $scope.$watch(\"node.power_parameters\", updatePower);\n            $scope.$watchCollection(\"power_types\", updatePower);\n\n            // Update the services when the services list is updated.\n            $scope.$watch(\"node.service_ids\", updateServices);\n        }\n\n        // Called when the node has been loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n\n            updateTitle();\n            updateSummary();\n            updateServices();\n            startWatching();\n\n            // Tell the storageController and networkingController that the\n            // node has been loaded.\n            if(angular.isObject($scope.storageController)) {\n                $scope.storageController.nodeLoaded();\n            }\n            if(angular.isObject($scope.networkingController)) {\n                $scope.networkingController.nodeLoaded();\n            }\n        }\n\n        $scope.getAllActionOptions = function(node_type) {\n            if(typeof node_type !== 'number' ||\n                    node_type < 0 || node_type > 4) {\n                return [];\n            }\n            var actionTypeForNodeType = {\n                0: \"machine_actions\",\n                1: \"device_actions\",\n                2: \"rack_controller_actions\",\n                3: \"region_controller_actions\",\n                4: \"region_and_rack_controller_actions\"\n            };\n            return GeneralManager.getData(actionTypeForNodeType[node_type]);\n        };\n\n        // Update the node with new data on the region.\n        $scope.updateNode = function(node, queryPower) {\n            if(angular.isUndefined(queryPower)) {\n                queryPower = false;\n            }\n            return $scope.nodesManager.updateItem(node).then(function(node) {\n                updateHeader();\n                updateSummary();\n                if(queryPower) {\n                    $scope.checkPowerState();\n                }\n            }, function(error) {\n                console.log(error);\n                updateHeader();\n                updateSummary();\n            });\n        };\n\n        // Called for autocomplete when the user is typing a tag name.\n        $scope.tagsAutocomplete = function(query) {\n            return TagsManager.autocomplete(query);\n        };\n\n        $scope.getPowerStateClass = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return \"\";\n            }\n\n            if($scope.checkingPower) {\n                return \"checking\";\n            } else {\n                return $scope.node.power_state;\n            }\n        };\n\n        // Get the power state text to show.\n        $scope.getPowerStateText = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return \"\";\n            }\n\n            if($scope.checkingPower) {\n                return \"Checking power\";\n            } else if($scope.node.power_state === \"unknown\") {\n                return \"\";\n            } else {\n                return \"Power \" + $scope.node.power_state;\n            }\n        };\n\n        // Returns true when the \"check now\" button for updating the power\n        // state should be shown.\n        $scope.canCheckPowerState = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return false. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n            return (\n                $scope.node.power_state !== \"unknown\" &&\n                !$scope.checkingPower);\n        };\n\n        // Check the power state of the node.\n        $scope.checkPowerState = function() {\n            $scope.checkingPower = true;\n            $scope.nodesManager.checkPowerState($scope.node).then(function() {\n                $scope.checkingPower = false;\n            });\n        };\n\n        $scope.isUbuntuOS = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n\n            if($scope.node.osystem === \"ubuntu\") {\n                return true;\n            }\n            return false;\n        };\n\n        $scope.isUbuntuCoreOS = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n\n            if($scope.node.osystem === \"ubuntu-core\") {\n                return true;\n            }\n            return false;\n        };\n\n        $scope.isCustomOS = function() {\n            // This will get called very early and node can be empty.\n            // In that case just return an empty string. It will be\n            // called again to show the correct information.\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n\n            if($scope.node.osystem === \"custom\") {\n                return true;\n            }\n            return false;\n        };\n\n        // Return true if there is an action error.\n        $scope.isActionError = function() {\n            return $scope.action.error !== null;\n        };\n\n        // Return True if in deploy action and the osinfo is missing.\n        $scope.isDeployError = function() {\n            // Never a deploy error when there is an action error.\n            if($scope.isActionError()) {\n                return false;\n            }\n\n            var missing_osinfo = (\n                angular.isUndefined($scope.osinfo.osystems) ||\n                $scope.osinfo.osystems.length === 0);\n            if(angular.isObject($scope.action.option) &&\n                $scope.action.option.name === \"deploy\" &&\n                missing_osinfo) {\n                return true;\n            }\n            return false;\n        };\n\n        // Return True if unable to deploy because of missing ssh keys.\n        $scope.isSSHKeyError = function() {\n            // Never a deploy error when there is an action error.\n            if($scope.isActionError()) {\n                return false;\n            }\n            if(angular.isObject($scope.action.option) &&\n                $scope.action.option.name === \"deploy\" &&\n                UsersManager.getSSHKeyCount() === 0) {\n                return true;\n            }\n            return false;\n        };\n\n        // Called when the actionOption has changed.\n        $scope.action.optionChanged = function() {\n            // Clear the action error.\n            $scope.action.error = null;\n            $scope.action.showing_confirmation = false;\n        };\n\n        // Cancel the action.\n        $scope.actionCancel = function() {\n            $scope.action.option = null;\n            $scope.action.error = null;\n            $scope.action.showing_confirmation = false;\n        };\n\n        // Perform the action.\n        $scope.actionGo = function() {\n            var extra = {};\n            var i;\n            // Set deploy parameters if a deploy.\n            if($scope.action.option.name === \"deploy\" &&\n                angular.isString($scope.osSelection.osystem) &&\n                angular.isString($scope.osSelection.release)) {\n\n                // Set extra. UI side the release is structured os/release, but\n                // when it is sent over the websocket only the \"release\" is\n                // sent.\n                extra.osystem = $scope.osSelection.osystem;\n                var release = $scope.osSelection.release;\n                release = release.split(\"/\");\n                release = release[release.length-1];\n                extra.distro_series = release;\n                // hwe_kernel is optional so only include it if its specified\n                if(angular.isString($scope.osSelection.hwe_kernel) &&\n                   ($scope.osSelection.hwe_kernel.indexOf('hwe-') >= 0 ||\n                    $scope.osSelection.hwe_kernel.indexOf('ga-') >= 0)) {\n                    extra.hwe_kernel = $scope.osSelection.hwe_kernel;\n                }\n            } else if($scope.action.option.name === \"commission\") {\n                extra.enable_ssh = $scope.commissionOptions.enableSSH;\n                extra.skip_networking = (\n                    $scope.commissionOptions.skipNetworking);\n                extra.skip_storage = $scope.commissionOptions.skipStorage;\n                extra.commissioning_scripts = [];\n                for(i=0;i<$scope.commissioningSelection.length;i++) {\n                    extra.commissioning_scripts.push(\n                        $scope.commissioningSelection[i].id);\n                }\n                if($scope.commissionOptions.updateFirmware) {\n                    extra.commissioning_scripts.push('update_firmware')\n                }\n                if($scope.commissionOptions.configureHBA) {\n                    extra.commissioning_scripts.push('configure_hba')\n                }\n                if(extra.commissioning_scripts.length === 0) {\n                    // Tell the region not to run any custom commissioning\n                    // scripts.\n                    extra.commissioning_scripts.push('none');\n                }\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.testSelection.length;i++) {\n                    extra.testing_scripts.push($scope.testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.action.option.name === \"test\") {\n                if($scope.node.status_code === 6 &&\n                        !$scope.action.showing_confirmation) {\n                    $scope.action.showing_confirmation = true;\n                    return;\n                }\n                // Set the test options.\n                extra.enable_ssh = $scope.commissionOptions.enableSSH;\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.testSelection.length;i++) {\n                    extra.testing_scripts.push($scope.testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.action.option.name === \"release\") {\n                // Set the release options.\n                extra.erase = $scope.releaseOptions.erase;\n                extra.secure_erase = $scope.releaseOptions.secureErase;\n                extra.quick_erase = $scope.releaseOptions.quickErase;\n            }\n\n            $scope.nodesManager.performAction(\n                $scope.node, $scope.action.option.name, extra).then(function() {\n                    // If the action was delete, then go back to listing.\n                    if($scope.action.option.name === \"delete\") {\n                        $location.path(\"/nodes\");\n                    }\n                    $scope.action.option = null;\n                    $scope.action.error = null;\n                    $scope.action.showing_confirmation = false;\n                    $scope.osSelection.$reset();\n                    $scope.commissionOptions.enableSSH = false;\n                    $scope.commissionOptions.skipNetworking = false;\n                    $scope.commissionOptions.skipStorage = false;\n                    $scope.commissionOptions.updateFirmware = false;\n                    $scope.commissionOptions.configureHBA = false;\n                    $scope.commissioningSelection = [];\n                    $scope.testSelection = [];\n                }, function(error) {\n                    $scope.action.error = error;\n                });\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if their are usable architectures.\n        $scope.hasUsableArchitectures = function() {\n            return $scope.summary.architecture.options.length > 0;\n        };\n\n        // Return the placeholder text for the architecture dropdown.\n        $scope.getArchitecturePlaceholder = function() {\n            if($scope.hasUsableArchitectures()) {\n                return \"Choose an architecture\";\n            } else {\n                return \"-- No usable architectures --\";\n            }\n        };\n\n        // Return true if the saved architecture is invalid.\n        $scope.hasInvalidArchitecture = function() {\n            if(angular.isObject($scope.node)) {\n                return (\n                    !$scope.isDevice && (\n                        $scope.node.architecture === \"\" ||\n                        $scope.summary.architecture.options.indexOf(\n                            $scope.node.architecture) === -1));\n            } else {\n                return false;\n            }\n        };\n\n        // Return true if the current architecture selection is invalid.\n        $scope.invalidArchitecture = function() {\n            return (\n                !$scope.isDevice && !$scope.isController && (\n                    $scope.summary.architecture.selected === \"\" ||\n                    $scope.summary.architecture.options.indexOf(\n                        $scope.summary.architecture.selected) === -1));\n        };\n\n        // Return true if at least a rack controller is connected to the\n        // region controller.\n        $scope.isRackControllerConnected = function() {\n            // If power_types exist then a rack controller is connected.\n            return $scope.power_types.length > 0;\n        };\n\n        // Return true if the node is locked\n        $scope.isLocked = function() {\n            if ($scope.node === null) {\n                return false;\n            }\n\n            return $scope.node.locked;\n        };\n\n        // Return true when the edit buttons can be clicked.\n        $scope.canEdit = function() {\n            return (\n                $scope.isRackControllerConnected() &&\n                    $scope.isSuperUser() &&\n                    ! $scope.isLocked());\n        };\n\n        // Called to edit the domain name.\n        $scope.editHeaderDomain = function() {\n            if($scope.canEdit()) {\n                return;\n            }\n\n            // Do nothing if already editing because we don't want to reset\n            // the current value.\n            if($scope.header.editing_domain) {\n                return;\n            }\n            $scope.header.editing = false;\n            $scope.header.editing_domain = true;\n\n            // Set the value to the hostname, as hostname and domain are edited\n            // using different fields.\n            $scope.header.hostname.value = $scope.node.hostname;\n        };\n\n        // Called to edit the node name.\n        $scope.editHeader = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n\n            // Do nothing if already editing because we don't want to reset\n            // the current value.\n            if($scope.header.editing) {\n                return;\n            }\n            $scope.header.editing = true;\n            $scope.header.editing_domain = false;\n\n            // Set the value to the hostname, as hostname and domain are edited\n            // using different fields.\n            $scope.header.hostname.value = $scope.node.hostname;\n        };\n\n        // Return true when the hostname or domain in the header is invalid.\n        $scope.editHeaderInvalid = function() {\n            // Not invalid unless editing.\n            if(!$scope.header.editing && !$scope.header.editing_domain) {\n                return false;\n            }\n\n            // The value cannot be blank.\n            var value = $scope.header.hostname.value;\n            if(value.length === 0) {\n                return true;\n            }\n            return !ValidationService.validateHostname(value);\n        };\n\n        // Called to cancel editing of the node hostname and domain.\n        $scope.cancelEditHeader = function() {\n            $scope.header.editing = false;\n            $scope.header.editing_domain = false;\n            updateHeader();\n        };\n\n        // Called to save editing of node hostname or domain.\n        $scope.saveEditHeader = function() {\n            // Does nothing if invalid.\n            if($scope.editHeaderInvalid()) {\n                return;\n            }\n            $scope.header.editing = false;\n            $scope.header.editing_domain = false;\n\n            // Copy the node and make the changes.\n            var node = angular.copy($scope.node);\n            node.hostname = $scope.header.hostname.value;\n            node.domain = $scope.header.domain.selected;\n\n            // Update the node.\n            $scope.updateNode(node);\n        };\n\n        // Called to enter edit mode in the summary section.\n        $scope.editSummary = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n            $scope.summary.editing = true;\n        };\n\n        // Called to cancel editing in the summary section.\n        $scope.cancelEditSummary = function() {\n            // Leave edit mode only if node has valid architecture.\n            if($scope.isDevice || $scope.isController) {\n                $scope.summary.editing = false;\n            } else if(!$scope.hasInvalidArchitecture()) {\n                $scope.summary.editing = false;\n            }\n\n            updateSummary();\n        };\n\n        // Called to save the changes made in the summary section.\n        $scope.saveEditSummary = function() {\n            // Do nothing if invalidArchitecture.\n            if($scope.invalidArchitecture()) {\n                return;\n            }\n\n            $scope.summary.editing = false;\n\n            // Copy the node and make the changes.\n            var node = angular.copy($scope.node);\n            node.zone = angular.copy($scope.summary.zone.selected);\n            node.architecture = $scope.summary.architecture.selected;\n            if($scope.summary.min_hwe_kernel.selected === null) {\n                node.min_hwe_kernel = \"\";\n            }else{\n                node.min_hwe_kernel = $scope.summary.min_hwe_kernel.selected;\n            }\n            node.tags = [];\n            angular.forEach($scope.summary.tags, function(tag) {\n                node.tags.push(tag.text);\n            });\n\n            // Update the node.\n            $scope.updateNode(node);\n        };\n\n        // Return true if the current power type selection is invalid.\n        $scope.invalidPowerType = function() {\n            return !angular.isObject($scope.power.type);\n        };\n\n        // Called to enter edit mode in the power section.\n        $scope.editPower = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n            $scope.power.editing = true;\n        };\n\n        // Called to cancel editing in the power section.\n        $scope.cancelEditPower = function() {\n            // If the node is not a machine, only leave edit mode if node has\n            // valid power type.\n            if ($scope.node.node_type !== 0 || $scope.node.power_type !== \"\") {\n                $scope.power.editing = false;\n            }\n            updatePower();\n        };\n\n        // Called to save the changes made in the power section.\n        $scope.saveEditPower = function() {\n            // Does nothing if invalid power type.\n            if($scope.invalidPowerType()) {\n                return;\n            }\n            $scope.power.editing = false;\n\n            // Copy the node and make the changes.\n            var node = angular.copy($scope.node);\n            node.power_type = $scope.power.type.name;\n            node.power_parameters = angular.copy($scope.power.parameters);\n\n            // Update the node.\n            $scope.updateNode(node, true);\n        };\n\n        // Return true if the \"load more\" events button should be available.\n        $scope.allowShowMoreEvents = function() {\n            if(!angular.isObject($scope.node)) {\n                return false;\n            }\n            if(!angular.isArray($scope.node.events)) {\n                return false;\n            }\n            return (\n                $scope.node.events.length > 0 &&\n                $scope.node.events.length > $scope.events.limit &&\n                $scope.events.limit < 50);\n        };\n\n        // Show another 10 events.\n        $scope.showMoreEvents = function() {\n            $scope.events.limit += 10;\n        };\n\n        // Return the nice text for the given event.\n        $scope.getEventText = function(event) {\n            var text = event.type.description;\n            if(angular.isString(event.description) &&\n                event.description.length > 0) {\n                text += \" - \" + event.description;\n            }\n            return text;\n        };\n\n        $scope.getPowerEventError = function() {\n            if(!angular.isObject($scope.node) ||\n                !angular.isArray($scope.node.events)) {\n                return;\n            }\n\n            var i;\n            for(i = 0; i < $scope.node.events.length; i++) {\n                var event = $scope.node.events[i];\n                if(event.type.level === \"warning\" &&\n                   event.type.description === \"Failed to query node's BMC\") {\n                    // Latest power event is an error\n                    return event;\n                } else if(event.type.level === \"info\" &&\n                          event.type.description === \"Queried node's BMC\") {\n                    // Latest power event is not an error\n                    return;\n                }\n            }\n            // No power event found, thus no error\n            return;\n        };\n\n        $scope.hasPowerEventError = function() {\n            var event = $scope.getPowerEventError();\n            return angular.isObject(event);\n        };\n\n        $scope.getPowerEventErrorText = function() {\n            var event = $scope.getPowerEventError();\n            if(angular.isObject(event)) {\n                // Return text\n                return event.description;\n            } else {\n                return \"\";\n            }\n        };\n\n        // true if power error prevents the provided action\n        $scope.hasActionPowerError = function(actionName) {\n            if(!$scope.hasPowerError()) {\n                return false; // no error, no need to check state\n            }\n            // these states attempt to manipulate power\n            var powerChangingStates = [\n                'commission',\n                'deploy',\n                'on',\n                'off',\n                'release'\n            ];\n            if(actionName && powerChangingStates.indexOf(actionName) > -1) {\n                return true;\n            }\n            return false;\n        };\n\n        // Check to see if the power type has any missing system packages.\n        $scope.hasPowerError = function() {\n            if(angular.isObject($scope.power.type)) {\n                return $scope.power.type.missing_packages.length > 0;\n            } else {\n                return false;\n            }\n        };\n\n        // Returns a formatted string of missing system packages.\n        $scope.getPowerErrors = function() {\n            var i;\n            var result = \"\";\n            if(angular.isObject($scope.power.type)) {\n                var packages = $scope.power.type.missing_packages;\n                packages.sort();\n                for(i = 0; i < packages.length; i++) {\n                    result += packages[i];\n                    if(i+2 < packages.length) {\n                        result += \", \";\n                    }\n                    else if(i+1 < packages.length) {\n                        result += \" and \";\n                    }\n                }\n                result += packages.length > 1 ? \" packages\" : \" package\";\n            }\n            return result;\n        };\n\n        // Return the class to apply to the service.\n        $scope.getServiceClass = function(service) {\n            if(!angular.isObject(service)) {\n                return \"none\";\n            } else {\n                if(service.status === \"running\") {\n                    return \"success\";\n                } else if(service.status === \"dead\") {\n                    return \"error\";\n                } else if(service.status === \"degraded\") {\n                    return \"warning\";\n                } else {\n                    return \"none\";\n                }\n            }\n        };\n\n        $scope.hasCustomCommissioningScripts = function() {\n            var i;\n            for(i=0;i<$scope.scripts.length;i++) {\n                if($scope.scripts[i].script_type === 0) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Called by the children controllers to let the parent know.\n        $scope.controllerLoaded = function(name, scope) {\n            $scope[name] = scope;\n            if(angular.isObject(scope.node)) {\n              scope.nodeLoaded();\n            }\n        };\n\n        // Only show a warning that tests have failed if there are failed tests\n        // and the node isn't currently commissioning or testing.\n        $scope.showFailedTestWarning = function() {\n            // Devices can't have failed tests and don't have status_code\n            // defined.\n            if($scope.node.node_type === 1 || !$scope.node.status_code) {\n                return false;\n            }\n            switch($scope.node.status_code) {\n                // NEW\n                case 0:\n                // COMMISSIONING\n                case 1:\n                // FAILED_COMMISSIONING\n                case 2:\n                // TESTING\n                case 21:\n                // FAILED_TESTING\n                case 22:\n                    return false;\n            }\n            switch($scope.node.testing_status) {\n                // Tests havn't been run\n                case -1:\n                // Tests have passed\n                case 2:\n                    return false;\n            }\n            return true;\n        };\n\n        // Get the subtext for the CPU card. Only nodes commissioned after\n        // MAAS 2.4 will have the CPU speed.\n        $scope.getCPUSubtext = function() {\n            var label = $scope.node.cpu_count + \" cores\";\n            if(!$scope.node.cpu_speed || $scope.node.cpu_speed === 0) {\n                return label;\n            }else if($scope.node.cpu_speed < 1000) {\n                return label + \" @ \" + $scope.node.cpu_speed + \" Mhz\";\n            }else{\n                return label + \" @ \" + ($scope.node.cpu_speed / 1000) + \" Ghz\";\n            }\n        }\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            MachinesManager,\n            DevicesManager,\n            ControllersManager,\n            ZonesManager,\n            GeneralManager,\n            UsersManager,\n            TagsManager,\n            DomainsManager,\n            ServicesManager,\n            ScriptsManager\n        ]).then(function() {\n            if('controller' === $routeParams.type) {\n                $scope.nodesManager = ControllersManager;\n                $scope.isController = true;\n                $scope.isDevice = false;\n                $scope.type_name = 'controller';\n                $scope.type_name_title = 'Controller';\n            }else if('device' === $routeParams.type) {\n                $scope.nodesManager = DevicesManager;\n                $scope.isController = false;\n                $scope.isDevice = true;\n                $scope.type_name = 'device';\n                $scope.type_name_title = 'Device';\n            }else{\n                $scope.nodesManager = MachinesManager;\n                $scope.isController = false;\n                $scope.isDevice = false;\n                $scope.type_name = 'machine';\n                $scope.type_name_title = 'Machine';\n            }\n\n            // Possibly redirected from another controller that already had\n            // this node set to active. Only call setActiveItem if not already\n            // the activeItem.\n            var activeNode = $scope.nodesManager.getActiveItem();\n            if(angular.isObject(activeNode) &&\n                activeNode.system_id === $routeParams.system_id) {\n                nodeLoaded(activeNode);\n            } else {\n                $scope.nodesManager.setActiveItem(\n                    $routeParams.system_id).then(function(node) {\n                        nodeLoaded(node);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n                activeNode = $scope.nodesManager.getActiveItem();\n            }\n            if($scope.isDevice) {\n                $scope.ip_assignment = activeNode.ip_assignment;\n            }\n\n            // Poll for architectures, hwe_kernels, and osinfo the whole\n            // time. This is because the user can always see the architecture\n            // and operating system. Need to keep this information up-to-date\n            // so the user is viewing current data.\n            GeneralManager.startPolling($scope, \"architectures\");\n            GeneralManager.startPolling($scope, \"hwe_kernels\");\n            GeneralManager.startPolling($scope, \"osinfo\");\n        });\n\n        // Stop polling for architectures, hwe_kernels, and osinfo when the\n        // scope is destroyed.\n        $scope.$on(\"$destroy\", function() {\n            GeneralManager.stopPolling($scope, \"architectures\");\n            GeneralManager.stopPolling($scope, \"hwe_kernels\");\n            GeneralManager.stopPolling($scope, \"osinfo\");\n        });\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Networking Controller\n */\n\n// Filter that is specific to the NodeNetworkingController. Filters the\n// list of VLANs to be only those that are unused by the interface.\nangular.module('MAAS').filter('filterByUnusedForInterface', function() {\n    return function(vlans, nic, originalInterfaces) {\n        var filtered = [];\n        if(!angular.isObject(nic) ||\n            !angular.isObject(originalInterfaces)) {\n            return filtered;\n        }\n        var usedVLANs = [];\n        angular.forEach(originalInterfaces, function(inter) {\n            if(inter.type === \"vlan\") {\n                var parent = inter.parents[0];\n                if(parent === nic.id) {\n                    usedVLANs.push(inter.vlan_id);\n                }\n            }\n        });\n        angular.forEach(vlans, function(vlan) {\n            var idx = usedVLANs.indexOf(vlan.id);\n            if(idx === -1) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n\n\n// Filter that is specific to the NodeNetworkingController. Filters the\n// list of interfaces to not include the current parent interfaces being\n// bonded together.\nangular.module('MAAS').filter('removeInterfaceParents', function() {\n    return function(interfaces, childInterface, skip) {\n        if(skip || !angular.isObject(childInterface) ||\n            !angular.isArray(childInterface.parents)) {\n            return interfaces;\n        }\n        var filtered = [];\n        angular.forEach(interfaces, function(nic) {\n            var i, parent, found = false;\n            for(i = 0; i < childInterface.parents.length; i++) {\n                parent = childInterface.parents[i];\n                if(parent.id === nic.id && parent.link_id === nic.link_id) {\n                    found = true;\n                    break;\n                }\n            }\n            if(!found) {\n                filtered.push(nic);\n            }\n        });\n        return filtered;\n    };\n});\n\n\n// Filter that is specific to the NodeNetworkingController. Remove the default\n// VLAN if the interface is a VLAN interface.\nangular.module('MAAS').filter('removeDefaultVLANIfVLAN', function() {\n    return function(vlans, interfaceType) {\n        if(!angular.isString(interfaceType)) {\n            return vlans;\n        }\n        var filtered = [];\n        angular.forEach(vlans, function(vlan) {\n            if(interfaceType !== \"vlan\") {\n                filtered.push(vlan);\n            } else if(vlan.vid !== 0) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n\n\n// Filter that is specific to the NodeNetworkingController. Only provide the\n// available modes for that interface type.\nangular.module('MAAS').filter('filterLinkModes', function() {\n    return function(modes, nic) {\n        if(!angular.isObject(nic)) {\n            return modes;\n        }\n        var filtered = [];\n\n        // If this is not a $maasForm, make it work like one.\n        // We need to use getValue() to access attributes, because each\n        // type of maas-obj-form gets to define how values come out.\n        if(!angular.isFunction(nic.getValue)) {\n            nic.getValue = function(name) {\n                return this[name];\n            };\n        }\n\n        if(!angular.isObject(nic.getValue('subnet'))) {\n            // No subnet is configure so the only allowed mode\n            // is 'link_up'.\n            angular.forEach(modes, function(mode) {\n                if(mode.mode === \"link_up\") {\n                    filtered.push(mode);\n                }\n            });\n        } else {\n            // Don't add LINK_UP if more than one link exists or\n            // if the interface is an alias.\n            var links = nic.getValue('links');\n            var nicType = nic.getValue('type');\n            var allowLinkUp = (\n                (angular.isObject(links) && links.length > 1) ||\n                (nicType === \"alias\"));\n            angular.forEach(modes, function(mode) {\n                if(allowLinkUp && mode.mode === \"link_up\") {\n                    return;\n                }\n                // Can't run DHCP twice on one NIC.\n                if(nicType === \"alias\" && mode.mode === \"dhcp\") {\n                    return;\n                }\n                filtered.push(mode);\n            });\n        }\n        return filtered;\n    };\n});\n\n\nangular.module('MAAS').controller('NodeNetworkingController', [\n    '$scope', '$filter', 'FabricsManager', 'VLANsManager', 'SubnetsManager',\n    'MachinesManager', 'ControllersManager', 'DevicesManager',\n    'GeneralManager', 'UsersManager',\n    'ManagerHelperService', 'ValidationService', 'JSONService',\n    function(\n        $scope, $filter, FabricsManager, VLANsManager, SubnetsManager,\n        MachinesManager, ControllersManager, DevicesManager,\n        GeneralManager, UsersManager,\n        ManagerHelperService, ValidationService, JSONService) {\n\n        // Different interface types.\n        var INTERFACE_TYPE = {\n            PHYSICAL: \"physical\",\n            BOND: \"bond\",\n            BRIDGE: \"bridge\",\n            VLAN: \"vlan\",\n            ALIAS: \"alias\"\n        };\n        var INTERFACE_TYPE_TEXTS = {\n            \"physical\": \"Physical\",\n            \"bond\": \"Bond\",\n            \"bridge\": \"Bridge\",\n            \"vlan\": \"VLAN\",\n            \"alias\": \"Alias\"\n        };\n\n        // Different link modes for an interface.\n        var LINK_MODE = {\n            AUTO: \"auto\",\n            STATIC: \"static\",\n            DHCP: \"dhcp\",\n            LINK_UP: \"link_up\"\n        };\n        var LINK_MODE_TEXTS = {\n            \"auto\": \"Auto assign\",\n            \"static\": \"Static assign\",\n            \"dhcp\": \"DHCP\",\n            \"link_up\": \"Unconfigured\"\n        };\n\n        // Different selection modes.\n        var SELECTION_MODE = {\n            NONE: null,\n            SINGLE: \"single\",\n            MULTI: \"multi\",\n            DELETE: \"delete\",\n            ADD: \"add\",\n            CREATE_BOND: \"create-bond\",\n            CREATE_BRIDGE: \"create-bridge\",\n            CREATE_PHYSICAL: \"create-physical\",\n            EDIT: \"edit\"\n        };\n\n        var IP_ASSIGNMENT = {\n            DYNAMIC: \"dynamic\",\n            EXTERNAL: \"external\",\n            STATIC: \"static\"\n        };\n\n        // Device ip assignment options.\n        $scope.ipAssignments = [\n            {\n                name: IP_ASSIGNMENT.EXTERNAL,\n                text: \"External\"\n            },\n            {\n                name: IP_ASSIGNMENT.DYNAMIC,\n                text: \"Dynamic\"\n            },\n            {\n                name: IP_ASSIGNMENT.STATIC,\n                text: \"Static\"\n            }\n        ];\n\n        // Set the initial values for this scope.\n        $scope.loaded = false;\n        $scope.nodeHasLoaded = false;\n        $scope.managersHaveLoaded = false;\n        $scope.tableInfo = {column: 'name'};\n        $scope.fabrics = FabricsManager.getItems();\n        $scope.vlans = VLANsManager.getItems();\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.interfaces = [];\n        $scope.interfaceLinksMap = {};\n        $scope.interfaceErrorsByLinkId = {};\n        $scope.originalInterfaces = {};\n        $scope.selectedInterfaces = [];\n        $scope.selectedMode = null;\n        $scope.newInterface = {};\n        $scope.newBondInterface = {};\n        $scope.newBridgeInterface = {};\n        $scope.editInterface = null;\n        $scope.bondOptions = GeneralManager.getData(\"bond_options\");\n        $scope.modes = [\n            {\n                mode: LINK_MODE.AUTO,\n                text: LINK_MODE_TEXTS[LINK_MODE.AUTO]\n            },\n            {\n                mode: LINK_MODE.STATIC,\n                text: LINK_MODE_TEXTS[LINK_MODE.STATIC]\n            },\n            {\n                mode: LINK_MODE.DHCP,\n                text: LINK_MODE_TEXTS[LINK_MODE.DHCP]\n            },\n            {\n                mode: LINK_MODE.LINK_UP,\n                text: LINK_MODE_TEXTS[LINK_MODE.LINK_UP]\n            }\n        ];\n\n        // Sets loaded to true if both the node has been loaded at the\n        // other required managers for this scope have been loaded.\n        function updateLoaded() {\n            $scope.loaded = $scope.nodeHasLoaded && $scope.managersHaveLoaded;\n            if($scope.loaded) {\n                updateInterfaces();\n            }\n        }\n\n        // Update the list of interfaces for the node. For each link on the\n        // interface, the interface is duplicated in the list to make render\n        // in a data-ng-repeat easier.\n        function updateInterfaces() {\n            $scope.originalInterfaces = {};\n            angular.forEach($scope.node.interfaces, function(nic) {\n                $scope.originalInterfaces[nic.id] = nic;\n            });\n\n            var interfaces = [];\n            // vlanTable contains data packaged for the 'Served VLANs' section,\n            // which is essentially Interface LEFT JOIN VLAN LEFT JOIN Subnet.\n            var vlanTable = [];\n            // Keep track of VLAN IDs we've processed.\n            var addedVlans = {};\n\n            angular.forEach($scope.node.interfaces, function(nic) {\n                // When a interface has a child that is a bond or bridge.\n                // Then that interface is not included in the interface list.\n                // Parent interface with a bond or bridge child can only have\n                // one child.\n                if(nic.children.length === 1) {\n                    var child = $scope.originalInterfaces[nic.children[0]];\n                    if(child.type === INTERFACE_TYPE.BOND ||\n                       child.type === INTERFACE_TYPE.BRIDGE) {\n                        // This parent now has a bond or bridge for a child.\n                        // If this was the editInterface, then it needs to be\n                        // unset. We only need to check the \"id\" (not\n                        // the \"link_id\"), because if this interface did have\n                        // aliases they have now been removed.\n                        if(angular.isObject($scope.editInterface) &&\n                            $scope.editInterface.id === nic.id) {\n                            $scope.editInterface = null;\n                            $scope.selectedMode = SELECTION_MODE.NONE;\n                        }\n                        return;\n                    }\n                }\n\n                // When the interface is a bond or a bridge, place the children\n                // as members for that interface.\n                if(nic.type === INTERFACE_TYPE.BOND ||\n                   nic.type === INTERFACE_TYPE.BRIDGE) {\n                    nic.members = [];\n                    angular.forEach(nic.parents, function(parent) {\n                        nic.members.push(\n                            angular.copy($scope.originalInterfaces[parent]));\n                    });\n                }\n\n                // Format the tags when they have not already been formatted.\n                if(angular.isArray(nic.tags) &&\n                    nic.tags.length > 0 &&\n                    !angular.isString(nic.tags[0].text)) {\n                    nic.tags = formatTags(nic.tags);\n                }\n\n                nic.vlan = VLANsManager.getItemFromList(nic.vlan_id);\n                if(angular.isObject(nic.vlan)) {\n                    nic.fabric = FabricsManager.getItemFromList(\n                            nic.vlan.fabric);\n\n                    // Build the vlanTable for controller detail page.\n                    if ($scope.$parent.isController) {\n                        // Skip duplicate VLANs (by id, they can share names).\n                        if(!(Object.prototype.hasOwnProperty.call(\n                                addedVlans, nic.vlan.id))) {\n                            addedVlans[nic.vlan.id] = true;\n                            var vlanRecord = {\n                                \"fabric\": nic.fabric,\n                                \"vlan\": nic.vlan,\n                                \"subnets\": $filter('filter')(\n                                    $scope.subnets, {vlan:nic.vlan.id}, true),\n                                \"primary_rack\": null,\n                                \"secondary_rack\": null,\n                                \"sort_key\": nic.fabric.name + \"|\" +\n                                    $scope.getVLANText(nic.vlan)\n                            };\n                            if(nic.vlan.primary_rack) {\n                                vlanRecord.primary_rack =\n                                    ControllersManager.getItemFromList(\n                                        nic.vlan.primary_rack);\n                            }\n                            if(nic.vlan.secondary_rack) {\n                                vlanRecord.secondary_rack =\n                                    ControllersManager.getItemFromList(\n                                        nic.vlan.secondary_rack);\n                            }\n                            vlanTable.push(vlanRecord);\n                        }\n                        // Sort the table by (VLANText, fabric.name).\n                        vlanTable.sort(function(a, b) {\n                            return a.sort_key.localeCompare(b.sort_key);\n                        });\n                    }\n                }\n\n                // Update the interface based on its links or duplicate the\n                // interface if it has multiple links.\n                if(nic.links.length === 0) {\n                    // No links on this interface. The interface is either\n                    // disabled or has no links (which means the interface\n                    // is in LINK_UP mode).\n                    nic.link_id = -1;\n                    nic.subnet = null;\n                    nic.mode = LINK_MODE.LINK_UP;\n                    nic.ip_address = \"\";\n                    interfaces.push(nic);\n                } else {\n                    var idx = 0;\n                    angular.forEach(nic.links, function(link) {\n                        var nic_copy = angular.copy(nic);\n                        nic_copy.link_id = link.id;\n                        nic_copy.subnet = SubnetsManager.getItemFromList(\n                            link.subnet_id);\n                        nic_copy.mode = link.mode;\n                        nic_copy.ip_address = link.ip_address;\n                        if(angular.isUndefined(nic_copy.ip_address)) {\n                            nic_copy.ip_address = \"\";\n                        }\n                        // We don't want to deep copy the VLAN and fabric\n                        // object so we set those back to the original.\n                        nic_copy.vlan = nic.vlan;\n                        nic_copy.fabric = nic.fabric;\n                        if(idx > 0) {\n                            // Each extra link is an alais on the original\n                            // interface.\n                            nic_copy.type = INTERFACE_TYPE.ALIAS;\n                            nic_copy.name += \":\" + idx;\n                        }\n                        idx++;\n                        interfaces.push(nic_copy);\n                    });\n                }\n            });\n\n            // Update the scopes interfaces.\n            $scope.interfaces = interfaces;\n            $scope.vlanTable = vlanTable;\n\n            // Update the scope interface links mapping.\n            $scope.interfaceLinksMap = {};\n            angular.forEach($scope.interfaces, function(nic) {\n                var linkMaps = $scope.interfaceLinksMap[nic.id];\n                if(angular.isUndefined(linkMaps)) {\n                    linkMaps = {};\n                    $scope.interfaceLinksMap[nic.id] = linkMaps;\n                }\n                linkMaps[nic.link_id] = nic;\n            });\n\n            // Clear the editInterface if it no longer exists in the\n            // interfaceLinksMap.\n            if(angular.isObject($scope.editInterface)) {\n                var links = $scope.interfaceLinksMap[$scope.editInterface.id];\n                if(angular.isUndefined(links)) {\n                    $scope.editInterface = null;\n                    $scope.selectedMode = SELECTION_MODE.NONE;\n                } else {\n                    var link = links[$scope.editInterface.link_id];\n                    if(angular.isUndefined(link)) {\n                        $scope.editInterface = null;\n                        $scope.selectedMode = SELECTION_MODE.NONE;\n                    }\n                }\n            }\n\n            // Update newInterface.parent if it has changed.\n            updateNewInterface();\n        }\n\n        // Return the original link object for the given interface.\n        function mapNICToOriginalLink(nic_id, link_id) {\n            var originalInteface = $scope.originalInterfaces[nic_id];\n            if(angular.isObject(originalInteface)) {\n                var i, link = null;\n                for(i = 0; i < originalInteface.links.length; i++) {\n                    link = originalInteface.links[i];\n                    if(link.id === link_id) {\n                        break;\n                    }\n                }\n                return link;\n            } else {\n                return null;\n            }\n        }\n\n        // Leave single selection mode.\n        function leaveSingleSelectionMode() {\n            if($scope.selectedMode === SELECTION_MODE.SINGLE ||\n                $scope.selectedMode === SELECTION_MODE.ADD ||\n                $scope.selectedMode === SELECTION_MODE.DELETE) {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n            }\n        }\n\n        // Update the new interface since the interfaces list has\n        // been reloaded.\n        function updateNewInterface() {\n            if(angular.isObject($scope.newInterface.parent)) {\n                var parentId = $scope.newInterface.parent.id;\n                var linkId = $scope.newInterface.parent.link_id;\n                var links = $scope.interfaceLinksMap[parentId];\n                if(angular.isObject(links)) {\n                    var newParent = links[linkId];\n                    if(angular.isObject(newParent)) {\n                        $scope.newInterface.parent = newParent;\n\n                        var iType = $scope.newInterface.type;\n                        var isAlias = iType === INTERFACE_TYPE.ALIAS;\n                        var isVLAN = iType === INTERFACE_TYPE.VLAN;\n                        var canAddAlias = $scope.canAddAlias(newParent);\n                        var canAddVLAN = $scope.canAddVLAN(newParent);\n                        if(!canAddAlias && !canAddVLAN) {\n                            // Cannot do any adding now.\n                            $scope.newInterface = {};\n                            leaveSingleSelectionMode();\n                        } else {\n                            if(isAlias && !canAddAlias && canAddVLAN) {\n                                $scope.newInterface.type = \"vlan\";\n                                $scope.addTypeChanged();\n                            } else if(isVLAN && !canAddVLAN && canAddAlias) {\n                                $scope.newInterface.type = \"alias\";\n                                $scope.addTypeChanged();\n                            }\n                        }\n                        return;\n                    }\n                }\n\n                // Parent no longer exists. Exit the single selection modes.\n                $scope.newInterface = {};\n                leaveSingleSelectionMode();\n            }\n        }\n\n        // Return the default VLAN for a fabric.\n        function getDefaultVLAN(fabric) {\n            return VLANsManager.getItemFromList(fabric.default_vlan_id);\n        }\n\n        // Return list of unused VLANs for an interface. Also remove the\n        // ignoreVLANs from the returned list.\n        function getUnusedVLANs(nic, ignoreVLANs) {\n            var vlans = $filter('removeDefaultVLAN')($scope.vlans);\n            vlans = $filter('filterByFabric')(vlans, nic.fabric);\n            vlans = $filter('filterByUnusedForInterface')(\n                vlans, nic, $scope.originalInterfaces);\n\n            // Remove the VLAN's that should be ignored when getting the unused\n            // VLANs. This is done to help the selection of the next default.\n            if(angular.isUndefined(ignoreVLANs)) {\n                ignoreVLANs = [];\n            }\n            angular.forEach(ignoreVLANs, function(vlan) {\n                var i;\n                for(i = 0; i < vlans.length; i++) {\n                    if(vlans[i].id === vlan.id) {\n                        vlans.splice(i, 1);\n                        break;\n                    }\n                }\n            });\n            return vlans;\n        }\n\n        // Return the currently selected interface objects.\n        function getSelectedInterfaces() {\n            var interfaces = [];\n            angular.forEach($scope.selectedInterfaces, function(key) {\n                var splitKey = key.split('/');\n                var links = $scope.interfaceLinksMap[splitKey[0]];\n                if(angular.isObject(links)) {\n                    var nic = links[splitKey[1]];\n                    if(angular.isObject(nic)) {\n                        interfaces.push(nic);\n                    }\n                }\n            });\n            return interfaces;\n        }\n\n        // Get the next available name.\n        function getNextName(prefix) {\n            var idx = 0;\n            angular.forEach($scope.originalInterfaces, function(nic) {\n                if(nic.name === prefix + idx) {\n                    idx++;\n                }\n            });\n            return prefix + idx;\n        }\n\n        // Return the tags formatted for ngTagInput.\n        function formatTags(tags) {\n            var formatted = [];\n            angular.forEach(tags, function(tag) {\n                formatted.push({ text: tag });\n            });\n            return formatted;\n        }\n\n        // Called by $parent when the node has been loaded.\n        $scope.nodeLoaded = function() {\n            $scope.$watch(\"node.interfaces\", updateInterfaces);\n            // Watch subnets for the served VLANs section.\n            if ($scope.$parent.isController) {\n                $scope.$watch(\"subnets\", updateInterfaces, true);\n            }\n            $scope.nodeHasLoaded = true;\n            updateLoaded();\n        };\n\n        // Return true if only the name or mac address of an interface can\n        // be edited.\n        $scope.isLimitedEditingAllowed = function(nic) {\n            if (!$scope.isSuperUser()) {\n                // If the user is not the superuser, pretend it's not Ready.\n                return false;\n            }\n            if ($scope.$parent.isController || $scope.$parent.isDevice) {\n                // Controllers and Devices are never in limited mode.\n                return false;\n            }\n            return (\n                angular.isObject($scope.node) &&\n                $scope.node.status === \"Deployed\" &&\n                nic.type !== \"vlan\");\n        };\n\n        // Return true if the networking information cannot be edited.\n        // (it can't be changed when the node is in any state other\n        // than Ready or Broken and the user is not a superuser)\n        $scope.isAllNetworkingDisabled = function() {\n            if (!$scope.isSuperUser()) {\n                // If the user is not a superuser, disable the networking panel.\n                return true;\n            }\n            if ($scope.$parent.isController || $scope.$parent.isDevice) {\n                // Never disable the full networking panel when its a\n                // Controller or Device.\n                return false;\n            }\n            if (angular.isObject($scope.node) &&\n                    [\"Ready\", \"Allocated\", \"Broken\"].indexOf(\n                        $scope.node.status) === -1) {\n                // If a non-controller node is not ready allocated, or broken,\n                // disable networking panel.\n                return true;\n            }\n            // User must be a superuser and the node must be\n            // either ready or broken. Enable it.\n            return false;\n        };\n\n        // Return true if the interface is the boot interface or has a parent\n        // that is the boot interface.\n        $scope.isBootInterface = function(nic) {\n            if(!angular.isObject(nic)) {\n                return false;\n            }\n\n            if(nic.is_boot && nic.type !== INTERFACE_TYPE.ALIAS) {\n                return true;\n            } else if(nic.type === INTERFACE_TYPE.BOND ||\n                      nic.type === INTERFACE_TYPE.BRIDGE) {\n                var i;\n                for(i = 0; i < nic.members.length; i++) {\n                    if(nic.members[i].is_boot) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Get the text for the type of the interface.\n        $scope.getInterfaceTypeText = function(nic) {\n            var text = INTERFACE_TYPE_TEXTS[nic.type];\n            if(angular.isDefined(text)) {\n                return text;\n            } else {\n                return nic.type;\n            }\n        };\n\n        // Get the text for the link mode of the interface.\n        $scope.getLinkModeText = function(nic) {\n            var text = LINK_MODE_TEXTS[nic.mode];\n            if(angular.isDefined(text)) {\n                return text;\n            } else {\n                return nic.mode;\n            }\n        };\n\n        // Get the text to display in the VLAN dropdown.\n        $scope.getVLANText = function(vlan) {\n            if(!angular.isObject(vlan)) {\n                return \"\";\n            }\n\n            if(vlan.vid === 0) {\n                return \"untagged\";\n            } else if(angular.isString(vlan.name) && vlan.name.length > 0) {\n                return vlan.vid + \" (\" + vlan.name + \")\";\n            } else {\n                return vlan.vid;\n            }\n        };\n\n        // Get the text to display in the subnet dropdown.\n        $scope.getSubnetText = function(subnet) {\n            if(!angular.isObject(subnet)) {\n                return \"Unconfigured\";\n            } else if(angular.isString(subnet.name) &&\n                subnet.name.length > 0 &&\n                subnet.cidr !== subnet.name) {\n                return subnet.cidr + \" (\" + subnet.name + \")\";\n            } else {\n                return subnet.cidr;\n            }\n        };\n\n        // Get the subnet from its ID.\n        $scope.getSubnet = function(subnetId) {\n            return SubnetsManager.getItemFromList(subnetId);\n        };\n\n        // Return True if the interface name that the user typed is invalid.\n        $scope.isInterfaceNameInvalid = function(nic) {\n            if(!angular.isString(nic.name) || nic.name.length === 0) {\n                return true;\n            } else if(angular.isArray($scope.node.interfaces)) {\n                var i;\n                for(i = 0; i < $scope.node.interfaces.length; i++) {\n                    var otherNic = $scope.node.interfaces[i];\n                    if(otherNic.name === nic.name && otherNic.id !== nic.id) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Return True if the link mode select should be disabled.\n        $scope.isLinkModeDisabled = function(nic) {\n            // This is only disabled when a subnet has not been selected.\n            if(angular.isFunction(nic.getValue)) {\n                return !angular.isObject(nic.getValue('subnet'));\n            } else {\n                return !angular.isObject(nic.subnet);\n            }\n        };\n\n        // Return the interface errors.\n        $scope.getInterfaceError = function(nic) {\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                return $scope.interfaceErrorsByLinkId[nic.link_id];\n            }\n            return null;\n        };\n\n        // Return True if the interface IP address that the user typed is\n        // invalid.\n        $scope.isIPAddressInvalid = function(nic) {\n            if(angular.isString(nic.ip_address) && nic.mode === 'static') {\n                return (\n                    !ValidationService.validateIP(nic.ip_address) ||\n                    !ValidationService.validateIPInNetwork(\n                        nic.ip_address, nic.subnet.cidr));\n            } else {\n                return false;\n            }\n        };\n\n        // Return unique key for the interface.\n        $scope.getUniqueKey = function(nic) {\n            return nic.id + \"/\" + nic.link_id;\n        };\n\n        // Toggle selection of the interface.\n        $scope.toggleInterfaceSelect = function(nic) {\n            var key = $scope.getUniqueKey(nic);\n            var idx = $scope.selectedInterfaces.indexOf(key);\n            if(idx > -1) {\n                $scope.selectedInterfaces.splice(idx, 1);\n            } else {\n                $scope.selectedInterfaces.push(key);\n            }\n\n            if($scope.selectedInterfaces.length > 1) {\n                if($scope.selectedMode !== SELECTION_MODE.BOND) {\n                    $scope.selectedMode = SELECTION_MODE.MULTI;\n                }\n            } else if($scope.selectedInterfaces.length === 1) {\n                $scope.selectedMode = SELECTION_MODE.SINGLE;\n            } else {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n            }\n        };\n\n        // Return true when the interface is selected.\n        $scope.isInterfaceSelected = function(nic) {\n            return $scope.selectedInterfaces.indexOf(\n                $scope.getUniqueKey(nic)) > -1;\n        };\n\n        // Returns true if the interface is not selected\n        $scope.cannotEditInterface = function(nic) {\n            if ($scope.selectedMode === SELECTION_MODE.NONE) {\n                return false;\n            } else if (\n                  $scope.selectedMode !== SELECTION_MODE.MULTI &&\n                  $scope.isInterfaceSelected(nic)) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Return true if in editing mode for the interface.\n        $scope.isEditing = function(nic) {\n            if($scope.selectedMode !== SELECTION_MODE.EDIT) {\n                return false;\n            } else {\n                return $scope.editInterface.id === nic.id;\n            }\n        };\n\n        // Start editing this interface.\n        $scope.edit = function(nic) {\n            $scope.selectedInterfaces = [$scope.getUniqueKey(nic)];\n            $scope.selectedMode = SELECTION_MODE.EDIT;\n            if($scope.$parent.isDevice) {\n                $scope.editInterface = {\n                    id: nic.id,\n                    name: nic.name,\n                    mac_address: nic.mac_address,\n                    tags: nic.tags.map(function(tag) { return tag.text; }),\n                    subnet: nic.subnet,\n                    ip_address: nic.ip_address,\n                    ip_assignment: nic.ip_assignment,\n                    link_id: nic.link_id\n                };\n                if(nic.subnet !== undefined && nic.subnet !== null) {\n                    $scope.editInterface.defaultSubnet = nic.subnet;\n                } else {\n                    $scope.editInterface.defaultSubnet = $scope.subnets[0];\n                }\n            } else {\n                $scope.editInterface = {\n                    id: nic.id,\n                    name: nic.name,\n                    mac_address: nic.mac_address,\n                    tags: nic.tags.map(function(tag) { return tag.text; }),\n                    fabric: nic.fabric,\n                    vlan: nic.vlan,\n                    subnet: nic.subnet,\n                    mode: nic.mode,\n                    ip_address: nic.ip_address,\n                    link_id: nic.link_id\n                };\n            }\n        };\n\n        // Called when the fabric is changed.\n        $scope.fabricChanged = function(nic) {\n            // Update the VLAN on the node to be the default VLAN for that\n            // fabric. The first VLAN for the fabric is the default.\n            if(nic.fabric !== null) {\n                nic.vlan = getDefaultVLAN(nic.fabric);\n            } else {\n                nic.vlan = null;\n            }\n            $scope.vlanChanged(nic);\n        };\n\n        // Called when the fabric is changed in a maas-obj-form.\n        $scope.fabricChangedForm = function(key, value, form) {\n            var vlan;\n            if(value !== null) {\n                vlan = getDefaultVLAN(value);\n            } else {\n                vlan = null;\n            }\n            form.updateValue('vlan', vlan);\n            $scope.vlanChangedForm('vlan', vlan, form);\n        };\n\n        // Called when the VLAN is changed.\n        $scope.vlanChanged = function(nic) {\n            nic.subnet = null;\n            $scope.subnetChanged(nic);\n        };\n\n        // Called when the VLAN is changed on a maas-obj-form\n        $scope.vlanChangedForm = function(key, value, form) {\n            form.updateValue('subnet', null);\n            $scope.subnetChangedForm('subnet', null, form);\n        };\n\n        // Called when the subnet is changed.\n        $scope.subnetChanged = function(nic) {\n            if(!angular.isObject(nic.subnet)) {\n                // Set to 'Unconfigured' so the link mode should be set to\n                // 'link_up'.\n                nic.mode = LINK_MODE.LINK_UP;\n            }\n            if ($scope.$parent.isDevice) {\n                nic.ip_address = null;\n            }\n            $scope.modeChanged(nic);\n        };\n\n        // Called when the subnet is changed.\n        $scope.subnetChangedForm = function(key, value, form) {\n            if(!angular.isObject(value)) {\n                // Set to 'Unconfigured' so the link mode should be set to\n                // 'link_up'.\n                form.updateValue('mode', LINK_MODE.LINK_UP);\n            }\n            mode = form.getValue('mode');\n            form.updateValue('ip_address', null);\n            $scope.modeChangedForm('mode', mode, form);\n        };\n\n        // Called when the mode is changed.\n        $scope.modeChanged = function(nic) {\n            // Clear the IP address when the mode is changed.\n            nic.ip_address = \"\";\n            if(nic.mode === 'static') {\n                var originalLink = mapNICToOriginalLink(nic.id, nic.link_id);\n                if(angular.isObject(originalLink) &&\n                    nic.subnet.id === originalLink.subnet_id) {\n                    // Set the original IP address if same subnet.\n                    nic.ip_address = originalLink.ip_address;\n                }\n            }\n        };\n\n        // Called when the mode is changed on a maas-obj-form.\n        $scope.modeChangedForm = function(key, value, form) {\n            // Clear the IP address when the mode is changed.\n            form.updateValue('ip_address', \"\");\n            if(value === 'static') {\n                var originalLink = mapNICToOriginalLink(\n                  form.getValue('id'), form.getValue('link_id'));\n                if(angular.isObject(originalLink) &&\n                    form.getValue('subnet').id === originalLink.subnet_id) {\n                    // Set the original IP address if same subnet.\n                    form.updateValue('ip_address', originalLink.ip_address);\n                }\n            }\n        };\n\n        // Called to cancel edit mode.\n        $scope.editCancel = function(nic) {\n            $scope.selectedInterfaces = [];\n            $scope.selectedMode = SELECTION_MODE.NONE;\n            $scope.editInterface = null;\n        };\n\n        // Preprocess things for updateInterfaceForm.\n        $scope.preProcessInterface = function(nic) {\n            var params = angular.copy(nic);\n\n            delete params.id;\n            params.system_id = $scope.node.system_id;\n            params.interface_id = nic.id;\n\n            // we need IDs not objects.\n            if(nic.fabric !== undefined && nic.fabric !== null) {\n                params.fabric = nic.fabric.id;\n            } else {\n                params.fabric = null;\n            }\n            if(nic.vlan !== undefined && nic.vlan !== null) {\n                params.vlan = nic.vlan.id;\n            } else {\n                params.vlan = null;\n            }\n            if(nic.subnet !== undefined && nic.subnet !== null) {\n                params.subnet = params.subnet.id;\n            } else {\n                delete params.subnet;\n            }\n\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                params.link_id = nic.link_id;\n                delete $scope.interfaceErrorsByLinkId[nic.link_id];\n            } else {\n                delete params.link_id;\n            }\n            if((nic.mode === LINK_MODE.STATIC ||\n                nic.ip_assignment !== IP_ASSIGNMENT.DYNAMIC) &&\n               angular.isString(nic.ip_address) &&\n               nic.ip_address.length > 0) {\n                params.ip_address = nic.ip_address;\n            } else {\n                delete params.ip_address;\n            }\n            return params;\n        };\n\n        // Save the following interface on the node.\n        $scope.saveInterface = function(nic) {\n            var params;\n            if($scope.$parent.isDevice) {\n                params = {\n                    \"name\": nic.name,\n                    \"mac_address\": nic.mac_address,\n                    \"ip_assignment\": nic.ip_assignment,\n                    \"ip_address\": nic.ip_address\n                };\n            } else {\n                params = {\n                    \"name\": nic.name,\n                    \"mac_address\": nic.mac_address,\n                    \"mode\": nic.mode,\n                    \"tags\": nic.tags.map(\n                        function(tag) { return tag.text; })\n                };\n            }\n            if(nic.fabric !== undefined && nic.fabric !== null) {\n                params.fabric = nic.fabric.id;\n            } else {\n                params.fabric = null;\n            }\n            if(nic.vlan !== undefined && nic.vlan !== null) {\n                params.vlan = nic.vlan.id;\n            } else {\n                params.vlan = null;\n            }\n            if (nic.subnet !== undefined && nic.subnet !== null) {\n                params.subnet = nic.subnet.id;\n            } else {\n                params.subnet = null;\n            }\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                params.link_id = nic.link_id;\n                delete $scope.interfaceErrorsByLinkId[nic.link_id];\n            }\n            if(angular.isString(nic.ip_address) && nic.ip_address.length > 0) {\n                params.ip_address = nic.ip_address;\n            }\n            return $scope.$parent.nodesManager.updateInterface(\n                $scope.node, nic.id, params).then(null, function(error) {\n                    // XXX blake_r: Just log the error in the console, but\n                    // we need to expose this as a better message to the\n                    // user.\n                    console.log(error);\n\n                    // Update the interfaces so it is back to the way it\n                    // was before the user changed it.\n                    updateInterfaces();\n                });\n        };\n\n        // Save the following link on the node.\n        $scope.saveInterfaceLink = function(nic) {\n            var params = {\n                \"mode\": nic.mode\n            };\n            if($scope.$parent.isDevice) {\n                params.ip_assignment = nic.ip_assignment;\n            }\n            if(angular.isObject(nic.subnet)) {\n                params.subnet = nic.subnet.id;\n            }\n            if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                params.link_id = nic.link_id;\n                delete $scope.interfaceErrorsByLinkId[nic.link_id];\n            }\n            if(nic.mode === LINK_MODE.STATIC &&\n                angular.isString(nic.ip_address) &&\n                nic.ip_address.length > 0) {\n                params.ip_address = nic.ip_address;\n            }\n            return $scope.$parent.nodesManager.linkSubnet(\n                $scope.node, nic.id, params).then(null, function(error) {\n                    console.log(error);\n                    if(angular.isDefined(nic.link_id) && nic.link_id >= 0) {\n                        $scope.interfaceErrorsByLinkId[nic.link_id] = error;\n                    }\n                    // Update the interfaces so it is back to the way it\n                    // was before the user changed it.\n                    updateInterfaces();\n                    throw error;\n                });\n        };\n\n        // Called to save the interface.\n        $scope.editSave = function(editInterface) {\n            $scope.editCancel();\n            return editInterface;\n        };\n\n        // Return true if the interface delete confirm is being shown.\n        $scope.isShowingDeleteConfirm = function() {\n            return $scope.selectedMode === SELECTION_MODE.DELETE;\n        };\n\n        // Return true if the interface add interface is being shown.\n        $scope.isShowingAdd = function() {\n            return $scope.selectedMode === SELECTION_MODE.ADD;\n        };\n\n        // Return true if either an alias or VLAN can be added.\n        $scope.canAddAliasOrVLAN = function(nic) {\n            if($scope.$parent.isController) {\n                return false;\n            } else if ($scope.isAllNetworkingDisabled()) {\n                return false;\n            } else {\n                return $scope.canAddAlias(nic) || $scope.canAddVLAN(nic);\n            }\n        };\n\n        // Return true if the alias can be added to interface.\n        $scope.canAddAlias = function(nic) {\n            if(!angular.isObject(nic)) {\n                return false;\n            } else if(nic.type === INTERFACE_TYPE.ALIAS) {\n                return false;\n            } else if(nic.links.length === 0 ||\n                nic.links[0].mode === LINK_MODE.LINK_UP) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Return true if the VLAN can be added to interface.\n        $scope.canAddVLAN = function(nic) {\n            if(!angular.isObject(nic)) {\n                return false;\n            } else if(nic.type === INTERFACE_TYPE.ALIAS ||\n                nic.type === INTERFACE_TYPE.VLAN) {\n                return false;\n            }\n            var unusedVLANs = getUnusedVLANs(nic);\n            return unusedVLANs.length > 0;\n        };\n\n        // Return true if another VLAN can be added to this already being\n        // added interface.\n        $scope.canAddAnotherVLAN = function(nic) {\n            if(!$scope.canAddVLAN(nic)) {\n                return false;\n            }\n            var unusedVLANs = getUnusedVLANs(nic);\n            return unusedVLANs.length > 1;\n        };\n\n        // Return the text to use for the remove link and message.\n        $scope.getRemoveTypeText = function(nic) {\n            if(nic.type === INTERFACE_TYPE.PHYSICAL) {\n                return \"interface\";\n            } else if(nic.type === INTERFACE_TYPE.VLAN) {\n                return \"VLAN\";\n            } else {\n                return nic.type;\n            }\n        };\n\n        // Return true if the interface can be removed.\n        $scope.canBeRemoved = function() {\n            return (\n                !$scope.$parent.isController &&\n                !$scope.isAllNetworkingDisabled());\n        };\n\n        // Enter remove mode.\n        $scope.remove = function() {\n            $scope.selectedMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter remove by selecting the node first.\n        $scope.quickRemove = function(nic) {\n            $scope.selectedInterfaces = [$scope.getUniqueKey(nic)];\n            $scope.remove();\n        };\n\n        // Cancel the current mode go back to sinle selection mode.\n        $scope.cancel = function() {\n            $scope.newInterface = {};\n            $scope.newBondInterface = {};\n            $scope.newBridgeInterface = {};\n            if($scope.selectedMode === SELECTION_MODE.CREATE_BOND) {\n                $scope.selectedMode = SELECTION_MODE.MULTI;\n            } else if($scope.selectedMode === SELECTION_MODE.CREATE_PHYSICAL) {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n            } else {\n                $scope.selectedMode = SELECTION_MODE.SINGLE;\n            }\n        };\n\n        // Confirm the removal of interface.\n        $scope.confirmRemove = function(nic) {\n            $scope.selectedMode = SELECTION_MODE.NONE;\n            $scope.selectedInterfaces = [];\n            if(nic.type !== INTERFACE_TYPE.ALIAS) {\n                $scope.$parent.nodesManager.deleteInterface(\n                    $scope.node, nic.id);\n            } else {\n                $scope.$parent.nodesManager.unlinkSubnet(\n                    $scope.node, nic.id, nic.link_id);\n            }\n\n            // Remove the interface from available interfaces\n            var idx = $scope.interfaces.indexOf(nic);\n            if(idx > -1) {\n                $scope.interfaces.splice(idx, 1);\n            }\n        };\n\n        // Enter add mode.\n        $scope.add = function(type, nic) {\n            // When this is called right after another VLAN was just added, we\n            // remove its used VLAN from the available list.\n            var ignoreVLANs = [];\n            if(angular.isObject($scope.newInterface.vlan)) {\n                ignoreVLANs.push($scope.newInterface.vlan);\n            }\n\n            // Get the default VLAN for the new interface.\n            var vlans = getUnusedVLANs(nic, ignoreVLANs);\n            var defaultVLAN = null;\n            if(vlans.length > 0) {\n                defaultVLAN = vlans[0];\n            }\n            var defaultSubnet = null;\n            var defaultMode = LINK_MODE.LINK_UP;\n\n            // Alias used defaults based from its parent.\n            if(type === INTERFACE_TYPE.ALIAS) {\n                defaultVLAN = nic.vlan;\n                defaultSubnet = $filter('filter')(\n                    $scope.subnets, {vlan:defaultVLAN.id}, true)[0];\n                defaultMode = LINK_MODE.AUTO;\n            }\n\n            // Setup the new interface and enter add mode.\n            $scope.newInterface = {\n                type: type,\n                vlan: defaultVLAN,\n                subnet: defaultSubnet,\n                mode: defaultMode,\n                parent: nic,\n                tags: []\n            };\n            $scope.selectedMode = SELECTION_MODE.ADD;\n        };\n\n        // Quickly enter add by selecting the node first.\n        $scope.quickAdd = function(nic) {\n            $scope.selectedInterfaces = [$scope.getUniqueKey(nic)];\n            var type = 'alias';\n            if(!$scope.canAddAlias(nic)) {\n                type = 'vlan';\n            }\n            $scope.add(type, nic);\n        };\n\n        // Return the name of the interface being added.\n        $scope.getAddName = function() {\n            if($scope.newInterface.type === INTERFACE_TYPE.ALIAS) {\n                var aliasIdx = $scope.newInterface.parent.links.length;\n                return $scope.newInterface.parent.name + \":\" + aliasIdx;\n            } else if ($scope.newInterface.type === INTERFACE_TYPE.VLAN) {\n                return (\n                    $scope.newInterface.parent.name + \".\" +\n                    $scope.newInterface.vlan.vid);\n            }\n        };\n\n        // Called when the type of interface is changed.\n        $scope.addTypeChanged = function() {\n            if($scope.newInterface.type === INTERFACE_TYPE.ALIAS) {\n                $scope.newInterface.vlan = $scope.newInterface.parent.vlan;\n                $scope.newInterface.subnet = $filter('filter')(\n                    $scope.subnets,\n                    {vlan:$scope.newInterface.vlan.id}, true)[0];\n                $scope.newInterface.mode = LINK_MODE.AUTO;\n            } else if($scope.newInterface.type === INTERFACE_TYPE.VLAN) {\n                var vlans = getUnusedVLANs($scope.newInterface.parent);\n                $scope.newInterface.vlan = null;\n                if(vlans.length > 0) {\n                    $scope.newInterface.vlan = vlans[0];\n                }\n                $scope.newInterface.subnet = null;\n                $scope.newInterface.mode = LINK_MODE.LINK_UP;\n            }\n        };\n\n        // Perform the add action over the websocket.\n        $scope.addInterface = function(type) {\n            var nic;\n            if($scope.$parent.isDevice) {\n                nic = {\n                    id: $scope.newInterface.parent.id,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; }),\n                    ip_assignment: $scope.newInterface.ip_assignment,\n                    subnet: $scope.newInterface.subnet,\n                    ip_address: $scope.newInterface.ip_address\n                };\n                $scope.saveInterfaceLink(nic);\n            } else if($scope.newInterface.type === INTERFACE_TYPE.ALIAS) {\n                // Add a link to the current interface.\n                nic = {\n                    id: $scope.newInterface.parent.id,\n                    mode: $scope.newInterface.mode,\n                    subnet: $scope.newInterface.subnet,\n                    ip_address: $scope.newInterface.ip_address\n                };\n                $scope.saveInterfaceLink(nic);\n            } else if($scope.newInterface.type === INTERFACE_TYPE.VLAN) {\n                var params = {\n                    parent: $scope.newInterface.parent.id,\n                    vlan: $scope.newInterface.vlan.id,\n                    mode: $scope.newInterface.mode,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; })\n                };\n                if(angular.isObject($scope.newInterface.subnet)) {\n                    params.subnet = $scope.newInterface.subnet.id;\n                    params.ip_address = $scope.newInterface.ip_address;\n                }\n                $scope.$parent.nodesManager.createVLANInterface(\n                    $scope.node, params).then(null, function(error) {\n                        // Should do something better but for now just log\n                        // the error.\n                        console.log(error);\n                    });\n            }\n\n            // Add again based on the clicked option.\n            if(angular.isString(type)) {\n                $scope.add(type, $scope.newInterface.parent);\n            } else {\n                $scope.selectedMode = SELECTION_MODE.NONE;\n                $scope.selectedInterfaces = [];\n                $scope.newInterface = {};\n            }\n        };\n\n        // Return true if the networking information cannot be edited\n        // or if this interface should be disabled in the list. Only\n        // returns true when in create bond mode.\n        $scope.isDisabled = function() {\n            if ($scope.isAllNetworkingDisabled()) {\n                return true;\n            } else {\n                return (\n                    $scope.selectedMode !== SELECTION_MODE.NONE &&\n                    $scope.selectedMode !== SELECTION_MODE.SINGLE &&\n                    $scope.selectedMode !== SELECTION_MODE.MULTI);\n            }\n        };\n\n        // Return true when a bond can be created based on the current\n        // selection. Only can be done if no aliases are selected and all\n        // selected interfaces are on the same VLAN.\n        $scope.canCreateBond = function() {\n            if($scope.selectedMode !== SELECTION_MODE.MULTI) {\n                return false;\n            }\n            var interfaces = getSelectedInterfaces();\n            var i, vlan;\n            for(i = 0; i < interfaces.length; i++) {\n                var nic = interfaces[i];\n                if(nic.type === INTERFACE_TYPE.ALIAS ||\n                    nic.type === INTERFACE_TYPE.BOND) {\n                    return false;\n                } else if(!angular.isObject(vlan)) {\n                    vlan = nic.vlan;\n                } else if(vlan !== nic.vlan) {\n                    return false;\n                }\n            }\n            return true;\n        };\n\n        // Return true when the create bond view is being shown.\n        $scope.isShowingCreateBond = function() {\n            return $scope.selectedMode === SELECTION_MODE.CREATE_BOND;\n        };\n\n        // Show the create bond view.\n        $scope.showCreateBond = function() {\n            if($scope.selectedMode === SELECTION_MODE.MULTI &&\n                $scope.canCreateBond()) {\n                $scope.selectedMode = SELECTION_MODE.CREATE_BOND;\n\n                var parents = getSelectedInterfaces();\n                $scope.newBondInterface = {\n                    name: getNextName(\"bond\"),\n                    tags: [],\n                    parents: parents,\n                    primary: parents[0],\n                    mac_address: \"\",\n                    mode: \"active-backup\",\n                    lacpRate: \"slow\",\n                    xmitHashPolicy: \"layer2\"\n                };\n            }\n        };\n\n        // Return true if the interface has a parent that is a boot interface.\n        $scope.hasBootInterface = function(nic) {\n            if(!angular.isArray(nic.parents)) {\n                return false;\n            }\n            var i;\n            for(i = 0; i < nic.parents.length; i++) {\n                if(nic.parents[i].is_boot) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Return the MAC address that should be shown as a placeholder. This\n        // this is the MAC address of the primary interface.\n        $scope.getInterfacePlaceholderMACAddress = function(nic) {\n            if(!angular.isObject(nic.primary)) {\n                return \"\";\n            } else {\n                return nic.primary.mac_address;\n            }\n        };\n\n        // Return true if the user has inputed a value in the MAC address field\n        // but it is invalid.\n        $scope.isMACAddressInvalid = function(mac_address, invalidEmpty) {\n            if(angular.isUndefined(invalidEmpty)) {\n                invalidEmpty = false;\n            }\n            if(!angular.isString(mac_address) || mac_address === \"\") {\n                return invalidEmpty;\n            }\n            return !ValidationService.validateMAC(mac_address);\n        };\n\n        // Return true when the LACR rate selection should be shown.\n        $scope.showLACPRate = function() {\n            return $scope.newBondInterface.mode === \"802.3ad\";\n        };\n\n        // Return true when the XMIT hash policy should be shown.\n        $scope.showXMITHashPolicy = function() {\n            return (\n                $scope.newBondInterface.mode === \"balance-xor\" ||\n                $scope.newBondInterface.mode === \"802.3ad\" ||\n                $scope.newBondInterface.mode === \"balance-tlb\");\n        };\n\n        // Return true if cannot add the bond.\n        $scope.cannotAddBond = function() {\n            return (\n                $scope.isInterfaceNameInvalid($scope.newBondInterface) ||\n                $scope.isMACAddressInvalid(\n                    $scope.newBondInterface.mac_address));\n        };\n\n        // Actually add the bond.\n        $scope.addBond = function() {\n            if($scope.cannotAddBond()) {\n               return;\n            }\n\n            var parents = $scope.newBondInterface.parents.map(\n                function(nic) { return nic.id; });\n            var mac_address = $scope.newBondInterface.mac_address;\n            if(mac_address === \"\") {\n                mac_address = $scope.newBondInterface.primary.mac_address;\n            }\n            var vlan_id, vlan = $scope.newBondInterface.primary.vlan;\n            if(angular.isObject(vlan)) {\n                vlan_id = vlan.id;\n            } else {\n                vlan_id = null;\n            }\n            var params = {\n                name: $scope.newBondInterface.name,\n                mac_address: mac_address,\n                tags: $scope.newBondInterface.tags.map(\n                    function(tag) { return tag.text; }),\n                parents: parents,\n                vlan: vlan_id,\n                bond_mode: $scope.newBondInterface.mode,\n                bond_lacp_rate: $scope.newBondInterface.lacpRate,\n                bond_xmit_hash_policy: $scope.newBondInterface.xmitHashPolicy\n            };\n            $scope.$parent.nodesManager.createBondInterface(\n                $scope.node, params).then(null, function(error) {\n                    // Should do something better but for now just log\n                    // the error.\n                    console.log(error);\n                });\n\n            // Remove the parent interfaces so that they don't show up\n            // in the listing unti the new bond appears.\n            angular.forEach($scope.newBondInterface.parents, function(parent) {\n                var idx = $scope.interfaces.indexOf(parent);\n                if(idx > -1) {\n                    $scope.interfaces.splice(idx, 1);\n                }\n            });\n\n            // Clear the bond interface and reset the mode.\n            $scope.newBondInterface = {};\n            $scope.selectedInterfaces = [];\n            $scope.selectedMode = SELECTION_MODE.NONE;\n        };\n\n        // Return true when a bridge can be created based on the current\n        // selection. Only can be done if no aliases are selected and only\n        // one interface is selected.\n        $scope.canCreateBridge = function() {\n            if($scope.selectedMode !== SELECTION_MODE.SINGLE) {\n                return false;\n            }\n            var nic = getSelectedInterfaces()[0];\n            if(nic.type === INTERFACE_TYPE.ALIAS ||\n                nic.type === INTERFACE_TYPE.BRIDGE) {\n                return false;\n            }\n            return true;\n        };\n\n        // Return true when the create bridge view is being shown.\n        $scope.isShowingCreateBridge = function() {\n            return $scope.selectedMode === SELECTION_MODE.CREATE_BRIDGE;\n        };\n\n        // Show the create bridge view.\n        $scope.showCreateBridge = function() {\n            if($scope.selectedMode === SELECTION_MODE.SINGLE &&\n                $scope.canCreateBridge()) {\n                $scope.selectedMode = SELECTION_MODE.CREATE_BRIDGE;\n\n                var parents = getSelectedInterfaces();\n                $scope.newBridgeInterface = {\n                    name: getNextName(\"br\"),\n                    tags: [],\n                    parents: parents,\n                    primary: parents[0],\n                    mac_address: \"\",\n                    bridge_stp: false,\n                    bridge_fd: 15\n                };\n            }\n        };\n\n        // Return true if cannot add the bridge.\n        $scope.cannotAddBridge = function() {\n            return (\n                $scope.isInterfaceNameInvalid($scope.newBridgeInterface) ||\n                $scope.isMACAddressInvalid(\n                    $scope.newBridgeInterface.mac_address));\n        };\n\n        // Actually add the bridge.\n        $scope.addBridge = function() {\n            if($scope.cannotAddBridge()) {\n               return;\n            }\n\n            var parents = [$scope.newBridgeInterface.primary.id];\n            var mac_address = $scope.newBridgeInterface.mac_address;\n            if(mac_address === \"\") {\n                mac_address = $scope.newBridgeInterface.primary.mac_address;\n            }\n            var params = {\n                name: $scope.newBridgeInterface.name,\n                mac_address: mac_address,\n                tags: $scope.newBridgeInterface.tags.map(\n                    function(tag) { return tag.text; }),\n                parents: parents,\n                vlan: $scope.newBridgeInterface.primary.vlan.id,\n                bridge_stp: $scope.newBridgeInterface.bridge_stp,\n                bridge_fd: $scope.newBridgeInterface.bridge_fd\n            };\n            $scope.$parent.nodesManager.createBridgeInterface(\n                $scope.node, params).then(null, function(error) {\n                    // Should do something better but for now just log\n                    // the error.\n                    console.log(error);\n                });\n\n            // Remove the parent interface so that they don't show up\n            // in the listing unti the new bond appears.\n            var idx = $scope.interfaces.indexOf(\n                $scope.newBridgeInterface.primary);\n            if(idx > -1) {\n                $scope.interfaces.splice(idx, 1);\n            }\n\n            // Clear the bridge interface and reset the mode.\n            $scope.newBridgeInterface = {};\n            $scope.selectedInterfaces = [];\n            $scope.selectedMode = SELECTION_MODE.NONE;\n        };\n\n        // Return true when the create physical interface view is being shown.\n        $scope.isShowingCreatePhysical = function() {\n            return $scope.selectedMode === SELECTION_MODE.CREATE_PHYSICAL;\n        };\n\n        // Show the create interface view.\n        $scope.showCreatePhysical = function() {\n            if($scope.selectedMode === SELECTION_MODE.NONE) {\n                $scope.selectedMode = SELECTION_MODE.CREATE_PHYSICAL;\n                if($scope.$parent.isDevice) {\n                    $scope.newInterface = {\n                        name: getNextName(\"eth\"),\n                        mac_address: \"\",\n                        macError: false,\n                        tags: [],\n                        errorMsg: null,\n                        subnet: null,\n                        ip_assignment: IP_ASSIGNMENT.DYNAMIC\n                    };\n                } else {\n                    $scope.newInterface = {\n                        name: getNextName(\"eth\"),\n                        mac_address: \"\",\n                        macError: false,\n                        tags: [],\n                        errorMsg: null,\n                        fabric: $scope.fabrics[0],\n                        vlan: getDefaultVLAN($scope.fabrics[0]),\n                        subnet: null,\n                        mode: LINK_MODE.LINK_UP\n                    };\n                }\n            }\n        };\n\n        // Return true if cannot add the interface.\n        $scope.cannotAddPhysicalInterface = function() {\n            return (\n                $scope.isInterfaceNameInvalid($scope.newInterface) ||\n                $scope.isMACAddressInvalid(\n                    $scope.newInterface.mac_address, true));\n        };\n\n        // Actually add the new physical interface.\n        $scope.addPhysicalInterface = function() {\n            if($scope.cannotAddPhysicalInterface()) {\n               return;\n            }\n\n            var params;\n            if($scope.$parent.isDevice) {\n                params = {\n                    name: $scope.newInterface.name,\n                    mac_address: $scope.newInterface.mac_address,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; }),\n                    ip_assignment: $scope.newInterface.ip_assignment,\n                    ip_address: $scope.newInterface.ip_address\n                };\n            } else {\n                params = {\n                    name: $scope.newInterface.name,\n                    tags: $scope.newInterface.tags.map(\n                        function(tag) { return tag.text; }),\n                    mac_address: $scope.newInterface.mac_address,\n                    vlan: $scope.newInterface.vlan.id,\n                    mode: $scope.newInterface.mode\n                };\n            }\n            if(angular.isObject($scope.newInterface.subnet)) {\n                params.subnet = $scope.newInterface.subnet.id;\n            }\n            $scope.newInterface.macError = false;\n            $scope.newInterface.errorMsg = null;\n            $scope.$parent.nodesManager.createPhysicalInterface(\n                $scope.node, params).then(function() {\n                    // Clear the interface and reset the mode.\n                    $scope.newInterface = {};\n                    $scope.selectedMode = SELECTION_MODE.NONE;\n                },\n                function(errorStr) {\n                    error = JSONService.tryParse(errorStr);\n                    if(!angular.isObject(error)) {\n                        // Was not a JSON error. This is wrong here as it\n                        // should be, so just log to the console.\n                        console.log(errorStr);\n                    } else {\n                        macError = error.mac_address;\n                        if(angular.isArray(macError)) {\n                            $scope.newInterface.macError = true;\n                            $scope.newInterface.errorMsg = macError[0];\n                        }\n                    }\n                });\n        };\n\n        // Load all the required managers. NodesManager and GeneralManager\n        // are loaded by the parent controller \"NodeDetailsController\".\n        ManagerHelperService.loadManagers($scope, [\n            FabricsManager,\n            VLANsManager,\n            SubnetsManager,\n            UsersManager,\n            ControllersManager\n        ]).then(function() {\n            $scope.managersHaveLoaded = true;\n            updateLoaded();\n        });\n\n        // Tell $parent that the networkingController has been loaded.\n        $scope.$parent.controllerLoaded('networkingController', $scope);\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Storage Controller\n */\n\n\n// Filter that is specific to the NodeStorageController. Remove the available\n// disks from the list if being used in the availableNew.\nangular.module('MAAS').filter('removeAvailableByNew', function() {\n    return function(disks, availableNew) {\n        if(!angular.isObject(availableNew) || (\n            !angular.isObject(availableNew.device) &&\n            !angular.isArray(availableNew.devices))) {\n            return disks;\n        }\n\n        var filtered = [];\n        var single = true;\n        if(angular.isArray(availableNew.devices)) {\n            single = false;\n        }\n        angular.forEach(disks, function(disk) {\n            if(single) {\n                if(disk !== availableNew.device) {\n                    filtered.push(disk);\n                }\n            } else {\n                var i, found = false;\n                for(i = 0; i < availableNew.devices.length; i++) {\n                    if(disk === availableNew.devices[i]) {\n                        found = true;\n                        break;\n                    }\n                }\n                if(!found) {\n                    filtered.push(disk);\n                }\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').controller('NodeStorageController', [\n    '$scope', 'MachinesManager', 'ConverterService', 'UsersManager',\n    function($scope, MachinesManager, ConverterService, UsersManager) {\n\n        // From models/partitiontable.py - must be kept in sync.\n        var INITIAL_PARTITION_OFFSET = 4 * 1024 * 1024;\n        var END_OF_PARTITION_TABLE_SPACE = 1024 * 1024;\n        var PARTITION_TABLE_EXTRA_SPACE = INITIAL_PARTITION_OFFSET +\n            END_OF_PARTITION_TABLE_SPACE;\n        var PREP_PARTITION_SIZE = 8 * 1024 * 1024;\n\n        // From models/partition.py - must be kept in sync.\n        var PARTITION_ALIGNMENT_SIZE = 4 * 1024 * 1024;\n        var MIN_PARTITION_SIZE = PARTITION_ALIGNMENT_SIZE;\n\n        // Different selection modes.\n        var SELECTION_MODE = {\n            NONE: null,\n            SINGLE: \"single\",\n            MUTLI: \"multi\",\n            UNMOUNT: \"unmount\",\n            UNFORMAT: \"unformat\",\n            EDIT: \"edit\",\n            DELETE: \"delete\",\n            FORMAT_AND_MOUNT: \"format-mount\",\n            PARTITION: \"partition\",\n            BCACHE: \"bcache\",\n            RAID: \"raid\",\n            VOLUME_GROUP: \"volume-group\",\n            LOGICAL_VOLUME: \"logical-volume\"\n        };\n\n        // Different available raid modes.\n        var RAID_MODES = [\n            {\n                level: \"raid-0\",\n                title: \"RAID 0\",\n                min_disks: 2,\n                allows_spares: false,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * numDisks;\n                }\n            },\n            {\n                level: \"raid-1\",\n                title: \"RAID 1\",\n                min_disks: 2,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize;\n                }\n            },\n            {\n                level: \"raid-5\",\n                title: \"RAID 5\",\n                min_disks: 3,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * (numDisks - 1);\n                }\n            },\n            {\n                level: \"raid-6\",\n                title: \"RAID 6\",\n                min_disks: 4,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * (numDisks - 2);\n                }\n            },\n            {\n                level: \"raid-10\",\n                title: \"RAID 10\",\n                min_disks: 3,\n                allows_spares: true,\n                calculateSize: function(minSize, numDisks) {\n                    return minSize * numDisks / 2;\n                }\n            }\n        ];\n\n        $scope.tableInfo = {column: 'name'};\n        $scope.has_disks = false;\n        $scope.filesystems = [];\n        $scope.filesystemsMap = {};\n        $scope.filesystemMode = SELECTION_MODE.NONE;\n        $scope.filesystemAllSelected = false;\n        $scope.cachesets = [];\n        $scope.cachesetsMap = {};\n        $scope.cachesetsMode = SELECTION_MODE.NONE;\n        $scope.cachesetsAllSelected = false;\n        $scope.available = [];\n        $scope.availableMap = {};\n        $scope.availableMode = SELECTION_MODE.NONE;\n        $scope.availableAllSelected = false;\n        $scope.availableNew = {};\n        $scope.used = [];\n        $scope.showMembers = [];\n\n        // Return True if the filesystem is mounted.\n        function isMountedFilesystem(filesystem) {\n            return angular.isObject(filesystem) &&\n                angular.isString(filesystem.mount_point) &&\n                filesystem.mount_point !== \"\";\n        }\n\n        // Return True if the item has a filesystem and it's mounted.\n        function hasMountedFilesystem(item) {\n            return angular.isObject(item) &&\n                isMountedFilesystem(item.filesystem);\n        }\n\n        // Returns the fstype if the item has a filesystem and its unmounted.\n        function hasFormattedUnmountedFilesystem(item) {\n            if(angular.isObject(item.filesystem) &&\n                angular.isString(item.filesystem.fstype) &&\n                item.filesystem.fstype !== '' &&\n                (angular.isString(item.filesystem.mount_point) === false ||\n                    item.filesystem.mount_point === '')) {\n                return item.filesystem.fstype;\n            }else{\n                return null;\n            }\n        }\n\n        // Return True if the item is in use.\n        function isInUse(item) {\n            if(item.type === \"cache-set\") {\n                return true;\n            } else if(angular.isObject(item.filesystem)) {\n                if(item.filesystem.is_format_fstype &&\n                    angular.isString(item.filesystem.mount_point) &&\n                    item.filesystem.mount_point !== \"\") {\n                    return true;\n                } else if(!item.filesystem.is_format_fstype) {\n                    return true;\n                }\n                return false;\n            }\n            return item.available_size < MIN_PARTITION_SIZE;\n        }\n\n        // Return the tags formatted for ngTagInput.\n        function getTags(disk) {\n            var tags = [];\n            angular.forEach(disk.tags, function(tag) {\n                tags.push({ text: tag });\n            });\n            return tags;\n        }\n\n        // Return a unique key that will never change.\n        function getUniqueKey(disk) {\n            if(disk.type === \"cache-set\") {\n                return \"cache-set-\" + disk.cache_set_id;\n            } else {\n                var key = disk.type + \"-\" + disk.block_id;\n                if(angular.isNumber(disk.partition_id)) {\n                    key += \"-\" + disk.partition_id;\n                }\n                return key;\n            }\n        }\n\n        // Update the list of filesystems. Only filesystems with a mount point\n        // set go here. If no mount point is set, it goes in available.\n        function updateFilesystems() {\n            // Create the new list of filesystems.\n            var filesystems = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(hasMountedFilesystem(disk)) {\n                    var data = {\n                        \"type\": \"filesystem\",\n                        \"name\": disk.name,\n                        \"size_human\": disk.size_human,\n                        \"fstype\": disk.filesystem.fstype,\n                        \"mount_point\": disk.filesystem.mount_point,\n                        \"mount_options\": disk.filesystem.mount_options,\n                        \"block_id\": disk.id,\n                        \"partition_id\": null,\n                        \"filesystem_id\": disk.filesystem.id,\n                        \"original_type\": disk.type,\n                        \"original\": disk\n                    };\n                    if(disk.type === \"virtual\") {\n                        disk.parent_type = disk.parent.type;\n                    }\n                    filesystems.push(data);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    if(hasMountedFilesystem(partition)) {\n                        filesystems.push({\n                            \"type\": \"filesystem\",\n                            \"name\": partition.name,\n                            \"size_human\": partition.size_human,\n                            \"fstype\": partition.filesystem.fstype,\n                            \"mount_point\": partition.filesystem.mount_point,\n                            \"mount_options\":\n                                partition.filesystem.mount_options,\n                            \"block_id\": disk.id,\n                            \"partition_id\": partition.id,\n                            \"filesystem_id\": partition.filesystem.id,\n                            \"original_type\": \"partition\",\n                            \"original\": partition\n                        });\n                    }\n                });\n            });\n\n            // Add special filesystems to the filesystem list. A special\n            // filesystem cannot exist unless mounted, so we don't need\n            // to check.\n            angular.forEach(\n                $scope.node.special_filesystems,\n                function(filesystem) {\n                    filesystems.push({\n                        \"type\": \"filesystem\",\n                        \"name\": \"—\",\n                        \"size_human\": \"—\",\n                        \"fstype\": filesystem.fstype,\n                        \"mount_point\": filesystem.mount_point,\n                        \"mount_options\": filesystem.mount_options,\n                        \"block_id\": null,\n                        \"partition_id\": null,\n                        \"original_type\": \"special\"\n                    });\n                });\n\n            // Update the selected filesystems with the currently selected\n            // filesystems.\n            angular.forEach(filesystems, function(filesystem) {\n                var key = getUniqueKey(filesystem);\n                var oldFilesystem = $scope.filesystemsMap[key];\n                if(angular.isObject(oldFilesystem)) {\n                    filesystem.$selected = oldFilesystem.$selected;\n                } else {\n                    filesystem.$selected = false;\n                }\n            });\n\n            // Update the filesystems and filesystemsMap on the scope.\n            $scope.filesystems = filesystems;\n            $scope.filesystemsMap = {};\n            angular.forEach(filesystems, function(filesystem) {\n                $scope.filesystemsMap[getUniqueKey(filesystem)] = filesystem;\n            });\n\n            // Update the selection mode.\n            $scope.updateFilesystemSelection(false);\n        }\n\n        // Update the list of cache sets.\n        function updateCacheSets() {\n            // Create the new list of cache sets.\n            var cachesets = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(disk.type === \"cache-set\") {\n                    cachesets.push({\n                        \"type\": \"cache-set\",\n                        \"name\": disk.name,\n                        \"size_human\": disk.size_human,\n                        \"cache_set_id\": disk.id,\n                        \"used_by\": disk.used_for\n                    });\n                }\n            });\n\n            // Update the selected cache sets with the currently selected\n            // cache sets.\n            angular.forEach(cachesets, function(cacheset) {\n                var key = getUniqueKey(cacheset);\n                var oldCacheSet = $scope.cachesetsMap[key];\n                if(angular.isObject(oldCacheSet)) {\n                    cacheset.$selected = oldCacheSet.$selected;\n                } else {\n                    cacheset.$selected = false;\n                }\n            });\n\n            // Update the cachesets and cachesetsMap on the scope.\n            $scope.cachesets = cachesets;\n            $scope.cachesetsMap = {};\n            angular.forEach(cachesets, function(cacheset) {\n                $scope.cachesetsMap[getUniqueKey(cacheset)] = cacheset;\n            });\n\n            // Update the selection mode.\n            $scope.updateCacheSetsSelection(false);\n        }\n\n        // Update list of all available disks.\n        function updateAvailable() {\n            var available = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(!isInUse(disk)) {\n                    var has_partitions = false;\n                    if(angular.isArray(disk.partitions) &&\n                        disk.partitions.length > 0) {\n                        has_partitions = true;\n                    }\n                    var data = {\n                        \"name\": disk.name,\n                        \"size_human\": disk.size_human,\n                        \"available_size_human\": disk.available_size_human,\n                        \"used_size_human\": disk.used_size_human,\n                        \"type\": disk.type,\n                        \"model\": disk.model,\n                        \"serial\": disk.serial,\n                        \"tags\": getTags(disk),\n                        \"fstype\": hasFormattedUnmountedFilesystem(disk),\n                        \"mount_point\": null,\n                        \"mount_options\": null,\n                        \"block_id\": disk.id,\n                        \"partition_id\": null,\n                        \"has_partitions\": has_partitions,\n                        \"is_boot\": disk.is_boot,\n                        \"original\": disk,\n                        \"test_status\": disk.test_status,\n                        \"firmware_version\": disk.firmware_version\n                    };\n                    if(disk.type === \"virtual\") {\n                        data.parent_type = disk.parent.type;\n                    }\n                    available.push(data);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    if(!isInUse(partition)) {\n                        available.push({\n                            \"name\": partition.name,\n                            \"size_human\": partition.size_human,\n                            \"available_size_human\": (\n                                partition.available_size_human),\n                            \"used_size_human\": partition.used_size_human,\n                            \"type\": \"partition\",\n                            \"model\": \"\",\n                            \"serial\": \"\",\n                            \"tags\": [],\n                            \"fstype\":\n                                hasFormattedUnmountedFilesystem(partition),\n                            \"mount_point\": null,\n                            \"mount_options\": null,\n                            \"block_id\": disk.id,\n                            \"partition_id\": partition.id,\n                            \"has_partitions\": false,\n                            \"is_boot\": false,\n                            \"original\": partition\n                        });\n                    }\n                });\n            });\n\n            // Update the selected available disks with the currently selected\n            // available disks. Also copy the $options so they are not lost\n            // for the current action.\n            angular.forEach(available, function(disk) {\n                var key = getUniqueKey(disk);\n                var oldDisk = $scope.availableMap[key];\n                if(angular.isObject(oldDisk)) {\n                    disk.$selected = oldDisk.$selected;\n                    disk.$options = oldDisk.$options;\n                } else {\n                    disk.$selected = false;\n                    disk.$options = {};\n                }\n            });\n\n            // Update available and availableMap on the scope.\n            $scope.available = available;\n            $scope.availableMap = {};\n            angular.forEach(available, function(disk) {\n                $scope.availableMap[getUniqueKey(disk)] = disk;\n            });\n\n            // Update device or devices on the availableNew object to be\n            // there new objects.\n            if(angular.isObject($scope.availableNew)) {\n                // Update device.\n                if(angular.isObject($scope.availableNew.device)) {\n                    var key = getUniqueKey($scope.availableNew.device);\n                    $scope.availableNew.device = $scope.availableMap[key];\n                // Update devices.\n                } else if(angular.isArray($scope.availableNew.devices)) {\n                    var newDevices = [];\n                    angular.forEach(\n                        $scope.availableNew.devices, function(device) {\n                            var key = getUniqueKey(device);\n                            var newDevice = $scope.availableMap[key];\n                            if(angular.isObject(newDevice)) {\n                                newDevices.push(newDevice);\n                            }\n                        });\n                    $scope.availableNew.devices = newDevices;\n                }\n            }\n\n            // Update the selection mode.\n            $scope.updateAvailableSelection(false);\n        }\n\n        // Update list of all used disks.\n        function updateUsed() {\n            var used = [];\n            angular.forEach($scope.node.disks, function(disk) {\n                if(isInUse(disk) && disk.type !== \"cache-set\") {\n                    var has_partitions = false;\n                    if(angular.isArray(disk.partitions) &&\n                        disk.partitions.length > 0) {\n                        has_partitions = true;\n                    }\n                    var data = {\n                        \"name\": disk.name,\n                        \"type\": disk.type,\n                        \"model\": disk.model,\n                        \"serial\": disk.serial,\n                        \"tags\": getTags(disk),\n                        \"used_for\": disk.used_for,\n                        \"is_boot\": disk.is_boot,\n                        \"has_partitions\": has_partitions,\n                        \"test_status\": disk.test_status,\n                        \"firmware_version\": disk.firmware_version\n                    };\n                    if(disk.type === \"virtual\") {\n                        data.parent_type = disk.parent.type;\n                    }\n                    used.push(data);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    if(isInUse(partition) && partition.type !== \"cache-set\") {\n                        used.push({\n                            \"name\": partition.name,\n                            \"type\": \"partition\",\n                            \"model\": \"\",\n                            \"serial\": \"\",\n                            \"tags\": [],\n                            \"used_for\": partition.used_for,\n                            \"is_boot\": false\n                        });\n                    }\n                });\n            });\n            $scope.used = used;\n        }\n\n        // Updates the filesystem, available, and used list.\n        function updateDisks() {\n            if(angular.isArray($scope.node.disks)) {\n                $scope.has_disks = $scope.node.disks.length > 0;\n                updateFilesystems();\n                updateCacheSets();\n                updateAvailable();\n                updateUsed();\n            } else {\n                $scope.has_disks = false;\n                $scope.filesystems = [];\n                $scope.filesystemsMap = {};\n                $scope.filesystemMode = SELECTION_MODE.NONE;\n                $scope.filesystemAllSelected = false;\n                $scope.cachesets = [];\n                $scope.cachesetsMap = {};\n                $scope.cachesetsMode = SELECTION_MODE.NONE;\n                $scope.cachesetsAllSelected = false;\n                $scope.available = [];\n                $scope.availableMap = {};\n                $scope.availableMode = SELECTION_MODE.NONE;\n                $scope.availableAllSelected = false;\n                $scope.availableNew = {};\n                $scope.used = [];\n            }\n        }\n\n        // Deselect all items in the array.\n        function deselectAll(items) {\n            angular.forEach(items, function(item) {\n                item.$selected = false;\n            });\n        }\n\n        // Capitalize the first letter of the string.\n        function capitalizeFirstLetter(string) {\n            return string.charAt(0).toUpperCase() + string.slice(1);\n        }\n\n        // Return true if the string is a number.\n        function isNumber(string) {\n            var pattern = /^-?\\d+\\.?\\d*$/;\n            return pattern.test(string);\n        }\n\n        // Extract the index from the name based on prefix.\n        function getIndexFromName(prefix, name) {\n            var pattern = new RegExp(\"^\" + prefix + \"([0-9]+)$\");\n            var match = pattern.exec(name);\n            if(angular.isArray(match) && match.length === 2) {\n                return parseInt(match[1], 10);\n            }\n        }\n\n        // Get the next device name based on prefix.\n        function getNextName(prefix) {\n            var idx = -1;\n            angular.forEach($scope.node.disks, function(disk) {\n                var dIdx = getIndexFromName(prefix, disk.name);\n                if(angular.isNumber(dIdx)) {\n                    idx = Math.max(idx, dIdx);\n                }\n                angular.forEach(disk.partitions, function(partition) {\n                    dIdx = getIndexFromName(prefix, partition.name);\n                    if(angular.isNumber(dIdx)) {\n                        idx = Math.max(idx, dIdx);\n                    }\n                });\n            });\n            return prefix + (idx + 1);\n        }\n\n        // Return true if another disk exists with name.\n        function isNameAlreadyInUse(name, exclude_disk) {\n            if(!angular.isArray($scope.node.disks)) {\n                return false;\n            }\n\n            var i, j;\n            for(i = 0; i < $scope.node.disks.length; i++) {\n                var disk = $scope.node.disks[i];\n                if(disk.name === name) {\n                    if(!angular.isObject(exclude_disk) ||\n                        exclude_disk.type === \"partition\" ||\n                        exclude_disk.block_id !== disk.id) {\n                        return true;\n                    }\n                }\n                if(angular.isArray(disk.partitions)) {\n                    for(j = 0; j < disk.partitions.length; j++) {\n                        var partition = disk.partitions[j];\n                        if(partition.name === name) {\n                            if(!angular.isObject(exclude_disk) ||\n                                exclude_disk.type !== \"partition\" ||\n                                exclude_disk.partition_id !== partition.id) {\n                                return true;\n                            }\n                        }\n                    }\n                }\n            }\n            return false;\n        }\n\n        // Return true if the disk is a logical volume.\n        function isLogicalVolume(disk) {\n            return disk.type === \"virtual\" && disk.parent_type === \"lvm-vg\";\n        }\n\n        // Called by $parent when the node has been loaded.\n        $scope.nodeLoaded = function() {\n            $scope.$watch(\"node.disks\", updateDisks);\n        };\n\n        // Return true if the item can be a boot disk.\n        $scope.isBootDiskDisabled = function(item, section) {\n            // Only superusers can change the boot disk.\n            if(!$scope.isSuperUser()) {\n                return true;\n            }\n\n            // Not ready or allocated so the boot disk cannot be changed.\n            if (angular.isObject($scope.node) &&\n                [\"Ready\", \"Allocated\"].indexOf(\n                    $scope.node.status) === -1) {\n                return true;\n            }\n\n            // Only physical disks can be the boot disk.\n            if(item.type !== \"physical\") {\n                return true;\n            }\n\n            // If the disk is in the used section and does not have any\n            // partitions then it cannot be a boot disk. Boot disk either\n            // require that it be unused or that some partitions exists\n            // on the disk. This is because the boot disk has to have a\n            // partition table header.\n            if(section === \"used\") {\n                return !item.has_partitions;\n            }\n            return false;\n        };\n\n        // Called to change the disk to a boot disk.\n        $scope.setAsBootDisk = function(item) {\n            // Do nothing if already the boot disk.\n            if(item.is_boot) {\n                return;\n            }\n            // Do nothing if disabled.\n            if($scope.isBootDiskDisabled(item)) {\n                return;\n            }\n\n            MachinesManager.setBootDisk($scope.node, item.block_id);\n        };\n\n        // Return array of selected filesystems.\n        $scope.getSelectedFilesystems = function() {\n            var filesystems = [];\n            angular.forEach($scope.filesystems, function(filesystem) {\n                if(filesystem.$selected) {\n                    filesystems.push(filesystem);\n                }\n            });\n            return filesystems;\n        };\n\n        // Update the currect mode for the filesystem section and the all\n        // selected value.\n        $scope.updateFilesystemSelection = function(force) {\n            if(angular.isUndefined(force)) {\n                force = false;\n            }\n            var filesystems = $scope.getSelectedFilesystems();\n            if(filesystems.length === 0) {\n                $scope.filesystemMode = SELECTION_MODE.NONE;\n            } else if(filesystems.length === 1 && force) {\n                $scope.filesystemMode = SELECTION_MODE.SINGLE;\n            } else if(force) {\n                $scope.filesystemMode = SELECTION_MODE.MUTLI;\n            }\n\n            if($scope.filesystems.length === 0) {\n                $scope.filesystemAllSelected = false;\n            } else if(filesystems.length === $scope.filesystems.length) {\n                $scope.filesystemAllSelected = true;\n            } else {\n                $scope.filesystemAllSelected = false;\n            }\n        };\n\n        // Toggle the selection of the filesystem.\n        $scope.toggleFilesystemSelect = function(filesystem) {\n            filesystem.$selected = !filesystem.$selected;\n            $scope.updateFilesystemSelection(true);\n        };\n\n        // Toggle the selection of all filesystems.\n        $scope.toggleFilesystemAllSelect = function() {\n            angular.forEach($scope.filesystems, function(filesystem) {\n                if($scope.filesystemAllSelected) {\n                    filesystem.$selected = false;\n                } else {\n                    filesystem.$selected = true;\n                }\n            });\n            $scope.updateFilesystemSelection(true);\n        };\n\n        // Return true if checkboxes in the filesystem section should be\n        // disabled.\n        $scope.isFilesystemsDisabled = function() {\n            return ((\n                $scope.filesystemMode !== SELECTION_MODE.NONE &&\n                $scope.filesystemMode !== SELECTION_MODE.SINGLE &&\n                $scope.filesystemMode !== SELECTION_MODE.MUTLI) ||\n                $scope.isAllStorageDisabled());\n        };\n\n        // Cancel the current filesystem operation.\n        $scope.filesystemCancel = function() {\n            deselectAll($scope.filesystems);\n            $scope.updateFilesystemSelection(true);\n        };\n\n        // Enter unmount mode.\n        $scope.filesystemUnmount = function() {\n            $scope.filesystemMode = SELECTION_MODE.UNMOUNT;\n        };\n\n        // Quickly enter unmount by selecting the filesystem first.\n        $scope.quickFilesystemUnmount = function(filesystem) {\n            deselectAll($scope.filesystems);\n            filesystem.$selected = true;\n            $scope.updateFilesystemSelection(true);\n            $scope.filesystemUnmount();\n        };\n\n        // Confirm the unmount action for filesystem.\n        $scope.filesystemConfirmUnmount = function(filesystem) {\n            MachinesManager.updateFilesystem(\n                $scope.node,\n                filesystem.block_id, filesystem.partition_id,\n                filesystem.fstype, null, null);\n\n            var idx = $scope.filesystems.indexOf(filesystem);\n            $scope.filesystems.splice(idx, 1);\n            $scope.updateFilesystemSelection();\n        };\n\n        // Enter delete mode.\n        $scope.filesystemDelete = function() {\n            $scope.filesystemMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter delete by selecting the filesystem first.\n        $scope.quickFilesystemDelete = function(filesystem) {\n            deselectAll($scope.filesystems);\n            filesystem.$selected = true;\n            $scope.updateFilesystemSelection(true);\n            $scope.filesystemDelete();\n        };\n\n        // Confirm the delete action for filesystem.\n        $scope.filesystemConfirmDelete = function(filesystem) {\n            if(filesystem.original_type === \"special\") {\n                // Delete the special filesystem.\n                MachinesManager.unmountSpecialFilesystem(\n                    $scope.node, filesystem.mount_point);\n            } else if(filesystem.original_type === \"partition\") {\n                // Delete the partition.\n                MachinesManager.deletePartition(\n                    $scope.node, filesystem.original.id);\n            } else {\n                // Delete the disk.\n                MachinesManager.deleteFilesystem(\n                    $scope.node, filesystem.block_id, filesystem.partition_id,\n                    filesystem.filesystem_id);\n            }\n\n            var idx = $scope.filesystems.indexOf(filesystem);\n            $scope.filesystems.splice(idx, 1);\n            $scope.updateFilesystemSelection();\n        };\n\n        // Return true if the disk has an unmouted filesystem.\n        $scope.hasUnmountedFilesystem = function(disk) {\n            if(angular.isString(disk.fstype) && disk.fstype !== \"\") {\n                if(!angular.isString(disk.mount_point) ||\n                    disk.mount_point === \"\") {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Return true if the free space label should be shown.\n        $scope.showFreeSpace = function(disk) {\n            if(disk.type === \"lvm-vg\") {\n                return true;\n            } else if(disk.type === \"physical\" || disk.type === \"virtual\") {\n                return disk.has_partitions;\n            } else {\n                return false;\n            }\n        };\n\n        // Return the device type for the disk.\n        $scope.getDeviceType = function(disk) {\n            if(angular.isUndefined(disk)) {\n                return \"\";\n            }\n\n            if(disk.type === \"virtual\") {\n                if(disk.parent_type === \"lvm-vg\") {\n                    return \"Logical volume\";\n                } else if(disk.parent_type.indexOf(\"raid-\") === 0) {\n                    return \"RAID \" + disk.parent_type.split(\"-\")[1];\n                } else {\n                    return capitalizeFirstLetter(disk.parent_type);\n                }\n            } else if(disk.type === \"lvm-vg\") {\n                return \"Volume group\";\n            } else {\n                return capitalizeFirstLetter(disk.type);\n            }\n        };\n\n        // Return array of selected available disks.\n        $scope.getSelectedAvailable = function() {\n            var available = [];\n            angular.forEach($scope.available, function(disk) {\n                if(disk.$selected) {\n                    available.push(disk);\n                }\n            });\n            return available;\n        };\n\n        // Update the currect mode for the available section and the all\n        // selected value.\n        $scope.updateAvailableSelection = function(force) {\n            if(angular.isUndefined(force)) {\n                force = false;\n            }\n            var available = $scope.getSelectedAvailable();\n            if(available.length === 0) {\n                $scope.availableMode = SELECTION_MODE.NONE;\n            } else if(available.length === 1 && force) {\n                $scope.availableMode = SELECTION_MODE.SINGLE;\n            } else if(force) {\n                $scope.availableMode = SELECTION_MODE.MUTLI;\n            }\n\n            if($scope.available.length === 0) {\n                $scope.availableAllSelected = false;\n            } else if(available.length === $scope.available.length) {\n                $scope.availableAllSelected = true;\n            } else {\n                $scope.availableAllSelected = false;\n            }\n        };\n\n        // Toggle the selection of the available disk.\n        $scope.toggleAvailableSelect = function(disk) {\n            disk.$selected = !disk.$selected;\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Toggle the selection of all available disks.\n        $scope.toggleAvailableAllSelect = function() {\n            angular.forEach($scope.available, function(disk) {\n                if(!$scope.availableAllSelected) {\n                    disk.$selected = true;\n                } else {\n                    disk.$selected = false;\n                }\n            });\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if checkboxes in the avaiable section should be\n        // disabled.\n        $scope.isAvailableDisabled = function() {\n            return ((\n                $scope.availableMode !== SELECTION_MODE.NONE &&\n                $scope.availableMode !== SELECTION_MODE.SINGLE &&\n                $scope.availableMode !== SELECTION_MODE.MUTLI) ||\n                $scope.isAllStorageDisabled());\n        };\n\n        // Return true if the disk can be formatted and mounted.\n        $scope.canFormatAndMount = function(disk) {\n            if($scope.isAllStorageDisabled()) {\n                return false;\n            } else if(disk.type === \"lvm-vg\" || disk.has_partitions) {\n                return false;\n            } else if(disk.type === \"physical\" && disk.original.is_boot) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Return the text for the partition button.\n        $scope.getPartitionButtonText = function(disk) {\n            if(disk.has_partitions) {\n                return \"Add partition\";\n            } else {\n                return \"Partition\";\n            }\n        };\n\n        $scope.availablePartitionSpace = function(disk) {\n            var space_to_reserve = 0;\n            if(!angular.isString(disk.original.partition_table_type)\n                || disk.original.partition_table_type === \"\") {\n                // Disk has no partition table, so reserve space for it.\n                space_to_reserve = PARTITION_TABLE_EXTRA_SPACE;\n                // ppc64el node requires that space be saved for the prep\n                // partition.\n                if($scope.node.architecture.indexOf(\"ppc64el\") === 0) {\n                    space_to_reserve += PREP_PARTITION_SIZE;\n                }\n            }\n            return ConverterService.roundByBlockSize(\n                disk.original.available_size - space_to_reserve,\n                PARTITION_ALIGNMENT_SIZE);\n        };\n\n        // Return true if a partition can be added to disk.\n        $scope.canAddPartition = function(disk) {\n            if(!$scope.isSuperUser() || $scope.isAllStorageDisabled()) {\n                return false;\n            } else if(disk.type === \"partition\" || disk.type === \"lvm-vg\") {\n                return false;\n            } else if(disk.type === \"virtual\" &&\n                (disk.parent_type === \"lvm-vg\" ||\n                    disk.parent_type === \"bcache\")) {\n                return false;\n            } else if(angular.isString(disk.fstype) && disk.fstype !== \"\") {\n                return false;\n            }\n            // If we can fit a minimum partition, we're golden.\n            return ($scope.availablePartitionSpace(disk) -\n                MIN_PARTITION_SIZE) >= 0;\n        };\n\n        // Return true if the name is invalid.\n        $scope.isNameInvalid = function(disk) {\n            if(disk.name === \"\") {\n                return false;\n            } else if(isNameAlreadyInUse(disk.name, disk)) {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Prevent logical volumes from changing the volume group prefix.\n        $scope.nameHasChanged = function(disk) {\n            if(isLogicalVolume(disk)) {\n                var parentName = disk.original.name.split(\"-\")[0] + \"-\";\n                var startsWith = disk.name.indexOf(parentName);\n                if(startsWith !== 0) {\n                    disk.name = parentName;\n                }\n            }\n        };\n\n        // Cancel the current available operation.\n        $scope.availableCancel = function(disk) {\n            $scope.updateAvailableSelection(true);\n            $scope.availableNew = {};\n        };\n\n        // Return true if the filesystem can be mounted at a directory.\n        $scope.usesMountPoint = function(fstype) {\n            return angular.isString(fstype) && fstype !== \"swap\";\n        };\n\n        // Return true if the filesystem uses storage (partition or\n        // block device).\n        $scope.usesStorage = function(fstype) {\n            return angular.isString(fstype) &&\n                fstype !== \"tmpfs\" && fstype !== \"ramfs\";\n        };\n\n        // Return true if the mount point is invalid.\n        $scope.isMountPointInvalid = function(mountPoint) {\n            if(angular.isUndefined(mountPoint) || mountPoint === \"\") {\n                return false;\n            } else if (mountPoint === \"none\") {\n                // XXX: Hack to allow \"swap\" filesystems to be mounted.\n                // This should be allowed only when fstype is 'swap' but\n                // doing that would require more refactoring (or more\n                // hacks) that I have time for right now.\n                return false;\n            } else if(mountPoint[0] !== \"/\") {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Return true if the disk can be deleted.\n        $scope.canDelete = function(disk) {\n            if (!$scope.isSuperUser() || $scope.isAllStorageDisabled()) {\n                return false;\n            } else if(disk.type === \"lvm-vg\") {\n                return disk.original.used_size === 0;\n            } else {\n                return !disk.has_partitions;\n            }\n        };\n\n        // Enter delete mode.\n        $scope.availableDelete = function() {\n            $scope.availableMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter delete mode.\n        $scope.availableQuickDelete = function(disk) {\n            deselectAll($scope.available);\n            disk.$selected = true;\n            $scope.updateAvailableSelection(true);\n            $scope.availableDelete();\n        };\n\n        // Return true if it can be edited.\n        $scope.canEdit = function(disk) {\n          if (!$scope.isSuperUser() || $scope.isAllStorageDisabled()) {\n              return false;\n          } else {\n              return true;\n          }\n        };\n\n        // Enter Edit mode, disable certain fields based on disk type\n        $scope.availableEdit = function(disk) {\n            $scope.availableMode = SELECTION_MODE.EDIT;\n\n            if (disk.type === \"lvm-vg\") {\n                disk.$options = {\n                    editingTags: false,\n                    editingFilesystem: false\n                };\n            } else if (disk.type === \"partition\") {\n                disk.$options = {\n                    editingTags: false,\n                    editingFilesystem: true,\n                    fstype: disk.fstype\n                };\n            } else {\n                disk.$options = {\n                    editingFilesystem: true,\n                    editingTags: true,\n                    tags: angular.copy(disk.tags),\n                    fstype: disk.fstype\n                };\n                if (!$scope.canFormatAndMount(disk)) {\n                    disk.$options.editingFilesystem = false;\n                }\n            }\n        };\n\n        // Quickly enter Edit mode\n        $scope.availableQuickEdit = function(disk) {\n            deselectAll($scope.available);\n            disk.$selected = true;\n            $scope.updateAvailableSelection(true);\n            $scope.availableEdit(disk);\n        };\n\n        // Save the disk which is in Edit mode\n        $scope.availableConfirmEdit = function(disk) {\n            var params = {\n                name: disk.name\n            };\n\n            // Do nothing if not valid.\n            if($scope.isNameInvalid(disk) ||\n                $scope.isMountPointInvalid(disk.$options.mountPoint)) {\n                return;\n            }\n\n            // Reset the name if its blank.\n            if(disk.name === \"\") {\n                disk.name = disk.original.name;\n            }\n\n            // Ensure logical volume has parent prefix in its name.\n            if(isLogicalVolume(disk)){\n                var parentName = disk.original.name.split(\"-\")[0] + \"-\";\n                params.name = disk.name.slice(parentName.length);\n            }\n\n            // Set filesystem options so formatting and mounting is performed.\n            if(angular.isDefined(disk.$options.fstype)) {\n                params.fstype = disk.$options.fstype;\n                params.mount_point = disk.$options.mountPoint || '';\n                params.mount_options = disk.$options.mountOptions || '';\n            }\n\n            // Update the tags for the disk.\n            if(angular.isArray(disk.$options.tags)) {\n                params.tags = disk.$options.tags.map(\n                    function(tag) { return tag.text; });\n            }\n\n            // Save the options.\n            MachinesManager.updateDisk(\n                $scope.node, disk.block_id, params);\n\n            // Set the options on the object so no flicker occurs while waiting\n            // for the new object to be received.\n            disk.fstype = disk.$options.fstype;\n            disk.mount_point = disk.$options.mountPoint;\n            disk.mount_options = disk.$options.mountOptions;\n            disk.tags = disk.$options.tags;\n            disk.$options = {};\n\n            // If the mount_point is set the we need to transition this to\n            // the filesystem section.\n            if(angular.isString(disk.mount_point) && disk.mount_point !== \"\") {\n                $scope.filesystems.push({\n                    \"name\": disk.name,\n                    \"size_human\": disk.size_human,\n                    \"fstype\": disk.fstype,\n                    \"mount_point\": disk.mount_point,\n                    \"mount_options\": disk.mount_options,\n                    \"block_id\": disk.block_id,\n                    \"partition_id\": disk.partition_id\n                });\n\n                // Remove the selected disk from available.\n                var idx = $scope.available.indexOf(disk);\n                $scope.available.splice(idx, 1);\n            }\n\n            // Deselect the disk after saving\n            disk.$selected = false;\n\n            // Update the current selections.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return the text for remove confirmation message.\n        $scope.getRemoveTypeText = function(disk) {\n            if(disk.type === \"filesystem\") {\n                if (angular.isObject(disk.original)) {\n                    disk = disk.original;\n                } else {\n                    return \"special filesystem\";\n                }\n            }\n\n            if(disk.type === \"physical\") {\n                return \"physical disk\";\n            } else if(disk.type === \"partition\") {\n                return \"partition\";\n            } else if(disk.type === \"lvm-vg\") {\n                return \"volume group\";\n            } else if(disk.type === \"virtual\") {\n                if(disk.parent_type === \"lvm-vg\") {\n                    return \"logical volume\";\n                } else if(disk.parent_type.indexOf(\"raid-\") === 0) {\n                    return \"RAID \" + disk.parent_type.split(\"-\")[1] + \" disk\";\n                } else {\n                    return disk.parent_type + \" disk\";\n                }\n            }\n        };\n\n        // Delete the disk, partition, or volume group.\n        $scope.availableConfirmDelete = function(disk) {\n            if(disk.type === \"lvm-vg\") {\n                // Delete the volume group.\n                MachinesManager.deleteVolumeGroup(\n                    $scope.node, disk.block_id);\n            } else if(disk.type === \"partition\") {\n                // Delete the partition.\n                MachinesManager.deletePartition(\n                    $scope.node, disk.partition_id);\n            } else {\n                // Delete the disk.\n                MachinesManager.deleteDisk(\n                    $scope.node, disk.block_id);\n            }\n\n            // Remove the selected disk from available.\n            var idx = $scope.available.indexOf(disk);\n            $scope.available.splice(idx, 1);\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Enter partition mode.\n        $scope.availablePartition = function(disk) {\n            $scope.availableMode = SELECTION_MODE.PARTITION;\n            // Set starting size to the maximum available space.\n            var size_and_units = disk.available_size_human.split(\" \");\n            disk.$options = {\n                size: size_and_units[0],\n                sizeUnits: size_and_units[1],\n                fstype: null,\n                mountPoint: \"\",\n                mountOptions: \"\"\n            };\n        };\n\n        // Quickly enter partition mode.\n        $scope.availableQuickPartition = function(disk) {\n            deselectAll($scope.available);\n            disk.$selected = true;\n            $scope.updateAvailableSelection(true);\n            $scope.availablePartition(disk);\n        };\n\n        // Get the new name of the partition.\n        $scope.getAddPartitionName = function(disk) {\n            var length, partitions = disk.original.partitions;\n            if(angular.isArray(partitions)) {\n                length = partitions.length;\n            } else {\n                length = 0;\n            }\n            if(disk.original.partition_table_type === \"mbr\" &&\n                length > 2) {\n                return disk.name + \"-part\" + (length + 2);\n            } else if($scope.node.architecture.indexOf(\"ppc64el\") === 0 &&\n                disk.original.is_boot) {\n                // Boot disk on ppc64el machines skip the first partition as\n                // its reserved for the prep partition.\n                return disk.name + \"-part\" + (length + 2);\n            } else {\n                return disk.name + \"-part\" + (length + 1);\n            }\n        };\n\n        // Return true if the size is invalid.\n        $scope.isAddPartitionSizeInvalid = function(disk) {\n            if(disk.$options.size === \"\" || !isNumber(disk.$options.size)) {\n                return true;\n            } else {\n                var bytes = ConverterService.unitsToBytes(\n                    disk.$options.size, disk.$options.sizeUnits);\n                if(bytes < MIN_PARTITION_SIZE) {\n                    return true;\n                } else if(bytes > disk.original.available_size) {\n                    // Round the size down to the lowest tolerance for that\n                    // to see if it now fits.\n                    var rounded = ConverterService.roundUnits(\n                        disk.$options.size, disk.$options.sizeUnits);\n                    if(rounded > disk.original.available_size) {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                } else {\n                    return false;\n                }\n            }\n        };\n\n        // Confirm the partition creation.\n        $scope.availableConfirmPartition = function(disk) {\n            // Do nothing if not valid.\n            if($scope.isAddPartitionSizeInvalid(disk) ||\n                $scope.isMountPointInvalid(disk.$options.mountPoint)) {\n                return;\n            }\n\n            // Get the bytes to create the partition.\n            var bytes = ConverterService.unitsToBytes(\n                disk.$options.size, disk.$options.sizeUnits);\n\n            // Accepting prefilled defaults means use whole disk (lp:1509535).\n            var size_and_units = disk.original.available_size_human.split(\" \");\n            if(disk.$options.size === size_and_units[0] &&\n               disk.$options.sizeUnits === size_and_units[1]) {\n                bytes = disk.original.available_size;\n            }\n\n            var removeDisk = false;\n            var available_space = $scope.availablePartitionSpace(disk);\n            if(bytes >= available_space) {\n                // Clamp to available space.\n                bytes = available_space;\n                // Remove the disk if partition uses all the remaining space.\n                removeDisk = true;\n            }\n\n            // Create the partition.\n            var params = {};\n            if(angular.isString(disk.$options.fstype) &&\n                disk.$options.fstype !== \"\") {\n                params.fstype = disk.$options.fstype;\n                if(disk.$options.mountPoint !== \"\") {\n                    params.mount_point = disk.$options.mountPoint;\n                    params.mount_options = disk.$options.mountOptions;\n                }\n            }\n            MachinesManager.createPartition(\n                $scope.node, disk.block_id, bytes, params);\n\n            // Remove the disk if needed.\n            if(removeDisk) {\n                var idx = $scope.available.indexOf(disk);\n                $scope.available.splice(idx, 1);\n            }\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return array of selected cache sets.\n        $scope.getSelectedCacheSets = function() {\n            var cachesets = [];\n            angular.forEach($scope.cachesets, function(cacheset) {\n                if(cacheset.$selected) {\n                    cachesets.push(cacheset);\n                }\n            });\n            return cachesets;\n        };\n\n        // Update the currect mode for the cache sets section and the all\n        // selected value.\n        $scope.updateCacheSetsSelection = function(force) {\n            if(angular.isUndefined(force)) {\n                force = false;\n            }\n            var cachesets = $scope.getSelectedCacheSets();\n            if(cachesets.length === 0) {\n                $scope.cachesetsMode = SELECTION_MODE.NONE;\n            } else if(cachesets.length === 1 && force) {\n                $scope.cachesetsMode = SELECTION_MODE.SINGLE;\n            } else if(force) {\n                $scope.cachesetsMode = SELECTION_MODE.MUTLI;\n            }\n\n            if($scope.cachesets.length === 0) {\n                $scope.cachesetsAllSelected = false;\n            } else if(cachesets.length === $scope.cachesets.length) {\n                $scope.cachesetsAllSelected = true;\n            } else {\n                $scope.cachesetsAllSelected = false;\n            }\n        };\n\n        // Toggle the selection of the filesystem.\n        $scope.toggleCacheSetSelect = function(cacheset) {\n            cacheset.$selected = !cacheset.$selected;\n            $scope.updateCacheSetsSelection(true);\n        };\n\n        // Toggle the selection of all filesystems.\n        $scope.toggleCacheSetAllSelect = function() {\n            angular.forEach($scope.cachesets, function(cacheset) {\n                if($scope.cachesetsAllSelected) {\n                    cacheset.$selected = false;\n                } else {\n                    cacheset.$selected = true;\n                }\n            });\n            $scope.updateCacheSetsSelection(true);\n        };\n\n        // Return true if checkboxes in the cache sets section should be\n        // disabled.\n        $scope.isCacheSetsDisabled = function() {\n            return ((\n                $scope.isAllStorageDisabled() &&\n                !$scope.isSuperUser()) || (\n                $scope.cachesetsMode !== SELECTION_MODE.NONE &&\n                $scope.cachesetsMode !== SELECTION_MODE.SINGLE &&\n                $scope.cachesetsMode !== SELECTION_MODE.MUTLI));\n        };\n\n        // Cancel the current cache set operation.\n        $scope.cacheSetCancel = function() {\n            deselectAll($scope.cachesets);\n            $scope.updateCacheSetsSelection(true);\n        };\n\n        // Can delete the cache set.\n        $scope.canDeleteCacheSet = function(cacheset) {\n            return (cacheset.used_by === \"\" &&\n                    !$scope.isAllStorageDisabled() &&\n                    $scope.isSuperUser());\n        };\n\n        // Enter delete mode.\n        $scope.cacheSetDelete = function() {\n            $scope.cachesetsMode = SELECTION_MODE.DELETE;\n        };\n\n        // Quickly enter delete by selecting the cache set first.\n        $scope.quickCacheSetDelete = function(cacheset) {\n            deselectAll($scope.cachesets);\n            cacheset.$selected = true;\n            $scope.updateCacheSetsSelection(true);\n            $scope.cacheSetDelete();\n        };\n\n        // Confirm the delete action for cache set.\n        $scope.cacheSetConfirmDelete = function(cacheset) {\n            MachinesManager.deleteCacheSet(\n                $scope.node, cacheset.cache_set_id);\n\n            var idx = $scope.cachesets.indexOf(cacheset);\n            $scope.cachesets.splice(idx, 1);\n            $scope.updateCacheSetsSelection();\n        };\n\n        // Return true if a cache set can be created.\n        $scope.canCreateCacheSet = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var selected = $scope.getSelectedAvailable();\n            if(selected.length === 1) {\n                return (\n                    !selected[0].has_partitions &&\n                    !$scope.hasUnmountedFilesystem(selected[0]) &&\n                    selected[0].type !== \"lvm-vg\");\n            }\n            return false;\n        };\n\n        // Called to create a cache set.\n        $scope.createCacheSet = function() {\n            if(!$scope.canCreateCacheSet()) {\n                return;\n            }\n\n            // Create cache set.\n            var disk = $scope.getSelectedAvailable()[0];\n            MachinesManager.createCacheSet(\n                $scope.node, disk.block_id, disk.partition_id);\n\n            // Remove from available.\n            var idx = $scope.available.indexOf(disk);\n            $scope.available.splice(idx, 1);\n        };\n\n        // Return the reason a bcache device cannot be created.\n        $scope.getCannotCreateBcacheMsg = function() {\n            if($scope.cachesets.length === 0) {\n                return \"Create at least one cache set to create bcache\";\n            } else {\n                var selected = $scope.getSelectedAvailable();\n                if(selected.length === 1) {\n                    if($scope.hasUnmountedFilesystem(selected[0])) {\n                        return (\n                            \"Device is formatted; unformat the \" +\n                            \"device to create bcache\");\n                    } else if(selected[0].type === \"lvm-vg\") {\n                        return (\n                            \"Cannot use a logical volume as a backing \" +\n                            \"device for bcache.\");\n                    } else if(selected[0].has_partitions) {\n                        return (\n                            \"Device has already been partitioned; create a \" +\n                            \"new partition to use as the bcache backing \" +\n                            \"device\");\n                    } else {\n                        return null;\n                    }\n                } else {\n                    return \"Select only one available device to create bcache\";\n                }\n            }\n        };\n\n        // Return true if a bcache can be created.\n        $scope.canCreateBcache = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var msg = $scope.getCannotCreateBcacheMsg();\n            if(msg === null) {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Enter bcache mode.\n        $scope.createBcache = function() {\n            if(!$scope.canCreateBcache()) {\n                return;\n            }\n            $scope.availableMode = SELECTION_MODE.BCACHE;\n            $scope.availableNew = {\n                name: getNextName(\"bcache\"),\n                device: $scope.getSelectedAvailable()[0],\n                cacheset: $scope.cachesets[0],\n                cacheMode: \"writeback\",\n                fstype: null,\n                mountPoint: \"\",\n                mountOptions: \"\",\n                tags: []\n            };\n        };\n\n        // Clear mount point when the fstype is changed.\n        $scope.fstypeChanged = function(options) {\n            if(options.fstype === null) {\n                options.mountPoint = \"\";\n                options.mountOptions = \"\";\n            }\n            else {\n                // Update the mount point to \"none\" if \"swap\" is\n                // selected, and vice-versa.\n                if ($scope.usesMountPoint(options.fstype)) {\n                    if (options.mountPoint === \"none\") {\n                        options.mountPoint = \"\";\n                    }\n                }\n                else {\n                    options.mountPoint = \"none\";\n                }\n            }\n        };\n\n        // Return true when the name of the new disk is invalid.\n        $scope.isNewDiskNameInvalid = function() {\n            if(!angular.isObject($scope.node) ||\n                !angular.isArray($scope.node.disks)) {\n                return true;\n            }\n\n            if($scope.availableNew.name === \"\") {\n                return true;\n            } else {\n                var i, j;\n                for(i = 0; i < $scope.node.disks.length; i++) {\n                    var disk = $scope.node.disks[i];\n                    if($scope.availableNew.name === disk.name) {\n                        return true;\n                    }\n                    if(angular.isArray(disk.partitions)) {\n                        for(j = 0; j < disk.partitions.length; j++) {\n                            var partition = disk.partitions[j];\n                            if($scope.availableNew.name === partition.name) {\n                                return true;\n                            }\n                        }\n                    }\n                }\n            }\n            return false;\n        };\n\n        // Return true if bcache can be saved.\n        $scope.createBcacheCanSave = function() {\n            return (\n                !$scope.isNewDiskNameInvalid() &&\n                !$scope.isMountPointInvalid($scope.availableNew.mountPoint));\n        };\n\n        // Confirm and create the bcache device.\n        $scope.availableConfirmCreateBcache = function() {\n            if(!$scope.createBcacheCanSave()) {\n                return;\n            }\n\n            // Create the bcache.\n            var params = {\n                name: $scope.availableNew.name,\n                cache_set: $scope.availableNew.cacheset.cache_set_id,\n                cache_mode: $scope.availableNew.cacheMode\n            };\n            if($scope.availableNew.device.type === \"partition\") {\n                params.partition_id = $scope.availableNew.device.partition_id;\n            } else {\n                params.block_id = $scope.availableNew.device.block_id;\n            }\n            if(angular.isString($scope.availableNew.fstype) &&\n                $scope.availableNew.fstype !== \"\") {\n                params.fstype = $scope.availableNew.fstype;\n                // XXX: Inconsistent tests of mountPoint/mount_point; in\n                // places it's compared to \"\" (like here), in others\n                // it's tested with angular.isDefined(), others with\n                // angular.isString(), others angular.isString() ===\n                // false. This is *begging* for bugs.\n                if($scope.availableNew.mountPoint !== \"\") {\n                    params.mount_point = $scope.availableNew.mountPoint;\n                    params.mount_options = $scope.availableNew.mountOptions;\n                }\n            }\n            if(angular.isArray($scope.availableNew.tags)\n                && $scope.availableNew.tags.length > 0) {\n                params.tags = $scope.availableNew.tags.map(\n                    function(tag) { return tag.text; });\n            }\n            MachinesManager.createBcache($scope.node, params);\n\n            // Remove device from available.\n            var idx = $scope.available.indexOf($scope.availableNew.device);\n            $scope.available.splice(idx, 1);\n            $scope.availableNew = {};\n\n            // Update the selection.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if a RAID can be created.\n        $scope.canCreateRAID = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var selected = $scope.getSelectedAvailable();\n            if(selected.length > 1) {\n                var i;\n                for(i = 0; i < selected.length; i++) {\n                    if($scope.hasUnmountedFilesystem(selected[i])) {\n                        return false;\n                    } else if(selected[i].type === \"lvm-vg\") {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return false;\n        };\n\n        // Called to create a RAID.\n        $scope.createRAID = function() {\n            if(!$scope.canCreateRAID()) {\n                return;\n            }\n            $scope.availableMode = SELECTION_MODE.RAID;\n            $scope.availableNew = {\n                name: getNextName(\"md\"),\n                devices: $scope.getSelectedAvailable(),\n                mode: null,\n                spares: [],\n                fstype: null,\n                mountPoint: \"\",\n                mountOptions: \"\",\n                tags: []\n            };\n            $scope.availableNew.mode = $scope.getAvailableRAIDModes()[0];\n        };\n\n        // Get the available RAID modes.\n        $scope.getAvailableRAIDModes = function() {\n            if(!angular.isObject($scope.availableNew) ||\n                !angular.isArray($scope.availableNew.devices)) {\n                return [];\n            }\n\n            var modes = [];\n            angular.forEach(RAID_MODES, function(mode) {\n                if($scope.availableNew.devices.length >= mode.min_disks) {\n                    modes.push(mode);\n                }\n            });\n            return modes;\n        };\n\n        // Return the total number of available spares for the current mode.\n        $scope.getTotalNumberOfAvailableSpares = function() {\n            var mode = $scope.availableNew.mode;\n            if(angular.isUndefined(mode) || !mode.allows_spares) {\n                return 0;\n            } else {\n                var diff = $scope.availableNew.devices.length - mode.min_disks;\n                if(diff < 0) {\n                    diff = 0;\n                }\n                return diff;\n            }\n        };\n\n        // Return the number of remaining spares that can be selected.\n        $scope.getNumberOfRemainingSpares = function() {\n            var allowed = $scope.getTotalNumberOfAvailableSpares();\n            if(allowed <= 0) {\n                return 0;\n            } else {\n                return allowed - $scope.availableNew.spares.length;\n            }\n        };\n\n        // Return true if the spares column should be shown.\n        $scope.showSparesColumn = function() {\n            return $scope.getTotalNumberOfAvailableSpares() > 0;\n        };\n\n        // Called when the RAID mode is changed to reset the selected spares.\n        $scope.RAIDModeChanged = function() {\n            $scope.availableNew.spares = [];\n        };\n\n        // Return true if the disk is an active RAID member.\n        $scope.isActiveRAIDMember = function(disk) {\n            if(!angular.isArray($scope.availableNew.spares)) {\n                return true;\n            } else {\n                var idx = $scope.availableNew.spares.indexOf(\n                    getUniqueKey(disk));\n                return idx === -1;\n            }\n        };\n\n        // Return true if the disk is a spare RAID member.\n        $scope.isSpareRAIDMember = function(disk) {\n            return !$scope.isActiveRAIDMember(disk);\n        };\n\n        // Set the disk as an active RAID member.\n        $scope.setAsActiveRAIDMember = function(disk) {\n            var idx = $scope.availableNew.spares.indexOf(getUniqueKey(disk));\n            if(idx > -1) {\n                $scope.availableNew.spares.splice(idx, 1);\n            }\n        };\n\n        // Set the disk as a spare RAID member.\n        $scope.setAsSpareRAIDMember = function(disk) {\n            var key = getUniqueKey(disk);\n            var idx = $scope.availableNew.spares.indexOf(key);\n            if(idx === -1) {\n                $scope.availableNew.spares.push(key);\n            }\n        };\n\n        // Return the size of the new RAID device.\n        $scope.getNewRAIDSize = function() {\n            if(angular.isUndefined($scope.availableNew.mode)) {\n                return \"\";\n            }\n            var calculateSize = $scope.availableNew.mode.calculateSize;\n            if(!angular.isFunction(calculateSize)) {\n                return \"\";\n            }\n\n            // Get the number of disks and the minimum disk size in the RAID.\n            var numDisks = (\n                $scope.availableNew.devices.length -\n                $scope.availableNew.spares.length);\n            var minSize = Number.MAX_VALUE;\n            angular.forEach($scope.availableNew.devices, function(device) {\n                // Get the size of the device. For a block device it will be\n                // at available_size and for a partition it will be at size.\n                var deviceSize = (\n                    device.original.available_size || device.original.size);\n                minSize = Math.min(minSize, deviceSize);\n            });\n\n            // Calculate the new size.\n            var size = calculateSize(minSize, numDisks);\n            return ConverterService.bytesToUnits(size).string;\n        };\n\n        // Return true if RAID can be saved.\n        $scope.createRAIDCanSave = function() {\n            return (\n                !$scope.isNewDiskNameInvalid() &&\n                !$scope.isMountPointInvalid($scope.availableNew.mountPoint));\n        };\n\n        // Confirm and create the RAID device.\n        $scope.availableConfirmCreateRAID = function() {\n            if(!$scope.createRAIDCanSave()) {\n                return;\n            }\n\n            // Create the RAID.\n            var params = {\n                name: $scope.availableNew.name,\n                level: $scope.availableNew.mode.level,\n                block_devices: [],\n                partitions: [],\n                spare_devices: [],\n                spare_partitions: []\n            };\n            angular.forEach($scope.availableNew.devices, function(device) {\n                if($scope.isActiveRAIDMember(device)) {\n                    if(device.type === \"partition\") {\n                        params.partitions.push(device.partition_id);\n                    } else {\n                        params.block_devices.push(device.block_id);\n                    }\n                } else {\n                    if(device.type === \"partition\") {\n                        params.spare_partitions.push(device.partition_id);\n                    } else {\n                        params.spare_devices.push(device.block_id);\n                    }\n                }\n            });\n            if(angular.isString($scope.availableNew.fstype) &&\n                $scope.availableNew.fstype !== \"\") {\n                params.fstype = $scope.availableNew.fstype;\n                if($scope.availableNew.mountPoint !== \"\") {\n                    params.mount_point = $scope.availableNew.mountPoint;\n                    params.mount_options = $scope.availableNew.mountOptions;\n                }\n            }\n            if(angular.isArray($scope.availableNew.tags)\n                && $scope.availableNew.tags.length > 0) {\n                params.tags = $scope.availableNew.tags.map(\n                    function(tag) { return tag.text; });\n            }\n            MachinesManager.createRAID($scope.node, params);\n\n            // Remove devices from available.\n            angular.forEach($scope.availableNew.devices, function(device) {\n                var idx = $scope.available.indexOf($scope.availableNew.device);\n                $scope.available.splice(idx, 1);\n            });\n            $scope.availableNew = {};\n\n            // Update the selection.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if a volume group can be created.\n        $scope.canCreateVolumeGroup = function() {\n            if($scope.isAvailableDisabled() || !$scope.isSuperUser()) {\n                return false;\n            }\n\n            var selected = $scope.getSelectedAvailable();\n            if(selected.length > 0) {\n                var i;\n                for(i = 0; i < selected.length; i++) {\n                    if(selected[i].has_partitions) {\n                        return false;\n                    } else if($scope.hasUnmountedFilesystem(selected[i])) {\n                        return false;\n                    } else if(selected[i].type === \"lvm-vg\") {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return false;\n        };\n\n        // Called to create a volume group.\n        $scope.createVolumeGroup = function() {\n            if(!$scope.canCreateVolumeGroup()) {\n                return;\n            }\n            $scope.availableMode = SELECTION_MODE.VOLUME_GROUP;\n            $scope.availableNew = {\n                name: getNextName(\"vg\"),\n                devices: $scope.getSelectedAvailable()\n            };\n        };\n\n        // Return the size of the new volume group.\n        $scope.getNewVolumeGroupSize = function() {\n            var total = 0;\n            angular.forEach($scope.availableNew.devices, function(device) {\n                // Add available_size or size if available_size is not set.\n                total += (\n                    device.original.available_size || device.original.size);\n            });\n            return ConverterService.bytesToUnits(total).string;\n        };\n\n        // Return true if volume group can be saved.\n        $scope.createVolumeGroupCanSave = function() {\n            return !$scope.isNewDiskNameInvalid();\n        };\n\n        // Confirm and create the volume group device.\n        $scope.availableConfirmCreateVolumeGroup = function() {\n            if(!$scope.createVolumeGroupCanSave()) {\n                return;\n            }\n\n            // Create the RAID.\n            var params = {\n                name: $scope.availableNew.name,\n                block_devices: [],\n                partitions: []\n            };\n            angular.forEach($scope.availableNew.devices, function(device) {\n                if(device.type === \"partition\") {\n                    params.partitions.push(device.partition_id);\n                } else {\n                    params.block_devices.push(device.block_id);\n                }\n            });\n            MachinesManager.createVolumeGroup($scope.node, params);\n\n            // Remove devices from available.\n            angular.forEach($scope.availableNew.devices, function(device) {\n                var idx = $scope.available.indexOf($scope.availableNew.device);\n                $scope.available.splice(idx, 1);\n            });\n            $scope.availableNew = {};\n\n            // Update the selection.\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Return true if a logical volume can be added to disk.\n        $scope.canAddLogicalVolume = function(disk) {\n            if(disk.type !== \"lvm-vg\") {\n                return false;\n            } else if(disk.original.available_size < MIN_PARTITION_SIZE) {\n                return false;\n            } else {\n                return true;\n            }\n        };\n\n        // Enter logical volume mode.\n        $scope.availableLogicalVolume = function(disk) {\n            $scope.availableMode = SELECTION_MODE.LOGICAL_VOLUME;\n            disk.$selected = true;\n            // Set starting size to the maximum available space.\n            var size_and_units = disk.available_size_human.split(\" \");\n            var namePrefix = disk.name + \"-lv\";\n            disk.$options = {\n                name: getNextName(namePrefix),\n                size: size_and_units[0],\n                sizeUnits: size_and_units[1],\n                fstype: null,\n                tags: []\n            };\n        };\n\n        // Return true if the name of the logical volume is invalid.\n        $scope.isLogicalVolumeNameInvalid = function(disk) {\n            if(!angular.isString(disk.$options.name)) {\n                return false;\n            }\n            var startsWith = disk.$options.name.indexOf(disk.name + \"-\");\n            return (\n                startsWith !== 0 ||\n                disk.$options.name.length <= disk.name.length + 1 ||\n                isNameAlreadyInUse(disk.$options.name));\n        };\n\n        // Don't allow the name of the logical volume to remove the volume\n        // group name.\n        $scope.newLogicalVolumeNameChanged = function(disk) {\n            if(!angular.isString(disk.$options.name)) {\n                return;\n            }\n            var startsWith = disk.$options.name.indexOf(disk.name + \"-\");\n            if(startsWith !== 0) {\n                disk.$options.name = disk.name + \"-\";\n            }\n        };\n\n        // Return true if the logical volume size is invalid.\n        $scope.isAddLogicalVolumeSizeInvalid = function(disk) {\n            // Uses the same logic as the partition size checked.\n            return $scope.isAddPartitionSizeInvalid(disk);\n        };\n\n        // Confirm the logical volume creation.\n        $scope.availableConfirmLogicalVolume = function(disk) {\n            // Do nothing if not valid.\n            if($scope.isLogicalVolumeNameInvalid(disk) ||\n                $scope.isAddLogicalVolumeSizeInvalid(disk) ||\n                $scope.isMountPointInvalid(disk.$options.mountPoint)) {\n                return;\n            }\n\n            // Get the bytes to create the partition.\n            var bytes = ConverterService.unitsToBytes(\n                disk.$options.size, disk.$options.sizeUnits);\n\n            // Accepting prefilled defaults means use whole disk (lp:1509535).\n            var size_and_units = disk.original.available_size_human.split(\" \");\n            if(disk.$options.size === size_and_units[0] &&\n               disk.$options.sizeUnits === size_and_units[1]) {\n                bytes = disk.original.available_size;\n            }\n\n            // Clamp to available space.\n            if(bytes > disk.original.available_size) {\n                bytes = disk.original.available_size;\n            }\n\n            // Remove the disk if it is going to use all the remaining space.\n            var removeDisk = false;\n            if(bytes === disk.original.available_size) {\n                removeDisk = true;\n            }\n\n            // Remove the volume group name from the name.\n            var name = disk.$options.name.slice(disk.name.length + 1);\n\n            // Create the logical volume.\n            var params = {};\n            if(angular.isString(disk.$options.fstype) &&\n                disk.$options.fstype !== \"\") {\n                params.fstype = disk.$options.fstype;\n                if(disk.$options.mountPoint !== \"\") {\n                    params.mount_point = disk.$options.mountPoint;\n                    params.mount_options = disk.$options.mountOptions;\n                }\n            }\n            if(angular.isArray(disk.$options.tags)\n                && disk.$options.tags.length > 0) {\n                params.tags = disk.$options.tags.map(\n                    function(tag) { return tag.text; });\n            }\n            MachinesManager.createLogicalVolume(\n                $scope.node, disk.block_id, name, bytes, params);\n\n            // Remove the disk if needed.\n            if(removeDisk) {\n                var idx = $scope.available.indexOf(disk);\n                $scope.available.splice(idx, 1);\n            }\n            $scope.updateAvailableSelection(true);\n        };\n\n        // Returns true if storage cannot be edited.\n        // (it can't be changed when the node is in any state other\n        //  than Ready or Allocated)\n        $scope.isAllStorageDisabled = function() {\n            var authUser = UsersManager.getAuthUser();\n            if(!angular.isObject(authUser) || !angular.isObject($scope.node) ||\n                (!authUser.is_superuser &&\n                 authUser.username !== $scope.node.owner)) {\n                return true;\n            }else if (angular.isObject($scope.node) &&\n                [\"Ready\", \"Allocated\"].indexOf(\n                    $scope.node.status) === -1) {\n                // If the node is not ready or allocated, disable storage panel.\n                return true;\n            } else {\n                // The node must be either ready or broken. Enable it.\n                return false;\n            }\n        };\n\n        // Returns true if there are storage layout errors\n        $scope.hasStorageLayoutIssues = function() {\n            if(angular.isObject($scope.node) &&\n                angular.isArray($scope.node.storage_layout_issues)) {\n                return $scope.node.storage_layout_issues.length > 0;\n            }\n            return false;\n        };\n\n        // Tell $parent that the storageController has been loaded.\n        $scope.$parent.controllerLoaded('storageController', $scope);\n    }]);\n","/*\n * Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Manage a node's filesystems, including adding special filesystems.\n */\n\n(function() {\n\n    function SpecialFilesystem() {\n        this.fstype = \"tmpfs\";\n        this.mountPoint = \"\";\n        this.mountOptions = \"\";\n    }\n\n    SpecialFilesystem.prototype.isValid = function() {\n        return this.mountPoint.startsWith(\"/\");\n    };\n\n    SpecialFilesystem.prototype.describe = function() {\n        var parts = [this.fstype];\n        // Add the mount point if specified and valid.\n        if (this.mountPoint.startsWith(\"/\")) {\n            parts.push(\"at \" + this.mountPoint);\n        }\n        // Filesystem-specific bits.\n        switch (this.fstype) {\n        case \"tmpfs\":\n            // Extract size=n parameter from mount options. Other\n            // options could be added in the future.\n            var size = this.mountOptions.match(/\\bsize=(\\d+)(%?)/);\n            if (size !== null) {\n                if (size[2] === \"%\") {\n                    parts.push(\"limited to \" + size[1] + \"% of memory\");\n                } else {\n                    parts.push(\"limited to \" + size[1] + \" bytes\");\n                }\n            }\n            break;\n        case \"ramfs\":\n            // This filesystem does not recognise any options. Consider\n            // warning about lack of a size limit.\n            break;\n        }\n        return parts.join(\" \");\n    };\n\n    function NodeFilesystemsController($scope) {\n\n        // Which drop-down is currently selected, e.g. \"special\".\n        $scope.dropdown = null;\n\n        // Select the \"special\" drop-down.\n        $scope.addSpecialFilesystem = function() {\n            $scope.dropdown = \"special\";\n        };\n\n        // Deselect the \"special\" drop-down.\n        $scope.addSpecialFilesystemFinished = function() {\n            if ($scope.dropdown === \"special\") {\n                $scope.dropdown = null;\n            }\n        };\n    }\n\n    function NodeAddSpecialFilesystemController($scope, MachinesManager) {\n\n        $scope.filesystem = new SpecialFilesystem();\n        $scope.description = null;  // Updated by watch.\n\n        $scope.$watch(\"filesystem\", function(filesystem) {\n            $scope.description = filesystem.describe();\n        }, true);\n\n        $scope.canMount = function() {\n            return $scope.filesystem.isValid();\n        };\n\n        $scope.mount = function() {\n            MachinesManager.mountSpecialFilesystem(\n                $scope.node, $scope.filesystem.fstype,\n                $scope.filesystem.mountPoint,\n                $scope.filesystem.mountOptions);\n            $scope.addSpecialFilesystemFinished();\n        };\n\n        $scope.cancel = function() {\n            $scope.filesystem = new SpecialFilesystem();\n            $scope.addSpecialFilesystemFinished();\n        };\n    }\n\n    angular.module(\"MAAS\").controller(\n        \"NodeFilesystemsController\", [\n            \"$scope\", NodeFilesystemsController\n        ]);\n\n    angular.module(\"MAAS\").controller(\n        \"NodeAddSpecialFilesystemController\", [\n            \"$scope\", \"MachinesManager\",\n            NodeAddSpecialFilesystemController\n        ]);\n\n}());\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Events Controller\n */\n\nangular.module('MAAS').controller('NodeEventsController', [\n    '$scope', '$rootScope', '$routeParams',\n    'MachinesManager', 'ControllersManager', 'EventsManagerFactory',\n    'ManagerHelperService', 'ErrorService', function($scope, $rootScope,\n        $routeParams, MachinesManager, ControllersManager, EventsManagerFactory,\n        ManagerHelperService, ErrorService) {\n\n        // Events manager that is loaded once the node is loaded.\n        var eventsManager = null;\n\n        // Set the title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"nodes\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.node = null;\n        $scope.events = [];\n        $scope.eventsLoaded = false;\n        $scope.days = 1;\n\n        // Called once the node is loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n\n            // Get the events manager and load it.\n            eventsManager = EventsManagerFactory.getManager(node.id);\n            $scope.events = eventsManager.getItems();\n            $scope.days = eventsManager.getMaximumDays();\n            eventsManager.loadItems().then(function() {\n                $scope.eventsLoaded = true;\n            });\n\n            // Update the title when the fqdn of the node changes.\n            $scope.$watch(\"node.fqdn\", function() {\n                $rootScope.title = $scope.node.fqdn + \" - events\";\n            });\n        }\n\n        // Return the nice text for the given event.\n        $scope.getEventText = function(event) {\n            var text = event.type.description;\n            if(angular.isString(event.description) &&\n                event.description.length > 0) {\n                text += \" - \" + event.description;\n            }\n            return text;\n        };\n\n        // Called to load more events.\n        $scope.loadMore = function() {\n            $scope.days += 1;\n            eventsManager.loadMaximumDays($scope.days);\n        };\n\n        if($routeParams.type === 'controller') {\n            $scope.nodesManager = ControllersManager;\n            $scope.type_name = 'controller';\n        }else{\n            $scope.nodesManager = MachinesManager;\n            $scope.type_name = 'machine';\n        }\n        // Load nodes manager.\n        ManagerHelperService.loadManager(\n            $scope, $scope.nodesManager).then(function() {\n            // If redirected from the NodeDetailsController then the node\n            // will already be active. No need to set it active again.\n            var activeNode = $scope.nodesManager.getActiveItem();\n            if(angular.isObject(activeNode) &&\n                activeNode.system_id === $routeParams.system_id) {\n                nodeLoaded(activeNode);\n            } else {\n                $scope.nodesManager.setActiveItem(\n                    $routeParams.system_id).then(function(node) {\n                        nodeLoaded(node);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n\n        // Destroy the events manager when the scope is destroyed. This is so\n        // the client will not recieve any more notifications about events\n        // for this node.\n        $scope.$on(\"$destroy\", function() {\n            if(angular.isObject(eventsManager)) {\n                eventsManager.destroy();\n            }\n        });\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Script Result Controller\n */\n\nangular.module('MAAS').controller('NodeResultController', [\n    '$scope', '$rootScope', '$routeParams', '$location',\n    'MachinesManager', 'ControllersManager', 'NodeResultsManagerFactory',\n    'ManagerHelperService', 'ErrorService',\n    function($scope, $rootScope, $routeParams, $location, MachinesManager,\n             ControllersManager, NodeResultsManagerFactory,\n             ManagerHelperService, ErrorService) {\n        // Set the title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"nodes\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.resultLoaded = false;\n        $scope.node = null;\n        $scope.output = 'combined';\n        $scope.result = null;\n\n        $scope.get_result_data = function(output) {\n            $scope.output = output;\n            $scope.data = \"Loading...\";\n            var nodeResultsManager = NodeResultsManagerFactory.getManager(\n                $scope.node);\n            nodeResultsManager.get_result_data(\n                $scope.result.id, $scope.output).then(\n                    function(data) {\n                        if(data === '') {\n                            $scope.data = \"Empty file.\";\n                        }else{\n                            $scope.data = data;\n                        }\n                    });\n        };\n\n        // Called once the node is loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n\n            // Get the NodeResultsManager and load it.\n            var nodeResultsManager = NodeResultsManagerFactory.getManager(\n                $scope.node);\n            var requestedResult = parseInt($routeParams.id, 10);\n            nodeResultsManager.getItem(requestedResult).then(function(result) {\n                $scope.result = result;\n                $scope.get_result_data($scope.output);\n                $scope.resultLoaded = true;\n                $rootScope.title = $scope.node.fqdn + \" - \" +\n                    $scope.result.name;\n            });\n        }\n\n        // Update the title when the fqdn of the node changes.\n        $scope.$watch(\"node.fqdn\", function() {\n            if(angular.isObject($scope.node) &&\n               angular.isObject($scope.result)) {\n                $rootScope.title = $scope.node.fqdn + \" - \" +\n                    $scope.result.name;\n            }\n        });\n\n        if($routeParams.type === 'controller') {\n            $scope.nodesManager = ControllersManager;\n            $scope.type_name = 'controller';\n        }else{\n            $scope.nodesManager = MachinesManager;\n            $scope.type_name = 'machine';\n        }\n        // Load nodes manager.\n        ManagerHelperService.loadManager(\n            $scope, $scope.nodesManager).then(function() {\n            // If redirected from the NodeDetailsController then the node\n            // will already be active. No need to set it active again.\n            var activeNode = $scope.nodesManager.getActiveItem();\n            if(angular.isObject(activeNode) &&\n                activeNode.system_id === $routeParams.system_id) {\n                nodeLoaded(activeNode);\n            } else {\n                $scope.nodesManager.setActiveItem(\n                    $routeParams.system_id).then(function(node) {\n                        nodeLoaded(node);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n\n        // Destroy the NodeResultsManager when the scope is destroyed. This is\n        // so the client will not recieve any more notifications about results\n        // from this node.\n        $scope.$on(\"$destroy\", function() {\n            var nodeResultsManager = NodeResultsManagerFactory.getManager(\n                $scope.node);\n            if(angular.isObject(nodeResultsManager)) {\n                nodeResultsManager.destroy();\n            }\n        });\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Node Results Controller\n */\n\nangular.module('MAAS').controller('NodeResultsController', [\n    '$scope', '$routeParams', 'MachinesManager', 'ControllersManager',\n    'NodeResultsManagerFactory', 'ManagerHelperService', 'ErrorService',\n    function($scope, $routeParams, MachinesManager, ControllersManager,\n             NodeResultsManagerFactory, ManagerHelperService, ErrorService) {\n\n        // NodeResultsManager that is loaded once the node is loaded.\n        $scope.nodeResultsManager = null;\n        // References to manager data used in scope.\n        $scope.commissioning_results = null;\n        $scope.testing_results = null;\n        $scope.installation_results = null;\n        $scope.results = null;\n\n        // List of logs available.\n        $scope.logs = {\n            option: null,\n            availableOptions: []\n        };\n        // Log content being displayed.\n        $scope.logOutput = 'Loading...';\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.resultsLoaded = false;\n        $scope.node = null;\n\n        function updateLogs() {\n            var i;\n            var option;\n            var had_installation = $scope.logs.availableOptions.length === 3;\n            $scope.logs.availableOptions.length = 0;\n            // XXX ltrager 2017-12-01 - Only show the current installation log\n            // if the machine is deploying, deployed, or failed deploying. The\n            // logs page needs to be redesigned to show previous installation\n            // results.\n            if($scope.installation_results &&\n                    $scope.installation_results.length > 0 && (\n                        $scope.node.status_code === 6 ||\n                        $scope.node.status_code === 9 ||\n                        $scope.node.status_code === 11)) {\n                $scope.logs.availableOptions.push({\n                    'title': 'Installation output',\n                    'id': $scope.installation_results[0].id\n                });\n            }\n            $scope.logs.availableOptions.push({\n                'title': 'Machine output (YAML)',\n                'id': 'summary_yaml'\n            });\n            $scope.logs.availableOptions.push({\n                'title': 'Machine output (XML)',\n                'id': 'summary_xml'\n            });\n            if(!had_installation &&\n               $scope.logs.availableOptions.length === 3) {\n                // A new installation log has appeared, show it.\n                $scope.logs.option = $scope.logs.availableOptions[0];\n            }else if(!$scope.selectedLog || (\n                had_installation && $scope.logs.length === 2)) {\n                // No longer in a deployed state.\n                $scope.logs.option = $scope.logs.availableOptions[0];\n            }\n        }\n\n        // Called once the node has loaded.\n        function nodeLoaded(node) {\n            $scope.node = node;\n            $scope.loaded = true;\n            // Get the NodeResultsManager and load it.\n            $scope.nodeResultsManager = NodeResultsManagerFactory.getManager(\n                node, $scope.section.area);\n            $scope.nodeResultsManager.loadItems().then(function() {\n                $scope.commissioning_results =\n                    $scope.nodeResultsManager.commissioning_results;\n                $scope.testing_results =\n                    $scope.nodeResultsManager.testing_results;\n                $scope.installation_results =\n                    $scope.nodeResultsManager.installation_results;\n                $scope.results = $scope.nodeResultsManager.results;\n                // Only load and monitor logs when on the logs page.\n                if($scope.section.area === \"logs\") {\n                    updateLogs();\n                    $scope.$watch(\"installation_results\", updateLogs, true);\n                    $scope.$watch(\n                        \"installation_results\", $scope.updateLogOutput, true);\n                }\n                $scope.resultsLoaded = true;\n            });\n        }\n\n        if($routeParams.type === 'controller') {\n            $scope.nodesManager = ControllersManager;\n        } else {\n            $scope.nodesManager = MachinesManager;\n        }\n        // Load nodes manager.\n        ManagerHelperService.loadManager(\n            $scope, $scope.nodesManager).then(function() {\n                // If redirected from the NodeDetailsController then the node\n                // will already be active. No need to set it active again.\n                var activeNode = $scope.nodesManager.getActiveItem();\n                if(angular.isObject(activeNode) &&\n                   activeNode.system_id === $routeParams.system_id) {\n                    nodeLoaded(activeNode);\n                } else {\n                    $scope.nodesManager.setActiveItem(\n                        $routeParams.system_id).then(function(node) {\n                            nodeLoaded(node);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                }\n            });\n\n        $scope.updateLogOutput = function() {\n            $scope.logOutput = \"Loading...\";\n            if(!$scope.node) {\n                return;\n            }else if($scope.logs.option.id === 'summary_xml') {\n                $scope.nodesManager.getSummaryXML($scope.node).then(\n                    function(output) {\n                        $scope.logOutput = output;\n                    });\n            }else if($scope.logs.option.id === 'summary_yaml') {\n                $scope.nodesManager.getSummaryYAML($scope.node).then(\n                    function(output) {\n                        $scope.logOutput = output;\n                    });\n            } else {\n                var result = null;\n                var i, j;\n                // Find the installation result to be displayed.\n                for(i = 0; i < $scope.installation_results.length; i++) {\n                    var hlist = $scope.installation_results[i].history_list;\n                    for(j = 0; j < hlist.length; j++) {\n                        if(hlist[j].id === $scope.logs.option.id) {\n                            result = hlist[j];\n                            break;\n                        }\n                    }\n                    if(result) {\n                        break;\n                    }\n                }\n                switch(result.status) {\n                    case 0:\n                        $scope.logOutput = \"System is booting...\";\n                        break;\n                    case 1:\n                        $scope.logOutput = \"Installation has begun!\";\n                        break;\n                    case 2:\n                        $scope.nodeResultsManager.get_result_data(\n                            result.id, 'combined').then(function(output) {\n                                if(output === '') {\n                                    $scope.logOutput =\n                                        \"Installation has succeeded but \" +\n                                        \"no output was given.\";\n                                } else {\n                                    $scope.logOutput = output;\n                                }\n                            });\n                        break;\n                    case 3:\n                        $scope.nodeResultsManager.get_result_data(\n                            result.id, 'combined').then(function(output) {\n                                if(output === '') {\n                                    $scope.logOutput =\n                                        \"Installation has failed and no \" +\n                                        \"output was given.\";\n                                } else {\n                                    $scope.logOutput = output;\n                                }\n                            });\n                        break;\n                    case 4:\n                        $scope.logOutput =\n                            \"Installation failed after 40 minutes.\";\n                        break;\n                    case 5:\n                        $scope.logOutput = \"Installation was aborted.\";\n                        break;\n                    default:\n                        $scope.logOutput = \"BUG: Unknown log status \" +\n                            result.status;\n                        break;\n                }\n            }\n        };\n\n        // Destroy the NodeResultsManager when the scope is destroyed. This is\n        // so the client will not recieve any more notifications about results\n        // from this node.\n        $scope.$on(\"$destroy\", function() {\n            if(angular.isObject($scope.nodeResultsManager)) {\n                $scope.nodeResultsManager.destroy();\n            }\n        });\n    }]);\n","/* Copyright 2015-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes List Controller\n */\n\nangular.module('MAAS').controller('NodesListController', [\n    '$scope', '$interval', '$rootScope', '$routeParams', '$location',\n    'MachinesManager', 'DevicesManager', 'ControllersManager',\n    'GeneralManager', 'ManagerHelperService', 'SearchService',\n    'ZonesManager', 'UsersManager', 'ServicesManager', 'ScriptsManager',\n    'SwitchesManager',\n    function($scope, $interval, $rootScope, $routeParams, $location,\n        MachinesManager, DevicesManager, ControllersManager, GeneralManager,\n        ManagerHelperService, SearchService, ZonesManager, UsersManager,\n        ServicesManager, ScriptsManager, SwitchesManager) {\n\n        // Mapping of device.ip_assignment to viewable text.\n        var DEVICE_IP_ASSIGNMENT = {\n            external: \"External\",\n            dynamic: \"Dynamic\",\n            \"static\": \"Static\"\n        };\n\n        // Set title and page.\n        $rootScope.title = \"Nodes\";\n        $rootScope.page = \"nodes\";\n\n        // Set initial values.\n        $scope.nodes = MachinesManager.getItems();\n        $scope.zones = ZonesManager.getItems();\n        $scope.devices = DevicesManager.getItems();\n        $scope.controllers = ControllersManager.getItems();\n        $scope.switches = SwitchesManager.getItems();\n        $scope.showswitches = $routeParams.switches === 'on';\n        $scope.currentpage = \"nodes\";\n        $scope.osinfo = GeneralManager.getData(\"osinfo\");\n        $scope.scripts = ScriptsManager.getItems();\n        $scope.loading = true;\n\n        $scope.tabs = {};\n        // Nodes tab.\n        $scope.tabs.nodes = {};\n        $scope.tabs.nodes.pagetitle = \"Machines\";\n        $scope.tabs.nodes.currentpage = \"nodes\";\n        $scope.tabs.nodes.manager = MachinesManager;\n        $scope.tabs.nodes.previous_search = \"\";\n        $scope.tabs.nodes.search = \"\";\n        $scope.tabs.nodes.searchValid = true;\n        $scope.tabs.nodes.selectedItems = MachinesManager.getSelectedItems();\n        $scope.tabs.nodes.metadata = MachinesManager.getMetadata();\n        $scope.tabs.nodes.filters = SearchService.getEmptyFilter();\n        $scope.tabs.nodes.actionOption = null;\n        $scope.tabs.nodes.takeActionOptions = GeneralManager.getData(\n            \"machine_actions\");\n        $scope.tabs.nodes.actionErrorCount = 0;\n        $scope.tabs.nodes.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.nodes.osSelection = {\n            osystem: null,\n            release: null,\n            hwe_kernel: null\n        };\n        $scope.tabs.nodes.zoneSelection = null;\n        $scope.tabs.nodes.commissionOptions = {\n            enableSSH: false,\n            skipNetworking: false,\n            skipStorage: false,\n            updateFirmware: false,\n            configureHBA: false\n        };\n        $scope.tabs.nodes.releaseOptions = {};\n        $scope.tabs.nodes.commissioningSelection = [];\n        $scope.tabs.nodes.testSelection = [];\n\n        // Device tab.\n        $scope.tabs.devices = {};\n        $scope.tabs.devices.pagetitle = \"Devices\";\n        $scope.tabs.devices.currentpage = \"devices\";\n        $scope.tabs.devices.manager = DevicesManager;\n        $scope.tabs.devices.previous_search = \"\";\n        $scope.tabs.devices.search = \"\";\n        $scope.tabs.devices.searchValid = true;\n        $scope.tabs.devices.selectedItems = DevicesManager.getSelectedItems();\n        $scope.tabs.devices.filtered_items = [];\n        $scope.tabs.devices.predicate = 'fqdn';\n        $scope.tabs.devices.allViewableChecked = false;\n        $scope.tabs.devices.metadata = DevicesManager.getMetadata();\n        $scope.tabs.devices.filters = SearchService.getEmptyFilter();\n        $scope.tabs.devices.column = 'fqdn';\n        $scope.tabs.devices.actionOption = null;\n        $scope.tabs.devices.takeActionOptions = GeneralManager.getData(\n            \"device_actions\");\n        $scope.tabs.devices.actionErrorCount = 0;\n        $scope.tabs.devices.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.devices.zoneSelection = null;\n\n        // Controller tab.\n        $scope.tabs.controllers = {};\n        $scope.tabs.controllers.pagetitle = \"Controllers\";\n        $scope.tabs.controllers.currentpage = \"controllers\";\n        $scope.tabs.controllers.manager = ControllersManager;\n        $scope.tabs.controllers.previous_search = \"\";\n        $scope.tabs.controllers.search = \"\";\n        $scope.tabs.controllers.searchValid = true;\n        $scope.tabs.controllers.selectedItems =\n            ControllersManager.getSelectedItems();\n        $scope.tabs.controllers.filtered_items = [];\n        $scope.tabs.controllers.predicate = 'fqdn';\n        $scope.tabs.controllers.allViewableChecked = false;\n        $scope.tabs.controllers.metadata = ControllersManager.getMetadata();\n        $scope.tabs.controllers.filters = SearchService.getEmptyFilter();\n        $scope.tabs.controllers.column = 'fqdn';\n        $scope.tabs.controllers.actionOption = null;\n        // Rack controllers contain all options\n        $scope.tabs.controllers.takeActionOptions = GeneralManager.getData(\n            \"rack_controller_actions\");\n        $scope.tabs.controllers.actionErrorCount = 0;\n        $scope.tabs.controllers.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.controllers.zoneSelection = null;\n        $scope.tabs.controllers.syncStatuses = {};\n        $scope.tabs.controllers.addController = false;\n        $scope.tabs.controllers.registerUrl = MAAS_config.register_url;\n        $scope.tabs.controllers.registerSecret = MAAS_config.register_secret;\n\n        // Switch tab.\n        $scope.tabs.switches = {};\n        $scope.tabs.switches.pagetitle = \"Switches\";\n        $scope.tabs.switches.currentpage = \"switches\";\n        $scope.tabs.switches.manager = SwitchesManager;\n        $scope.tabs.switches.previous_search = \"\";\n        $scope.tabs.switches.search = \"\";\n        $scope.tabs.switches.searchValid = true;\n        $scope.tabs.switches.selectedItems = SwitchesManager.getSelectedItems();\n        $scope.tabs.switches.predicate = 'fqdn';\n        $scope.tabs.switches.allViewableChecked = false;\n        $scope.tabs.switches.metadata = SwitchesManager.getMetadata();\n        $scope.tabs.switches.filters = SearchService.getEmptyFilter();\n        $scope.tabs.switches.column = 'fqdn';\n        $scope.tabs.switches.actionOption = null;\n        // XXX: Which actions should there be?\n        $scope.tabs.switches.takeActionOptions = GeneralManager.getData(\n            \"machine_actions\");\n        $scope.tabs.switches.actionErrorCount = 0;\n        $scope.tabs.switches.actionProgress = {\n            total: 0,\n            completed: 0,\n            errors: {},\n            showing_confirmation: false,\n            affected_nodes: 0\n        };\n        $scope.tabs.switches.osSelection = {\n            osystem: null,\n            release: null,\n            hwe_kernel: null\n        };\n        $scope.tabs.switches.zoneSelection = null;\n        $scope.tabs.switches.commissioningSelection = [];\n        $scope.tabs.switches.commissionOptions = {\n            enableSSH: false,\n            skipNetworking: false,\n            skipStorage: false,\n            updateFirmware: false,\n            configureHBA: false\n        };\n        $scope.tabs.switches.releaseOptions = {};\n\n\n        // Options for add hardware dropdown.\n        $scope.addHardwareOption = null;\n        $scope.addHardwareOptions = [\n            {\n                name: \"machine\",\n                title: \"Machine\"\n            },\n            {\n                name: \"chassis\",\n                title: \"Chassis\"\n            }\n        ];\n\n        // This will hold the AddHardwareController once it is initialized.\n        // The controller will set this variable as it's always a child of\n        // this scope.\n        $scope.addHardwareScope = null;\n\n        // This will hold the AddDeviceController once it is initialized.\n        // The controller will set this variable as it's always a child of\n        // this scope.\n        $scope.addDeviceScope = null;\n\n        // When the addHardwareScope is hidden it will emit this event. We\n        // clear the call to action button, so it can be used again.\n        $scope.$on(\"addHardwareHidden\", function() {\n            $scope.addHardwareOption = null;\n        });\n\n        // Return true if the tab is in viewing selected mode.\n        function isViewingSelected(tab) {\n            var search = $scope.tabs[tab].search.toLowerCase();\n            return search === \"in:(selected)\" || search === \"in:selected\";\n        }\n\n        // Sets the search bar to only show selected.\n        function enterViewSelected(tab) {\n            $scope.tabs[tab].previous_search = $scope.tabs[tab].search;\n            $scope.tabs[tab].search = \"in:(Selected)\";\n        }\n\n        // Clear search bar from viewing selected.\n        function leaveViewSelected(tab) {\n            if(isViewingSelected(tab)) {\n                $scope.tabs[tab].search = $scope.tabs[tab].previous_search;\n                $scope.updateFilters(tab);\n            }\n        }\n\n        // Called to update `allViewableChecked`.\n        function updateAllViewableChecked(tab) {\n            // Not checked when the filtered nodes are empty.\n            if($scope.tabs[tab].filtered_items.length === 0) {\n                $scope.tabs[tab].allViewableChecked = false;\n                return;\n            }\n\n            // Loop through all filtered nodes and see if all are checked.\n            var i;\n            for(i = 0; i < $scope.tabs[tab].filtered_items.length; i++) {\n                if(!$scope.tabs[tab].filtered_items[i].$selected) {\n                    $scope.tabs[tab].allViewableChecked = false;\n                    return;\n                }\n            }\n            $scope.tabs[tab].allViewableChecked = true;\n        }\n\n        function clearAction(tab) {\n            resetActionProgress(tab);\n            leaveViewSelected(tab);\n            $scope.tabs[tab].actionOption = null;\n            $scope.tabs[tab].zoneSelection = null;\n            if(tab === \"nodes\" || tab === \"switches\") {\n                // Possible for this to be called before the osSelect\n                // direction is initialized. In that case it has not\n                // created the $reset function on the model object.\n                if(angular.isFunction(\n                    $scope.tabs[tab].osSelection.$reset)) {\n                    $scope.tabs[tab].osSelection.$reset();\n                }\n                $scope.tabs[tab].commissionOptions.enableSSH = false;\n                $scope.tabs[tab].commissionOptions.skipNetworking = false;\n                $scope.tabs[tab].commissionOptions.skipStorage = false;\n                $scope.tabs[tab].commissionOptions.updateFirmware = false;\n                $scope.tabs[tab].commissionOptions.configureHBA = false;\n            }\n            $scope.tabs[tab].commissioningSelection = [];\n            $scope.tabs[tab].testSelection = [];\n        }\n\n        // Clear the action if required.\n        function shouldClearAction(tab) {\n            if($scope.tabs[tab].selectedItems.length === 0) {\n                clearAction(tab);\n            }\n            if($scope.tabs[tab].actionOption && !isViewingSelected(tab)) {\n                $scope.tabs[tab].actionOption = null;\n            }\n        }\n\n        // Called when the filtered_items are updated. Checks if the\n        // filtered_items are empty and if the search still matches the\n        // previous search. This will reset the search when no nodes match\n        // the current filter.\n        function removeEmptyFilter(tab) {\n            if($scope.tabs[tab].filtered_items.length === 0 &&\n                $scope.tabs[tab].search !== \"\" &&\n                $scope.tabs[tab].search === $scope.tabs[tab].previous_search) {\n                $scope.tabs[tab].search = \"\";\n                $scope.updateFilters(tab);\n            }\n        }\n\n        // Update the number of selected items which have an error based on the\n        // current selected action.\n        function updateActionErrorCount(tab) {\n            var i;\n            $scope.tabs[tab].actionErrorCount = 0;\n            for(i = 0; i < $scope.tabs[tab].selectedItems.length; i++) {\n                var supported = $scope.supportsAction(\n                    $scope.tabs[tab].selectedItems[i], tab);\n                if(!supported) {\n                    $scope.tabs[tab].actionErrorCount += 1;\n                }\n                $scope.tabs[tab].selectedItems[i].action_failed = false;\n            }\n        }\n\n        // Reset actionProgress on tab to zero.\n        function resetActionProgress(tab) {\n            var progress = $scope.tabs[tab].actionProgress;\n            progress.completed = progress.total = 0;\n            progress.errors = {};\n            progress.showing_confirmation = false;\n            progress.affected_nodes = 0;\n        }\n\n        // Add error to action progress and group error messages by nodes.\n        function addErrorToActionProgress(tab, error, node) {\n            var progress = $scope.tabs[tab].actionProgress;\n            progress.completed += 1;\n            var nodes = progress.errors[error];\n            if(angular.isUndefined(nodes)) {\n                progress.errors[error] = [node];\n            } else {\n                nodes.push(node);\n            }\n        }\n\n        // After an action has been performed check if we can leave all nodes\n        // selected or if an error occured and we should only show the failed\n        // nodes.\n        function updateSelectedItems(tab) {\n            if(!$scope.hasActionsFailed(tab)) {\n                if(!$scope.hasActionsInProgress(tab)) {\n                     clearAction(tab);\n                     enterViewSelected(tab);\n                }\n                return;\n            }\n            angular.forEach($scope.tabs[tab].manager.getItems(),\n                    function(node) {\n                if(node.action_failed === false) {\n                    $scope.tabs[tab].manager.unselectItem(node.system_id);\n                }\n            });\n        }\n\n        // Toggles between the current tab.\n        $scope.toggleTab = function(tab) {\n            $rootScope.title = $scope.tabs[tab].pagetitle;\n            $scope.currentpage = tab;\n            $location.search('tab', tab);\n        };\n\n        // Clear the search bar.\n        $scope.clearSearch = function(tab) {\n            $scope.tabs[tab].search = \"\";\n            $scope.updateFilters(tab);\n        };\n\n        // Mark a node as selected or unselected.\n        $scope.toggleChecked = function(node, tab) {\n            if(tab !== 'nodes' && tab !== 'switches') {\n                if($scope.tabs[tab].manager.isSelected(node.system_id)) {\n                    $scope.tabs[tab].manager.unselectItem(node.system_id);\n                } else {\n                    $scope.tabs[tab].manager.selectItem(node.system_id);\n                }\n                updateAllViewableChecked(tab);\n            }\n            updateActionErrorCount(tab);\n            shouldClearAction(tab);\n        };\n\n        // Select all viewable nodes or deselect all viewable nodes.\n        $scope.toggleCheckAll = function(tab) {\n            if(tab !== 'nodes' && tab !== 'switches') {\n                if($scope.tabs[tab].allViewableChecked) {\n                    angular.forEach(\n                        $scope.tabs[tab].filtered_items, function(node) {\n                            $scope.tabs[tab].manager.unselectItem(\n                                node.system_id);\n                    });\n                } else {\n                    angular.forEach(\n                        $scope.tabs[tab].filtered_items, function(node) {\n                            $scope.tabs[tab].manager.selectItem(\n                                node.system_id);\n                    });\n                }\n                updateAllViewableChecked(tab);\n            }\n            updateActionErrorCount(tab);\n            shouldClearAction(tab);\n        };\n\n        $scope.onNodeListingChanged = function(nodes, tab) {\n            if(nodes.length === 0 &&\n                $scope.tabs[tab].search !== \"\" &&\n                $scope.tabs[tab].search === $scope.tabs[tab].previous_search) {\n                $scope.tabs[tab].search = \"\";\n                $scope.updateFilters(tab);\n            }\n        };\n\n        // When the filtered nodes change update if all check buttons\n        // should be checked or not.\n        $scope.$watchCollection(\"tabs.devices.filtered_items\", function() {\n            updateAllViewableChecked(\"devices\");\n            removeEmptyFilter(\"devices\");\n        });\n        $scope.$watchCollection(\"tabs.controllers.filtered_items\", function() {\n            updateAllViewableChecked(\"controllers\");\n            removeEmptyFilter(\"controllers\");\n        });\n\n        // Shows the current selection.\n        $scope.showSelected = function(tab) {\n            enterViewSelected(tab);\n            $scope.updateFilters(tab);\n        };\n\n        // Adds or removes a filter to the search.\n        $scope.toggleFilter = function(type, value, tab) {\n            // Don't allow a filter to be changed when an action is\n            // in progress.\n            if(angular.isObject($scope.tabs[tab].actionOption)) {\n                return;\n            }\n            $scope.tabs[tab].filters = SearchService.toggleFilter(\n                $scope.tabs[tab].filters, type, value, true);\n            $scope.tabs[tab].search = SearchService.filtersToString(\n                $scope.tabs[tab].filters);\n        };\n\n        // Return True if the filter is active.\n        $scope.isFilterActive = function(type, value, tab) {\n            return SearchService.isFilterActive(\n                $scope.tabs[tab].filters, type, value, true);\n        };\n\n        // Update the filters object when the search bar is updated.\n        $scope.updateFilters = function(tab) {\n            var filters = SearchService.getCurrentFilters(\n                $scope.tabs[tab].search);\n            if(filters === null) {\n                $scope.tabs[tab].filters = SearchService.getEmptyFilter();\n                $scope.tabs[tab].searchValid = false;\n            } else {\n                $scope.tabs[tab].filters = filters;\n                $scope.tabs[tab].searchValid = true;\n            }\n            shouldClearAction(tab);\n        };\n\n        // Sorts the table by predicate.\n        $scope.sortTable = function(predicate, tab) {\n            $scope.tabs[tab].predicate = predicate;\n            $scope.tabs[tab].reverse = !$scope.tabs[tab].reverse;\n        };\n\n        // Sets the viewable column or sorts.\n        $scope.selectColumnOrSort = function(predicate, tab) {\n            if($scope.tabs[tab].column !== predicate) {\n                $scope.tabs[tab].column = predicate;\n            } else {\n                $scope.sortTable(predicate, tab);\n            }\n        };\n\n        // Return True if the node supports the action.\n        $scope.supportsAction = function(node, tab) {\n            if(!$scope.tabs[tab].actionOption) {\n                return true;\n            }\n            return node.actions.indexOf(\n                $scope.tabs[tab].actionOption.name) >= 0;\n        };\n\n        // Called when the action option gets changed.\n        $scope.actionOptionSelected = function(tab) {\n            updateActionErrorCount(tab);\n            enterViewSelected(tab);\n\n            // Hide the add hardware/device section.\n            if (tab === 'nodes') {\n                if(angular.isObject($scope.addHardwareScope)) {\n                    $scope.addHardwareScope.hide();\n                }\n            } else if(tab === 'devices') {\n                if(angular.isObject($scope.addDeviceScope)) {\n                    $scope.addDeviceScope.hide();\n                }\n            }\n        };\n\n        // Return True if there is an action error.\n        $scope.isActionError = function(tab) {\n            if(angular.isObject($scope.tabs[tab].actionOption) &&\n                $scope.tabs[tab].actionOption.name === \"deploy\" &&\n                $scope.tabs[tab].actionErrorCount === 0 &&\n                ($scope.osinfo.osystems.length === 0 ||\n                UsersManager.getSSHKeyCount() === 0)) {\n                return true;\n            }\n            return $scope.tabs[tab].actionErrorCount !== 0;\n        };\n\n        // Return True if unable to deploy because of missing images.\n        $scope.isDeployError = function(tab) {\n            if($scope.tabs[tab].actionErrorCount !== 0) {\n                return false;\n            }\n            if(angular.isObject($scope.tabs[tab].actionOption) &&\n                $scope.tabs[tab].actionOption.name === \"deploy\" &&\n                $scope.osinfo.osystems.length === 0) {\n                return true;\n            }\n            return false;\n        };\n\n        // Return True if unable to deploy because of missing ssh keys.\n        $scope.isSSHKeyError = function(tab) {\n            if($scope.tabs[tab].actionErrorCount !== 0) {\n                return false;\n            }\n            if(angular.isObject($scope.tabs[tab].actionOption) &&\n                $scope.tabs[tab].actionOption.name === \"deploy\" &&\n                UsersManager.getSSHKeyCount() === 0) {\n                return true;\n            }\n            return false;\n        };\n\n        // Called when the current action is cancelled.\n        $scope.actionCancel = function(tab) {\n            resetActionProgress(tab);\n            leaveViewSelected(tab);\n            $scope.tabs[tab].actionOption = null;\n        };\n\n        // Perform the action on all nodes.\n        $scope.actionGo = function(tab) {\n            var extra = {};\n            var i;\n            // Set deploy parameters if a deploy or set zone action.\n            if($scope.tabs[tab].actionOption.name === \"deploy\" &&\n                angular.isString($scope.tabs[tab].osSelection.osystem) &&\n                angular.isString($scope.tabs[tab].osSelection.release)) {\n\n                // Set extra. UI side the release is structured os/release, but\n                // when it is sent over the websocket only the \"release\" is\n                // sent.\n                extra.osystem = $scope.tabs[tab].osSelection.osystem;\n                var release = $scope.tabs[tab].osSelection.release;\n                release = release.split(\"/\");\n                release = release[release.length-1];\n                extra.distro_series = release;\n                // hwe_kernel is optional so only include it if its specified\n                if(angular.isString($scope.tabs[tab].osSelection.hwe_kernel) &&\n                   ($scope.tabs[tab].osSelection.hwe_kernel.indexOf('hwe-')\n                    >= 0 ||\n                    $scope.tabs[tab].osSelection.hwe_kernel.indexOf('ga-')\n                    >= 0)) {\n                    extra.hwe_kernel = $scope.tabs[tab].osSelection.hwe_kernel;\n                }\n            } else if($scope.tabs[tab].actionOption.name === \"set-zone\" &&\n                angular.isNumber($scope.tabs[tab].zoneSelection.id)) {\n                // Set the zone parameter.\n                extra.zone_id = $scope.tabs[tab].zoneSelection.id;\n            } else if($scope.tabs[tab].actionOption.name === \"commission\") {\n                // Set the commission options.\n                extra.enable_ssh = (\n                    $scope.tabs[tab].commissionOptions.enableSSH);\n                extra.skip_networking = (\n                    $scope.tabs[tab].commissionOptions.skipNetworking);\n                extra.skip_storage = (\n                    $scope.tabs[tab].commissionOptions.skipStorage);\n                extra.commissioning_scripts = [];\n                for(i=0;i<$scope.tabs[tab].commissioningSelection.length;i++) {\n                    extra.commissioning_scripts.push(\n                        $scope.tabs[tab].commissioningSelection[i].id);\n                }\n                if($scope.tabs[tab].commissionOptions.updateFirmware) {\n                    extra.commissioning_scripts.push('update_firmware')\n                }\n                if($scope.tabs[tab].commissionOptions.configureHBA) {\n                    extra.commissioning_scripts.push('configure_hba')\n                }\n                if(extra.commissioning_scripts.length === 0) {\n                    // Tell the region not to run any custom commissioning\n                    // scripts.\n                    extra.commissioning_scripts.push('none');\n                }\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.tabs[tab].testSelection.length;i++) {\n                    extra.testing_scripts.push(\n                        $scope.tabs[tab].testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.tabs[tab].actionOption.name === \"test\") {\n                if(!$scope.tabs[tab].actionProgress.showing_confirmation) {\n                    var progress = $scope.tabs[tab].actionProgress;\n                    for(i=0;i<$scope.tabs[tab].selectedItems.length;i++) {\n                        if($scope.tabs[tab].selectedItems[i].status_code === 6)\n                        {\n                            progress.showing_confirmation = true;\n                            progress.affected_nodes++;\n                        }\n                    }\n                    if($scope.tabs[tab].actionProgress.affected_nodes != 0) {\n                        return;\n                    }\n                }\n                // Set the test options.\n                extra.enable_ssh = (\n                    $scope.tabs[tab].commissionOptions.enableSSH);\n                extra.testing_scripts = [];\n                for(i=0;i<$scope.tabs[tab].testSelection.length;i++) {\n                    extra.testing_scripts.push(\n                        $scope.tabs[tab].testSelection[i].id);\n                }\n                if(extra.testing_scripts.length === 0) {\n                    // Tell the region not to run any tests.\n                    extra.testing_scripts.push('none');\n                }\n            } else if($scope.tabs[tab].actionOption.name === \"release\") {\n                // Set the release options.\n                extra.erase = (\n                    $scope.tabs[tab].releaseOptions.erase);\n                extra.secure_erase = (\n                    $scope.tabs[tab].releaseOptions.secureErase);\n                extra.quick_erase = (\n                    $scope.tabs[tab].releaseOptions.quickErase);\n            }\n\n            // Setup actionProgress.\n            resetActionProgress(tab);\n            $scope.tabs[tab].actionProgress.total =\n                $scope.tabs[tab].selectedItems.length;\n\n            // Perform the action on all selected items.\n            angular.forEach($scope.tabs[tab].selectedItems, function(node) {\n                $scope.tabs[tab].manager.performAction(\n                    node, $scope.tabs[tab].actionOption.name,\n                    extra).then(function() {\n                        $scope.tabs[tab].actionProgress.completed += 1;\n                        node.action_failed = false;\n                        updateSelectedItems(tab);\n                    }, function(error) {\n                        addErrorToActionProgress(tab, error, node);\n                        node.action_failed = true;\n                        updateSelectedItems(tab);\n                    });\n            });\n        };\n\n        // Returns true when actions are being performed.\n        $scope.hasActionsInProgress = function(tab) {\n            var progress = $scope.tabs[tab].actionProgress;\n            return progress.total > 0 && progress.completed !== progress.total;\n        };\n\n        // Returns true if any of the actions have failed.\n        $scope.hasActionsFailed = function(tab) {\n            return Object.keys(\n                $scope.tabs[tab].actionProgress.errors).length > 0;\n        };\n\n        // Called to when the addHardwareOption has changed.\n        $scope.addHardwareOptionChanged = function() {\n            if($scope.addHardwareOption) {\n                $scope.addHardwareScope.show(\n                    $scope.addHardwareOption.name);\n            }\n        };\n\n        // Called when the add device button is pressed.\n        $scope.addDevice = function() {\n            $scope.addDeviceScope.show();\n        };\n\n        // Called when the cancel add device button is pressed.\n        $scope.cancelAddDevice = function() {\n            $scope.addDeviceScope.cancel();\n        };\n\n        // Get the display text for device ip assignment type.\n        $scope.getDeviceIPAssignment = function(ipAssignment) {\n            return DEVICE_IP_ASSIGNMENT[ipAssignment];\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        $scope.hasCustomCommissioningScripts = function() {\n            var i;\n            for(i=0;i<$scope.scripts.length;i++) {\n                if($scope.scripts[i].script_type === 0) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Load the required managers for this controller. The ServicesManager\n        // is required by the maasControllerStatus directive that is used\n        // in the partial for this controller.\n        ManagerHelperService.loadManagers($scope, [\n            MachinesManager, DevicesManager, ControllersManager,\n            GeneralManager, ZonesManager, UsersManager, ServicesManager,\n            ScriptsManager, SwitchesManager]).then(function() {\n                $scope.loading = false;\n            });\n\n        // Start polling for the os information.\n        GeneralManager.startPolling($scope, \"osinfo\");\n\n        // Stop polling and save the current filter when the scope is destroyed.\n        $scope.$on(\"$destroy\", function() {\n            $interval.cancel($scope.statusPoll);\n            GeneralManager.stopPolling($scope, \"osinfo\");\n            SearchService.storeFilters(\"nodes\", $scope.tabs.nodes.filters);\n            SearchService.storeFilters(\"devices\", $scope.tabs.devices.filters);\n            SearchService.storeFilters(\n                \"controllers\", $scope.tabs.controllers.filters);\n            SearchService.storeFilters(\n                \"switches\", $scope.tabs.switches.filters);\n        });\n\n        // Restore the filters if any saved.\n        var nodesFilter = SearchService.retrieveFilters(\"nodes\");\n        if(angular.isObject(nodesFilter)) {\n            $scope.tabs.nodes.search = SearchService.filtersToString(\n                nodesFilter);\n            $scope.updateFilters(\"nodes\");\n        }\n        var devicesFilter = SearchService.retrieveFilters(\"devices\");\n        if(angular.isObject(devicesFilter)) {\n            $scope.tabs.devices.search = SearchService.filtersToString(\n                devicesFilter);\n            $scope.updateFilters(\"devices\");\n        }\n        var controllersFilter = SearchService.retrieveFilters(\"controllers\");\n        if(angular.isObject(controllersFilter)) {\n            $scope.tabs.controllers.search = SearchService.filtersToString(\n                controllersFilter);\n            $scope.updateFilters(\"controllers\");\n        }\n        var switchesFilter = SearchService.retrieveFilters(\"switches\");\n        if(angular.isObject(switchesFilter)) {\n            $scope.tabs.switches.search = SearchService.filtersToString(\n                switchesFilter);\n            $scope.updateFilters(\"switches\");\n        }\n\n\n        // Switch to the specified tab, if specified.\n        if($routeParams.tab === \"nodes\" || $routeParams.tab === \"devices\" ||\n                $routeParams.tab === \"controllers\" ||\n                $routeParams.tab === \"switches\") {\n            $scope.toggleTab($routeParams.tab);\n        }\n\n        // Set the query if the present in $routeParams.\n        var query = $routeParams.query;\n        if(angular.isString(query)) {\n            $scope.tabs[$scope.currentpage].search = query;\n            $scope.updateFilters($scope.currentpage);\n        }\n    }]);\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Pod Details Controller\n */\n\nangular.module('MAAS').controller('PodDetailsController', [\n    '$scope', '$rootScope', '$location', '$routeParams',\n    'PodsManager', 'GeneralManager', 'UsersManager', 'DomainsManager',\n    'ZonesManager', 'ManagerHelperService', 'ErrorService', function(\n        $scope, $rootScope, $location, $routeParams,\n        PodsManager, GeneralManager, UsersManager, DomainsManager,\n        ZonesManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"pods\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.pod = null;\n        $scope.podManager = PodsManager;\n        $scope.action = {\n          option: null,\n          options: [\n            {\n              name: 'refresh',\n              title: 'Refresh',\n              sentence: 'refresh',\n              operation: angular.bind(PodsManager, PodsManager.refresh)\n            },\n            {\n              name: 'delete',\n              title: 'Delete',\n              sentence: 'delete',\n              operation: angular.bind(PodsManager, PodsManager.deleteItem)\n            }\n          ],\n          inProgress: false,\n          error: null\n        };\n        $scope.compose = {\n          action: {\n            name: 'compose',\n            title: 'Compose',\n            sentence: 'compose'\n          },\n          obj: {\n            storage: [{\n              type: 'local',\n              size: 8,\n              tags: [],\n              boot: true\n            }]\n          }\n        };\n        $scope.power_types = GeneralManager.getData(\"power_types\");\n        $scope.domains = DomainsManager.getItems();\n        $scope.zones = ZonesManager.getItems();\n        $scope.section = {\n          area: 'summary'\n        };\n        $scope.machinesSearch = 'pod-id:=invalid';\n        $scope.editing = false;\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if at least a rack controller is connected to the\n        // region controller.\n        $scope.isRackControllerConnected = function() {\n            // If power_types exist then a rack controller is connected.\n            return $scope.power_types.length > 0;\n        };\n\n        // Return true when the edit buttons can be clicked.\n        $scope.canEdit = function() {\n            return (\n                $scope.isRackControllerConnected() &&\n                    $scope.isSuperUser());\n        };\n\n        // Called to edit the pod configuration.\n        $scope.editPodConfiguration = function() {\n            if(!$scope.canEdit()) {\n                return;\n            }\n            $scope.editing = true;\n        };\n\n        // Called when the cancel or save button is pressed.\n        $scope.exitEditPodConfiguration = function() {\n            $scope.editing = false;\n        };\n\n        // Return true if there is an action error.\n        $scope.isActionError = function() {\n            return $scope.action.error !== null;\n        };\n\n        // Called when the action.option has changed.\n        $scope.actionOptionChanged = function() {\n            // Clear the action error.\n            $scope.action.error = null;\n        };\n\n        // Cancel the action.\n        $scope.actionCancel = function() {\n            $scope.action.option = null;\n            $scope.action.error = null;\n        };\n\n        // Perform the action.\n        $scope.actionGo = function() {\n            $scope.action.inProgress = true;\n            $scope.action.option.operation($scope.pod).then(function() {\n                  // If the action was delete, then go back to listing.\n                  if($scope.action.option.name === \"delete\") {\n                      $location.path(\"/pods\");\n                  }\n                  $scope.action.inProgress = false;\n                  $scope.action.option = null;\n                  $scope.action.error = null;\n              }, function(error) {\n                  $scope.action.inProgress = false;\n                  $scope.action.error = error;\n              });\n        };\n\n        // Return the title of the pod type.\n        $scope.getPodTypeTitle = function() {\n            var i;\n            for(i = 0; i < $scope.power_types.length; i++) {\n                var power_type = $scope.power_types[i];\n                if(power_type.name === $scope.pod.type) {\n                    return power_type.description;\n                }\n            }\n            return $scope.pod.type;\n        };\n\n        // Returns true if the pod is composable.\n        $scope.canCompose = function() {\n            if(angular.isObject($scope.pod)) {\n                return ($scope.isSuperUser() &&\n                    $scope.pod.capabilities.indexOf('composable') >= 0);\n            } else {\n                return false;\n            }\n        };\n\n        // Opens the compose action menu.\n        $scope.composeMachine = function() {\n            $scope.action.option = $scope.compose.action;\n        };\n\n        // Called before the compose params is sent over the websocket.\n        $scope.composePreProcess = function(params) {\n            params = angular.copy(params);\n            params.id = $scope.pod.id;\n            // Sort boot disk first.\n            var sorted = $scope.compose.obj.storage.sort(function(a, b) {\n              if(a.boot === b.boot) {\n                return 0;\n              } else if(a.boot && !b.boot) {\n                return -1;\n              } else {\n                return 1;\n              }\n            });\n            // Create the storage constraint.\n            var storage = [];\n            angular.forEach(sorted, function(disk, idx) {\n              var constraint = idx + ':' + disk.size;\n              var tags = disk.tags.map(function(tag) {\n                return tag.text;\n              });\n              tags.splice(0, 0, disk.type);\n              constraint += '(' + tags.join(',') + ')';\n              storage.push(constraint);\n            });\n            params.storage = storage.join(',');\n            return params;\n        };\n\n        // Called to cancel composition.\n        $scope.cancelCompose = function() {\n          $scope.compose.obj = {\n            storage: [{\n              type: 'local',\n              size: 8,\n              tags: [],\n              boot: true\n            }]\n          };\n          $scope.action.option = null;\n        };\n\n        // Add another storage device.\n        $scope.composeAddStorage = function() {\n          var storage = {\n            type: 'local',\n            size: 8,\n            tags: [],\n            boot: false\n          };\n          if($scope.pod.capabilities.indexOf('iscsi_storage') >= 0) {\n            storage.type = 'iscsi';\n          }\n          $scope.compose.obj.storage.push(storage);\n        };\n\n        // Change which disk is the boot disk.\n        $scope.composeSetBootDisk = function(storage) {\n          angular.forEach($scope.compose.obj.storage, function(disk) {\n            disk.boot = false;\n          });\n          storage.boot = true;\n        };\n\n        // Remove a disk from storage config.\n        $scope.composeRemoveDisk = function(storage) {\n          var idx = $scope.compose.obj.storage.indexOf(storage);\n          if(idx >= 0) {\n            $scope.compose.obj.storage.splice(idx, 1);\n          }\n        };\n\n        // Start watching key fields.\n        $scope.startWatching = function() {\n            $scope.$watch(\"pod.name\", function() {\n                $rootScope.title = 'Pod ' + $scope.pod.name;\n            });\n            $scope.$watch(\"pod.capabilities\", function() {\n                // Show the composable action if the pod supports composition.\n                var idx = $scope.action.options.indexOf(\n                    $scope.compose.action);\n                if(!$scope.canCompose()) {\n                    if(idx >= 0) {\n                        $scope.action.options.splice(idx, 1);\n                    }\n                } else {\n                    if(idx === -1) {\n                        $scope.action.options.splice(\n                            0, 0, $scope.compose.action);\n                    }\n                }\n            });\n            $scope.$watch(\"action.option\", function(now, then) {\n                // When the compose action is selected set the default\n                // parameters.\n                if(now && now.name === 'compose') {\n                    if(!then || then.name !== 'compose') {\n                        $scope.compose.obj.domain = (\n                            DomainsManager.getDefaultDomain().id);\n                        $scope.compose.obj.zone = (\n                            ZonesManager.getDefaultZone().id);\n                    }\n                }\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            PodsManager, GeneralManager, UsersManager,\n            DomainsManager, ZonesManager]).then(function() {\n\n            // Possibly redirected from another controller that already had\n            // this pod set to active. Only call setActiveItem if not already\n            // the activeItem.\n            var activePod = PodsManager.getActiveItem();\n            if(angular.isObject(activePod) &&\n                activePod.id === parseInt($routeParams.id, 10)) {\n                $scope.pod = activePod;\n                $scope.loaded = true;\n                $scope.machinesSearch = 'pod-id:=' + $scope.pod.id;\n                $scope.startWatching();\n            } else {\n                PodsManager.setActiveItem(\n                    parseInt($routeParams.id, 10)).then(function(pod) {\n                        $scope.pod = pod;\n                        $scope.loaded = true;\n                        $scope.machinesSearch = 'pod-id:=' + $scope.pod.id;\n                        $scope.startWatching();\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Pods List Controller\n */\n\nangular.module('MAAS').controller('PodsListController', [\n    '$scope', '$rootScope',\n    'PodsManager', 'UsersManager', 'GeneralManager', 'ZonesManager',\n    'ManagerHelperService', function(\n        $scope, $rootScope, PodsManager, UsersManager, GeneralManager,\n        ZonesManager, ManagerHelperService) {\n\n        // Set title and page.\n        $rootScope.title = \"Pods\";\n        $rootScope.page = \"pods\";\n\n        // Set initial values.\n        $scope.podManager = PodsManager;\n        $scope.pods = PodsManager.getItems();\n        $scope.loading = true;\n\n        $scope.filteredItems = [];\n        $scope.selectedItems = PodsManager.getSelectedItems();\n        $scope.predicate = 'name';\n        $scope.allViewableChecked = false;\n        $scope.action = {\n          option: null,\n          options: [\n            {\n              name: 'refresh',\n              title: 'Refresh',\n              sentence: 'refresh',\n              operation: angular.bind(PodsManager, PodsManager.refresh)\n            },\n            {\n              name: 'delete',\n              title: 'Delete',\n              sentence: 'delete',\n              operation: angular.bind(PodsManager, PodsManager.deleteItem)\n            }\n          ],\n          progress: {\n              total: 0,\n              completed: 0,\n              errors: 0\n          }\n        };\n        $scope.add = {\n          open: false,\n          obj: {}\n        };\n        $scope.powerTypes = GeneralManager.getData(\"power_types\");\n        $scope.zones = ZonesManager.getItems();\n\n        // Called to update `allViewableChecked`.\n        function updateAllViewableChecked() {\n            // Not checked when no pods.\n            if($scope.pods.length === 0) {\n                $scope.allViewableChecked = false;\n                return;\n            }\n\n            // Loop through all filtered pods and see if all are checked.\n            var i;\n            for(i = 0; i < $scope.pods.length; i++) {\n                if(!$scope.pods[i].$selected) {\n                    $scope.allViewableChecked = false;\n                    return;\n                }\n            }\n            $scope.allViewableChecked = true;\n        }\n\n        function clearAction() {\n            resetActionProgress();\n            $scope.action.option = null;\n        }\n\n        // Clear the action if required.\n        function shouldClearAction() {\n            if($scope.selectedItems.length === 0) {\n                clearAction();\n                if($scope.action.option) {\n                    $scope.action.option = null;\n                }\n            }\n        }\n\n        // Reset actionProgress to zero.\n        function resetActionProgress() {\n            var progress = $scope.action.progress;\n            progress.completed = progress.total = progress.errors = 0;\n            angular.forEach($scope.pods, function(pod) {\n                delete pod.action_failed;\n            });\n        }\n\n        // After an action has been performed check if we can leave all pods\n        // selected or if an error occured and we should only show the failed\n        // pods.\n        function updateSelectedItems() {\n            if(!$scope.hasActionsFailed()) {\n                if(!$scope.hasActionsInProgress()) {\n                     clearAction();\n                }\n                return;\n            }\n            angular.forEach($scope.pods, function(pod) {\n                if(pod.action_failed === false) {\n                    PodsManager.unselectItem(pod.id);\n                }\n            });\n            shouldClearAction();\n        }\n\n        // Mark a pod as selected or unselected.\n        $scope.toggleChecked = function(pod) {\n            if(PodsManager.isSelected(pod.id)) {\n                PodsManager.unselectItem(pod.id);\n            } else {\n                PodsManager.selectItem(pod.id);\n            }\n            updateAllViewableChecked();\n            shouldClearAction();\n        };\n\n        // Select all viewable pods or deselect all viewable pods.\n        $scope.toggleCheckAll = function() {\n            if($scope.allViewableChecked) {\n                angular.forEach($scope.pods, function(pod) {\n                    PodsManager.unselectItem(pod.id);\n                });\n            } else {\n                angular.forEach($scope.pods, function(pod) {\n                    PodsManager.selectItem(pod.id);\n                });\n            }\n            updateAllViewableChecked();\n            shouldClearAction();\n        };\n\n        // When the pods change update if all check buttons should be\n        // checked or not.\n        $scope.$watchCollection(\"pods\", function() {\n            updateAllViewableChecked();\n        });\n\n        // Sorts the table by predicate.\n        $scope.sortTable = function(predicate) {\n            $scope.predicate = predicate;\n            $scope.reverse = !$scope.reverse;\n        };\n\n        // Called when the current action is cancelled.\n        $scope.actionCancel = function() {\n            resetActionProgress();\n            $scope.action.option = null;\n        };\n\n        // Perform the action on all pods.\n        $scope.actionGo = function() {\n            var extra = {};\n\n            // Setup actionProgress.\n            resetActionProgress();\n            $scope.action.progress.total = $scope.selectedItems.length;\n\n            // Perform the action on all selected items.\n            var operation = $scope.action.option.operation;\n            angular.forEach($scope.selectedItems, function(pod) {\n                operation(pod).then(function() {\n                        $scope.action.progress.completed += 1;\n                        pod.action_failed = false;\n                        updateSelectedItems();\n                    }, function(error) {\n                        $scope.action.progress.errors += 1;\n                        pod.action_error = error;\n                        pod.action_failed = true;\n                        updateSelectedItems();\n                    });\n            });\n        };\n\n        // Returns true when actions are being performed.\n        $scope.hasActionsInProgress = function() {\n            var progress = $scope.action.progress;\n            return progress.total > 0 && (\n                progress.completed + progress.errors) !== progress.total;\n        };\n\n        // Returns true if any of the actions have failed.\n        $scope.hasActionsFailed = function() {\n            var progress = $scope.action.progress;\n            return progress.errors > 0;\n        };\n\n        // Called when the add pod button is pressed.\n        $scope.addPod = function() {\n            $scope.add.open = true;\n        };\n\n        // Called when the cancel add pod button is pressed.\n        $scope.cancelAddPod = function() {\n            $scope.add.open = false;\n            $scope.add.obj = {};\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return the title of the power type.\n        $scope.getPowerTypeTitle = function(power_type) {\n            var i;\n            for(i = 0; i < $scope.powerTypes.length; i++) {\n                var powerType = $scope.powerTypes[i];\n                if(powerType.name === power_type) {\n                    return powerType.description;\n                }\n            }\n            return power_type;\n        };\n\n        // Load the required managers for this controller.\n        ManagerHelperService.loadManagers($scope, [\n            PodsManager, UsersManager, GeneralManager, ZonesManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Preferences Controller\n */\n\nangular.module('MAAS').controller('PreferencesController', [\n    '$scope', 'UsersManager', 'ManagerHelperService',\n    function(\n        $scope, UsersManager, ManagerHelperService) {\n            $scope.loading = true;\n            ManagerHelperService.loadManager(\n                $scope, UsersManager).then(function() {\n                    $scope.loading = false;\n                });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Settings Controller\n */\n\nangular.module('MAAS').controller('SettingsController', [\n    '$scope', '$rootScope', '$routeParams', 'PackageRepositoriesManager',\n    'DHCPSnippetsManager', 'MachinesManager', 'ControllersManager',\n    'DevicesManager', 'SubnetsManager', 'GeneralManager',\n    'ManagerHelperService',\n    function($scope, $rootScope, $routeParams, PackageRepositoriesManager,\n             DHCPSnippetsManager, MachinesManager, ControllersManager,\n             DevicesManager, SubnetsManager, GeneralManager,\n             ManagerHelperService) {\n\n        // Set the title and page.\n        $rootScope.title = \"Loading...\";\n        $rootScope.page = \"settings\";\n\n        // Initial values.\n        $scope.loading = true;\n        $scope.snippetsManager = DHCPSnippetsManager;\n        $scope.snippets = DHCPSnippetsManager.getItems();\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.machines = MachinesManager.getItems();\n        $scope.devices = DevicesManager.getItems();\n        $scope.controllers = ControllersManager.getItems();\n        $scope.known_architectures =\n            GeneralManager.getData(\"known_architectures\");\n        $scope.pockets_to_disable =\n            GeneralManager.getData(\"pockets_to_disable\");\n        $scope.components_to_disable =\n            GeneralManager.getData(\"components_to_disable\");\n        $scope.packageRepositoriesManager = PackageRepositoriesManager;\n        $scope.repositories =\n            PackageRepositoriesManager.getItems();\n        $scope.newSnippet = null;\n        $scope.editSnippet = null;\n        $scope.deleteSnippet = null;\n        $scope.snippetTypes = [\"Global\", \"Subnet\", \"Node\"];\n        $scope.newRepository = null;\n        $scope.editRepository = null;\n        $scope.deleteRepository = null;\n\n        // Called when the enabled toggle is changed.\n        $scope.repositoryEnabledToggle = function(repository) {\n            PackageRepositoriesManager.updateItem(repository);\n        };\n\n        // Called to enter remove mode for a repository.\n        $scope.repositoryEnterRemove = function(repository) {\n            $scope.newRepository = null;\n            $scope.editRepository = null;\n            $scope.deleteRepository = repository;\n        };\n\n        // Called to exit remove mode for a repository.\n        $scope.repositoryExitRemove = function() {\n            $scope.deleteRepository = null;\n        };\n\n        // Called to confirm the removal of a repository.\n        $scope.repositoryConfirmRemove = function() {\n            PackageRepositoriesManager.deleteItem(\n                $scope.deleteRepository).then(function() {\n                    $scope.repositoryExitRemove();\n                });\n        };\n\n        // Return true if the repository is a PPA.\n        $scope.isPPA = function(data) {\n            if(!angular.isObject(data)) {\n                return false;\n            }\n            if(!angular.isString(data.url)) {\n                return false;\n            }\n            return data.url.indexOf(\"ppa:\") === 0 ||\n                data.url.indexOf(\"ppa.launchpad.net\") > -1;\n        };\n\n        // Return true if the repository is a mirror.\n        $scope.isMirror = function(data) {\n            if(!angular.isObject(data)) {\n                return false;\n            }\n            if(!angular.isString(data.name)) {\n                return false;\n            }\n            return data.name === \"main_archive\" ||\n                data.name === \"ports_archive\";\n        };\n\n        // Called to enter edit mode for a repository.\n        $scope.repositoryEnterEdit = function(repository) {\n            $scope.newRepository = null;\n            $scope.deleteRepository = null;\n            $scope.editRepository = repository;\n        };\n\n        // Called to exit edit mode for a repository.\n        $scope.repositoryExitEdit = function() {\n            $scope.editRepository = null;\n        };\n\n        // Called to start adding a new repository.\n        $scope.repositoryAdd = function(isPPA) {\n            var repo = {\n                name: \"\",\n                enabled: true,\n                url: \"\",\n                key: \"\",\n                arches: [\"i386\", \"amd64\"],\n                distributions: [],\n                components: []\n            };\n            if (isPPA) {\n                repo.url = \"ppa:\";\n            }\n            $scope.newRepository = repo;\n        };\n\n        // Called to cancel addind a new repository.\n        $scope.repositoryAddCancel = function() {\n            $scope.newRepository = null;\n        };\n\n        // Return the node from either the machines, devices, or controllers\n        // manager.\n        function getNode(system_id) {\n            var node = MachinesManager.getItemFromList(system_id);\n            if(angular.isObject(node)) {\n                return node;\n            }\n            node = DevicesManager.getItemFromList(system_id);\n            if(angular.isObject(node)) {\n                return node;\n            }\n            node = ControllersManager.getItemFromList(system_id);\n            if(angular.isObject(node)) {\n                return node;\n            }\n        }\n\n        // Return the name of the subnet.\n        $scope.getSubnetName = function(subnet) {\n            return SubnetsManager.getName(subnet);\n        };\n\n        // Return the text for the type of snippet.\n        $scope.getSnippetTypeText = function(snippet) {\n            if(angular.isString(snippet.node)) {\n                return \"Node\";\n            } else if(angular.isNumber(snippet.subnet)) {\n                return \"Subnet\";\n            } else {\n                return \"Global\";\n            }\n        };\n\n        // Return the object the snippet applies to.\n        $scope.getSnippetAppliesToObject = function(snippet) {\n            if(angular.isString(snippet.node)) {\n                return getNode(snippet.node);\n            } else if(angular.isNumber(snippet.subnet)) {\n                return SubnetsManager.getItemFromList(snippet.subnet);\n            }\n        };\n\n        // Return the applies to text that is disabled in none edit mode.\n        $scope.getSnippetAppliesToText = function(snippet) {\n            var obj = $scope.getSnippetAppliesToObject(snippet);\n            if(angular.isString(snippet.node) && angular.isObject(obj)) {\n                return obj.fqdn;\n            } else if(angular.isNumber(snippet.subnet) &&\n                angular.isObject(obj)) {\n                return SubnetsManager.getName(obj);\n            } else {\n                return \"\";\n            }\n        };\n\n        // Called to enter remove mode for a DHCP snippet.\n        $scope.snippetEnterRemove = function(snippet) {\n            $scope.newSnippet = null;\n            $scope.editSnippet = null;\n            $scope.deleteSnippet = snippet;\n        };\n\n        // Called to exit remove mode for a DHCP snippet.\n        $scope.snippetExitRemove = function() {\n            $scope.deleteSnippet = null;\n        };\n\n        // Called to confirm the removal of a snippet.\n        $scope.snippetConfirmRemove = function() {\n            DHCPSnippetsManager.deleteItem($scope.deleteSnippet).then(\n                function() {\n                    $scope.snippetExitRemove();\n                });\n        };\n\n        // Called to enter edit mode for a DHCP snippet.\n        $scope.snippetEnterEdit = function(snippet) {\n            $scope.newSnippet = null;\n            $scope.deleteSnippet = null;\n            $scope.editSnippet = snippet;\n            $scope.editSnippet.type = $scope.getSnippetTypeText(snippet);\n        };\n\n        // Called to exit edit mode for a DHCP snippet.\n        $scope.snippetExitEdit = function() {\n            $scope.editSnippet = null;\n        };\n\n        // Called when the active toggle is changed.\n        $scope.snippetToggle = function(snippet) {\n            DHCPSnippetsManager.updateItem(snippet).then(null,\n                function(error) {\n                    // Revert state change and clear toggling.\n                    snippet.enabled = !snippet.enabled;\n                    console.log(error);\n                });\n        };\n\n        // Called to start adding a new snippet.\n        $scope.snippetAdd = function() {\n            $scope.editSnippet = null;\n            $scope.deleteSnippet = null;\n            $scope.newSnippet = {\n                name: \"\",\n                type: \"Global\",\n                enabled: true\n            };\n        };\n\n        // Called to cancel addind a new snippet.\n        $scope.snippetAddCancel = function() {\n            $scope.newSnippet = null;\n        };\n\n        // Setup page variables based on section.\n        if($routeParams.section === \"dhcp\") {\n            $rootScope.title = \"DHCP snippets\";\n            $scope.currentpage = 'dhcp';\n        }\n        else if($routeParams.section === \"repositories\") {\n            $rootScope.title = \"Package repositories\";\n            $scope.currentpage = 'repositories';\n        }\n\n        // Load the required managers.\n        ManagerHelperService.loadManagers($scope, [\n                PackageRepositoriesManager, DHCPSnippetsManager,\n                MachinesManager, DevicesManager, ControllersManager,\n                SubnetsManager, GeneralManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Space Details Controller\n */\n\nangular.module('MAAS').controller('SpaceDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'SpacesManager', 'VLANsManager', 'SubnetsManager', 'FabricsManager',\n    'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $filter, $location,\n        SpacesManager, VLANsManager, SubnetsManager, FabricsManager,\n        UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        // Initial values.\n        $scope.space = null;\n        $scope.spaceManager = SpacesManager;\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.loaded = false;\n        $scope.editSummary = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.space.name;\n        }\n\n        // Called when the space has been loaded.\n        function spaceLoaded(space) {\n            $scope.space = space;\n            updateTitle();\n            $scope.predicate = \"[subnet_name, vlan_name]\";\n            $scope.$watch(\"subnets\", updateSubnets, true);\n            updateSubnets();\n            $scope.loaded = true;\n        }\n\n        // Generate a table that can easily be rendered in the view.\n        function updateSubnets() {\n            var rows = [];\n            angular.forEach($filter('filter')(\n                    $scope.subnets, {space:$scope.space.id}, true),\n                    function(subnet) {\n                var vlan = VLANsManager.getItemFromList(subnet.vlan);\n                var fabric = FabricsManager.getItemFromList(vlan.fabric);\n                var row = {\n                    vlan: vlan,\n                    vlan_name: VLANsManager.getName(vlan),\n                    subnet: subnet,\n                    subnet_name: SubnetsManager.getName(subnet),\n                    fabric: fabric,\n                    fabric_name: fabric.name\n                };\n                rows.push(row);\n            });\n            $scope.rows = rows;\n        }\n\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Called when the \"edit\" button is cliked in the space summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the space summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Return true if this is the default Space\n        $scope.isDefaultSpace = function() {\n            if(!angular.isObject($scope.space)) {\n                return false;\n            }\n            return $scope.space.id === 0;\n        };\n\n        // Called to check if the space can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.space)) {\n                return $scope.space.subnet_ids.length === 0;\n            }\n            return false;\n        };\n\n        // Called when the delete space button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete space button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete space button is pressed.\n        $scope.deleteConfirmButton = function() {\n            SpacesManager.deleteSpace($scope.space).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/networks\");\n                $location.search('by', 'space');\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            SpacesManager, SubnetsManager, VLANsManager, FabricsManager,\n            UsersManager]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this space set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeSpace = SpacesManager.getActiveItem();\n            var requestedSpace = parseInt($routeParams.space_id, 10);\n            if(isNaN(requestedSpace)) {\n                ErrorService.raiseError(\"Invalid space identifier.\");\n            } else if(angular.isObject(activeSpace) &&\n                activeSpace.id === requestedSpace) {\n                spaceLoaded(activeSpace);\n            } else {\n                SpacesManager.setActiveItem(\n                    requestedSpace).then(function(space) {\n                        spaceLoaded(space);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Subnet Details Controller\n */\n\nangular.module('MAAS').filter('filterSource', ['ValidationService',\n    function() {\n        return function(subnets, source) {\n            var filtered = [];\n            angular.forEach(subnets, function(subnet) {\n                if(subnet.id !== source.id &&\n                    subnet.version === source.version) {\n                    filtered.push(subnet);\n                }\n            });\n            return filtered;\n        };\n    }]);\n\nangular.module('MAAS').controller('SubnetDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'ConfigsManager', 'SubnetsManager', 'SpacesManager', 'VLANsManager',\n    'UsersManager', 'FabricsManager', 'StaticRoutesManager',\n    'ManagerHelperService', 'ErrorService', 'ConverterService',\n    function(\n        $scope, $rootScope, $routeParams, $filter, $location, ConfigsManager,\n        SubnetsManager, SpacesManager, VLANsManager, UsersManager,\n        FabricsManager, StaticRoutesManager, ManagerHelperService, ErrorService,\n        ConverterService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.subnet = null;\n        $scope.editSummary = false;\n        $scope.active_discovery_data = null;\n        $scope.active_discovery_interval = null;\n        $scope.subnets = SubnetsManager.getItems();\n        $scope.subnetManager = SubnetsManager;\n        $scope.staticRoutes = StaticRoutesManager.getItems();\n        $scope.staticRoutesManager = StaticRoutesManager;\n        $scope.space = null;\n        $scope.vlans = VLANsManager.getItems();\n        $scope.fabrics = FabricsManager.getItems();\n        $scope.actionError = null;\n        $scope.actionOption = null;\n        $scope.actionOptions = [];\n        $scope.reverse = false;\n        $scope.newStaticRoute = null;\n        $scope.editStaticRoute = null;\n        $scope.deleteStaticRoute = null;\n\n        $scope.MAP_SUBNET_ACTION = {\n            name: \"map_subnet\",\n            title: \"Map subnet\"\n        };\n        $scope.DELETE_ACTION = {\n            name: \"delete\",\n            title: \"Delete\"\n        };\n\n        // Alloc type mapping.\n        var ALLOC_TYPES = {\n            0: 'Automatic',\n            1: 'Static',\n            4: 'User reserved',\n            5: 'DHCP',\n            6: 'Observed'\n        };\n\n        // Node type mapping.\n        var NODE_TYPES = {\n            0: 'Machine',\n            1: 'Device',\n            2: 'Rack controller',\n            3: 'Region controller',\n            4: 'Rack and region controller',\n            5: 'Chassis',\n            6: 'Storage'\n        };\n\n        // Updates the page title.\n        function updateTitle() {\n            subnet = $scope.subnet;\n            if(subnet && subnet.cidr) {\n                $rootScope.title = subnet.cidr;\n                if(subnet.name && subnet.cidr !== subnet.name) {\n                    $rootScope.title += \" (\" +subnet.name + \")\";\n                }\n            }\n        }\n\n        // Update the IP version of the CIDR.\n        function updateIPVersion() {\n            var ip = $scope.subnet.cidr.split('/')[0];\n            if(ip.indexOf(':') === -1) {\n                $scope.ipVersion = 4;\n            } else {\n                $scope.ipVersion = 6;\n            }\n        }\n\n        // Sort for IP address.\n        $scope.ipSort = function(ipAddress) {\n            if($scope.ipVersion === 4) {\n                return ConverterService.ipv4ToInteger(ipAddress.ip);\n            } else {\n                return ConverterService.ipv6Expand(ipAddress.ip);\n            }\n        };\n\n        // Set default predicate to the ipSort function.\n        $scope.predicate = $scope.ipSort;\n\n        // Return the name of the allocation type.\n        $scope.getAllocType = function(allocType) {\n            var str = ALLOC_TYPES[allocType];\n            if(angular.isString(str)) {\n                return str;\n            } else {\n                return \"Unknown\";\n            }\n        };\n\n        $scope.getSubnetCIDR = function(destId) {\n            return SubnetsManager.getItemFromList(destId).cidr;\n        };\n\n        // Sort based on the name of the allocation type.\n        $scope.allocTypeSort = function(ipAddress) {\n            return $scope.getAllocType(ipAddress.alloc_type);\n        };\n\n        // Return the name of the node type for the given IP.\n        $scope.getUsageForIP = function(ip) {\n            if(angular.isObject(ip.node_summary)) {\n                var nodeType = ip.node_summary.node_type;\n                var str = NODE_TYPES[nodeType];\n                if(angular.isString(str)) {\n                    return str;\n                } else {\n                    return \"Unknown\";\n                }\n            } else if(angular.isObject(ip.bmcs)) {\n                return \"BMC\";\n            } else if(angular.isObject(ip.dns_records)) {\n                return \"DNS\";\n            } else {\n                return \"Unknown\";\n            }\n        };\n\n        // Sort based on the node type string.\n        $scope.nodeTypeSort = function(ipAddress) {\n            return $scope.getUsageForIP(ipAddress);\n        };\n\n        // Sort based on the owner name.\n        $scope.ownerSort = function(ipAddress) {\n            var owner = ipAddress.user;\n            if(angular.isString(owner) && owner.length > 0) {\n                return owner;\n            } else {\n                return \"MAAS\";\n            }\n        };\n\n        // Called to change the sort order of the IP table.\n        $scope.sortIPTable = function(predicate) {\n            $scope.predicate = predicate;\n            $scope.reverse = !$scope.reverse;\n        };\n\n        // Return the name of the VLAN.\n        $scope.getVLANName = function(vlan) {\n           return VLANsManager.getName(vlan);\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        $scope.actionRetry = function() {\n            // When we clear actionError, the HTML will be re-rendered to\n            // hide the error message (and the user will be taken back to\n            // the previous action they were performing, since we reset\n            // the actionOption in the error handler.\n            $scope.actionError = null;\n        };\n\n        // Perform the action.\n        $scope.actionGo = function() {\n            if($scope.actionOption.name === \"map_subnet\") {\n                SubnetsManager.scanSubnet($scope.subnet).then(function(result) {\n                    if(result && result.scan_started_on.length === 0) {\n                        $scope.actionError =\n                            ManagerHelperService.parseValidationError(\n                                result.result);\n                    } else {\n                        $scope.actionOption = null;\n                        $scope.actionError = null;\n                    }\n                }, function(error) {\n                    $scope.actionError =\n                        ManagerHelperService.parseValidationError(error);\n                });\n            } else if($scope.actionOption.name === \"delete\") {\n                SubnetsManager.deleteSubnet(\n                    $scope.subnet).then(function(result) {\n                        $scope.actionOption = null;\n                        $scope.actionError = null;\n                        $location.path(\"/networks\");\n                    }, function(error) {\n                        $scope.actionError =\n                            ManagerHelperService.parseValidationError(error);\n                });\n            }\n        };\n\n        // Called when a action is selected.\n        $scope.actionChanged = function() {\n            $scope.actionError = null;\n        };\n\n        // Called when the \"Cancel\" button is pressed.\n        $scope.cancelAction = function() {\n            $scope.actionOption = null;\n            $scope.actionError = null;\n        };\n\n        // Called when the managers load to populate the actions the user\n        // is allowed to perform.\n        $scope.updateActions = function() {\n            if(UsersManager.isSuperUser()) {\n                $scope.actionOptions = [\n                    $scope.MAP_SUBNET_ACTION,\n                    $scope.DELETE_ACTION\n                ];\n            } else {\n                $scope.actionOptions = [];\n            }\n        };\n\n        // Called when the \"edit\" button is cliked in the subnet summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the subnet summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Called by maas-obj-form before it saves the subnet. The passed\n        // subnet is the object right before its sent over the websocket.\n        $scope.subnetPreSave = function(subnet, changedFields) {\n            // Adjust the subnet object if the fabric changed.\n            if(changedFields.indexOf(\"fabric\") !== -1) {\n                // Fabric changed, the websocket expects VLAN to be updated, so\n                // we set the VLAN to the default VLAN for the new fabric.\n                subnet.vlan = FabricsManager.getItemFromList(\n                    subnet.fabric).default_vlan_id;\n            }\n            return subnet;\n        };\n\n        // Called to start adding a new static route.\n        $scope.addStaticRoute = function() {\n            $scope.editStaticRoute = null;\n            $scope.deleteStaticRoute = null;\n            $scope.newStaticRoute = {\n                source: $scope.subnet.id,\n                gateway_ip: \"\",\n                destination: null,\n                metric: 0\n            };\n        };\n\n        // Cancel adding the new static route.\n        $scope.cancelAddStaticRoute = function() {\n            $scope.newStaticRoute = null;\n        };\n\n        // Return true if the static route is in edit mode.\n        $scope.isStaticRouteInEditMode = function(route) {\n            return $scope.editStaticRoute === route;\n        };\n\n        // Toggle edit mode for the static route.\n        $scope.staticRouteToggleEditMode = function(route) {\n            $scope.newStaticRoute = null;\n            $scope.deleteStaticRoute = null;\n            if($scope.isStaticRouteInEditMode(route)) {\n                $scope.editStaticRoute  = null;\n            } else {\n                $scope.editStaticRoute = route;\n            }\n        };\n\n        // Return true if the static route is in delete mode.\n        $scope.isStaticRouteInDeleteMode = function(route) {\n            return $scope.deleteStaticRoute === route;\n        };\n\n        // Enter delete mode for the static route.\n        $scope.staticRouteEnterDeleteMode = function(route) {\n            $scope.newStaticRoute = null;\n            $scope.editStaticRoute = null;\n            $scope.deleteStaticRoute = route;\n        };\n\n        // Exit delete mode for the statc route.\n        $scope.staticRouteCancelDelete = function() {\n            $scope.deleteStaticRoute = null;\n        };\n\n        // Perform the delete operation on the static route.\n        $scope.staticRouteConfirmDelete = function() {\n            StaticRoutesManager.deleteItem($scope.deleteStaticRoute).then(\n                function() {\n                    $scope.deleteStaticRoute = null;\n                });\n        };\n\n        // Called when the subnet has been loaded.\n        function subnetLoaded(subnet) {\n            $scope.subnet = subnet;\n            $scope.loaded = true;\n\n            updateTitle();\n\n            // Watch the vlan and fabric field so if its changed on the subnet\n            // we make sure that the fabric is updated. It is possible that\n            // fabric is removed from the subnet since it is injected from this\n            // controller, so when it is removed we add it back.\n            var updateFabric = function() {\n                $scope.subnet.fabric = (\n                    VLANsManager.getItemFromList($scope.subnet.vlan).fabric);\n                $scope.subnet.fabric_name = (\n                  FabricsManager.getItemFromList(subnet.fabric).name);\n            };\n            var updateSpace = function() {\n                $scope.space = (\n                    SpacesManager.getItemFromList($scope.subnet.space));\n            };\n            var updateVlan = function() {\n                var vlan = VLANsManager.getItemFromList($scope.subnet.vlan);\n                $scope.subnet.vlan_name = (\n                    VLANsManager.getName(vlan)\n                );\n            };\n\n            $scope.$watch(\"subnet.fabric\", updateFabric);\n            $scope.$watch(\"subnet.fabric_name\", updateFabric);\n            $scope.$watch(\"subnet.vlan\", updateFabric);\n            $scope.$watch(\"subnet.vlan_name\", updateVlan);\n            $scope.$watch(\"subnet.space\", updateSpace);\n            $scope.$watch(\"subnet.cidr\", updateIPVersion);\n        }\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            ConfigsManager, SubnetsManager, SpacesManager, VLANsManager,\n            UsersManager, FabricsManager, StaticRoutesManager\n        ]).then(function() {\n\n            $scope.updateActions();\n            $scope.active_discovery_data = ConfigsManager.getItemFromList(\n                \"active_discovery_interval\");\n            // Find active discovery interval\n            angular.forEach(\n                $scope.active_discovery_data.choices, function(choice) {\n                    if(choice[0] === $scope.active_discovery_data.value) {\n                        $scope.active_discovery_interval = choice[1];\n                    }\n                });\n\n            // Possibly redirected from another controller that already had\n            // this subnet set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeSubnet = SubnetsManager.getActiveItem();\n            var requestedSubnet = parseInt($routeParams.subnet_id, 10);\n            if(isNaN(requestedSubnet)) {\n                ErrorService.raiseError(\"Invalid subnet identifier.\");\n            } else if(angular.isObject(activeSubnet) &&\n                activeSubnet.id === requestedSubnet) {\n                subnetLoaded(activeSubnet);\n            } else {\n                SubnetsManager.setActiveItem(\n                    requestedSubnet).then(function(subnet) {\n                        subnetLoaded(subnet);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS VLAN Details Controller\n */\n\nangular.module('MAAS').filter('ignoreSelf', function () {\n    return function(objects, self) {\n        var filtered = [];\n        angular.forEach(objects, function(obj) {\n            if(obj !== self) {\n                filtered.push(obj);\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').controller('VLANDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', '$location',\n    'VLANsManager', 'SubnetsManager', 'SpacesManager', 'FabricsManager',\n    'ControllersManager', 'UsersManager', 'ManagerHelperService',\n    'ErrorService', 'ValidationService', function(\n        $scope, $rootScope, $routeParams, $filter, $location,\n        VLANsManager, SubnetsManager, SpacesManager, FabricsManager,\n        ControllersManager, UsersManager, ManagerHelperService, ErrorService,\n        ValidationService) {\n        var vm = this;\n\n        var filterByVLAN = $filter('filterByVLAN');\n        var filterControllersByVLAN = $filter('filterControllersByVLAN');\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"networks\";\n\n        vm.PROVIDE_DHCP_ACTION = {\n            // Note: 'title' is set dynamically depending on whether or not\n            // DHCP is already enabled on this VLAN.\n            name: \"enable_dhcp\"\n        };\n        vm.RELAY_DHCP_ACTION = {\n            // Note: 'title' is set ndynamically depending on whether or not\n            // DHCP relay is already enabled on this VLAN.\n            name: \"relay_dhcp\"\n        };\n        vm.DISABLE_DHCP_ACTION = {\n            name: \"disable_dhcp\",\n            title: \"Disable DHCP\"\n        };\n        vm.DELETE_ACTION = {\n            name: \"delete\",\n            title: \"Delete\"\n        };\n\n        // Initial values.\n        vm.loaded = false;\n        vm.vlan = null;\n        vm.title = null;\n        vm.actionOption = null;\n        vm.actionOptions = [];\n        vm.vlanManager = VLANsManager;\n        vm.vlans = VLANsManager.getItems();\n        vm.subnets = SubnetsManager.getItems();\n        vm.spaces = SpacesManager.getItems();\n        vm.fabrics = FabricsManager.getItems();\n        vm.controllers = ControllersManager.getItems();\n        vm.actionError = null;\n        vm.relatedSubnets = [];\n        vm.relatedControllers = [];\n        vm.provideDHCPAction = {};\n        vm.primaryRack = null;\n        vm.secondaryRack = null;\n        vm.editSummary = false;\n\n\n        // Return true if the authenticated user is super user.\n        vm.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Called when the \"edit\" button is cliked in the vlan summary\n        vm.enterEditSummary = function() {\n            vm.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the vlan summary\n        vm.exitEditSummary = function() {\n            vm.editSummary = false;\n        };\n\n        // Get the space name for the VLAN.\n        vm.getSpaceName = function() {\n            var space = SpacesManager.getItemFromList(vm.vlan.space);\n            if(space) {\n              return space.name;\n            } else {\n              return \"(undefined)\";\n            }\n        };\n\n        // Get the aciton structure for the action with the specified name.\n        vm.getActionByName = function(name) {\n            var i;\n            for(i = 0 ; i < vm.actionOptions.length ; i++) {\n                if(vm.actionOptions[i].name === name) {\n                    return vm.actionOptions[i];\n                }\n            }\n            return null;\n        };\n\n        // Initialize the provideDHCPAction structure with the current primary\n        // and secondary rack, plus an indication regarding whether or not\n        // adding a dynamic IP range is required.\n        vm.initProvideDHCP = function(forRelay) {\n            vm.provideDHCPAction = {};\n            var dhcp = vm.provideDHCPAction;\n            dhcp.subnet = null;\n            dhcp.relayVLAN = null;\n            if (angular.isNumber(vm.vlan.relay_vlan)) {\n                dhcp.relayVLAN = VLANsManager.getItemFromList(\n                    vm.vlan.relay_vlan);\n            }\n            if (angular.isObject(vm.primaryRack)) {\n                dhcp.primaryRack = vm.primaryRack.system_id;\n            } else if(vm.relatedControllers.length > 0) {\n                // Select the primary controller arbitrarily by default.\n                dhcp.primaryRack = vm.relatedControllers[0].system_id;\n            }\n            if (angular.isObject(vm.secondaryRack)) {\n                dhcp.secondaryRack = vm.secondaryRack.system_id;\n            } else if(vm.relatedControllers.length > 1) {\n                // Select the secondary controller arbitrarily by default.\n                dhcp.secondaryRack = vm.relatedControllers[1].system_id;\n            }\n            dhcp.maxIPs = 0;\n            dhcp.startIP = null;\n            dhcp.endIP = null;\n            dhcp.gatewayIP = \"\";\n            if (angular.isObject(vm.relatedSubnets)) {\n                // Select a subnet arbitrarily by default.\n                if (vm.relatedSubnets.length > 0 &&\n                        angular.isObject(vm.relatedSubnets[0].subnet)) {\n                    dhcp.subnet = vm.relatedSubnets[0].subnet.id;\n                }\n                dhcp.needsDynamicRange = true;\n                var i, subnet;\n                for (i = 0; i < vm.relatedSubnets.length; i++) {\n                    subnet = vm.relatedSubnets[i].subnet;\n                    // If any related subnet already has a dynamic range, we\n                    // cannot prompt the user to enter one here. If a\n                    // suggestion does not exist, a range does not exist\n                    // already.\n                    var iprange = subnet.statistics.suggested_dynamic_range;\n                    if (!angular.isObject(iprange)) {\n                        // If there is already a dynamic range on one of the\n                        // subnets, it's the \"subnet of least surprise\" if\n                        // the user is choosing to reconfigure their rack\n                        // controllers. (if they want DHCP on *another* subnet,\n                        // they should need to be explicit about it.)\n                        dhcp.subnet = subnet.id;\n                        dhcp.needsDynamicRange = false;\n                        break;\n                    }\n                }\n                // We must prompt the user for a subnet and a gateway IP\n                // address if any subnet does not yet contain a gateway IP\n                // address.\n                dhcp.needsGatewayIP = false;\n                dhcp.subnetMissingGatewayIP = true;\n                for (i = 0; i < vm.relatedSubnets.length; i++) {\n                    subnet = vm.relatedSubnets[i].subnet;\n                    if(subnet.gateway_ip === null ||\n                        subnet.gateway_ip === '') {\n                        dhcp.needsGatewayIP = true;\n                        break;\n                    }\n                }\n            }\n            // Since we are setting default values for these three options,\n            // ensure all the appropriate updates occur.\n            if(!forRelay) {\n                vm.updatePrimaryRack();\n                vm.updateSecondaryRack();\n            }\n            vm.updateSubnet(forRelay);\n        };\n\n        // Called when the actionOption has changed.\n        vm.actionOptionChanged = function() {\n            if(vm.actionOption.name === \"enable_dhcp\") {\n                vm.initProvideDHCP(false);\n            } else if(vm.actionOption.name === \"relay_dhcp\") {\n                vm.initProvideDHCP(true);\n            }\n            // Clear the action error.\n            vm.actionError = null;\n        };\n\n        // Cancel the action.\n        vm.actionCancel = function() {\n            // When the user wants to cancel an action, we need to clear out\n            // both the actionOption (so that the action screen will not be\n            // presented again) and the actionError (so that the error screen\n            // is hidden).\n            vm.actionOption = null;\n            vm.actionError = null;\n        };\n\n        // Called from the Provide DHCP form when the primary rack changes.\n        vm.updatePrimaryRack = function() {\n            var dhcp = vm.provideDHCPAction;\n            // If the user selects the secondary controller to be the primary,\n            // then the primary controller needs to be cleared out.\n            if(dhcp.primaryRack === dhcp.secondaryRack) {\n                dhcp.secondaryRack = null;\n            }\n            var i;\n            for(i = 0 ; i < vm.relatedControllers.length ; i++) {\n                if(vm.relatedControllers[i].system_id !== dhcp.primaryRack) {\n                    dhcp.secondaryRack = vm.relatedControllers[i].system_id;\n                    break;\n                }\n            }\n        };\n\n        // Called from the Provide DHCP form when the secondary rack changes.\n        vm.updateSecondaryRack = function() {\n            var dhcp = vm.provideDHCPAction;\n            // This should no longer be possible due to the filters on the\n            // drop-down boxes, but just in case.\n            if(dhcp.primaryRack === dhcp.secondaryRack) {\n                dhcp.primaryRack = null;\n                dhcp.secondaryRack = null;\n            }\n        };\n\n        // Called from the view to exclude the primary rack when selecting\n        // the secondary rack controller.\n        vm.filterPrimaryRack = function(rack) {\n            var dhcp = vm.provideDHCPAction;\n            return rack.system_id !== dhcp.primaryRack;\n        };\n\n        // Called from the Provide DHCP form when the subnet selection changes.\n        vm.updateSubnet = function(forRelay) {\n            var dhcp = vm.provideDHCPAction;\n            var subnet = SubnetsManager.getItemFromList(dhcp.subnet);\n            if(angular.isObject(subnet)) {\n                var suggested_gateway = null;\n                var iprange = null;\n                if(angular.isObject(subnet.statistics)) {\n                    suggested_gateway = subnet.statistics.suggested_gateway;\n                    iprange = subnet.statistics.suggested_dynamic_range;\n                }\n                if(angular.isObject(iprange) && iprange.num_addresses > 0) {\n                    dhcp.maxIPs = iprange.num_addresses;\n                    if(forRelay) {\n                        dhcp.startIP = \"\";\n                        dhcp.endIP = \"\";\n                        dhcp.startPlaceholder = iprange.start + \"(optional)\";\n                        dhcp.endPlaceholder = iprange.end + \" (optional)\";\n                    } else {\n                        dhcp.startIP = iprange.start;\n                        dhcp.endIP = iprange.end;\n                        dhcp.startPlaceholder = iprange.start;\n                        dhcp.endPlaceholder = iprange.end;\n                    }\n                } else {\n                    // Need to add a dynamic range, but according to our data,\n                    // there is no room on the subnet for a dynamic range.\n                    dhcp.maxIPs = 0;\n                    dhcp.startIP = \"\";\n                    dhcp.endIP = \"\";\n                    dhcp.startPlaceholder = \"(no available IPs)\";\n                    dhcp.endPlaceholder = \"(no available IPs)\";\n                }\n                if(angular.isString(suggested_gateway)) {\n                    if(forRelay) {\n                      dhcp.gatewayIP = \"\";\n                      dhcp.gatewayPlaceholder = (\n                          suggested_gateway + \" (optional)\");\n                    } else {\n                        dhcp.gatewayIP = suggested_gateway;\n                        dhcp.gatewayPlaceholder = suggested_gateway;\n                    }\n                } else {\n                    // This means the subnet already has a gateway, so don't\n                    // bother populating it.\n                    dhcp.gatewayIP = \"\";\n                    dhcp.gatewayPlaceholder = \"\";\n                }\n            } else {\n                // Don't need to add a dynamic range, so ensure these fields\n                // are cleared out.\n                dhcp.maxIPs = 0;\n                dhcp.startIP = null;\n                dhcp.endIP = null;\n                dhcp.gatewayIP = \"\";\n            }\n            if(angular.isObject(subnet)) {\n                dhcp.subnetMissingGatewayIP = !angular.isString(\n                    subnet.gateway_ip);\n            } else {\n                dhcp.subnetMissingGatewayIP = false;\n            }\n            if(dhcp.subnetMissingGatewayIP === false) {\n                dhcp.gatewayIP = null;\n            }\n       };\n\n        vm.actionRetry = function() {\n            // When we clear actionError, the HTML will be re-rendered to\n            // hide the error message (and the user will be taken back to\n            // the previous action they were performing, since we reset\n            // the actionOption in the error handler.\n            vm.actionError = null;\n        };\n\n        // Return True if the current action can be performed.\n        vm.canPerformAction = function() {\n            if(vm.actionOption.name === \"enable_dhcp\") {\n                return vm.relatedSubnets.length > 0;\n            } else if(vm.actionOption.name === \"relay_dhcp\") {\n                return angular.isObject(vm.provideDHCPAction.relayVLAN);\n            } else {\n                return true;\n            }\n        };\n\n        // Perform the action.\n        vm.actionGo = function() {\n            // Do nothing if action cannot be performed.\n            if(!vm.canPerformAction()) {\n               return;\n            }\n\n            if(vm.actionOption.name === \"enable_dhcp\") {\n                var dhcp = vm.provideDHCPAction;\n                var controllers = [];\n                // These will be undefined if they don't exist, and the region\n                // will simply get an empty dictionary.\n                var extra = {};\n                extra.subnet = dhcp.subnet;\n                extra.start = dhcp.startIP;\n                extra.end = dhcp.endIP;\n                extra.gateway = dhcp.gatewayIP;\n                if(angular.isString(dhcp.primaryRack)) {\n                    controllers.push(dhcp.primaryRack);\n                }\n                if(angular.isString(dhcp.secondaryRack)) {\n                    controllers.push(dhcp.secondaryRack);\n                }\n                // Abort the action without calling down to the region if\n                // the user didn't select a controller.\n                if(controllers.length === 0) {\n                    vm.actionError =\n                        \"A primary rack controller must be specified.\";\n                    return;\n                }\n                VLANsManager.configureDHCP(\n                    vm.vlan, controllers, extra).then(function() {\n                        vm.actionOption = null;\n                        vm.actionError = null;\n                    }, function(result) {\n                        vm.actionError = result.error;\n                        vm.actionOption = vm.PROVIDE_DHCP_ACTION;\n                    });\n            } else if(vm.actionOption.name === \"relay_dhcp\") {\n                // These will be undefined if they don't exist, and the region\n                // will simply get an empty dictionary.\n                var extraDHCP = {};\n                extraDHCP.subnet = vm.provideDHCPAction.subnet;\n                extraDHCP.start = vm.provideDHCPAction.startIP;\n                extraDHCP.end = vm.provideDHCPAction.endIP;\n                extraDHCP.gateway = vm.provideDHCPAction.gatewayIP;\n                var relay = vm.provideDHCPAction.relayVLAN.id;\n                VLANsManager.configureDHCP(\n                    vm.vlan, [], extraDHCP, relay).then(function() {\n                        vm.actionOption = null;\n                        vm.actionError = null;\n                    }, function(result) {\n                        vm.actionError = result.error;\n                        vm.actionOption = vm.RELAY_DHCP_ACTION;\n                    });\n            } else if(vm.actionOption.name === \"disable_dhcp\") {\n                VLANsManager.disableDHCP(vm.vlan).then(function() {\n                    vm.actionOption = null;\n                    vm.actionError = null;\n                }, function(result) {\n                    vm.actionError = result.error;\n                    vm.actionOption = vm.DISABLE_DHCP_ACTION;\n                });\n            } else if(vm.actionOption.name === \"delete\") {\n                VLANsManager.deleteVLAN(vm.vlan).then(function() {\n                    $location.path(\"/networks\");\n                    vm.actionOption = null;\n                    vm.actionError = null;\n                }, function(result) {\n                    vm.actionError = result.error;\n                    vm.actionOption = vm.DELETE_ACTION;\n                });\n            }\n        };\n\n        // Return true if there is an action error.\n        vm.isActionError = function() {\n            return vm.actionError !== null;\n        };\n\n        // Return the name of the VLAN.\n        vm.getFullVLANName = function(vlan_id) {\n            var vlan = VLANsManager.getItemFromList(vlan_id);\n            var fabric = FabricsManager.getItemFromList(vlan.fabric);\n            return (\n                FabricsManager.getName(fabric) + \".\" +\n                VLANsManager.getName(vlan));\n        };\n\n        // Return the current DHCP status.\n        vm.getDHCPStatus = function() {\n            if(vm.vlan) {\n              if(vm.vlan.dhcp_on) {\n                return \"Enabled\";\n              } else if(vm.vlan.relay_vlan) {\n                return \"Relayed via \" + vm.getFullVLANName(vm.vlan.relay_vlan);\n              } else {\n                return \"Disabled\";\n              }\n            } else {\n              return \"\";\n            }\n        };\n\n        // Updates the page title.\n        function updateTitle() {\n            var vlan = vm.vlan;\n            var fabric = vm.fabric;\n            if(angular.isObject(vlan) && angular.isObject(fabric)) {\n                if (!vlan.name) {\n                    if(vlan.vid === 0) {\n                        vm.title = \"Default VLAN\";\n                    } else {\n                        vm.title = \"VLAN \" + vlan.vid;\n                    }\n                } else {\n                    vm.title = vlan.name;\n                }\n                vm.title += \" in \" + fabric.name;\n                $rootScope.title = vm.title;\n            }\n        }\n\n        // Called from a $watch when the management racks are updated.\n        function updateManagementRacks() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            if(vlan.primary_rack) {\n                vm.primaryRack = ControllersManager.getItemFromList(\n                    vlan.primary_rack);\n            } else {\n                vm.primaryRack = null;\n            }\n            if(vlan.secondary_rack) {\n                vm.secondaryRack = ControllersManager.getItemFromList(\n                    vlan.secondary_rack);\n            } else {\n                vm.secondaryRack = null;\n            }\n        }\n\n        // Called from a $watch when the related controllers may have changed.\n        function updateRelatedControllers() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            var racks = [];\n            angular.forEach(vlan.rack_sids, function(rack_sid) {\n                var rack = ControllersManager.getItemFromList(rack_sid);\n                if(angular.isObject(rack)) {\n                    racks.push(rack);\n                }\n            });\n            vm.relatedControllers = racks;\n        }\n\n        // Called from a $watch when the related subnets or spaces may have\n        // changed.\n        function updateRelatedSubnets() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            var subnets = [];\n            angular.forEach(\n                    filterByVLAN(vm.subnets, vlan), function(subnet) {\n                var space = SpacesManager.getItemFromList(subnet.space);\n                if(!angular.isObject(space)) {\n                    space = {name: \"(undefined)\"};\n                }\n                var row = {\n                    subnet: subnet,\n                    space: space\n                };\n                subnets.push(row);\n            });\n            vm.relatedSubnets = subnets;\n        }\n\n        function updatePossibleActions() {\n            var vlan = vm.vlan;\n            if(!angular.isObject(vlan)) {\n                return;\n            }\n            // Clear out the actionOptions array. (this needs to be the same\n            // object, since it's watched from $scope.)\n            vm.actionOptions.length = 0;\n            if(UsersManager.isSuperUser()) {\n                if(!vlan.relay_vlan) {\n                  if(vlan.dhcp_on === true) {\n                      vm.PROVIDE_DHCP_ACTION.title = \"Reconfigure DHCP\";\n                      vm.actionOptions.push(vm.PROVIDE_DHCP_ACTION);\n                      vm.actionOptions.push(vm.DISABLE_DHCP_ACTION);\n                  } else {\n                      vm.PROVIDE_DHCP_ACTION.title = \"Provide DHCP\";\n                      vm.RELAY_DHCP_ACTION.title = \"Relay DHCP\";\n                      vm.actionOptions.push(vm.PROVIDE_DHCP_ACTION);\n                      vm.actionOptions.push(vm.RELAY_DHCP_ACTION);\n                  }\n                } else {\n                  vm.actionOptions.push(vm.RELAY_DHCP_ACTION);\n                  vm.actionOptions.push(vm.DISABLE_DHCP_ACTION);\n                  vm.RELAY_DHCP_ACTION.title = \"Reconfigure DHCP relay\";\n                }\n                if(!vm.isFabricDefault) {\n                    vm.actionOptions.push(vm.DELETE_ACTION);\n                }\n            }\n        }\n\n        // Called when the vlan has been loaded.\n        function vlanLoaded(vlan) {\n            vm.vlan = vlan;\n            vm.fabric = FabricsManager.getItemFromList(vlan.fabric);\n            vm.isFabricDefault = vm.fabric.default_vlan_id === vm.vlan.id;\n            vm.loaded = true;\n\n            updateTitle();\n            updateManagementRacks();\n            updateRelatedControllers();\n            updateRelatedSubnets();\n            updatePossibleActions();\n        }\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers($scope, [\n            VLANsManager, SubnetsManager, SpacesManager, FabricsManager,\n            ControllersManager, UsersManager\n        ]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this vlan set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeVLAN = VLANsManager.getActiveItem();\n            var requestedVLAN = parseInt($routeParams.vlan_id, 10);\n            if(isNaN(requestedVLAN)) {\n                ErrorService.raiseError(\"Invalid VLAN identifier.\");\n            } else if(angular.isObject(activeVLAN) &&\n                activeVLAN.id === requestedVLAN) {\n                vlanLoaded(activeVLAN);\n            } else {\n                VLANsManager.setActiveItem(\n                    requestedVLAN).then(function(vlan) {\n                        vlanLoaded(vlan);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n\n            $scope.$watch(\"vlanDetails.vlan.name\", updateTitle);\n            $scope.$watch(\"vlanDetails.vlan.vid\", updateTitle);\n            $scope.$watch(\"vlanDetails.vlan.dhcp_on\", updatePossibleActions);\n            $scope.$watch(\n                \"vlanDetails.vlan.relay_vlan\", updatePossibleActions);\n            $scope.$watch(\"vlanDetails.fabric.name\", updateTitle);\n            $scope.$watch(\n                \"vlanDetails.vlan.primary_rack\", updateManagementRacks);\n            $scope.$watch(\n                \"vlanDetails.vlan.secondary_rack\", updateManagementRacks);\n\n            $scope.$watchCollection(\n                \"vlanDetails.subnets\", updateRelatedSubnets);\n            $scope.$watchCollection(\n                \"vlanDetails.spaces\", updateRelatedSubnets);\n            $scope.$watchCollection(\n                \"vlanDetails.controllers\", updateRelatedControllers);\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Zone Details Controller\n */\n\nangular.module('MAAS').controller('ZoneDetailsController', [\n    '$scope', '$rootScope', '$routeParams', '$location', 'MachinesManager',\n    'DevicesManager', 'ZonesManager', 'UsersManager',\n    'ManagerHelperService', 'ErrorService',\n    function(\n        $scope, $rootScope, $routeParams, $location, MachinesManager,\n        DevicesManager, ZonesManager, UsersManager, ManagerHelperService,\n        ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Loading...\";\n\n        // Note: this value must match the top-level tab, in order for\n        // highlighting to occur properly.\n        $rootScope.page = \"zones\";\n\n        // Initial values.\n        $scope.loaded = false;\n        $scope.zone = null;\n        $scope.zoneManager = ZonesManager;\n        $scope.editSummary = false;\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n\n        // Updates the page title.\n        function updateTitle() {\n            $rootScope.title = $scope.zone.name;\n        }\n\n        // Called when the zone has been loaded.\n        function zoneLoaded(zone) {\n            $scope.zone = zone;\n            $scope.loaded = true;\n            updateTitle();\n        }\n\n\n        // Called when the \"edit\" button is cliked in the zone summary\n        $scope.enterEditSummary = function() {\n            $scope.editSummary = true;\n        };\n\n        // Called when the \"cancel\" button is cliked in the zone summary\n        $scope.exitEditSummary = function() {\n            $scope.editSummary = false;\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        // Return true if this is the default zone.\n        $scope.isDefaultZone = function() {\n            if(angular.isObject($scope.zone)) {\n                return $scope.zone.id === 1;\n            }\n            return false;\n        };\n\n        // Called to check if the zone can be deleted.\n        $scope.canBeDeleted = function() {\n            if(angular.isObject($scope.zone)) {\n                return $scope.zone.id !== 0;\n            }\n            return false;\n        };\n\n        // Called when the delete zone button is pressed.\n        $scope.deleteButton = function() {\n            $scope.error = null;\n            $scope.confirmingDelete = true;\n        };\n\n        // Called when the cancel delete zone button is pressed.\n        $scope.cancelDeleteButton = function() {\n            $scope.confirmingDelete = false;\n        };\n\n        // Called when the confirm delete space button is pressed.\n        $scope.deleteConfirmButton = function() {\n            ZonesManager.deleteItem($scope.zone).then(function() {\n                $scope.confirmingDelete = false;\n                $location.path(\"/zones\");\n            }, function(error) {\n                $scope.error =\n                    ManagerHelperService.parseValidationError(error);\n            });\n        };\n\n        // Load all the required managers.\n        ManagerHelperService.loadManagers(\n            $scope, [ZonesManager, UsersManager]).then(function() {\n            // Possibly redirected from another controller that already had\n            // this zone set to active. Only call setActiveItem if not\n            // already the activeItem.\n            var activeZone = ZonesManager.getActiveItem();\n            var requestedZone = parseInt($routeParams.zone_id, 10);\n            if(isNaN(requestedZone)) {\n                ErrorService.raiseError(\"Invalid zone identifier.\");\n            } else if(angular.isObject(activeZone) &&\n                activeZone.id === requestedZone) {\n                zoneLoaded(activeZone);\n            } else {\n                ZonesManager.setActiveItem(\n                    requestedZone).then(function(zone) {\n                        zoneLoaded(zone);\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n            }\n        });\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Zones List Controller\n */\n\nangular.module('MAAS').controller('ZonesListController', [\n    '$scope', '$rootScope', '$routeParams', '$filter', 'MachinesManager',\n    'DevicesManager', 'ControllersManager', 'ZonesManager', 'ServicesManager',\n    'UsersManager', 'ManagerHelperService', 'ErrorService',\n    function($scope, $rootScope, $routeParams, $filter, MachinesManager,\n        DevicesManager, ControllersManager, ZonesManager, ServicesManager,\n        UsersManager, ManagerHelperService, ErrorService) {\n\n        // Set title and page.\n        $rootScope.title = \"Zones\";\n        $rootScope.page = \"zones\";\n\n        // Set initial values.\n        $scope.zoneManager = ZonesManager;\n        $scope.zones = ZonesManager.getItems();\n        $scope.currentpage = \"zones\";\n        $scope.predicate = \"name\";\n        $scope.reverse = false;\n        $scope.loading = true;\n        $scope.action = {\n          open: false,\n          obj: {}\n        };\n\n        // Open add zone view.\n        $scope.addZone = function() {\n          $scope.action.open = true;\n        };\n\n        // Saving has completed.\n        $scope.closeZone = function() {\n          $scope.action.open = false;\n          $scope.action.obj = {};\n        };\n\n        // Return true if the authenticated user is super user.\n        $scope.isSuperUser = function() {\n            return UsersManager.isSuperUser();\n        };\n\n        ManagerHelperService.loadManagers(\n            $scope, [ZonesManager, UsersManager]).then(\n            function() {\n                $scope.loading = false;\n            });\n        }\n    ]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Accordion directive.\n *\n * Provides an accordion effect to an element with maas-accordion class and\n * all child elements with maas-accordion-tab. Only one accordion tab is open\n * at a time, selecting another accordion will set \"active\" on that\n * accordion tab.\n */\n\n\nangular.module('MAAS').directive('maasAccordion', function() {\n    return {\n        restrict: \"C\",\n        link: function(scope, element, attrs) {\n\n            // Called when accordion tabs are clicked. Removes active on\n            // all other tabs except to the tab that was clicked.\n            var clickHandler = function(evt) {\n                var tab = evt.data.tab;\n                angular.element(tab).toggleClass(\"is-selected\");\n            };\n\n            // Listen for the click event on all tabs in the accordion.\n            var tabs = element.find(\".maas-accordion-tab\");\n            angular.forEach(tabs, function(tab) {\n                tab = angular.element(tab);\n                tab.on(\"click\", {\n                    tab: tab\n                }, clickHandler);\n            });\n\n            // Remove the handlers when the scope is destroyed.\n            scope.$on(\"$destroy\", function() {\n                angular.forEach(tabs, function(tab) {\n                    angular.element(tab).off(\"click\", clickHandler);\n                });\n            });\n        }\n    };\n});\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Boot images directive.\n*/\n\nangular.module('MAAS').directive('maasBootImagesStatus', [\n    'BootResourcesManager',\n    function(BootResourcesManager) {\n        return {\n            restrict: \"E\",\n            scope: {},\n            template: [\n                '<p class=\"page-header__status\" ',\n                    'data-ng-if=\"data.region_import_running\">',\n                    '<span class=\"u-text--loading\">',\n                        '<i class=\"p-icon--loading u-animation--spin\"></i>',\n                        'Step 1/2: Region controller importing',\n                    '</span>',\n                '</p>',\n                '<p class=\"page-header__status\" ',\n                    'data-ng-if=\"!data.region_import_running && ',\n                    'data.rack_import_running\">',\n                    '<span class=\"u-text--loading\">',\n                        '<i class=\"p-icon--loading u-animation--spin\"></i>',\n                        'Step 2/2: Rack controller(s) importing',\n                    '</span>',\n                '</p>'\n            ].join(''),\n            controller: function($scope, $rootScope, $element, $document) {\n                // This controller doesn't start the polling. The\n                // `maasBootImages` controller should be used on the page to\n                // start the polling. This just presents a nice status spinner\n                // when the polling is enabled.\n                $scope.data = BootResourcesManager.getData();\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasBootImages', [\n    '$filter', 'BootResourcesManager', 'UsersManager', 'ManagerHelperService',\n    function($filter, BootResourcesManager,\n        UsersManager, ManagerHelperService) {\n        return {\n            restrict: \"E\",\n            scope: {\n                design: \"=?\"\n            },\n            templateUrl: (\n                'static/partials/boot-images.html?v=' + (\n                    MAAS_config.files_version)),\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                $scope.saving = false;\n                $scope.stopping = false;\n                $scope.design = $scope.design || 'page';\n                $scope.bootResources = BootResourcesManager.getData();\n                $scope.ubuntuImages = [];\n                $scope.source = {\n                    isNew: false,\n                    tooMany: false,\n                    showingAdvanced: false,\n                    connecting: false,\n                    errorMessage: \"\",\n                    source_type: 'maas.io',\n                    url: '',\n                    keyring_filename: '',\n                    keyring_data: '',\n                    releases: [],\n                    arches: [],\n                    selections: {\n                        changed: false,\n                        releases: [],\n                        arches: []\n                    }\n                };\n                $scope.ubuntuCoreImages = [];\n                $scope.ubuntu_core = {\n                    changed: false,\n                    images: []\n                };\n                $scope.otherImages = [];\n                $scope.other = {\n                    changed: false,\n                    images: []\n                };\n                $scope.generatedImages = [];\n                $scope.customImages = [];\n                $scope.ubuntuDeleteId = null;\n                $scope.removingImage = null;\n\n                // Return true if the authenticated user is super user.\n                $scope.isSuperUser = function() {\n                    return UsersManager.isSuperUser();\n                };\n\n                // Return the overall title icon.\n                $scope.getTitleIcon = function() {\n                    if($scope.bootResources.resources.length === 0) {\n                        return 'p-icon--success-muted';\n                    } else {\n                        return 'p-icon--success';\n                    }\n                };\n\n                // Return true if the mirror path section should be shown.\n                $scope.showMirrorPath = function() {\n                    if($scope.source.source_type === 'custom') {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                };\n\n                // Return true if the advanced options are shown.\n                $scope.isShowingAdvancedOptions = function() {\n                    return $scope.source.showingAdvanced;\n                };\n\n                // Toggle showing the advanced options.\n                $scope.toggleAdvancedOptions = function() {\n                    $scope.source.showingAdvanced = (\n                        !$scope.source.showingAdvanced);\n                };\n\n                // Return true if both keyring options are set.\n                $scope.bothKeyringOptionsSet = function() {\n                    return (\n                        $scope.source.keyring_filename.length > 0 &&\n                        $scope.source.keyring_data.length > 0);\n                };\n\n                // Return true when the connect button for the mirror path\n                // should be shown.\n                $scope.showConnectButton = function() {\n                    return $scope.source.isNew;\n                };\n\n                // Called when the source radio chanaged.\n                $scope.sourceChanged = function() {\n                    var currentSources = $scope.bootResources.ubuntu.sources;\n                    if(currentSources.length === 0) {\n                        $scope.source.isNew = true;\n                    } else {\n                        var prevNew = $scope.source.isNew;\n                        $scope.source.isNew = (\n                            $scope.source.source_type !==\n                            currentSources[0].source_type);\n                        if($scope.source.source_type === 'custom') {\n                            $scope.source.isNew = $scope.source.isNew || (\n                                $scope.source.url !==\n                                currentSources[0].url\n                            );\n                        }\n                        if(prevNew && !$scope.source.isNew) {\n                            // No longer a new source set url and keyring to\n                            // original.\n                            $scope.source.url = currentSources[0].url;\n                            $scope.source.keyring_filename = (\n                                currentSources[0].keyring_filename);\n                            $scope.source.keyring_data = (\n                                currentSources[0].keyring_data);\n                        }\n                        $scope.source.releases = [];\n                        $scope.source.arches = [];\n                        $scope.source.selections = {\n                            changed: false,\n                            releases: [],\n                            arches: []\n                        };\n                    }\n                    $scope.updateSource();\n                    $scope.regenerateUbuntuImages();\n\n                    // When the source is new and its maas.io automatically\n                    // fetch the source information.\n                    if($scope.source.isNew &&\n                        $scope.source.source_type === 'maas.io') {\n                        $scope.connect();\n                    }\n                };\n\n                // Return true when the connect button should be disabled.\n                $scope.isConnectButtonDisabled = function() {\n                    if($scope.source.source_type === 'maas.io') {\n                        return false;\n                    } else {\n                        return ($scope.bothKeyringOptionsSet() ||\n                            $scope.source.url.length === 0 ||\n                            $scope.source.connecting);\n                    }\n                };\n\n                // Return the source parameters.\n                $scope.getSourceParams = function() {\n                    if($scope.source.source_type === 'maas.io') {\n                        return {\n                            source_type: 'maas.io'\n                        };\n                    } else {\n                        return {\n                            source_type: $scope.source.source_type,\n                            url: $scope.source.url,\n                            keyring_filename: $scope.source.keyring_filename,\n                            keyring_data: $scope.source.keyring_data\n                        };\n                    }\n                };\n\n                // Select the default images that should be selected. Current\n                // defaults are '16.04 LTS' and 'amd64'.\n                $scope.selectDefaults = function() {\n                    angular.forEach($scope.source.releases, function(release) {\n                        if(release.name === \"xenial\") {\n                            $scope.source.selections.releases.push(release);\n                        }\n                    });\n                    angular.forEach($scope.source.arches, function(arch) {\n                        if(arch.name === \"amd64\") {\n                            $scope.source.selections.arches.push(arch);\n                        }\n                    });\n                };\n\n                // Connected to the simplestreams endpoint. This only gets the\n                // information from the endpoint it does not save it into the\n                // database.\n                $scope.connect = function() {\n                    if($scope.isConnectButtonDisabled()) {\n                        return;\n                    }\n\n                    var source = $scope.getSourceParams();\n                    $scope.source.connecting = true;\n                    $scope.source.releases = [];\n                    $scope.source.arches = [];\n                    $scope.source.selections.changed = true;\n                    $scope.source.selections.releases = [];\n                    $scope.source.selections.arches = [];\n                    $scope.regenerateUbuntuImages();\n                    BootResourcesManager.fetch(source).then(function(data) {\n                        $scope.source.connecting = false;\n                        data = angular.fromJson(data);\n                        $scope.source.releases = data.releases;\n                        $scope.source.arches = data.arches;\n                        $scope.selectDefaults();\n                        $scope.regenerateUbuntuImages();\n                    }, function(error) {\n                        $scope.source.connecting = false;\n                        $scope.source.errorMessage = error;\n                    });\n                };\n\n                // Return true if the connect block should be shown.\n                $scope.showConnectBlock = function() {\n                    return $scope.source.tooMany || (\n                        $scope.source.isNew && !$scope.showSelections());\n                };\n\n                // Return true if the release and architecture selection\n                // should be shown.\n                $scope.showSelections = function() {\n                    return (\n                        $scope.source.releases.length > 0 &&\n                        $scope.source.arches.length > 0);\n                };\n\n                // Return the Ubuntu LTS releases.\n                $scope.getUbuntuLTSReleases = function() {\n                    var releases = $scope.bootResources.ubuntu.releases;\n                    if($scope.source.isNew) {\n                        releases = $scope.source.releases;\n                    }\n                    var filtered = [];\n                    angular.forEach(releases, function(release) {\n                        if(!release.deleted &&\n                            release.title.indexOf('LTS') !== -1) {\n                            filtered.push(release);\n                        }\n                    });\n                    return filtered;\n                };\n\n                // Return the Ubuntu non-LTS releases.\n                $scope.getUbuntuNonLTSReleases = function() {\n                    var releases = $scope.bootResources.ubuntu.releases;\n                    if($scope.source.isNew) {\n                        releases = $scope.source.releases;\n                    }\n                    var filtered = [];\n                    angular.forEach(releases, function(release) {\n                        if(!release.deleted &&\n                            release.title.indexOf('LTS') === -1) {\n                            filtered.push(release);\n                        }\n                    });\n                    return filtered;\n                };\n\n                // Return the available architectures.\n                $scope.getArchitectures = function() {\n                    var arches = $scope.bootResources.ubuntu.arches;\n                    if($scope.source.isNew) {\n                        arches = $scope.source.arches;\n                    }\n                    var filtered = [];\n                    angular.forEach(arches, function(arch) {\n                        if(!arch.deleted) {\n                            filtered.push(arch);\n                        }\n                    });\n                    return filtered;\n                };\n\n                // Return true if the source has this selected.\n                $scope.isSelected = function(type, obj) {\n                    return $scope.source.selections[type].indexOf(obj) >= 0;\n                };\n\n                // Toggle the selection of the release or the architecture.\n                $scope.toggleSelection = function(type, obj) {\n                    var idx = $scope.source.selections[type].indexOf(obj);\n                    if(idx === -1) {\n                        $scope.source.selections[type].push(obj);\n                    } else {\n                        $scope.source.selections[type].splice(idx, 1);\n                    }\n                    $scope.source.selections.changed = true;\n                    $scope.regenerateUbuntuImages();\n                };\n\n                // Return true if the images table should be shown.\n                $scope.showImagesTable = function() {\n                    if($scope.ubuntuImages.length > 0) {\n                        return true;\n                    } else {\n                        // Show the images table source has\n                        // releases and architectures.\n                        return (\n                            $scope.source.arches.length > 0 &&\n                            $scope.source.releases.length > 0);\n                    }\n                };\n\n                // Regenerates the Ubuntu images list for the directive.\n                $scope.regenerateUbuntuImages = function() {\n                    var getResource = function() { return null; };\n                    var resources = $scope.bootResources.resources.filter(\n                        function(resource) {\n                            var name_split = resource.name.split('/');\n                            var resource_os = name_split[0];\n                            return (\n                                resource.rtype === 0 &&\n                                resource_os === 'ubuntu');\n                        });\n                    if(!$scope.source.isNew) {\n                        getResource = function(release, arch) {\n                            var i;\n                            for(i = 0; i < resources.length; i++) {\n                                // Only care about Ubuntu images.\n                                var resource = (resources[i]);\n                                var name_split = resource.name.split('/');\n                                var resource_release = name_split[1];\n                                if(resource_release === release &&\n                                    resource.arch === arch) {\n                                    resources.splice(i, 1);\n                                    return resource;\n                                }\n                            }\n                            return null;\n                        };\n                    }\n\n                    // Create the images based on the selections.\n                    $scope.ubuntuImages.length = 0;\n                    angular.forEach($scope.source.selections.releases,\n                        function(release) {\n                            angular.forEach($scope.source.selections.arches,\n                                function(arch) {\n                                    var image = {\n                                        icon: 'p-icon--status-queued',\n                                        title: release.title,\n                                        arch: arch.title,\n                                        size: '-',\n                                        status: 'Selected for download',\n                                        beingDeleted: false,\n                                        name: release.name\n                                    };\n                                    var resource = getResource(\n                                        release.name, arch.name);\n                                    if(angular.isObject(resource)) {\n                                        image.resourceId = resource.id;\n                                        image.icon = (\n                                            'p-icon--status-' + resource.icon);\n                                        image.size = resource.size;\n                                        image.status = resource.status;\n                                        if(resource.downloading) {\n                                            image.icon += ' u-animation--pulse';\n                                        }\n                                    }\n                                    $scope.ubuntuImages.push(image);\n                                });\n                        });\n\n                    // If not a new source and images remain in resources, then\n                    // those are set to be deleted.\n                    if(!$scope.source.isNew) {\n                        angular.forEach(resources, function(resource) {\n                            var name_split = resource.name.split('/');\n                            var image = {\n                                icon: 'p-icon--status-failed',\n                                title: resource.title,\n                                arch: resource.arch,\n                                size: resource.size,\n                                status: 'Will be deleted',\n                                beingDeleted: true,\n                                name: name_split[1]\n                            };\n                            $scope.ubuntuImages.push(image);\n                        });\n                    }\n                };\n\n                // Regenerates the Ubuntu Core images list for the directive.\n                $scope.regenerateUbuntuCoreImages = function() {\n                    var isUbuntuCore = function(resource) {\n                        var name_split = resource.name.split('/');\n                        var resource_os = name_split[0];\n                        return (\n                            resource.rtype === 0 &&\n                            resource_os === 'ubuntu-core');\n                    };\n                    var resources = (\n                        $scope.bootResources.resources.filter(isUbuntuCore));\n                    var getResource = function(release, arch) {\n                        var i;\n                        for(i = 0; i < resources.length; i++) {\n                            // Only care about other images. Removing custom,\n                            // bootloaders, and Ubuntu images.\n                            var resource = (resources[i]);\n                            var name_split = resource.name.split('/');\n                            var resource_release = name_split[1];\n                            if(resource_release === release &&\n                                resource.arch === arch) {\n                                resources.splice(i, 1);\n                                return resource;\n                            }\n                        }\n                        return null;\n                    };\n\n                    // Create the images based on the selections.\n                    $scope.ubuntuCoreImages.length = 0;\n                    angular.forEach($scope.ubuntu_core.images,\n                        function(ubuntuCoreImage) {\n                            if(ubuntuCoreImage.checked) {\n                                var name_split = ubuntuCoreImage.name.split(\n                                    '/');\n                                var image = {\n                                    icon: 'p-icon--status-queued',\n                                    title: ubuntuCoreImage.title,\n                                    arch: name_split[1],\n                                    size: '-',\n                                    status: 'Selected for download',\n                                    beingDeleted: false\n                                };\n                                var resource = getResource(\n                                    name_split[3], name_split[1]);\n                                if(angular.isObject(resource)) {\n                                    image.icon = (\n                                        'p-icon--status-' + resource.icon);\n                                    image.size = resource.size;\n                                    image.status = resource.status;\n                                    if(resource.downloading) {\n                                        image.icon += ' u-animation--pulse';\n                                    }\n                                }\n                                $scope.ubuntuCoreImages.push(image);\n                            }\n                        });\n\n                    // If not a new source and images remain in resources, then\n                    // those are set to be deleted.\n                    angular.forEach(resources, function(resource) {\n                        var image = {\n                            icon: 'p-icon--status-failed',\n                            title: resource.title,\n                            arch: resource.arch,\n                            size: resource.size,\n                            status: 'Will be deleted',\n                            beingDeleted: true\n                        };\n                        $scope.ubuntuCoreImages.push(image);\n                    });\n                };\n\n                // Regenerates the other images list for the directive.\n                $scope.regenerateOtherImages = function() {\n                    var isOther = function(resource) {\n                        var name_split = resource.name.split('/');\n                        var resource_os = name_split[0];\n                        return (\n                            resource.rtype === 0 &&\n                            resource_os !== 'ubuntu' &&\n                            resource_os !== 'ubuntu-core' &&\n                            resource_os !== 'custom');\n                    };\n                    var resources = (\n                        $scope.bootResources.resources.filter(isOther));\n                    var getResource = function(release, arch) {\n                        var i;\n                        for(i = 0; i < resources.length; i++) {\n                            // Only care about other images. Removing custom,\n                            // bootloaders, and Ubuntu images.\n                            var resource = (resources[i]);\n                            var name_split = resource.name.split('/');\n                            var resource_release = name_split[1];\n                            if(resource_release === release &&\n                                resource.arch === arch) {\n                                resources.splice(i, 1);\n                                return resource;\n                            }\n                        }\n                        return null;\n                    };\n\n                    // Create the images based on the selections.\n                    $scope.otherImages.length = 0;\n                    angular.forEach($scope.other.images,\n                        function(otherImage) {\n                            if(otherImage.checked) {\n                                var name_split = otherImage.name.split('/');\n                                var image = {\n                                    icon: 'p-icon--status-queued',\n                                    title: otherImage.title,\n                                    arch: name_split[1],\n                                    size: '-',\n                                    status: 'Selected for download',\n                                    beingDeleted: false\n                                };\n                                var resource = getResource(\n                                    name_split[3], name_split[1]);\n                                if(angular.isObject(resource)) {\n                                    image.icon = (\n                                        'p-icon--status-' + resource.icon);\n                                    image.size = resource.size;\n                                    image.status = resource.status;\n                                    if(resource.downloading) {\n                                        image.icon += ' u-animation--pulse';\n                                    }\n                                }\n                                $scope.otherImages.push(image);\n                            }\n                        });\n\n                    // If not a new source and images remain in resources, then\n                    // those are set to be deleted.\n                    angular.forEach(resources, function(resource) {\n                        var image = {\n                            icon: 'p-icon--status-failed',\n                            title: resource.title,\n                            arch: resource.arch,\n                            size: resource.size,\n                            status: 'Will be deleted',\n                            beingDeleted: true\n                        };\n                        $scope.otherImages.push(image);\n                    });\n                };\n\n                // Helper for basic image generation.\n                $scope._regenerateImages = function(rtype, images) {\n                    // Create the generated images list.\n                    images.length = 0;\n                    angular.forEach($scope.bootResources.resources,\n                        function(resource) {\n                            if(resource.rtype === rtype) {\n                                var image = {\n                                    icon: 'p-icon--status-' + resource.icon,\n                                    title: resource.title,\n                                    arch: resource.arch,\n                                    image_id: resource.id,\n                                    size: resource.size,\n                                    status: resource.status\n                                };\n                                if(resource.downloading) {\n                                    image.icon += ' u-animation--pulse';\n                                }\n                                images.push(image);\n                            }\n                        });\n                };\n\n                // Regenerates the generated images list for the directive.\n                $scope.regenerateGeneratedImages = function() {\n                    $scope._regenerateImages(1, $scope.generatedImages);\n                };\n\n                // Regenerates the custom images list for the directive.\n                $scope.regenerateCustomImages = function() {\n                    $scope._regenerateImages(2, $scope.customImages);\n                };\n\n                // Returns true if at least one LTS is selected.\n                $scope.ltsIsSelected = function() {\n                    var i;\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        // Must have LTS in the title and not being deleted.\n                        if(!$scope.ubuntuImages[i].beingDeleted &&\n                            $scope.ubuntuImages[i].title.indexOf('LTS') >= 0) {\n                            // Must be greater than Ubuntu series 14.\n                            var series = parseInt(\n                                $scope.ubuntuImages[i].title.split('.')[0], 10);\n                            if(series >= 14) {\n                                return true;\n                            }\n                        }\n                    }\n                    return false;\n                };\n\n                // Returns true if the commission series is selected\n                $scope.commissioningSeriesSelected = function() {\n                    var i;\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        if(!$scope.ubuntuImages[i].beingDeleted &&\n                           $scope.ubuntuImages[i].name ===\n                           $scope.bootResources.ubuntu.commissioning_series) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n\n                // Return if we are asking about deleting this image.\n                $scope.isShowingDeleteConfirm = function(image) {\n                    return image === $scope.removingImage;\n                };\n\n                // Mark the image for deletion.\n                $scope.quickRemove = function(image) {\n                    $scope.removingImage = image;\n                };\n\n                // Cancel image deletion.\n                $scope.cancelRemove = function() {\n                    $scope.removingImage = null;\n                };\n\n                // Mark the image for deletion.\n                $scope.confirmRemove = function(image) {\n                    if(image === $scope.removingImage) {\n                        BootResourcesManager.deleteImage(\n                            {id: image.image_id});\n                    }\n                    $scope.cancelRemove();\n                };\n\n                // Return true if the stop import button should be shown.\n                $scope.showStopImportButton = function() {\n                    return $scope.bootResources.region_import_running;\n                };\n\n                // Return true if should show save selection button, this\n                // doesn't mean it can actually be clicked.\n                $scope.showSaveSelection = function() {\n                    return $scope.showImagesTable();\n                };\n\n                // Return true if can save the current selection.\n                $scope.canSaveSelection = function() {\n                    var commissioning_series_being_deleted = false;\n                    var commissioning_series_arches = 0;\n                    var i;\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        if($scope.ubuntuImages[i].name ===\n                           $scope.bootResources.ubuntu.commissioning_series) {\n                            commissioning_series_arches++;\n                        }\n                    }\n                    // Only prevent the current commissioning series from\n                    // being deleted if it isn't the commissioning series isn't\n                    // available on another architecture.. If the current\n                    // commissioning series isn't currently selected another\n                    // LTS may be choosen, downloaded, and configured as the\n                    // commissioning series.\n                    for(i = 0; i < $scope.ubuntuImages.length; i++) {\n                        if($scope.ubuntuImages[i].beingDeleted &&\n                           $scope.ubuntuImages[i].name ===\n                           $scope.bootResources.ubuntu.commissioning_series &&\n                           commissioning_series_arches === 1) {\n                            commissioning_series_being_deleted = true;\n                            break;\n                        }\n                    }\n                    return (\n                        !commissioning_series_being_deleted &&\n                        !$scope.saving &&\n                        !$scope.stopping &&\n                        $scope.ltsIsSelected());\n                };\n\n                // Return the text for the save selection button.\n                $scope.getSaveSelectionText = function() {\n                    if($scope.saving) {\n                        return \"Saving...\";\n                    } else {\n                        return \"Update selection\";\n                    }\n                };\n\n                // Return true if can stop current import.\n                $scope.canStopImport = function() {\n                    return !$scope.saving && !$scope.stopping;\n                };\n\n                // Return the text for the stop import button.\n                $scope.getStopImportText = function() {\n                    if($scope.stopping) {\n                        return \"Stopping...\";\n                    } else {\n                        return \"Stop import\";\n                    }\n                };\n\n                // Called to stop the import.\n                $scope.stopImport = function() {\n                    if(!$scope.canStopImport()) {\n                        return;\n                    }\n\n                    $scope.stopping = true;\n                    BootResourcesManager.stopImport().then(function() {\n                        $scope.stopping = false;\n                    });\n                };\n\n                // Save the selections into boot selections.\n                $scope.saveSelection = function() {\n                    if(!$scope.canSaveSelection()) {\n                        return;\n                    }\n\n                    var params = $scope.getSourceParams();\n                    params.releases = (\n                        $scope.source.selections.releases.map(function(obj) {\n                            return obj.name;\n                        }));\n                    params.arches = (\n                        $scope.source.selections.arches.map(function(obj) {\n                            return obj.name;\n                        }));\n                    $scope.saving = true;\n                    BootResourcesManager.saveUbuntu(params).then(function() {\n                        $scope.saving = false;\n                        $scope.source.isNew = false;\n                        $scope.source.selections.changed = false;\n                        $scope.updateSource();\n                    });\n                };\n\n                // Re-create an array with the new objects using the old\n                // selected array.\n                $scope.getNewSelections = function(newObjs, oldSelections) {\n                    var newSelections = [];\n                    angular.forEach(newObjs, function(obj) {\n                        angular.forEach(oldSelections, function(selection) {\n                            if(obj.name === selection.name) {\n                                newSelections.push(obj);\n                            }\n                        });\n                    });\n                    return newSelections;\n                };\n\n                // Update the source information.\n                $scope.updateSource = function() {\n                    // Do not update if the source is new.\n                    if($scope.source.isNew) {\n                        return;\n                    }\n\n                    var source_len = $scope.bootResources.ubuntu.sources.length;\n                    if(source_len === 0) {\n                        $scope.source.isNew = true;\n                        $scope.source.source_type = 'custom';\n                        $scope.source.errorMessage = (\n                            \"Currently no source exists.\");\n                    } else if(source_len === 1) {\n                        var source = $scope.bootResources.ubuntu.sources[0];\n                        $scope.source.source_type = source.source_type;\n                        if(source.source_type === \"maas.io\") {\n                            $scope.source.url = \"\";\n                            $scope.source.keyring_filename = \"\";\n                            $scope.source.keyring_data = \"\";\n                        } else {\n                            $scope.source.url = source.url;\n                            $scope.source.keyring_filename = (\n                                source.keyring_filename);\n                            $scope.source.keyring_data = source.keyring_data;\n                        }\n                        $scope.source.releases = (\n                            $scope.bootResources.ubuntu.releases);\n                        $scope.source.arches = (\n                            $scope.bootResources.ubuntu.arches);\n                        if(!$scope.source.selections.changed) {\n                            // User didn't make a change update to the\n                            // current selections server side.\n                            $scope.source.selections.releases = (\n                                $scope.source.releases.filter(function(obj) {\n                                    return obj.checked;\n                                }));\n                            $scope.source.selections.arches = (\n                                $scope.source.arches.filter(function(obj) {\n                                return obj.checked;\n                            }));\n                        } else {\n                            // Update the objects to be the new objects, with\n                            // the same selections.\n                            $scope.source.selections.releases = (\n                                $scope.getNewSelections(\n                                    $scope.source.releases,\n                                    $scope.source.selections.releases));\n                            $scope.source.selections.arches = (\n                                $scope.getNewSelections(\n                                    $scope.source.arches,\n                                    $scope.source.selections.arches));\n                        }\n                        $scope.regenerateUbuntuImages();\n                    } else {\n                        // Having more than one source prevents modification\n                        // of the sources.\n                        $scope.source.tooMany = true;\n                        $scope.source.releases = (\n                            $scope.bootResources.ubuntu.releases);\n                        $scope.source.arches = (\n                            $scope.bootResources.ubuntu.arches);\n                        $scope.source.selections.releases = (\n                            $scope.source.releases.filter(function(obj) {\n                                return obj.checked;\n                            }));\n                        $scope.source.selections.arches = (\n                            $scope.source.arches.filter(function(obj) {\n                            return obj.checked;\n                        }));\n                        $scope.source.errorMessage = (\n                            \"More than one image source exists. UI does not \" +\n                            \"support modification of sources when more than \" +\n                            \"one has been defined. Used the API to adjust \" +\n                            \"your sources.\");\n                        $scope.regenerateUbuntuImages();\n                    }\n                };\n\n                // Toggle the selection of Ubuntu Core images.\n                $scope.toggleUbuntuCoreSelection = function(image) {\n                    $scope.ubuntu_core.changed = true;\n                    image.checked = !image.checked;\n                    $scope.regenerateUbuntuCoreImages();\n                };\n\n                // Save the Ubuntu Core image selections into boot selections.\n                $scope.saveUbuntuCoreSelection = function() {\n                    var params = {\n                        images: $scope.ubuntu_core.images.filter(function(\n                                image) {\n                            return image.checked;\n                        }).map(function(image) {\n                            return image.name;\n                        })\n                    };\n                    $scope.saving = true;\n                    BootResourcesManager.saveUbuntuCore(params).then(\n                            function() {\n                        $scope.saving = false;\n                    });\n                };\n\n                // Toggle the selection of other images.\n                $scope.toggleOtherSelection = function(image) {\n                    $scope.other.changed = true;\n                    image.checked = !image.checked;\n                    $scope.regenerateOtherImages();\n                };\n\n                // Save the other image selections into boot selections.\n                $scope.saveOtherSelection = function() {\n                    var params = {\n                        images: $scope.other.images.filter(function(image) {\n                            return image.checked;\n                        }).map(function(image) {\n                            return image.name;\n                        })\n                    };\n                    $scope.saving = true;\n                    BootResourcesManager.saveOther(params).then(function() {\n                        $scope.saving = false;\n                    });\n                };\n\n                // Return True if the Ubuntu image can be removed.\n                $scope.canBeRemoved = function(image) {\n                    // Image must have a resourceId to be able to be removed.\n                    if(!angular.isNumber(image.resourceId)) {\n                        return false;\n                    }\n\n                    // If the release or architecture is set to deleted\n                    // then this image can be deleted.\n                    var i;\n                    var releases = $scope.bootResources.ubuntu.releases;\n                    var arches = $scope.bootResources.ubuntu.arches;\n                    for(i = 0; i < releases.length; i++) {\n                        var release = releases[i];\n                        if(release.deleted && image.title === release.title) {\n                            return true;\n                        }\n                    }\n                    for(i = 0; i < arches.length; i++) {\n                        var arch = arches[i];\n                        if(arch.deleted && image.arch === arch.name) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n\n                // Deletes the give image.\n                $scope.deleteImage = function(image) {\n                    if(angular.isObject(image)) {\n                        $scope.ubuntuDeleteId = image.resourceId;\n                    } else {\n                        $scope.ubuntuDeleteId = null;\n                    }\n                };\n\n                // Deletes the give image.\n                $scope.confirmDeleteImage = function() {\n                    // Delete the image by its resourceId.\n                    BootResourcesManager.deleteImage(\n                        {id: $scope.ubuntuDeleteId});\n                    $scope.ubuntuDeleteId = null;\n                };\n\n                // Start polling now that the directive is viewable and ensure\n                // the UserManager is loaded.\n                var ready = 2;\n                BootResourcesManager.startPolling().then(function() {\n                    ready -= 1;\n                    if(ready === 0) {\n                        $scope.loading = false;\n                    }\n                });\n                ManagerHelperService.loadManager(\n                    $scope, UsersManager).then(function() {\n                    ready -= 1;\n                    if(ready === 0) {\n                        $scope.loading = false;\n                    }\n                });\n\n                // Update the source information with the ubuntu source\n                // information changes.\n                $scope.$watch(\"bootResources.ubuntu\", function() {\n                    if(!angular.isObject($scope.bootResources.ubuntu)) {\n                        return;\n                    }\n                    $scope.updateSource();\n                });\n\n                // Regenerate the images array when the resources change.\n                $scope.$watch(\"bootResources.resources\", function() {\n                    if(!angular.isArray($scope.bootResources.resources)) {\n                        return;\n                    }\n                    $scope.regenerateUbuntuImages();\n                    $scope.regenerateUbuntuCoreImages();\n                    $scope.regenerateOtherImages();\n                    $scope.regenerateGeneratedImages();\n                    $scope.regenerateCustomImages();\n                });\n\n                $scope.$watch(\"bootResources.ubuntu_core_images\", function() {\n                    var images = $scope.bootResources.ubuntu_core_images;\n                    if(!angular.isArray(images)) {\n                        return;\n                    }\n                    if(!$scope.ubuntu_core.changed) {\n                        $scope.ubuntu_core.images = images;\n                    }\n                    $scope.regenerateUbuntuCoreImages();\n                });\n\n                $scope.$watch(\"bootResources.other_images\", function() {\n                    if(!angular.isArray($scope.bootResources.other_images)) {\n                        return;\n                    }\n                    if(!$scope.other.changed) {\n                        $scope.other.images = $scope.bootResources.other_images;\n                    }\n                    $scope.regenerateOtherImages();\n                });\n\n                // Stop polling when the directive is destroyed.\n                $scope.$on('$destroy', function() {\n                    BootResourcesManager.stopPolling();\n                });\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Call to action directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the cta.html into the template cache.\n    $templateCache.put('directive/templates/cta.html', [\n      '<div class=\"p-contextual-menu\">',\n        '<button ',\n          'class=\"p-button p-contextual-menu__toggle\" ',\n          'aria-controls=\"#cta-menu\" ',\n          'aria-expanded=\"false\" ',\n          'aria-haspopup=\"true\" ',\n          'data-ng-click=\"shown=!shown\"',\n        '>',\n          '{$ getTitle() $}',\n          '<i class=\"p-icon--chevron on-right\"></i>',\n        '</button>',\n        '<div class=\"p-contextual-menu__dropdown\" ',\n          'id=\"cta-menu\" ',\n          'aria-hidden=\"false\" ',\n          'aria-label=\"submenu\"',\n          'data-ng-show=\"shown\"',\n        '>',\n          '<button ',\n            'class=\"',\n              'p-button u-no-margin--left p-contextual-menu__link',\n            '\" ',\n            'data-ng-repeat=\"select in maasCta\" ',\n            'data-ng-click=\"selectItem(select)\">',\n              '{$ getOptionTitle(select) $}',\n          '</button>',\n        '</div>',\n      '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasCta', function() {\n    return {\n        restrict: \"A\",\n        replace: true,\n        require: \"ngModel\",\n        scope: {\n            maasCta: '=',\n            ngModel: '='\n        },\n        templateUrl: 'directive/templates/cta.html',\n        link : function(scope, element, attrs, ngModelCtrl) {\n            // Use the link function to grab the ngModel controller.\n\n            // Title of the button when not active.\n            var defaultTitle = \"Take action\";\n            if(angular.isString(attrs.defaultTitle) &&\n                attrs.defaultTitle !== \"\") {\n                defaultTitle = attrs.defaultTitle;\n            }\n\n            // When an item is selected in the list set the title, hide the\n            // dropdown, and set the value to the given model.\n            scope.selectItem = function(select) {\n                scope.shown = false;\n                ngModelCtrl.$setViewValue(select);\n            };\n\n            // Return the title of the dropdown button.\n            scope.getTitle = function() {\n                if(angular.isObject(ngModelCtrl.$modelValue)) {\n                    option = ngModelCtrl.$modelValue;\n                    scope.secondary = true;\n                    // Some designs have the requirement that the title of\n                    // the menu option change if it is selected.\n                    if(angular.isString(option.selectedTitle)) {\n                        return option.selectedTitle;\n                    }\n                    return option.title;\n                } else {\n                    scope.secondary = false;\n                    return defaultTitle;\n                }\n            };\n\n            // Called to get the title for each option. (Sometimes the title\n            // of an option is different when it is selected.)\n            scope.getOptionTitle = function(option) {\n                if(!scope.secondary) {\n                    return option.title;\n                } else {\n                    if(angular.isString(option.selectedTitle)) {\n                        return option.selectedTitle;\n                    } else {\n                        return option.title;\n                    }\n                }\n            };\n\n            // When the model changes in the above selectItem function this\n            // function will be called causing the ngChange directive to be\n            // fired.\n            ngModelCtrl.$viewChangeListeners.push(function() {\n                scope.$eval(attrs.ngChange);\n            });\n        },\n        controller: function($scope, $rootScope, $element, $document) {\n            // Default dropdown is hidden.\n            $scope.shown = false;\n            $scope.secondary = false;\n\n            // Don't propagate the element click. This stops the click event\n            // from firing on the body element.\n            $element.bind('click', function (evt) {\n                evt.stopPropagation();\n            });\n\n            // If a click makes it to the body element then hide the dropdown.\n            $document.find('body').bind('click', function () {\n                // Use $apply because this function will be called outside\n                // of the digest cycle.\n                $rootScope.$apply($scope.shown = false);\n            });\n        }\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Controller status icon. Used in the controllers listing on the nodes page.\n */\n\nangular.module('MAAS').directive('maasCardLoader', ['$compile',\n  function($compile) {\n      return {\n          restrict: \"A\",\n          link: function(scope, element, attrs) {\n            var templateUrl = (\n                'static/partials/cards/' + attrs.maasCardLoader + (\n                  '.html?v=' + MAAS_config.files_version));\n            var include = (\n              '<ng-include src=\"\\'' + templateUrl + '\\'\"></ng-include>');\n            element.html(include);\n            $compile(element.contents())(scope);\n          }\n      };\n  }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Accordion directive.\n *\n * Provides an accordion effect to an element with maas-accordion class and\n * all child elements with maas-accordion-tab. Only one accordion tab is open\n * at a time, selecting another accordion will set \"active\" on that\n * accordion tab.\n */\n\n\n angular.module('MAAS').directive('maasCodeLines', function () {\n     return {\n         restrict: \"A\",\n         scope: {\n             maasCodeLines: '&'\n         },\n         link: function(scope, element, attributes) {\n\n             function insertContent() {\n\n                 // Empty the element contents and include again, this asures\n                 // its the most up-to-date content\n                 element.empty();\n                 element.text(scope.maasCodeLines);\n\n                 // Count the line contents\n                 var lines = element.html().split('\\n'),\n                     newLine = '',\n                     insert = \"<code>\";\n\n                 // Each line is to be wrapped by a span which is style & given\n                 // its appropriate line number\n                 $.each(lines, function() {\n                   insert += newLine + '<span class=\"code-line\">' +\n                   this + '</span>';\n                   newLine = '\\n';\n                 });\n                 insert += \"</code>\";\n\n                 // Re-insert the contents\n                 element.html(insert);\n             }\n\n             // Watch the contents of the element so when it changes to\n             // re-add the line numbers.\n             scope.$watch(scope.maasCodeLines, insertContent);\n         }\n     };\n });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Content editable directive.\n *\n * HTML provides a feature that allows any element to be editable with\n * contenteditable attribute. This directive uses that attribute to link\n * the contents of that element to a model. This directive is not prefixed\n * with maas so Angular can identify all elements with this attribute.\n */\n\n\nangular.module('MAAS').directive('contenteditable', function() {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            ngDisabled: \"&\",\n            maasEditing: \"&\"\n        },\n        link: function(scope, element, attrs, ngModel) {\n\n            // If the element is disabled then make the element lose focus.\n            var focusHandler = function() {\n                if(scope.ngDisabled()) {\n                    element.blur();\n                } else {\n                    // Didn't lose focus, so its now editing.\n                    scope.$apply(scope.maasEditing());\n                }\n            };\n            element.bind(\"focus\", focusHandler);\n\n            // Update the value of the model when events occur that\n            // can change the value of the model.\n            var changeHandler = function() {\n                scope.$apply(ngModel.$setViewValue(element.text()));\n            };\n            element.bind(\"blur keyup change\", changeHandler);\n\n            // When the model changes set the html content for that element.\n            ngModel.$render = function() {\n                element.html(ngModel.$viewValue || \"\");\n            };\n\n            // When the model changes this function will be called causing the\n            // ngChange directive to be fired.\n            ngModel.$viewChangeListeners.push(function() {\n                scope.$eval(attrs.ngChange);\n            });\n\n            // Remove the event handler on the element when the scope is\n            // destroyed.\n            scope.$on(\"$destroy\", function() {\n                element.unbind(\"blur keyup change\", changeHandler);\n                element.unbind(\"focus\", focusHandler);\n            });\n        }\n    };\n});\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Controller image status directive.\n *\n * Shows the image status for a controller.\n */\n\n angular.module('MAAS').service('ControllerImageStatusService',\n    ['$timeout', '$interval', 'ControllersManager', function(\n        $timeout, $interval, ControllersManager) {\n     var self = this;\n\n     // How often to check the sync status of a controller in seconds.\n     var CHECK_INTERVAL = 30;\n\n     // List of controllers that need to have the image status updated.\n     this.controllers = [];\n\n     // List of current controller statues.\n     this.statuses = {};\n\n     // Interval function that is called to update the statuses.\n     this.updateStatuses = function() {\n         var controllerIds = [];\n         angular.forEach(self.controllers, function(system_id) {\n             controllerIds.push({system_id: system_id});\n         });\n\n         // Check the image states.\n         ControllersManager.checkImageStates(controllerIds).then(\n                 function(results) {\n             angular.forEach(controllerIds, function(controller) {\n                 var status = results[controller.system_id];\n                 if(status) {\n                     self.statuses[controller.system_id] = status;\n                 } else {\n                     self.statuses[controller.system_id] = \"Unknown\";\n                 }\n             });\n         });\n     };\n\n     // Register this controller system_id.\n     this.register = function(system_id) {\n         var known = self.controllers.indexOf(system_id) >= 0;\n         if(!known) {\n             self.controllers.push(system_id);\n         }\n\n         // When the interval is already running and its a new controller then\n         // the interval needs to be reset. When it already exists it doesn't\n         // need to be reset.\n         if(angular.isDefined(self.runningInterval)) {\n             if(known) {\n                 return;\n             } else {\n                 $interval.cancel(self.runningInterval);\n                 self.runningInterval = undefined;\n             }\n         }\n\n         // If its not running and the timeout has been started we re-create\n         // the timeout. This delays the start of the interval until the\n         // all directives on the page have been fully loaded.\n         if(angular.isDefined(self.startTimeout)) {\n             $timeout.cancel(self.startTimeout);\n         }\n         self.startTimeout = $timeout(function() {\n             self.startTimeout = undefined;\n             self.runningInterval = $interval(function() {\n                 self.updateStatuses();\n             }, CHECK_INTERVAL * 1000);\n             self.updateStatuses();\n         }, 100);\n     };\n\n     // Unregister the controller.\n     this.unregister = function(system_id) {\n        var idx = self.controllers.indexOf(system_id);\n        if(idx > -1) {\n            self.controllers.splice(idx, 1);\n        }\n\n        // If no controllers are left stop all intervals and timeouts.\n        if(self.controllers.length === 0) {\n            if(angular.isDefined(self.startTimeout)) {\n                $timeout.cancel(self.startTimeout);\n                self.startTimeout = undefined;\n            }\n            if(angular.isDefined(self.runningInterval)) {\n                $interval.cancel(self.runningInterval);\n                self.runningInterval = undefined;\n            }\n        }\n     };\n\n     // Return true if the spinner should be shown.\n     this.showSpinner = function(system_id) {\n         var status = self.statuses[system_id];\n         if(angular.isString(status) && status !== \"Syncing\") {\n             return false;\n         } else {\n             return true;\n         }\n     };\n\n     // Get the image status.\n     this.getImageStatus = function(system_id) {\n         var status = self.statuses[system_id];\n         if(angular.isString(status)) {\n             return status;\n         } else {\n             return \"Asking for status...\";\n         }\n     };\n}]);\n\nangular.module('MAAS').directive('maasControllerImageStatus',\n    ['ControllerImageStatusService', function(\n        ControllerImageStatusService) {\n\n    return {\n        restrict: \"E\",\n        scope: {\n            systemId: \"=\"\n        },\n        template: [\n            '<i class=\"p-icon--loading u-animation--spin\"',\n                'data-ng-if=\"showSpinner()\"></i> ',\n            '{$ getImageStatus() $}'].join(''),\n        link: function(scope, element, attrs) {\n            // Don't register until the systemId is set.\n            var unwatch, registered = false;\n            unwatch = scope.$watch(\"systemId\", function() {\n                if(angular.isDefined(scope.systemId) && !registered) {\n                    ControllerImageStatusService.register(scope.systemId);\n                    registered = true;\n                    unwatch();\n                }\n            });\n\n            scope.showSpinner = function() {\n                return ControllerImageStatusService.showSpinner(\n                    scope.systemId);\n            };\n            scope.getImageStatus = function() {\n                return ControllerImageStatusService.getImageStatus(\n                    scope.systemId);\n            };\n\n            // Unregister when destroyed.\n            scope.$on(\"$destroy\", function() {\n                if(registered) {\n                    ControllerImageStatusService.unregister(scope.systemId);\n                }\n            });\n        }\n    };\n}]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Controller status icon. Used in the controllers listing on the nodes page.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the controller-status.html into the template cache.\n    $templateCache.put('directive/templates/controller-status.html', [\n        '<span>',\n          '<span class=\"p-icon--{$ serviceClass $}\" data-ng-if=\"!textOnly\">',\n          '</span>',\n          '<span data-ng-if=\"textOnly\" data-ng-bind=\"serviceText\"></span>',\n        '</span>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasControllerStatus', [\n    \"ControllersManager\", \"ServicesManager\",\n    function(ControllersManager, ServicesManager) {\n        return {\n            restrict: \"A\",\n            scope: {\n                controller: '=maasControllerStatus',\n                textOnly: '=?maasTextOnly'\n            },\n            templateUrl: 'directive/templates/controller-status.html',\n            controller: function($scope) {\n\n                $scope.serviceClass = \"unknown\";\n                $scope.services = ServicesManager.getItems();\n                $scope.serviceText = \"\";\n                if($scope.textOnly) {\n                  $scope.textOnly = true;\n                } else {\n                  $scope.textOnly = false;\n                }\n\n                // Return the status class for the service.\n                function getClass(service) {\n                    if(service.status === \"running\") {\n                        return \"success\";\n                    } else if (service.status === \"degraded\") {\n                        return \"warning\";\n                    } else if (service.status === \"dead\") {\n                        return \"error\";\n                    } else {\n                        return \"unknown\";\n                    }\n                }\n\n                // Return the number of times class is displayed.\n                function countClass(classes, class_name) {\n                  var counter = 0;\n                  angular.forEach(classes, function(name) {\n                    if(name === class_name) {\n                      counter++;\n                    }\n                  });\n                  return counter;\n                }\n\n                // Update the class based on status of the services on the\n                // controller.\n                function updateStatusClass() {\n                    $scope.serviceClass = \"unknown\";\n                    if(angular.isObject($scope.controller)) {\n                        var services = ControllersManager.getServices(\n                            $scope.controller);\n                        if(services.length > 0) {\n                            var classes = services.map(getClass);\n                            if(classes.indexOf(\"error\") !== -1) {\n                                $scope.serviceClass = \"power-error\";\n                                $scope.serviceText = countClass(\n                                  classes, \"error\") + \" dead\";\n                            } else if(classes.indexOf(\"warning\") !== -1) {\n                                $scope.serviceClass = \"warning\";\n                                $scope.serviceText = countClass(\n                                  classes, \"warning\") + \" degraded\";\n                            } else {\n                                $scope.serviceClass = \"success\";\n                                $scope.serviceText = countClass(\n                                  classes, \"success\") + \" running\";\n                            }\n                        }\n                    }\n                }\n\n                // Watch the services array and the services on the controller,\n                // if any changes then update the status.\n                $scope.$watch(\"controller.service_ids\", updateStatusClass);\n                $scope.$watchCollection(\"services\", updateStatusClass);\n\n                // Update on creation.\n                updateStatusClass();\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Double click overlay directive.\n *\n * Provides the ability for a disabled element to still accept the\n * double click event. By default if an element is disabled then it will\n * receive no click events. This overlays the element with another element\n * that will still receive click events.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the style for the maas-dbl-overlay class. We inject the style\n    // instead of placing it in maas-styles.css because it is required for\n    // this directive to work at all.\n    var styleElement = document.createElement('style');\n    styleElement.innerHTML = [\n        '.maas-dbl-overlay {',\n            'display: inline-block;',\n            'position: relative;',\n        '}',\n        '.maas-dbl-overlay--overlay {',\n            'position: absolute;',\n            'left: 0;',\n            'right: 0;',\n            'top: 0;',\n            'bottom: 0;',\n            '-webkit-touch-callout: none;',\n            '-webkit-user-select: none;',\n            '-khtml-user-select: none;',\n            '-moz-user-select: none;',\n            '-ms-user-select: none;',\n            'user-select: none;',\n        '}'\n    ].join('');\n    document.getElementsByTagName('head')[0].appendChild(styleElement);\n\n    // Inject the double_click_overlay.html into the template cache.\n    $templateCache.put('directive/templates/double_click_overlay.html', [\n        '<div class=\"maas-dbl-overlay\">',\n            '<span data-ng-transclude></span>',\n            '<div class=\"maas-dbl-overlay--overlay\"></div>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasDblClickOverlay', ['BrowserService',\n    function(BrowserService) {\n        return {\n            restrict: \"A\",\n            transclude: true,\n            replace: true,\n            scope: {\n                maasDblClickOverlay: '&'\n            },\n            templateUrl: 'directive/templates/double_click_overlay.html',\n            link: function(scope, element, attrs) {\n                // Create the click function that will be called when the\n                // overlay is clicked. This changes based on the element that\n                // is transcluded into this directive.\n                var overlay = element.find(\".maas-dbl-overlay--overlay\");\n                var transclude = element.find(\n                    \"span[data-ng-transclude]\").children()[0];\n                var clickElement;\n                if(transclude.tagName === \"SELECT\") {\n                    clickElement = function() {\n                        // Have to create a custom mousedown event for the\n                        // select click to be handled. Using 'click()' or\n                        //'focus()' will not work.\n                        var evt = document.createEvent('MouseEvents');\n                        evt.initMouseEvent(\n                            'mousedown', true, true, window, 0, 0, 0, 0, 0,\n                            false, false, false, false, 0, null);\n                        transclude.dispatchEvent(evt);\n                    };\n\n                    // Selects use a pointer for the cursor.\n                    overlay.css({ cursor: \"pointer\" });\n                } else if(transclude.tagName === \"INPUT\") {\n                    clickElement = function() {\n                        // An input will become in focus when clicked.\n                        angular.element(transclude).triggerHandler('focus');\n                    };\n\n                    // Inputs use a text for the cursor.\n                    overlay.css({ cursor: \"text\" });\n                } else {\n                    clickElement = function() {\n                        // Standard element just call click on that element.\n                        angular.element(transclude).triggerHandler('click');\n                    };\n\n                    // Don't set cursor on other element types.\n                }\n\n                // Add the click and double click handlers.\n                var overlayClick = function(evt) {\n                    clickElement();\n                    evt.preventDefault();\n                    evt.stopPropagation();\n                };\n                var overlayDblClick = function(evt) {\n                    // Call the double click handler with in the scope.\n                    scope.$apply(scope.maasDblClickOverlay);\n                    evt.preventDefault();\n                    evt.stopPropagation();\n                };\n\n                // Enable the handlers if not Firefox. It firefox, then hide\n                // the overlay as Firefox does not allow sending click events\n                // to select elements.\n                if(BrowserService.browser !== \"firefox\") {\n                    overlay.on(\"click\", overlayClick);\n                    overlay.on(\"dblclick\", overlayDblClick);\n                } else {\n                    overlay.addClass(\"ng-hide\");\n                }\n\n                // Remove the handlers when the scope is destroyed.\n                scope.$on(\"$destroy\", function() {\n                    overlay.off(\"click\", overlayClick);\n                    overlay.off(\"dblclick\", overlayDblClick);\n                });\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n*/\n\nangular.module('MAAS').directive('maasEnter', function () {\n    return {\n        restrict: \"A\",\n        link: function (scope, element, attrs) {\n            element.bind(\"keydown keypress\", function (evt) {\n                if(evt.which === 13) {\n                    scope.$apply(function () {\n                        scope.$eval(attrs.maasEnter);\n                    });\n                    evt.preventDefault();\n                }\n            });\n        }\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Enter blur directive.\n *\n * When the enter key is pressed make the element lose focus (aka. blur event).\n */\n\n\nangular.module('MAAS').directive('maasEnterBlur', function() {\n    return {\n        restrict: \"A\",\n        link: function(scope, element, attrs) {\n            element.bind(\"keydown keypress\", function(evt) {\n                if(evt.which === 13) {\n                    element.blur();\n                    evt.preventDefault();\n                }\n            });\n        }\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Error overlay.\n *\n * Directive overrides the entire transcluded element if an error occurs or\n * connection to the region over the websocket fails or becomes disconnected.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the error_overlay.html into the template cache.\n    $templateCache.put('directive/templates/error_overlay.html', [\n        '<header id=\"error-header\" class=\"page-header\" data-ng-show=\"show()\">',\n            '<div class=\"row\">',\n                '<h1 class=\"page-header__title\">',\n                    '<span class=\"p-icon--loading u-animation--spin ',\n                        'u-margin--right-small\"',\n                        'data-ng-hide=\"clientError\"></span>',\n                    '{$ getTitle() $}',\n                '</h1>',\n                '<div class=\"page-header__controls\">',\n                    '<button class=\"button--secondary button--inline\"',\n                        'data-ng-click=\"reload()\"',\n                        'data-ng-show=\"clientError\">Reload</button>',\n                '</div>',\n                '<div class=\"page-header__dropdown is-open\" ',\n                    'data-ng-show=\"error\">',\n                    '<div class=\"page-header__section twelve-col',\n                        'u-margin--bottom-none\">',\n                        '<p class=\"page-header__message',\n                                  'page-header__message--error\">',\n                            '{$ error $}',\n                        '</p>',\n                    '</div>',\n                '</div>',\n            '</div>',\n        '</header>',\n        '<div class=\"ng-hide u-no-margin--top\" data-ng-hide=\"show()\">',\n            '<div data-ng-transclude></div>',\n        '</div>'\n    ].join(''));\n\n    // Preload the svg and png error icon. Its possible that it has never been\n    // loaded by the browser and if the region connection goes down and the\n    // directive gets shown with an error the icon will be missing.\n    //\n    // Note: This is skipped if unit testing because it will throw 404 errors\n    // continuously.\n    if(!angular.isDefined(window.jasmine)) {\n        var image = new Image();\n        image.src = \"static/assets/images/icons/error.svg\";\n        image = new Image();\n        image.src = \"static/assets/images/icons/error.png\";\n    }\n}]);\n\nangular.module('MAAS').directive('maasErrorOverlay', [\n    '$window', '$timeout', 'RegionConnection', 'ErrorService',\n    function($window, $timeout, RegionConnection, ErrorService) {\n        return {\n            restrict: \"A\",\n            transclude: true,\n            scope: true,\n            templateUrl: 'directive/templates/error_overlay.html',\n            link: function(scope, element, attrs) {\n\n                scope.connected = false;\n                scope.showDisconnected = false;\n                scope.clientError = false;\n                scope.wasConnected = false;\n\n                // Holds the promise that sets showDisconnected to true. Will\n                // be cleared when the scope is destroyed.\n                var markDisconnected;\n\n                // Returns true when the overlay should be shown.\n                scope.show = function() {\n                    // Always show if clientError.\n                    if(scope.clientError) {\n                        return true;\n                    }\n                    // Never show if connected.\n                    if(scope.connected) {\n                        return false;\n                    }\n                    // Never been connected then always show.\n                    if(!scope.wasConnected) {\n                        return true;\n                    }\n                    // Not connected.\n                    return scope.showDisconnected;\n                };\n\n                // Returns the title for the header.\n                scope.getTitle = function() {\n                    if(scope.clientError) {\n                        return \"Error occurred\";\n                    } else if(scope.wasConnected) {\n                        return \"Connection lost, reconnecting...\";\n                    } else {\n                        return \"Connecting...\";\n                    }\n                };\n\n                // Called to reload the page.\n                scope.reload = function() {\n                    $window.location.reload();\n                };\n\n                // Called to when the connection status of the region\n                // changes. Updates the scope connected and error values.\n                var watchConnection = function() {\n                    // Do nothing if already a client error.\n                    if(scope.clientError) {\n                        return;\n                    }\n\n                    // Set connected and the time it changed.\n                    var connected = RegionConnection.isConnected();\n                    if(connected !== scope.connected) {\n                        scope.connected = connected;\n                        if(!connected) {\n                            scope.showDisconnected = false;\n\n                            // Show disconnected after 1/2 second. This removes\n                            // the flicker that can occur, if it disconnecets\n                            // and reconnected quickly.\n                            markDisconnected = $timeout(function() {\n                                scope.showDisconnected = true;\n                                markDisconnected = undefined;\n                            }, 500);\n                        }\n                    }\n\n                    // Set error and whether of not the connection\n                    // has ever been made.\n                    scope.error = RegionConnection.error;\n                    if(!scope.wasConnected && connected) {\n                        scope.wasConnected = true;\n                    }\n                };\n\n                // Watch the isConnected and error value on the\n                // RegionConnection.\n                scope.$watch(function() {\n                    return RegionConnection.isConnected();\n                }, watchConnection);\n                scope.$watch(function() {\n                    return RegionConnection.error;\n                }, watchConnection);\n\n                // Called then the error value on the ErrorService changes.\n                var watchError = function() {\n                    var error = ErrorService._error;\n                    if(angular.isString(error)) {\n                        scope.clientError = true;\n                        scope.error = ErrorService._error;\n                    }\n                };\n\n                // Watch _error on the ErrorService.\n                scope.$watch(function() {\n                    return ErrorService._error;\n                }, watchError);\n\n                // Cancel the timeout on scope destroy.\n                scope.$on(\"$destroy\", function() {\n                    if(angular.isDefined(markDisconnected)) {\n                        $timeout.cancel(markDisconnected);\n                    }\n                });\n            }\n        };\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Error toggle.\n *\n * Hides the element if an error occurs or no connection to the region\n * is present.\n */\n\nangular.module('MAAS').directive('maasErrorToggle', [\n    '$timeout', 'RegionConnection', 'ErrorService',\n    function($timeout, RegionConnection, ErrorService) {\n        return {\n            restrict: \"A\",\n            link: function(scope, element, attrs) {\n\n                // Holds timeout promise for setting ng-hide when\n                // connection is lost.\n                var disconnectedPromise;\n\n                // Cancel the disconnected timeout.\n                var cancelTimeout = function() {\n                    if(angular.isDefined(disconnectedPromise)) {\n                        $timeout.cancel(disconnectedPromise);\n                        disconnectedPromise = undefined;\n                    }\n                };\n\n                // Called to when the connection status of the region\n                // changes or the error on the ErrorService is set.\n                // The element is shown when connected and no errors.\n                var watchConnectionAndError = function() {\n                    var connected = RegionConnection.isConnected();\n                    var error = ErrorService._error;\n                    if(connected && !angular.isString(error)) {\n                        cancelTimeout();\n                        element.removeClass(\"ng-hide\");\n                    } else if(angular.isString(error)) {\n                        cancelTimeout();\n                        element.addClass(\"ng-hide\");\n                    } else if(!connected) {\n                        // Hide the element after 1/2 second. This stops\n                        // flickering when the connection goes down and\n                        // reconnects quickly.\n                        cancelTimeout();\n                        disconnectedPromise = $timeout(function() {\n                            element.addClass(\"ng-hide\");\n                        }, 500);\n                    }\n                };\n\n                // Watch the RegionConnection.isConnected() and\n                // ErrorService._error value.\n                scope.$watch(function() {\n                    return RegionConnection.isConnected();\n                }, watchConnectionAndError);\n                scope.$watch(function() {\n                    return ErrorService._error;\n                }, watchConnectionAndError);\n\n                // Cancel disconnect timeout on destroy.\n                scope.$on(\"$destroy\", function() {\n                    cancelTimeout();\n                });\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * IP Ranges directive.\n*/\n\nangular.module('MAAS').directive('maasIpRanges', [\n    '$filter', 'IPRangesManager', 'UsersManager',\n    'ManagerHelperService', 'ConverterService', function(\n        $filter, IPRangesManager, UsersManager, ManagerHelperService,\n        ConverterService) {\n        return {\n            restrict: \"E\",\n            scope: {\n                subnet: \"=\",\n                vlan: \"=\"\n            },\n            templateUrl: (\n                'static/partials/ipranges.html?v=' + (\n                    MAAS_config.files_version)),\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                $scope.ipranges = IPRangesManager.getItems();\n                $scope.iprangeManager = IPRangesManager;\n                $scope.newRange = null;\n                $scope.editIPRange = null;\n                $scope.deleteIPRange = null;\n\n                // Return true if the authenticated user is super user.\n                $scope.isSuperUser = function() {\n                    return UsersManager.isSuperUser();\n                };\n\n                // Called to start adding a new IP range.\n                $scope.addRange = function(type) {\n                    $scope.newRange = {\n                        type: type,\n                        start_ip: \"\",\n                        end_ip: \"\",\n                        comment: \"\"\n                    };\n                    if(angular.isObject($scope.subnet)) {\n                        $scope.newRange.subnet = $scope.subnet.id;\n                    }\n                    if(angular.isObject($scope.vlan)) {\n                        $scope.newRange.vlan = $scope.vlan.id;\n                    }\n                    if(type === \"dynamic\") {\n                        $scope.newRange.comment = \"Dynamic\";\n                    }\n                };\n\n                // Cancel adding the new IP range.\n                $scope.cancelAddRange = function() {\n                    $scope.newRange = null;\n                };\n\n                // Return true if the IP range can be modified by the\n                // authenticated user.\n                $scope.ipRangeCanBeModified = function(range) {\n                    if($scope.isSuperUser()) {\n                        return true;\n                    } else {\n                        // Can only modify reserved and same user.\n                        return (\n                            range.type === \"reserved\" &&\n                            range.user === UsersManager.getAuthUser().id);\n                    }\n                };\n\n                // Return true if the IP range is in edit mode.\n                $scope.isIPRangeInEditMode = function(range) {\n                    return $scope.editIPRange === range;\n                };\n\n                // Toggle edit mode for the IP range.\n                $scope.ipRangeToggleEditMode = function(range) {\n                    $scope.deleteIPRange = null;\n                    if($scope.isIPRangeInEditMode(range)) {\n                        $scope.editIPRange = null;\n                    } else {\n                        $scope.editIPRange = range;\n                    }\n                };\n\n                // Clear edit mode for the IP range.\n                $scope.ipRangeClearEditMode = function() {\n                    $scope.editIPRange = null;\n                };\n\n                // Return true if the IP range is in delete mode.\n                $scope.isIPRangeInDeleteMode = function(range) {\n                    return $scope.deleteIPRange === range;\n                };\n\n                // Enter delete mode for the IP range.\n                $scope.ipRangeEnterDeleteMode = function(range) {\n                    $scope.editIPRange = null;\n                    $scope.deleteIPRange = range;\n                };\n\n                // Exit delete mode for the IP range.\n                $scope.ipRangeCancelDelete = function() {\n                    $scope.deleteIPRange = null;\n                };\n\n                // Perform the delete operation on the IP range.\n                $scope.ipRangeConfirmDelete = function() {\n                    IPRangesManager.deleteItem(\n                        $scope.deleteIPRange).then(function() {\n                            $scope.deleteIPRange = null;\n                    });\n                };\n\n                // Sort ranges by starting IP address.\n                $scope.ipRangeSort = function(range) {\n                    if(range.start_ip.indexOf(':') !== -1) {\n                        return ConverterService.ipv6Expand(range.start_ip);\n                    } else {\n                        return ConverterService.ipv4ToInteger(range.start_ip);\n                    }\n                };\n\n                // Load the reqiured managers.\n                ManagerHelperService.loadManagers($scope, [\n                    IPRangesManager, UsersManager]).then(\n                        function() {\n                            $scope.loading = false;\n                        });\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS object directive.\n *\n * Directive that connects a field to an object from the websocket. The field\n * is an instant save on blur.\n */\n\nangular.module('MAAS').directive('maasObjForm', ['JSONService',\n    function(JSONService) {\n        function MAASFormController(scope) {\n            this.obj = scope.obj;\n            this.manager = scope.manager;\n            this.fields = {};\n            this.scope = scope;\n            this.scope.saving = false;\n            this.scope.savingKeys = [];\n            if(angular.isObject(this.scope.obj)) {\n                this.scope.obj.$maasForm = this;\n            }\n\n            // Set the managerMethod.\n            this.managerMethod = scope.managerMethod;\n            if(angular.isUndefined(this.managerMethod)) {\n                this.managerMethod = \"updateItem\";\n            }\n\n            var self = this;\n            scope.$watch(\"obj\", function() {\n                // Update the object when it changes.\n                self.obj = scope.obj;\n                if(angular.isObject(self.obj)) {\n                    self.obj.$maasForm = self;\n                }\n            });\n            scope.$on(\"$destroy\", function() {\n                // Remove the $maasForm from the object when directive is\n                // deleted.\n                if(angular.isObject(self.obj)) {\n                    delete self.obj.$maasForm;\n                }\n            });\n        }\n\n        // Get the current value for a field in the form.\n        MAASFormController.prototype.getValue = function (key) {\n            var field = this.fields[key];\n            if(angular.isObject(field) && angular.isObject(field.scope)) {\n                return field.scope.getValue();\n            }\n        };\n\n        // Update the current value for a field in the form.\n        MAASFormController.prototype.updateValue = function (key, value) {\n            var field = this.fields[key];\n            if(angular.isObject(field) && angular.isObject(field.scope)) {\n                return field.scope.updateValue(value);\n            }\n        };\n\n        // Clone the current object for this form without the $maasForm\n        // property set.\n        MAASFormController.prototype.cloneObject = function() {\n            if(!angular.isObject(this.obj)) {\n                return this.obj;\n            } else {\n                delete this.obj.$maasForm;\n                var clonedObj = angular.copy(this.obj);\n                this.obj.$maasForm = this;\n                return clonedObj;\n            }\n        };\n\n        // Return true if table form.\n        MAASFormController.prototype.isTableForm = function () {\n            if(angular.isUndefined(this.scope.tableForm)) {\n                // Default is not a table form.\n                return false;\n            } else {\n                return this.scope.tableForm;\n            }\n        };\n\n        // Return true if the form should be saved on blur.\n        MAASFormController.prototype.saveOnBlur = function() {\n            if(angular.isUndefined(this.scope.saveOnBlur)) {\n                // Default is save on blur.\n                return true;\n            } else {\n                return this.scope.saveOnBlur;\n            }\n        };\n\n        // Return true if the form is saving this field.\n        MAASFormController.prototype.isSaving = function(key) {\n            return (\n                this.scope.saving && this.scope.savingKeys.indexOf(key) >= 0);\n        };\n\n        // Return true if the input should show the saving spinner. This is\n        // only show on inputs in forms that are using save on blur.\n        MAASFormController.prototype.showInputSaving = function(key) {\n            return this.saveOnBlur() && this.isSaving(key);\n        };\n\n        // Return true if any field in the form as an error.\n        MAASFormController.prototype.hasErrors = function() {\n            var hasErrors = false;\n            angular.forEach(this.fields, function(field) {\n                if(field.scope.hasErrors()) {\n                    hasErrors = true;\n                }\n            });\n            if(angular.isDefined(this.errorScope)) {\n                if(this.errorScope.hasErrors()) {\n                    hasErrors = true;\n                }\n            }\n            return hasErrors;\n        };\n\n        // Called by maas-obj-field to register it as a editable field.\n        MAASFormController.prototype.registerField = function(key, scope) {\n            // Store the state of the field and its scope.\n            this.fields[key] = {\n                editing: false,\n                scope: scope\n            };\n\n            // Watch for changes on the value of the object.\n            var self = this;\n            this.scope.$watch(\"obj.\" + key, function() {\n                if(angular.isObject(self.obj) && !self.fields[key].editing) {\n                    self.fields[key].scope.updateValue(self.obj[key]);\n                }\n            });\n\n            // Return the current value for the field.\n            if(angular.isObject(this.obj)) {\n                return this.obj[key];\n            } else {\n                return null;\n            }\n        };\n\n        // Called by maas-obj-field to unregister it as a editable field.\n        MAASFormController.prototype.unregisterField = function(key) {\n            delete this.fields[key];\n        };\n\n        // Called by maas-obj-field to place field in edit mode.\n        MAASFormController.prototype.startEditingField = function(key) {\n            this.fields[key].editing = true;\n        };\n\n        // Called by maas-obj-field to end edit mode for the field.\n        MAASFormController.prototype.stopEditingField = function(key, value) {\n            var field = this.fields[key];\n\n            // Do nothing if not save on blur.\n            if(!this.saveOnBlur()) {\n                field.editing = false;\n                return;\n            }\n\n            // Clear errors before saving.\n            field.scope.clearErrors();\n\n            // Copy the object and update the editing field.\n            var updatedObj = this.cloneObject();\n            updatedObj[key] = value;\n            if(updatedObj[key] === this.obj[key]) {\n                // Nothing changed.\n                field.editing = false;\n                return;\n            }\n\n            // Update the item in the manager.\n            this.scope.saving = true;\n            this.scope.savingKeys = [key];\n            this.updateItem(updatedObj, [key]);\n        };\n\n        // Update the item using the manager.\n        MAASFormController.prototype.updateItem = function(updatedObj, keys) {\n            var key = keys[0];\n            var field = this.fields[key];\n            var self = this;\n\n            // Pre-process the updatedObj if one is defined.\n            if(angular.isFunction(this.scope.preProcess)) {\n                updatedObj = this.scope.preProcess(updatedObj, keys);\n            }\n\n            // Update the item with the manager.\n            return this.manager[this.managerMethod](\n                updatedObj).then(function(newObj) {\n                    // Update the value of the element.\n                    field.editing = false;\n                    field.scope.updateValue(newObj[key]);\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    if(angular.isFunction(self.scope.afterSave)) {\n                        self.scope.afterSave(newObj);\n                    }\n                    return newObj;\n                }, function(error) {\n                    var errorJson = JSONService.tryParse(error);\n                    if(angular.isObject(errorJson)) {\n                        // Add the error to each field it matches.\n                        angular.forEach(errorJson, function(value, key) {\n                            var errorField = self.fields[key];\n                            if(!angular.isArray(value)) {\n                                value = [value];\n                            }\n\n                            if(angular.isObject(errorField)) {\n                                // Error on a field we know about, place the\n                                // error on that field.\n                                errorField.scope.setErrors(value);\n                            } else {\n                                // Error on a field we don't know about, place\n                                // the error on the editing field. Prefixing\n                                // the error with the field.\n                                if(key !== \"__all__\") {\n                                    value = value.map(function(v) {\n                                        return key + \": \" + v;\n                                    });\n                                }\n                                field.scope.setErrors(value);\n                            }\n                        });\n                    } else {\n                        // Add the string error to just the field error.\n                        field.scope.setErrors([error]);\n                    }\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    return error;\n                });\n        };\n\n        // Called when saveOnBlur is false to save the whole form.\n        MAASFormController.prototype.saveForm = function () {\n            var keys = [];\n            var updatedObj = this.cloneObject();\n            angular.forEach(this.fields, function(value, key) {\n                value.scope.clearErrors();\n                var newValue = value.scope.getValue();\n                if(angular.isDefined(newValue) &&\n                    updatedObj[key] !== newValue) {\n                    updatedObj[key] = newValue;\n                    keys.push(key);\n                }\n            });\n\n\n            // Pre-process the updatedObj if one is defined.\n            if(angular.isFunction(this.scope.preProcess)) {\n                updatedObj = this.scope.preProcess(updatedObj, keys);\n            }\n\n            // Clear the errors on the errorScope before save.\n            if(angular.isDefined(this.errorScope)) {\n                this.errorScope.clearErrors();\n            }\n\n            var self = this;\n            this.scope.saving = true;\n            this.scope.savingKeys = keys;\n            return this.manager[this.managerMethod](\n                updatedObj).then(function(newObj) {\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    if(angular.isFunction(self.scope.afterSave)) {\n                        self.scope.afterSave(newObj);\n                    }\n                    return newObj;\n                }, function(error) {\n                    var errorJson = JSONService.tryParse(error);\n                    if(angular.isObject(errorJson)) {\n                        // Add the error to each field it matches.\n                        angular.forEach(errorJson, function(value, key) {\n                            var errorField = self.fields[key];\n                            if(!angular.isArray(value)) {\n                                value = [value];\n                            }\n\n                            if(angular.isObject(errorField)) {\n                                // Error on a field we know about, place the\n                                // error on that field.\n                                errorField.scope.setErrors(value);\n                            } else {\n                                if(key !== \"__all__\") {\n                                    value = value.map(function(v) {\n                                        return key + \": \" + v;\n                                    });\n                                }\n                                // Error on a field we don't know about, place\n                                // the error on errorScope if set.\n                                if(angular.isDefined(self.errorScope)) {\n                                    self.errorScope.setErrors(value);\n                                } else {\n                                    // No error scope, just log to console.\n                                    console.log(value);\n                                }\n                            }\n                        });\n                    } else {\n                        // Add the string error to just the field error.\n                        if(angular.isDefined(self.errorScope)) {\n                            self.errorScope.setErrors([error]);\n                        } else {\n                            // No error scope, just log to console.\n                            console.log(error);\n                        }\n                    }\n                    self.scope.saving = false;\n                    self.scope.savingKeys = [];\n                    return error;\n                });\n        };\n\n        return {\n            restrict: \"E\",\n            scope: {\n                obj: \"=\",\n                manager: \"=\",\n                managerMethod: \"@\",\n                preProcess: \"=\",\n                afterSave: \"=\",\n                tableForm: \"=\",\n                saveOnBlur: \"=\",\n                inline: \"=\",\n                ngDisabled: \"&\"\n            },\n            transclude: true,\n            template: (\n                '<form class=\"p-form\" data-ng-class=\"{saving: saving, ' +\n                '\\'p-form--inline\\': inline, ' +\n                '\\'p-form--stacked\\': tableForm}\" ' +\n                'ng-transclude></form>'),\n            controller: ['$scope', MAASFormController]\n        };\n    }]);\n\nangular.module('MAAS').directive('maasObjFieldGroup', ['JSONService',\n    function(JSONService) {\n        // Controller for this directive.\n        function MAASGroupController(scope, timeout) {\n            this.fields = {};\n            this.scope = scope;\n            this.scope.saving = false;\n            this.scope.savingKeys = [];\n            this.timeout = timeout;\n\n            var self = this;\n            this.scope.isEditing = function() {\n                var editing = false;\n                angular.forEach(self.fields, function(value) {\n                    if(!editing) {\n                        editing = value.editing;\n                    }\n                });\n                return editing;\n            };\n        }\n\n        // Return true if table form.\n        MAASGroupController.prototype.isTableForm = function () {\n            return this.formController.isTableForm();\n        };\n\n        // Return true if should save on blur.\n        MAASGroupController.prototype.saveOnBlur = function () {\n            return this.formController.saveOnBlur();\n        };\n\n        // Return true if group is saving.\n        MAASGroupController.prototype.isSaving = function(key) {\n            return (\n                this.scope.saving && this.scope.savingKeys.indexOf(key) >= 0);\n        };\n\n        // Return true if the input should show the saving spinner. This is\n        // only show on inputs in forms that are using save on blur.\n        MAASGroupController.prototype.showInputSaving = function(key) {\n            // In a group we say the entire group is saving, not just that\n            // one key in the field is being saved.\n            return this.saveOnBlur() && this.scope.saving;\n        };\n\n        // Called by maas-obj-field to register it as a editable field.\n        MAASGroupController.prototype.registerField = function(key, scope) {\n            // Store the state of the field and its scope.\n            this.fields[key] = {\n                editing: false,\n                scope: scope\n            };\n            return this.formController.registerField(key, scope);\n        };\n\n        // Called by maas-obj-field to unregister it as a editable field.\n        MAASGroupController.prototype.unregisterField = function(key) {\n            delete this.fields[key];\n            this.formController.unregisterField(key);\n        };\n\n        // Called by maas-obj-field to place field in edit mode.\n        MAASGroupController.prototype.startEditingField = function(key) {\n            this.fields[key].editing = true;\n\n            // Set all fields in the group as editing in the formController.\n            var self = this;\n            angular.forEach(this.fields, function(value, key) {\n                self.formController.startEditingField(key);\n            });\n        };\n\n        // Called by maas-obj-field to exit edit mode for the field.\n        MAASGroupController.prototype.stopEditingField = function(key, value) {\n            var field = this.fields[key];\n            field.editing = false;\n\n            // Exit early if not save on blur.\n            if(!this.saveOnBlur()) {\n                return;\n            }\n\n            // Delay the handling of stop to make sure start is not called on\n            // the next field in the group.\n            var self = this;\n            this.timeout(function() {\n                // If any other fields are in edit mode then nothing to do.\n                var editing = false;\n                angular.forEach(self.fields, function(value) {\n                    if(!editing) {\n                        editing = value.editing;\n                    }\n                });\n                if(editing) {\n                    return;\n                }\n\n                // Copy the object and update the editing fields.\n                var keys = [];\n                var changed = false;\n                var updatedObj = self.formController.cloneObject();\n                angular.forEach(self.fields, function(value, key) {\n                    value.scope.clearErrors();\n                    var newValue = value.scope.getValue();\n                    if(angular.isDefined(newValue) &&\n                        updatedObj[key] !== newValue) {\n                        keys.push(key);\n                        updatedObj[key] = newValue;\n                        changed = true;\n                    }\n                });\n                if(!changed) {\n                    return;\n                }\n\n                // Place the field that actually triggered the update first.\n                var keyIdx = keys.indexOf(key);\n                if(keyIdx !== -1) {\n                    keys.splice(keyIdx, 1);\n                    keys.splice(0, 0, key);\n                }\n\n                // Save the object.\n                self.scope.saving = true;\n                self.scope.savingKeys = keys;\n                self.formController.updateItem(updatedObj, keys).then(\n                    function(obj) {\n                      self.scope.saving = false;\n                      self.scope.savingKeys = [];\n                      return obj;\n                  }, function(error) {\n                      self.scope.saving = false;\n                      self.scope.savingKeys = [];\n                      return error;\n                  });\n            }, 10); // Really short has to be next click.\n        };\n\n        return {\n            restrict: \"E\",\n            require: [\"^^maasObjForm\", \"maasObjFieldGroup\"],\n            scope: {},\n            transclude: true,\n            template: (\n                '<div class=\"form__siblings\" ' +\n                'data-ng-class=\"{\\'is-active\\': isEditing()}\" ' +\n                'data-ng-transclude></div>'),\n            controller: ['$scope', '$timeout', MAASGroupController],\n            link: {\n                pre: function(scope, element, attrs, controllers) {\n                    // Set formController on the MAASGroupController to\n                    // point to its parent MAASFormController. This is done in\n                    // pre-link so the controller has the formController before\n                    // registerField is called.\n                    controllers[1].formController = controllers[0];\n\n                    // Set ngDisabled on this scope from the form controller.\n                    scope.ngDisabled = controllers[0].scope.ngDisabled;\n\n                    // Set the object to always be the same on the scope.\n                    controllers[0].scope.$watch(\"obj\", function(obj) {\n                        scope.obj = obj;\n                    });\n                }\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasObjField', ['$compile',\n    function($compile) {\n        return {\n            restrict: \"E\",\n            require: [\"^^maasObjForm\", \"?^^maasObjFieldGroup\"],\n            scope: {\n                onChange: \"=\",\n                subtleText: \"@\"\n            },\n            transclude: true,\n            template: (\n                '<div data-ng-transclude></div>'),\n            link: function(scope, element, attrs, controllers) {\n                // Select the controller based on which is available.\n                var controller = controllers[1];\n                if(!angular.isObject(controller)) {\n                    controller = controllers[0];\n                }\n\n                // Set ngDisabled from the parent controller.\n                scope.ngDisabled = controller.scope.ngDisabled;\n\n                element.addClass(\"p-form__group\");\n                if(attrs.subtle !== \"false\") {\n                    element.addClass(\"form__group--subtle\");\n                }\n\n                // type and key required.\n                var missingAttrs = [];\n                if(!angular.isString(attrs.type) && attrs.type.length === 0) {\n                    missingAttrs.push(\"type\");\n                }\n                if(!angular.isString(attrs.key) && attrs.key.length === 0) {\n                    missingAttrs.push(\"key\");\n                }\n                if(missingAttrs.length > 0) {\n                    throw new Error(\n                        missingAttrs.join(\", \") +\n                        \" are required on maas-obj-field.\");\n                }\n\n                // Remove transcluded element.\n                element.find(\"div\").remove();\n\n                // Render the label.\n                var label = attrs.label || attrs.key;\n\n                if(attrs.disableLabel !== \"true\") {\n                    var labelElement = angular.element('<label/>');\n                    labelElement.attr('for', attrs.key);\n                    labelElement.text(label);\n                    labelElement.addClass('p-form__label');\n                    if(attrs.labelWidth) {\n                        labelElement.addClass(\"col-\" + attrs.labelWidth);\n                    } else {\n                        labelElement.addClass(\"u-margin--right\");\n                    }\n                    if(attrs.labelLeft === \"true\") {\n                        labelElement.addClass('u-padding--left');\n                        labelElement.addClass('u-position--relative');\n                    }\n                    element.append(labelElement);\n\n                    // Add a label info icon with tooltip.\n                    if(angular.isString(attrs.labelInfo)\n                            && attrs.labelInfo.length > 0) {\n                        var infoWrapper = angular.element(\n                            '<span>&nbsp;</span>');\n                        infoWrapper.addClass('p-tooltip p-tooltip--btm-right');\n\n                        var infoIcon = angular.element('<i/>');\n                        infoIcon.addClass('p-icon--information');\n                        infoIcon.attr(\n                            'aria-describedby', attrs.key + '-tooptip');\n\n                        var infoTooltip = angular.element('<p></p>');\n                        infoTooltip.addClass('p-tooltip__message');\n                        infoTooltip.text(attrs.labelInfo);\n                        infoTooltip.attr('id', attrs.key + '-tooptip');\n\n                        infoWrapper.append(infoIcon);\n                        infoWrapper.append(infoTooltip);\n\n                        labelElement.append(infoWrapper);\n\n                        // prevents the icon from being clickable\n                        infoIcon.bind('click', function (evt) {\n                            evt.preventDefault();\n                        });\n                    }\n                }\n\n                // Add the wrapper for the input.\n                var inputWrapper = angular.element('<div></div>');\n                inputWrapper.addClass(\"p-form__control\");\n\n                if(attrs.inputWidth) {\n                    inputWrapper.addClass(\"col-\" + attrs.inputWidth);\n                }\n\n                // Render the input based on the type.\n                var placeholder = attrs.placeholder || label;\n                var inputElement = null;\n                if(attrs.type === \"text\" || attrs.type === \"textarea\" ||\n                   attrs.type === \"password\") {\n                    if(attrs.type === \"text\") {\n                        inputElement = $compile(\n                            '<input type=\"text\" id=\"' + attrs.key +\n                            '\" placeholder=\"' + placeholder + '\"' +\n                            'data-ng-disabled=\"ngDisabled()\">')(scope);\n                    } else if(attrs.type === \"textarea\") {\n                        inputElement = $compile(\n                            '<textarea id=\"' + attrs.key +\n                            '\" placeholder=\"' + placeholder + '\"' +\n                            'data-ng-disabled=\"ngDisabled()\">' +\n                                '</textarea>')(scope);\n                    } else if(attrs.type === \"password\") {\n                        inputElement = $compile(\n                            '<input type=\"password\" id=\"' + attrs.key +\n                            '\" placeholder=\"' + placeholder + '\"' +\n                            'data-ng-disabled=\"ngDisabled()\">')(scope);\n                    }\n\n                    // Allow enter on blur, by default.\n                    if(attrs.blurOnEnter) {\n                        inputElement.bind(\"keydown keypress\", function(evt) {\n                            if(evt.which === 13) {\n                                inputElement.blur();\n                                evt.preventDefault();\n                            }\n                        });\n                    }\n\n                    // Revert value on esc.\n                    var self = this;\n                    inputElement.bind(\"keydown keypress\", function(evt) {\n                        if(evt.which === 27) {\n                            inputElement.val(controller.scope.obj[attrs.key]);\n                            inputElement.blur();\n                            evt.preventDefault();\n                        }\n                    });\n\n                    // Register the field with the controller and set the\n                    // current value for the field.\n                    var currentValue = controller.registerField(\n                        attrs.key, scope);\n                    inputElement.val(currentValue);\n\n                    // When element is in focus then editing is on.\n                    inputElement.on(\"focus\", function() {\n                        scope.$apply(function() {\n                            controller.startEditingField(attrs.key);\n                        });\n                    });\n\n                    // When element is not in focus then editing is done.\n                    inputElement.on(\"blur\", function() {\n                        scope.$apply(function() {\n                            controller.stopEditingField(\n                                attrs.key, inputElement.val());\n                        });\n                    });\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        inputElement.val(newValue);\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return inputElement.val();\n                    };\n                } else if(attrs.type === \"options\") {\n                    // Requires the options attribute on the element. This\n                    // is copied directly into the ngOptions directive on\n                    // the select.\n                    var options = attrs.options;\n                    if(!angular.isString(options) || options.length === 0) {\n                        throw new Error(\n                            \"options attribute is required on type \" +\n                            \"'options' on maas-obj-field.\");\n                    }\n\n                    // Placeholder by default is disabled, allow it to be\n                    // enabled.\n                    var disabled = \"disabled\";\n                    if(attrs.placeholderEnabled === \"true\") {\n                        disabled = \"\";\n                    }\n\n                    // Create a child scope of the parent scope for this\n                    // directive. Since this directive is created with an\n                    // isolated scope we need the child to use the parent so\n                    // ngOptions can use properties defined in that scope.\n                    var childScope = scope.$parent.$new();\n                    childScope._ngDisabled = scope.ngDisabled;\n                    childScope._selectValue = controller.registerField(\n                        attrs.key, scope);\n                    childScope._selectNgChange = function() {\n                        scope._change();\n                        controller.stopEditingField(\n                            attrs.key, childScope._selectValue);\n                    };\n\n                    // Construct the select.\n                    inputElement = $compile(\n                        '<select id=\"' + attrs.key + '\" ' +\n                        'data-ng-model=\"_selectValue\" ' +\n                        'data-ng-options=\"' + options + '\"' +\n                        'data-ng-change=\"_selectNgChange()\"' +\n                        'data-ng-disabled=\"_ngDisabled()\">' +\n                        '<option value=\"\" ' + disabled + '>' + placeholder +\n                        '</option></select>')(childScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        childScope._selectValue = newValue;\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return childScope._selectValue;\n                    };\n                } else if(attrs.type === \"checkboxes\") {\n                    // Requires the values attribute on the element.\n                    var values = attrs.values;\n                    if(!angular.isString(values) || values.length === 0) {\n                        throw new Error(\n                            \"values attribute is required on type \" +\n                            \"'checkboxes' on maas-obj-field.\");\n                    }\n\n                    // Create a child scope of the parent scope for this\n                    // directive. Since this directive is created with an\n                    // isolated scope we need the child to use the parent so\n                    // values can come from the parent scope.\n                    var checkScope = scope.$parent.$new();\n                    checkScope._selectedValues = controller.registerField(\n                        attrs.key, scope);\n                    checkScope._checked = function(val) {\n                        return checkScope._selectedValues.indexOf(val) > -1;\n                    };\n                    checkScope._toggleChecked = function(val) {\n                        var idx = checkScope._selectedValues.indexOf(val);\n                        if(idx > -1) {\n                            // Uncheck.\n                            checkScope._selectedValues.splice(idx, 1);\n                        } else {\n                            // Check.\n                            checkScope._selectedValues.push(val);\n                        }\n                    };\n\n                    // Construct the checkbox list.\n                    inputElement = angular.element([\n                        '<div class=\"width--full\" ',\n                            'data-ng-repeat=\"val in ' + values +'\">',\n                            '<input id=\"' + attrs.key + '_' + '{$ val $}',\n                                '\" type=\"checkbox\" value=\"{$ val $}\" ',\n                                'class=\"checkbox\" ',\n                                'data-ng-checked=\"_checked(val)\" ',\n                                'data-ng-click=\"_toggleChecked(val)\">',\n                            '<label for=\"' + attrs.key + '_',\n                                '{$ val $}' + '\" ',\n                                'class=\"checkbox-label\">{$ val $}</label>',\n                        '</div>'\n                    ].join(''));\n                    inputElement = $compile(inputElement)(checkScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        checkScope._selectedValues = newValue;\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return checkScope._selectedValues;\n                    };\n                } else if(attrs.type === \"tags\") {\n                    var tagsScope = scope.$new();\n                    var tags = controller.registerField(\n                        attrs.key, scope);\n                    tagsScope._tags = tags.map(function(val) {\n                        return {text: val};\n                    });\n\n                    // Construct the tags input.\n                    inputElement = angular.element([\n                        '<tags-input id=\"' + attrs.key + '\" ',\n                            'data-ng-model=\"_tags\" ',\n                            'placeholder=\"' + placeholder + '\" ',\n                            'data-ng-change=\"_change()\" ',\n                            'allow-tags-pattern=\"[\\\\w-]+\"></tags-input>'\n                    ].join(''));\n                    inputElement = $compile(inputElement)(tagsScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        tagsScope._tags = newValue.map(\n                            function(val) {\n                                return {text: val};\n                            });\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        return tagsScope._tags.map(\n                            function(val) {\n                                return val.text;\n                            });\n                    };\n                } else if(attrs.type === \"onoffswitch\") {\n                    var switchScope = scope.$new();\n                    switchScope._toggle = controller.registerField(\n                        attrs.key, scope);\n                    switchScope._changed = function() {\n                        scope._change();\n                        controller.startEditingField(attrs.key);\n                        controller.stopEditingField(\n                            attrs.key, switchScope.getValue());\n                    };\n\n                    // Construct the on and off toggle.\n                    inputElement = angular.element([\n                      '<div class=\"maas-p-switch\">',\n                        '<input type=\"checkbox\" name=\"' + attrs.key + '\" ',\n                          'class=\"maas-p-switch--input\" ',\n                          'id=\"' + attrs.key + '\" ',\n                          'data-ng-model=\"_toggle\" ',\n                          'data-ng-change=\"_changed()\">',\n                        '<div class=\"maas-p-switch--mask\"></div>',\n                      '</div>'\n                    ].join(''));\n                    inputElement = $compile(inputElement)(switchScope);\n\n                    // Called by controller to update the value.\n                    scope.updateValue = function(newValue) {\n                        // WARNING: This code is difficult to unit test, since\n                        // we could not figure out how to get the\n                        // isolateScope() from the transcluded element. Be sure\n                        // to manually test versions of this toggle with and\n                        // without the on-value and off-value attributes, such\n                        // as by verifying that both the on/off toggle on both\n                        // the discovery page and the subnet details page work.\n                        if(attrs.onValue && attrs.onValue === newValue) {\n                            switchScope._toggle = true;\n                        } else if(attrs.offValue &&\n                                attrs.offValue === newValue) {\n                            switchScope._toggle = false;\n                        } else {\n                            switchScope._toggle = newValue;\n                        }\n                    };\n\n                    // Called by controller to get the value.\n                    scope.getValue = function() {\n                        // WARNING: This code is difficult to unit test, since\n                        // we could not figure out how to get the\n                        // isolateScope() from the transcluded element. Be sure\n                        // to manually test versions of this toggle with and\n                        // without the on-value and off-value attributes, such\n                        // as by verifying that both the on/off toggle on both\n                        // the discovery page and the subnet details page work.\n                        if(switchScope._toggle) {\n                            if(attrs.onValue) {\n                                return attrs.onValue;\n                            } else {\n                                return true;\n                            }\n                        } else {\n                            if(attrs.offValue) {\n                                return attrs.offValue;\n                            } else {\n                                return false;\n                            }\n                        }\n                    };\n                } else {\n                    throw new Error(\n                        \"Unknown type on maas-obj-field: \" + attrs.type);\n                }\n\n                // Called on change.\n                scope._change = function() {\n                    if(angular.isFunction(scope.onChange)) {\n                        scope.onChange(\n                            attrs.key,\n                            controller.getValue(attrs.key),\n                            controller);\n                    }\n                };\n\n                // Copy input class to the input element.\n                if(attrs.inputClass) {\n                    inputElement.addClass(attrs.inputClass);\n                }\n                inputWrapper.append(inputElement);\n\n                // Errors element.\n                var errorsElement = angular.element(\n                    '<ul class=\"p-list u-no-margin--top\"></ul>');\n                if(!controller.isTableForm()) {\n                    errorsElement.addClass(\"form__error\");\n                }\n                inputWrapper.append(errorsElement);\n\n                // Help text elements\n                if (attrs.helpText) {\n                    var helpTextElement = angular.element(\n                        '<p>' + attrs.helpText + '</p>');\n                    helpTextElement.addClass(\"p-form-help-text\");\n                    inputWrapper.append(helpTextElement);\n                }\n\n                // Called by controller to clear all errors.\n                scope.clearErrors = function() {\n                    inputElement.removeClass(\"ng-dirty\");\n                    inputElement.removeClass(\"p-form-validation__input\");\n                    inputWrapper.removeClass(\"p-form-validation\");\n                    inputWrapper.removeClass(\"is-error\");\n                    inputWrapper.removeClass(\"u-no-margin--top\");\n                    errorsElement.empty();\n                };\n\n                // Called by controller to set errors.\n                scope.setErrors = function(errors) {\n                    if(errors.length > 0) {\n                        inputWrapper.addClass(\"p-form-validation\");\n                        inputWrapper.addClass(\"is-error\");\n                        inputWrapper.addClass(\"u-no-margin--top\");\n                        inputElement.addClass(\"ng-dirty\");\n                        inputElement.addClass(\"p-form-validation__input\");\n                        angular.forEach(errors, function(error) {\n                            errorsElement.append(\n                              '<li class=\"p-form-validation__message\">' +\n                              '<strong>Error:</strong> ' + error + '</li>'\n                            );\n                        });\n                        // Set the input in focus but outside of the current\n                        // digest cycle.\n                        setTimeout(function() {\n                            inputElement.focus();\n                        }, 1);\n                    }\n                };\n\n                // Called by controller to see if error is set on field.\n                scope.hasErrors = function() {\n                    return inputWrapper.hasClass(\"is-error\");\n                };\n\n                // Subtle text element.\n                if(attrs.subtleText) {\n                    var subtleTextElement = $compile(\n                        angular.element(\n                            '<span class=\"p-form-help-text\" ' +\n                            'data-ng-bind=\"subtleText\"></span>'))(scope);\n                    inputWrapper.append(subtleTextElement);\n                }\n                element.append(inputWrapper);\n\n                // Watch the showing of saving spinner. Update the elements\n                // correctly to show the saving.\n                scope.$watch(function() {\n                    return controller.showInputSaving(attrs.key);\n                }, function(value) {\n                    if(value) {\n                        inputWrapper.children(\n                            ':first').addClass('u-border--information');\n                        inputWrapper.append(\n                            '<i class=\"obj-saving icon ' +\n                            'p-icon--spinner u-animation--spin\"></i>');\n                        inputWrapper.addClass('p-tooltip');\n                        inputWrapper.addClass('p-tooltip--bottom');\n                        inputWrapper.attr('aria-label', 'Saving');\n                    } else {\n                      inputWrapper.children(\n                          ':first').removeClass('u-border--information');\n                        inputWrapper.find('i.obj-saving').remove();\n                        inputWrapper.removeClass('p-tooltip');\n                        inputWrapper.removeClass('p-tooltip--right');\n                        inputWrapper.removeAttr('aria-label');\n                    }\n                });\n\n                // Called when the scope is destroyed.\n                scope.$on(\"$destroy\", function() {\n                    controller.unregisterField(attrs.key);\n                });\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasObjSave', function() {\n        return {\n            restrict: \"A\",\n            require: [\"^^maasObjForm\"],\n            scope: {},\n            link: function(scope, element, attrs, controllers) {\n                // Only allow maas-obj-save when saveOnBlur is false.\n                var controller = controllers[0];\n                if(controller.saveOnBlur()) {\n                    throw new Error(\n                        \"maas-obj-save is only allowed when save-on-blur is \" +\n                        \"set to false.\");\n                }\n\n                element.on(\"click\", function() {\n                    scope.$apply(function() {\n                        controller.saveForm();\n                    });\n                });\n            }\n        };\n    });\n\nangular.module('MAAS').directive('maasObjErrors', function() {\n        return {\n            restrict: \"E\",\n            require: [\"^^maasObjForm\"],\n            scope: {},\n            template: '<ul class=\"p-list u-no-margin--top\"></ul>',\n            link: function(scope, element, attrs, controllers) {\n                // Set on the controller the global error handler.\n                controllers[0].errorScope = scope;\n                var ul = element.find(\"ul\");\n\n                // Called by controller to clear all errors.\n                scope.clearErrors = function() {\n                    ul.empty();\n                };\n\n                // Called by controller to set errors.\n                scope.setErrors = function(errors) {\n                    if(errors.length > 0) {\n                        angular.forEach(errors, function(error) {\n                            ul.append(\n                              '<li class=\"p-list__item\">' +\n                              '<i class=\"p-icon--error\"></i> ' +\n                              error + '</li>'\n                            );\n                        });\n                    }\n                };\n\n                // Called by controller to see if error is set on field.\n                scope.hasErrors = function() {\n                    return ul.children().length > 0;\n                };\n            }\n        };\n    });\n\n\nangular.module('MAAS').directive('maasObjSaving', function() {\n        return {\n            restrict: \"E\",\n            require: \"^^maasObjForm\",\n            scope: {},\n            transclude: true,\n            template: [\n              '<span data-ng-if=\"saving\">',\n                '<i class=\"p-icon--loading u-animation--spin\"></i>',\n                '<span data-ng-transclude></span>',\n              '</span>'].join(''),\n            link: function(scope, element, attrs, controller) {\n                scope.saving = false;\n                scope.$watch(function() {\n                    return controller.scope.saving;\n                }, function(value) {\n                    scope.saving = value;\n                });\n            }\n        };\n    });\n\n\nangular.module('MAAS').directive('maasObjShowSaving', function() {\n        return {\n            restrict: \"A\",\n            require: \"^^maasObjForm\",\n            link: function(scope, element, attrs, controller) {\n                scope.$watch(function() {\n                    return controller.scope.saving;\n                }, function(value) {\n                    if(value) {\n                        element.removeClass(\"ng-hide\");\n                    } else {\n                        element.addClass(\"ng-hide\");\n                    }\n                });\n            }\n        };\n    });\n\n\nangular.module('MAAS').directive('maasObjHideSaving', function() {\n        return {\n            restrict: \"A\",\n            require: \"^^maasObjForm\",\n            link: function(scope, element, attrs, controller) {\n                scope.$watch(function() {\n                    return controller.scope.saving;\n                }, function(value) {\n                    if(value) {\n                        element.addClass(\"ng-hide\");\n                    } else {\n                        element.removeClass(\"ng-hide\");\n                    }\n                });\n            }\n        };\n    });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Creates the auto-formatting for MAC address inputs.\n */\n\nangular.module('MAAS').directive('macAddress', function () {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        link: function (scope, ele, attr, ngModelCtrl, ngModel) {\n            if (!ngModelCtrl) {\n              return;\n            }\n\n            var macAddressParse = function (value) {\n                return value.toUpperCase();\n            };\n\n            var macAddressFormat = function (value) {\n\n                if (!value) {\n                  return undefined;\n                }\n\n                var numbers = value.replace(/:/g, \"\");\n\n                if (value.length % 3 === 0) {\n\n                    return numbers.replace(/([0-9A-Za-z]{2})/g, \"$1:\");\n                }\n            };\n\n            ngModelCtrl.$parsers.push(macAddressParse);\n            ngModelCtrl.$formatters.push(macAddressFormat);\n\n            ele.on('input', function () {\n                var value = macAddressFormat(ele.val());\n\n                if (value !== undefined) {\n                    ngModelCtrl.$setViewValue(value);\n                    ngModelCtrl.$render();\n                }\n                scope.$apply();\n            });\n        }\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n* GNU Affero General Public License version 3 (see the file LICENSE).\n*\n* Machines listing directive.\n*\n* Renders the machines listing.\n*/\n// testing\n\n\n\nangular.module('MAAS').directive('maasMachinesTable', [\n  'MachinesManager', 'GeneralManager', 'ManagerHelperService',\n  function (MachinesManager, GeneralManager, ManagerHelperService) {\n    return {\n      restrict: \"E\",\n      scope: {\n        search: \"=\",\n        ngDisabled: \"&\",\n        machineHasError: \"&\",\n        hideCheckboxes: \"=?\",\n        onListingChange: \"&\",\n        onCheckAll: \"&\",\n        onCheck: \"&\"\n      },\n      templateUrl: (\n        'static/partials/machines-table.html?v=' + (\n          MAAS_config.files_version)),\n      link: function(scope, element, attrs) {\n        // Statuses that should show spinner.\n        var SPINNER_STATUSES = [\n          1,   // commissioning\n          9,   // deploying\n          12,  // releasing\n          14,  // disk erasing\n          17,  // entering rescue mode\n          19,  // exiting rescue mode\n          21   // testing\n        ];\n\n        // Scope variables.\n        scope.table = {\n          column: 'fqdn',\n          predicate: 'fqdn',\n          reverse: false,\n          allViewableChecked: false,\n          machines: MachinesManager.getItems(),\n          filteredMachines: [],\n          osinfo: GeneralManager.getData(\"osinfo\")\n        };\n\n        // Ensures that the checkbox for select all is the correct value.\n        scope.updateAllChecked = function() {\n          // Not checked when the filtered machines are empty.\n          if(scope.table.filteredMachines.length === 0) {\n              scope.table.allViewableChecked = false;\n              return;\n          }\n\n          // Loop through all filtered machines and see if all are checked.\n          var i;\n          for(i = 0; i < scope.table.filteredMachines.length; i++) {\n              if(!scope.table.filteredMachines[i].$selected) {\n                  scope.table.allViewableChecked = false;\n                  return;\n              }\n          }\n          scope.table.allViewableChecked = true;\n        };\n\n        // Selects and deselects visible machines.\n        scope.toggleCheckAll = function() {\n          if(scope.table.allViewableChecked) {\n            angular.forEach(\n              scope.table.filteredMachines, function(machine) {\n                MachinesManager.unselectItem(machine.system_id);\n              });\n          } else {\n            angular.forEach(\n              scope.table.filteredMachines, function(machine) {\n                MachinesManager.selectItem(machine.system_id);\n              });\n          }\n          scope.updateAllChecked();\n          scope.onCheckAll();\n        };\n\n        // Selects and unselects machine.\n        scope.toggleChecked = function(machine) {\n          if(MachinesManager.isSelected(machine.system_id)) {\n            MachinesManager.unselectItem(machine.system_id);\n          } else {\n            MachinesManager.selectItem(machine.system_id);\n          }\n          scope.updateAllChecked();\n          scope.onCheck({$machine: machine});\n        };\n\n        // Sorts the table by predicate.\n        scope.sortTable = function(predicate) {\n            scope.table.predicate = predicate;\n            scope.table.reverse = !scope.table.reverse;\n        };\n\n        // Sets the viewable column or sorts.\n        scope.selectColumnOrSort = function(predicate) {\n            if(scope.table.column !== predicate) {\n                scope.table.column = predicate;\n            } else {\n                scope.sortTable(predicate);\n            }\n        };\n\n        // Return true if spinner should be shown.\n        scope.showSpinner = function(machine) {\n            return SPINNER_STATUSES.indexOf(machine.status_code) > -1;\n        };\n\n        scope.showFailedTestWarning = function(machine) {\n            if(scope.showSpinner(machine)) {\n                return false;\n            }\n            switch(machine.status_code) {\n                // NEW\n                case 0:\n                // COMMISSIONING\n                case 1:\n                // FAILED_COMMISSIONING\n                case 2:\n                // TESTING\n                case 21:\n                // FAILED_TESTING\n                case 22:\n                    return false;\n            }\n            switch(machine.testing_status) {\n                // Tests havn't been run\n                case -1:\n                // Tests have passed\n                case 2:\n                    return false;\n            }\n            return true;\n        };\n\n        // Return true if the other node status should be shown.\n        scope.showNodeStatus = function(machine) {\n            // -1 means tests havn't been run, 2 means tests have passed.\n            if(!scope.showSpinner(machine) &&\n               !scope.showFailedTestWarning(machine) &&\n               machine.other_test_status !== -1 &&\n               machine.other_test_status !== 2) {\n                return true;\n            } else {\n                return false;\n            }\n        };\n\n        // Returns the release title from osinfo.\n        scope.getReleaseTitle = function(os_release) {\n          if(angular.isArray(scope.table.osinfo.releases)) {\n            for(i = 0; i < scope.table.osinfo.releases.length; i++) {\n              var release = scope.table.osinfo.releases[i];\n              if(release[0] === os_release) {\n                return release[1];\n              }\n            }\n          }\n          return os_release;\n        };\n\n        // Returns the status text to show.\n        scope.getStatusText = function(machine) {\n          var showRelease = ['Deploying', 'Deployed'];\n          if(showRelease.indexOf(machine.status) === -1) {\n            return machine.status;\n          } else {\n            var releaseTitle = scope.getReleaseTitle(\n              machine.osystem + '/' + machine.distro_series);\n            if(machine.osystem === \"ubuntu\") {\n              releaseTitle = releaseTitle.split('\"')[0].trim();\n            }\n            if(machine.status === \"Deployed\") {\n              return releaseTitle;\n            }\n            if(machine.status === \"Deploying\") {\n              return machine.status + ' ' + releaseTitle;\n            }\n          }\n        };\n\n        // When the list of filtered machines change update the all checkbox.\n        scope.$watchCollection(\"table.filteredMachines\", function() {\n          scope.updateAllChecked();\n          scope.onListingChange({$machines: scope.table.filteredMachines});\n        });\n\n        // Load the required managers and start polling for osinfo.\n        ManagerHelperService.loadManagers(\n          scope, [MachinesManager, GeneralManager]).then(function() {\n            GeneralManager.startPolling(scope, \"osinfo\");\n          });\n\n        // Stop polling when the scope is destroyed.\n        scope.$on(\"$destroy\", function() {\n          GeneralManager.stopPolling(scope, \"osinfo\");\n        });\n      }\n    };\n}]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Notifications.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject notifications.html into the template cache.\n    $templateCache.put('directive/templates/notifications.html', [\n      '<div class=\"u-no-margin--top\" data-ng-repeat=\"category in categories\"',\n        ' data-ng-init=\"notifications = categoryNotifications[category]\">',\n        // 1 notification.\n        '<span class=\"row\" data-ng-if=\"notifications.length == 1\">',\n          '<ul class=\"p-list\" data-ng-class=\"{\\'is-open\\': shown}\">',\n            '<li data-ng-repeat=\"notification in notifications\"',\n            ' class=\"p-notification\"',\n            ' data-ng-class=\"categoryClasses[notification.category]\">',\n              '<p class=\"p-notification__response\">',\n                '<span data-ng-bind-html=\"notification.message\"></span> ',\n                '<a class=\"p-notification__action\"',\n                ' data-ng-click=\"dismiss(notification)\">Dismiss</a>',\n              '</p>',\n            '</li>',\n          '</ul>',\n        '</span>',\n        // 2 or more notifications.\n        '<div class=\"row p-notification--group\" ',\n             'data-ng-if=\"notifications.length >= 2\"',\n        ' data-ng-init=\"shown = false\">',\n            '<div data-ng-class=\"categoryClasses[notifications[0].category]\">',\n                '<a aria-label=\"{$ notifications.length $} ',\n                    '{$ categoryTitles[category] $}, click to open messages.\"',\n                    ' maas-enter=\"shown = !shown\"',\n                    ' class=\"p-notification__toggle\"',\n                    ' data-ng-click=\"shown = !shown\">',\n                    '<p class=\"p-notification__response\">',\n                        '<span class=\"p-notification__status\"',\n                        ' data-count=\"{$ notifications.length $}\"',\n                        ' data-ng-bind=\"notifications.length + \\' \\' + ',\n                                       'categoryTitles[category]\"></span>',\n                        '<small>',\n                        '<i data-ng-class=\"{ \\'p-icon--expand\\': !shown,',\n                        ' \\'p-icon--collapse\\': shown }\"></i></small>',\n                    '</p>',\n                '</a>',\n                '<ul class=\"p-list--divided\" ',\n                    'data-ng-class=\"{\\'u-hide\\': !shown}\">',\n                    '<li data-ng-repeat=\"notification in notifications\"',\n                    ' class=\"p-list__item\">',\n                    '<p class=\"p-notification__response\">',\n                        '<span data-ng-bind-html=\"notification.message\">',\n                        '</span> ',\n                        '<a class=\"p-notification__action\"',\n                        ' data-ng-click=\"dismiss(notification)\">Dismiss</a>',\n                    '</p>',\n                    '</li>',\n                '</ul>',\n            '</div>',\n        '</div>',\n      '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasNotifications', [\n    \"NotificationsManager\", \"ManagerHelperService\",\n    function(NotificationsManager, ManagerHelperService) {\n        return {\n            restrict: \"E\",\n            templateUrl: 'directive/templates/notifications.html',\n            link: function($scope, element, attrs) {\n                ManagerHelperService.loadManager($scope, NotificationsManager);\n                $scope.notifications = NotificationsManager.getItems();\n                $scope.dismiss = angular.bind(\n                    NotificationsManager, NotificationsManager.dismiss);\n\n                $scope.categories = [\n                    \"error\",\n                    \"warning\",\n                    \"success\",\n                    \"info\"\n                ];\n                $scope.categoryTitles = {\n                    error: \"Errors\",\n                    warning: \"Warnings\",\n                    success: \"Successes\",\n                    info: \"Other messages\"\n                };\n                $scope.categoryClasses = {\n                    error: \"p-notification--negative\",\n                    warning: \"p-notification--caution\",\n                    success: \"p-notification--positive\",\n                    info: \"p-notification\"  // No suffix.\n                };\n                $scope.categoryNotifications = {\n                    error: [],\n                    warning: [],\n                    success: [],\n                    info: []\n                };\n\n                $scope.$watchCollection(\n                    \"notifications\", function() {\n                        var cns = $scope.categoryNotifications;\n                        angular.forEach(\n                            $scope.categories, function(category) {\n                                cns[category].length = 0;\n                            }\n                        );\n                        angular.forEach(\n                            $scope.notifications, function(notification) {\n                                cns[notification.category].push(notification);\n                            }\n                        );\n                    }\n                );\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * OS/Release select directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the os-select.html into the template cache.\n    $templateCache.put('directive/templates/os-select.html', [\n        '<div class=\"form__group-input\"> ',\n            '<select name=\"os\" class=\"u-margin--right\" ',\n                'data-ng-model=\"ngModel.osystem\" ',\n                'data-ng-change=\"selectedOSChanged()\" ',\n                'data-ng-options=\"',\n                'os[0] as os[1] for os in maasOsSelect.osystems\">',\n            '</select>',\n        '</div>',\n        '<div class=\"form__group-input\"> ',\n            '<select name=\"release\" class=\"u-margin--right\" ',\n                'data-ng-model=\"ngModel.release\" ',\n                'data-ng-change=\"selectedReleaseChanged()\" ',\n                'data-ng-options=\"',\n                'release[0] as release[1] for release in releases\">',\n            '</select>',\n        '</div>',\n        '<div class=\"form__group-input\"> ',\n            '<select name=\"hwe_kernel\" data-ng-model=\"ngModel.hwe_kernel\" ',\n                'data-ng-show=\"hwe_kernels.length\"',\n                'data-ng-options=\"',\n                'hwe_kernel[0] as hwe_kernel[1] for hwe_kernel ',\n                'in hwe_kernels\">',\n                '<option value=\"\">Default kernel</option>',\n            '</select>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasOsSelect', function() {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            maasOsSelect: '=',\n            ngModel: '='\n        },\n        templateUrl: 'directive/templates/os-select.html',\n        controller: function($scope) {\n\n            // Return only the selectable releases based on the selected os.\n            function getSelectableReleases() {\n                if(angular.isObject($scope.maasOsSelect) &&\n                    angular.isArray($scope.maasOsSelect.releases)) {\n                    var i, allChoices = $scope.maasOsSelect.releases;\n                    var choice, choices = [];\n                    for(i = 0; i < allChoices.length; i++) {\n                        choice = allChoices[i];\n                        if(choice[0].indexOf($scope.ngModel.osystem + '/') > -1)\n                        {\n                            choices.push(choice);\n                        }\n                    }\n                    return choices;\n                }\n                return [];\n            }\n\n            // Return only the selectable kernels based on the selected os.\n            function getSelectableKernels() {\n                if(angular.isObject($scope.maasOsSelect) &&\n                    angular.isObject($scope.maasOsSelect.kernels) &&\n                    angular.isString($scope.ngModel.osystem) &&\n                    angular.isString($scope.ngModel.release)) {\n                    var os = $scope.ngModel.osystem;\n                    var release = $scope.ngModel.release.split('/')[1];\n                    var osKernels = $scope.maasOsSelect.kernels[os];\n                    if(angular.isObject(osKernels)) {\n                        return osKernels[release];\n                    }\n                }\n                return [];\n            }\n\n            // Returns the defaultValue if its in the choices array. Otherwise\n            // it returns the weighted choice if present, followed by the\n            // first choice.\n            function getDefaultOrFirst(array, defaultValue, weightValue) {\n                var i, first, weightedPresent = false;\n                for(i = 0; i < array.length; i++) {\n                    if(angular.isUndefined(first)) {\n                        first = array[i][0];\n                    }\n                    if(array[i][0] === defaultValue) {\n                        return defaultValue;\n                    }\n                    if(angular.isString(weightValue) &&\n                        array[i][0] === weightValue) {\n                        weightedPresent = true;\n                    }\n                }\n                if(weightedPresent) {\n                    return weightValue;\n                }\n                if(angular.isUndefined(first)) {\n                    return null;\n                }\n                return first;\n            }\n\n            // Sets the default selected values for the ngModel. Only sets the\n            // values once the maasOsSelect is populated. Sets the selected\n            // osystem to default_osystem if present, followed by 'ubuntu' if\n            // present, followed by the first available. Sets the selected\n            // release to the default_release if present, followed by the first\n            // available.\n            function setDefault() {\n                // Do nothing if model is already set.\n                if(angular.isString($scope.ngModel.osystem) &&\n                    angular.isString($scope.ngModel.release)) {\n                    return;\n                }\n                // Do nothing if the default is not set.\n                if(angular.isUndefined($scope.maasOsSelect.default_osystem) ||\n                    angular.isUndefined($scope.maasOsSelect.default_release)) {\n                    return;\n                }\n\n                // Set the intial defaults.\n                $scope.ngModel.osystem = getDefaultOrFirst(\n                    $scope.maasOsSelect.osystems,\n                    $scope.maasOsSelect.default_osystem, \"ubuntu\");\n                $scope.releases = getSelectableReleases();\n                $scope.ngModel.release = getDefaultOrFirst(\n                    $scope.releases,\n                    $scope.ngModel.osystem + \"/\" +\n                    $scope.maasOsSelect.default_release);\n                $scope.ngModel.kernel = \"\";\n            }\n\n            // Defaults\n            if(!angular.isObject($scope.ngModel)) {\n                $scope.ngModel = {\n                    osystem: null,\n                    release: null,\n                    hwe_kernel: null\n                };\n            }\n            $scope.releases = getSelectableReleases();\n            $scope.hwe_kernels = getSelectableKernels();\n\n            // Add the reset function to ngModel, allowing users to call\n            // this function to reset the defauls.\n            $scope.ngModel.$reset = function() {\n                $scope.ngModel.osystem = null;\n                $scope.ngModel.release = null;\n                $scope.ngModel.hwe_kernel = null;\n                setDefault();\n            };\n\n            // If the available os change update the available releases and\n            // set the default.\n            $scope.$watch(\"maasOsSelect.releases\", function() {\n                $scope.releases = getSelectableReleases();\n                setDefault();\n            });\n\n            // If the available release change update the available kernels and\n            // set the default.\n            $scope.$watch(\"maasOsSelect.kernels\", function() {\n                $scope.hwe_kernels = getSelectableKernels();\n                setDefault();\n            });\n\n            // Updates the default and selectable releases.\n            $scope.selectedOSChanged = function() {\n                $scope.releases = getSelectableReleases();\n                $scope.hwe_kernels = getSelectableKernels();\n                $scope.ngModel.release = null;\n                $scope.ngModel.hwe_kernel = null;\n                if($scope.releases.length > 0) {\n                    $scope.ngModel.release = $scope.releases[0][0];\n                }\n            };\n\n            // Updates the default and selectable kernels.\n            $scope.selectedReleaseChanged = function() {\n                $scope.hwe_kernels = getSelectableKernels();\n                $scope.ngModel.hwe_kernel = null;\n            };\n        }\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Placeholder directive.\n *\n * Allows the placeholder attribute on an element to be dynamic.\n */\n\n\nangular.module('MAAS').directive('ngPlaceholder', function() {\n    return {\n        restrict: \"A\",\n        scope: {\n            ngPlaceholder: \"=\"\n        },\n        link: function(scope, element, attrs) {\n            scope.$watch('ngPlaceholder', function() {\n                element[0].placeholder = scope.ngPlaceholder;\n            });\n        }\n    };\n});\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Pod parameters directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the power-parameters.html into the template cache.\n    $templateCache.put('directive/templates/pod-parameters.html', [\n        '<maas-obj-field type=\"options\" key=\"type\" label=\"Pod type\" ',\n          'label-width=\"2\" input-width=\"5\" ',\n          'placeholder=\"Select the pod type\" ',\n          'options=\"type.name as type.description for type in podTypes\" ',\n          'ng-if=\"!hideType\">',\n        '</maas-obj-field>',\n        '<div pod-fields></div>'\n    ].join(''));\n}]);\n\n\nangular.module('MAAS').directive(\n    'maasPodParameters', [\n        '$compile', 'GeneralManager', 'ManagerHelperService', function(\n        $compile, GeneralManager, ManagerHelperService) {\n    return {\n        restrict: \"E\",\n        require: \"^^maasObjForm\",\n        scope: {\n          hideType: '='\n        },\n        templateUrl: 'directive/templates/pod-parameters.html',\n        link: function(scope, element, attrs, controller) {\n            scope.powerTypes = GeneralManager.getData('power_types');\n            scope.podTypes = [];\n            scope.type = null;\n\n            var childScope, fieldsElement = angular.element(\n                element.find('div[pod-fields]'));\n\n            // Function to update the editable fields.\n            var updateFields = function(podType) {\n                var type = null;\n                var i;\n                for(i = 0; i < scope.podTypes.length; i++) {\n                    if(scope.podTypes[i].name === podType) {\n                      type = scope.podTypes[i];\n                    }\n                }\n\n                fieldsElement.empty();\n                if(childScope) {\n                  childScope.$destroy();\n                }\n                if(angular.isObject(type)) {\n                  var html = '<maas-obj-field-group>';\n                  angular.forEach(type.fields, function(field) {\n                      if(field.scope === 'bmc') {\n                          if(field.name === 'power_pass') {\n                              html += (\n                                  '<maas-obj-field type=\"password\" key=\"');\n                          } else {\n                              html += (\n                                  '<maas-obj-field type=\"text\" key=\"');\n                          }\n                          html += (field.name + '\" label=\"' + field.label +\n                            '\" ' + 'label-width=\"2\" input-width=\"5\">' +\n                            '</maas-obj-field>');\n                      }\n                  });\n                  html += '</maas-obj-field-group>';\n                  childScope = scope.$new();\n                  var ele = angular.element(html);\n                  fieldsElement.append(ele);\n                  $compile(ele)(\n                      childScope, undefined, {maasObjForm: controller});\n                }\n            };\n\n            // Return the selected type.\n            var getType = function() {\n                if(scope.hideType) {\n                    return controller.obj.type;\n                } else {\n                    return controller.getValue('type');\n                }\n            };\n\n            // Update the fields when the type changes.\n            scope.$watch(getType, updateFields);\n\n            // Update the pod types when the power types is updated.\n            scope.$watchCollection(\"powerTypes\", function() {\n                scope.podTypes.length = 0;\n                angular.forEach(scope.powerTypes, function(type) {\n                    if(type.driver_type === \"pod\") {\n                        scope.podTypes.push(type);\n                    }\n                });\n                updateFields(getType());\n            });\n\n            // Load the general manager.\n            ManagerHelperService.loadManager(scope, GeneralManager);\n        }\n    };\n}]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Power parameters directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the power-parameters.html into the template cache.\n    $templateCache.put('directive/templates/power-parameters.html', [\n        '<div class=\"p-form__group\">',\n            '<label for=\"power-type\" ',\n                    'class=\"form__group-label col-2\">Power type</label>',\n            '<div class=\"form__group-input col-3\">',\n                '<select name=\"power-type\" id=\"power-type\" ',\n                    'data-ng-disabled=\"ngDisabled\" ',\n                    'data-ng-class=\"{ invalid: !ngModel.type }\" ',\n                    'data-ng-model=\"ngModel.type\" ',\n                    'data-ng-options=\"',\n                    'type as type.description ',\n                    'for type in maasPowerParameters track by type.name\">',\n                    '<option value=\"\" disabled selected>',\n                        'Select your power type',\n                    '</option>',\n                '</select>',\n            '</div>',\n        '</div>',\n        '<div class=\"p-form__group\" ',\n            'data-ng-repeat=\"field in ngModel.type.fields\">',\n            '<label for=\"{$ field.name $}\" class=\"form__group-label col-2\">',\n                '{$ field.label $}',\n            '</label>',\n            '<div class=\"form__group-input col-3\">',\n                '<maas-power-input field=\"field\" ',\n                    'data-ng-disabled=\"ngDisabled\" ',\n                    'data-ng-model=\"ngModel.parameters[field.name]\">',\n            '</div>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasPowerInput', ['$compile',\n    function($compile) {\n        return {\n            restrict: \"E\",\n            require: \"ngModel\",\n            scope: {\n                field: '=',\n                ngModel: '='\n            },\n            link: function(scope, element, attrs) {\n                var type = scope.field.field_type;\n                var req = scope.field.required ? 'required=\"required\" ' : '';\n                var html = \"\";\n                if(type === \"string\" || type === \"mac_address\" ||\n                   type === \"password\") {\n                    // Build an input element with the correct attributes.\n                    var input_type = 'type=\"text\"';\n                    if(type === \"password\") {\n                        // If the input field is a password field, display it\n                        // as text or password depending on if we're editing\n                        // the fields.\n                        input_type = \"data-ng-type=\\\"ngModel.editing && \" +\n                            \"'text' || 'password'\\\"\";\n                    }\n                    html =\n                        '<input ' + input_type + ' ' +\n                        'name=\"' + scope.field.name + '\" ' +\n                        req + 'data-ng-model=\"' + attrs.ngModel + '\" ' +\n                        'data-ng-disabled=\"' + attrs.ngDisabled + '\" ';\n\n                    // Add mac address validation.\n                    if(type === \"mac_address\") {\n                        html +=\n                            'data-ng-pattern=\"' +\n                            '/^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$/\"';\n                    }\n                    html += '>';\n\n                    // Set the default value for the input on the model.\n                    if(angular.isUndefined(scope.ngModel)) {\n                        scope.ngModel = scope.field[\"default\"];\n                    }\n                } else if(type === \"choice\") {\n                    // Build a select element with the correct attributes.\n                    html =\n                        '<select name=\"' + scope.field.name + '\"' +\n                        req + 'data-ng-model=\"' + attrs.ngModel + '\" ' +\n                        'data-ng-disabled=\"' + attrs.ngDisabled + '\" ' +\n                        'data-ng-options=\"' +\n                        'choice[0] as choice[1] for choice in field.choices' +\n                        '\">';\n                    html += '</select>';\n\n                    // Set the default choice on the model.\n                    if(angular.isUndefined(scope.ngModel)) {\n                        var i;\n                        for(i = 0; i < scope.field.choices.length; i++) {\n                            var choice = scope.field.choices[i];\n                            if(scope.field[\"default\"] === choice[0]) {\n                                scope.ngModel = choice;\n                                break;\n                            }\n                        }\n                    }\n                } else {\n                    throw new Error(\"Unknown power_type: \"+ type);\n                }\n\n                // Replace the element with the compiled html using the parents\n                // scope. The parent scope is used because we want to build the\n                // element as if it was in the parent scope, not the scope that\n                // is defined in this directive.\n                element.replaceWith($compile(html)(scope.$parent));\n            }\n        };\n    }]);\n\nangular.module('MAAS').directive('maasPowerParameters', function() {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            maasPowerParameters: '=',\n            ngModel: '=',\n            ngDisabled: '='\n        },\n        templateUrl: 'directive/templates/power-parameters.html'\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Proxy settings directive.\n*/\n\nangular.module('MAAS').directive('maasProxySettings', [\n    '$sce', 'ConfigsManager', 'ManagerHelperService', 'JSONService',\n    function($sce, ConfigsManager, ManagerHelperService, JSONService) {\n        return {\n            restrict: \"E\",\n            scope: {},\n            templateUrl: 'static/partials/proxy-settings.html',\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                ManagerHelperService.loadManager(\n                    $scope, ConfigsManager).then(function() {\n                    $scope.loading = false;\n                    $scope.httpProxy = ConfigsManager.getItemFromList(\n                        \"http_proxy\");\n                    $scope.enableHttpProxy = ConfigsManager.getItemFromList(\n                        \"enable_http_proxy\");\n                    $scope.usePeerProxy = ConfigsManager.getItemFromList(\n                        \"use_peer_proxy\");\n                    if ($scope.enableHttpProxy.value) {\n                        if ($scope.httpProxy.value) {\n                            if ($scope.usePeerProxy.value) {\n                                $scope.proxy_type = \"peer-proxy\";\n                            } else {\n                                $scope.proxy_type = \"external-proxy\";\n                            }\n                        } else {\n                            $scope.proxy_type = \"builtin-proxy\";\n                        }\n                    } else {\n                        $scope.proxy_type = \"no-proxy\";\n                    }\n                });\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Release name.\n *\n * Converts the provided release name into the release title.\n */\n\n\nangular.module('MAAS').directive('maasReleaseName', [\n    'GeneralManager', 'ManagerHelperService',\n    function(GeneralManager, ManagerHelperService) {\n    return {\n        restrict: \"A\",\n        scope: {\n          releaseName: \"=maasReleaseName\"\n        },\n        link: function(scope, element, attrs) {\n            scope.osinfo = GeneralManager.getData(\"osinfo\");\n\n            // Gets the release name.\n            var getName = function() {\n                if(angular.isArray(scope.osinfo.releases)) {\n                  for(i = 0; i < scope.osinfo.releases.length; i++) {\n                      var release = scope.osinfo.releases[i];\n                      if(release[0] === scope.releaseName) {\n                          return release[1];\n                      }\n                  }\n                }\n                return scope.releaseName;\n            };\n\n            // Sets the text inside the element.\n            var setText = function() {\n                element.text(getName());\n            };\n\n            // Update the text when the release name or osinfo changes.\n            scope.$watch('releaseName', function() {\n              setText();\n            });\n            scope.$watchCollection('osinfo.releases', function() {\n              setText();\n            });\n\n            // Load the manager and start polling.\n            ManagerHelperService.loadManager(scope, GeneralManager).then(\n                function() {\n                    GeneralManager.startPolling(scope, 'osinfo');\n                });\n\n            // Stop polling when the scope is destroyed.\n            scope.$on('$destroy', function() {\n              GeneralManager.stopPolling(scope, 'osinfo');\n            });\n        }\n    };\n}]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Release options directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the release-options.html into the template cache.\n    $templateCache.put('directive/templates/release-options.html', [\n        '<div class=\"form__group u-margin--right u-margin--top-tiny\">',\n            '<input class=\"checkbox margin-right\" id=\"diskErase\" ',\n                'type=\"checkbox\" data-ng-model=\"maasReleaseOptions.erase\" ',\n                'data-ng-disabled=\"globalOptions.erase\" ',\n                'data-ng-change=\"onEraseChange()\">',\n            '<label class=\"checkbox-label\" for=\"diskErase\">',\n                'Erase disks before releasing',\n            '</label>',\n        '</div>',\n        '<div class=\"form__group u-margin--right u-margin--top-tiny\">',\n            '<input class=\"checkbox margin-right\" id=\"secureErase\" ',\n                'type=\"checkbox\" ',\n                'data-ng-model=\"maasReleaseOptions.secureErase\" ',\n                'data-ng-disabled=\"!maasReleaseOptions.erase\">',\n            '<label class=\"checkbox-label\" for=\"secureErase\">',\n                'Use secure erase',\n            '</label>',\n        '</div>',\n        '<div class=\"form__group u-margin--top-tiny\">',\n            '<input class=\"checkbox\" id=\"quickErase\" type=\"checkbox\" ',\n                'data-ng-model=\"maasReleaseOptions.quickErase\" ',\n                'data-ng-disabled=\"!maasReleaseOptions.erase\">',\n            '<label class=\"checkbox-label\" for=\"quickErase\">',\n                'Use quick erase (not secure)',\n            '</label>',\n        '</div>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasReleaseOptions', [\n    'GeneralManager', function(GeneralManager) {\n        return {\n            restrict: \"A\",\n            scope: {\n                maasReleaseOptions: '='\n            },\n            templateUrl: 'directive/templates/release-options.html',\n            link: function(scope, element, attrs) {\n                // On click of enabling erasing set the others to the\n                // global default value.\n                scope.onEraseChange = function() {\n                    if(scope.maasReleaseOptions.erase) {\n                        scope.maasReleaseOptions.secureErase = (\n                            scope.globalOptions.secure_erase);\n                        scope.maasReleaseOptions.quickErase = (\n                            scope.globalOptions.quick_erase);\n                    } else {\n                        scope.maasReleaseOptions.secureErase = false;\n                        scope.maasReleaseOptions.quickErase = false;\n                    }\n                };\n\n                // Watch the global options. Once set update the defaults\n                // of maasReleaseOptions.\n                scope.globalOptions = GeneralManager.getData(\n                    \"release_options\");\n                scope.$watch('globalOptions', function() {\n                    if(angular.isDefined(scope.globalOptions.erase)) {\n                        // Set the initial defauls for the release options.\n                        scope.maasReleaseOptions.erase = (\n                            scope.globalOptions.erase);\n                        scope.onEraseChange();\n                    }\n                }, true);\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n* GNU Affero General Public License version 3 (see the file LICENSE).\n*\n* Script results listing directive.\n*\n*/\n\nangular.module('MAAS').directive('maasScriptResultsList', function() {\n    return {\n        templateUrl: (\n        'static/partials/script-results-list.html?v=' + (\n            MAAS_config.files_version))\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Script runtime counter directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the script_runtime.html into the template cache.\n    $templateCache.put('directive/templates/script_runtime.html', [\n        '<span data-ng-if=\"(scriptStatus === 1 || scriptStatus === 7) &&',\n        \" estimatedRunTime !== 'Unknown'\" + '\">{{counter}} of ',\n        '~{{estimatedRunTime}}</span>',\n        '<span data-ng-if=\"(scriptStatus === 1 || scriptStatus === 7) &&',\n        \" estimatedRunTime == 'Unknown'\" + '\">{{counter}}</span>',\n        '<span data-ng-if=\"scriptStatus === 0 && estimatedRunTime !== ',\n        \"'Unknown'\" + '\">~{{estimatedRunTime}}</span>',\n        '<span data-ng-if=\"scriptStatus !== 0 && scriptStatus !== 1 ',\n        '&& scriptStatus !== 7\">{{runTime}}</span>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasScriptRunTime', function() {\n    return {\n        restrict: \"A\",\n        require: [\"startTime\", \"runTime\", \"estimatedRunTime\", \"scriptStatus\"],\n        scope: {\n            startTime: '=',\n            runTime: '@',\n            estimatedRunTime: '@',\n            scriptStatus: '='\n        },\n        templateUrl: 'directive/templates/script_runtime.html',\n        controller: function($scope, $interval) {\n            $scope.counter = \"0:00:00\";\n\n            function incrementCounter() {\n                if(($scope.scriptStatus === 1 || $scope.scriptStatus === 7) &&\n                    $scope.startTime) {\n                    var start_date = new Date(null);\n                    start_date.setSeconds($scope.startTime);\n                    var seconds = Math.floor((Date.now() - start_date) / 1000);\n                    var minutes = Math.floor(seconds / 60);\n                    var hours = Math.floor(minutes / 60);\n                    var days = Math.floor(hours / 24);\n                    hours = hours - (days * 24);\n                    minutes = minutes - (days * 24 * 60) - (hours * 60);\n                    seconds = seconds - (days * 24 * 60 * 60) -\n                        (hours * 60 * 60) - (minutes * 60);\n                    var new_counter = \"\";\n                    // This outputs the same format used by Python. It is\n                    // import to use the same format as when scripts are not\n                    // running runtime is taken from the region using Python's\n                    // format.\n                    if(days === 1) {\n                        new_counter = days + \" day, \";\n                    }else if(days > 1) {\n                        new_counter = days + \" days, \";\n                    }\n                    new_counter += hours + \":\";\n                    if(minutes < 10) {\n                        new_counter += \"0\" + minutes + \":\";\n                    } else {\n                        new_counter += minutes + \":\";\n                    }\n                    if(seconds < 10) {\n                        new_counter += \"0\" + seconds;\n                    } else {\n                        new_counter += seconds;\n                    }\n                    $scope.counter = new_counter;\n                }\n            }\n\n            // Update the counter on init, start the interval and stop it when\n            // the directive is destroyed.\n            incrementCounter();\n            var promise = $interval(incrementCounter, 1000);\n            $scope.$on('$destroy', function() {\n              $interval.cancel(promise);\n            });\n        }\n    };\n});\n","/* Copyright 2017-2018 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Script select directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the script-select.html into the template cache.\n    $templateCache.put('directive/templates/script-select.html', [\n        '<tags-input data-ng-model=\"ngModel\" placeholder=\"Select scripts\" ',\n                'key-property=\"id\" display-property=\"name\" min-length=1',\n                'on-tag-adding=\"onTagAdding($tag)\" spellcheck=\"false\"',\n                'add-from-autocomplete-only=\"true\" on-tag-removed=\"refocus()\"',\n                'on-tag-adding=\"onTagAdding($tag)\" on-tag-added=\"refocus()\">',\n            '<auto-complete source=\"getScripts($query)\" min-length=\"0\" ',\n                    'load-on-down-arrow=\"true\" load-on-focus=\"true\" ',\n                    'load-on-empty=\"true\" template=\"script-template\" ',\n                    'max-results-to-show=\"1000\">',\n            '</auto-complete>',\n        '</tags-input>',\n        '<script type=\"text/ng-template\" id=\"script-template\">',\n            '<div>',\n                '<p>',\n                    '{{data.name}} {{data.tags_string}}',\n                '</p>',\n                '<span class=\"p-form-help-text\">',\n                    '{{data.description}}',\n                '</span>',\n            '</div>',\n        '</script>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive(\n        'maasScriptSelect',\n        ['$q', 'ScriptsManager', 'ManagerHelperService',\n        function($q, ScriptsManager, ManagerHelperService) {\n    return {\n        restrict: \"A\",\n        require: \"ngModel\",\n        scope: {\n            ngModel: '=',\n            scriptType: '='\n        },\n        templateUrl: 'directive/templates/script-select.html',\n        link: function($scope, element, attrs, ngModelCtrl) {\n\n            $scope.allScripts = ScriptsManager.getItems();\n            $scope.scripts = [];\n            $scope.getScripts = function(query) {\n                $scope.scripts.length = 0;\n                angular.forEach($scope.allScripts, function(script) {\n                    if(script.script_type === $scope.scriptType &&\n                            script.name.indexOf(query) >= 0) {\n                        script.tags_string = '';\n                        angular.forEach(script.tags, function (tag) {\n                            if(script.tags_string === '') {\n                                script.tags_string = '(' + tag;\n                            } else {\n                                script.tags_string += ', ' + tag;\n                            }\n                        });\n                        if(script.tags_string !== '') {\n                            script.tags_string += ')';\n                        }\n                        $scope.scripts.push(script);\n                    }\n                });\n                return {\n                    data: $scope.scripts\n                };\n            };\n            $scope.onTagAdding = function(tag) {\n                return tag.id !== undefined;\n            };\n\n            $scope.refocus = function() {\n                var tagsInput = element.find('tags-input');\n                var tagsInputScope = tagsInput.isolateScope();\n                tagsInputScope.eventHandlers.input.change('');\n                tagsInputScope.eventHandlers.input.focus();\n                tagsInput.find('input').focus();\n            };\n\n            if(!angular.isArray($scope.ngModel)) {\n                $scope.ngModel = [];\n            }\n            ManagerHelperService.loadManager($scope, ScriptsManager).then(\n                function() {\n                    $scope.ngModel.length = 0;\n                    angular.forEach($scope.allScripts, function(script) {\n                        if(script.script_type === $scope.scriptType &&\n                           script.for_hardware.length === 0) {\n                            if($scope.scriptType === 0) {\n                                // By default MAAS runs all custom\n                                // commissioning scripts in addition to all\n                                // builtin commissioning scripts.\n                                $scope.ngModel.push(script);\n                            } else if($scope.scriptType === 2 &&\n                                    script.tags.indexOf('commissioning') >= 0) {\n                                // By default MAAS runs testing scripts which\n                                // have been tagged 'commissioning'\n                                $scope.ngModel.push(script);\n                            }\n                        }\n                    });\n                }\n            );\n        }\n    };\n}]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Script status icon select directive.\n */\n\nangular.module('MAAS').run(['$templateCache', function ($templateCache) {\n    // Inject the script_status.html into the template cache.\n    $templateCache.put('directive/templates/script_status.html', [\n        '<span data-ng-class=\"icon\" data-ng-show=\"show\"></span>'\n    ].join(''));\n}]);\n\nangular.module('MAAS').directive('maasScriptStatus', function() {\n    return {\n        restrict: \"A\",\n        require: \"scriptStatus\",\n        scope: {\n            scriptStatus: '='\n        },\n        templateUrl: 'directive/templates/script_status.html',\n        controller: function($scope) {\n            function getIcon() {\n                $scope.show = true;\n                switch($scope.scriptStatus) {\n                    // SCRIPT_STATUS.PENDING\n                    case 0:\n                        $scope.icon = 'p-icon--pending';\n                        break;\n                    // SCRIPT_STATUS.RUNNING\n                    case 1:\n                    // SCRIPT_STATUS.INSTALLING\n                    case 7:\n                        $scope.icon = 'p-icon--running';\n                        break;\n                    // SCRIPT_STATUS.PASSED\n                    case 2:\n                        $scope.icon = 'p-icon--pass';\n                        break;\n                    // SCRIPT_STATUS.FAILED\n                    case 3:\n                    // SCRIPT_STATUS.ABORTED\n                    case 5:\n                    // SCRIPT_STATUS.DEGRADED\n                    case 6:\n                    // SCRIPT_STATUS.FAILED_INSTALLING\n                    case 8:\n                        $scope.icon = 'p-icon--power-error';\n                        break;\n                    // SCRIPT_STATUS.TIMEDOUT\n                    case 4:\n                        $scope.icon = 'p-icon--timed-out';\n                        break;\n                    case -1:\n                        // No scripts have been run.\n                        $scope.show = false;\n                        break;\n                    default:\n                        $scope.icon = 'p-icon--help';\n                        break;\n                }\n            }\n\n            getIcon();\n\n            $scope.$watch(\"scriptStatus\", function() {\n                getIcon();\n            });\n        }\n    };\n});\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * SSH keys directive.\n*/\n\nangular.module('MAAS').directive('maasSshKeys', [\n    '$sce', 'SSHKeysManager', 'ManagerHelperService', 'JSONService',\n    function($sce, SSHKeysManager, ManagerHelperService, JSONService) {\n        return {\n            restrict: \"E\",\n            scope: {},\n            templateUrl: (\n                'static/partials/ssh-keys.html?v=' + (\n                    MAAS_config.files_version)),\n            controller: function($scope, $rootScope, $element, $document) {\n                $scope.loading = true;\n                $scope.keys = SSHKeysManager.getItems();\n                $scope.groupedKeys = [];\n                $scope.add = {\n                    source: 'lp',\n                    authId: '',\n                    key: '',\n                    error: null,\n                    saving: false\n                };\n                $scope.sourceTitles = {\n                    'lp': 'Launchpad',\n                    'gh': 'Github',\n                    'upload': 'Upload'\n                };\n                $scope.openRow = null;\n                $scope.rowMode = null;\n\n                // Expose trustAsHtml on the scope for the view to use.\n                $scope.trustAsHtml = $sce.trustAsHtml;\n\n                // Open a row.\n                $scope.open = function(obj, mode) {\n                    $scope.openRow = obj.id;\n                    $scope.rowMode = mode;\n                };\n\n                // Close the open row.\n                $scope.close = function() {\n                    $scope.openRow = null;\n                };\n\n                // Returns true if the key can be imported.\n                $scope.canImportKeys = function() {\n                    if($scope.add.saving) {\n                        return false;\n                    } else if ($scope.add.source === 'lp' ||\n                        $scope.add.source === 'gh') {\n                        return $scope.add.authId.length > 0;\n                    } else {\n                        return $scope.add.key.length > 0;\n                    }\n                };\n\n                // Called to import the key.\n                $scope.importKeys = function() {\n                    if(!$scope.canImportKeys()) {\n                        return;\n                    }\n                    $scope.add.error = null;\n                    $scope.add.saving = true;\n                    if($scope.add.source === 'lp' ||\n                        $scope.add.source === 'gh') {\n                        SSHKeysManager.importKeys({\n                            'protocol': $scope.add.source,\n                            'auth_id': $scope.add.authId\n                        }).then(function() {\n                            $scope.add.saving = false;\n                            $scope.add.source = 'lp';\n                            $scope.add.authId = '';\n                            $scope.add.key = '';\n                        }, function(error) {\n                            $scope.add.saving = false;\n                            var errorJson = JSONService.tryParse(error);\n                            if(angular.isObject(errorJson)) {\n                                if(angular.isArray(errorJson.__all__)) {\n                                    $scope.add.error = errorJson.__all__[0];\n                                } else {\n                                    $scope.add.error = error;\n                                }\n                            } else {\n                                $scope.add.error = error;\n                            }\n                        });\n                    } else {\n                        SSHKeysManager.createItem({\n                            'key': $scope.add.key\n                        }).then(function() {\n                            $scope.add.saving = false;\n                            $scope.add.source = 'lp';\n                            $scope.add.authId = '';\n                            $scope.add.key = '';\n                        }, function(error) {\n                            $scope.add.saving = false;\n                            var errorJson = JSONService.tryParse(error);\n                            if(angular.isObject(errorJson)) {\n                                if(angular.isArray(errorJson.key)) {\n                                    $scope.add.error = errorJson.key[0];\n                                } else if(angular.isArray(errorJson.__all__)) {\n                                    $scope.add.error = errorJson.__all__[0];\n                                } else {\n                                    $scope.add.error = error;\n                                }\n                            } else {\n                                $scope.add.error = error;\n                            }\n                        });\n                    }\n                };\n\n                // Called to delete the selected group of keys.\n                $scope.confirmDelete = function(obj) {\n                    angular.forEach(obj.keys, function(key) {\n                        SSHKeysManager.deleteItem(key);\n                    });\n                };\n\n                // Updates the groupedKeys that is used to render the table.\n                $scope.$watchCollection(\"keys\", function() {\n                    $scope.groupedKeys = [];\n                    var keyMap = {};\n                    angular.forEach($scope.keys, function(key) {\n                        var groupObj, keysource = key.keysource;\n                        if(angular.isObject(keysource)) {\n                            var keysourceKey = (\n                                keysource.protocol + '/' + keysource.auth_id);\n                            groupObj = keyMap[keysourceKey];\n                            if(angular.isObject(groupObj)) {\n                                groupObj.keys.push(key);\n                            } else {\n                                groupObj = {\n                                    id: keysourceKey,\n                                    source: keysource.protocol,\n                                    authId: keysource.auth_id,\n                                    keys: [key]\n                                };\n                                keyMap[keysourceKey] = groupObj;\n                                $scope.groupedKeys.push(groupObj);\n                            }\n                        } else {\n                            groupObj = {\n                                id: 'upload/' + key.id,\n                                source: 'upload',\n                                authId: '',\n                                keys: [key]\n                            };\n                            $scope.groupedKeys.push(groupObj);\n                        }\n                    });\n                });\n\n                ManagerHelperService.loadManager($scope, SSHKeysManager).then(\n                    function() {\n                        $scope.loading = false;\n                    });\n            }\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n* GNU Affero General Public License version 3 (see the file LICENSE).\n*\n* Switches listing directive.\n*\n* Renders the switches listing.\n*/\n\n\nangular.module('MAAS').directive('maasSwitchesTable', [\n  'SwitchesManager', 'GeneralManager', 'ManagerHelperService',\n  function (SwitchesManager, GeneralManager, ManagerHelperService) {\n    return {\n      restrict: \"E\",\n      scope: {\n        search: \"=\",\n        ngDisabled: \"&\",\n        switchHasError: \"&\",\n        hideCheckboxes: \"=?\",\n        onListingChange: \"&\",\n        onCheckAll: \"&\",\n        onCheck: \"&\"\n      },\n      templateUrl: (\n        'static/partials/switches-table.html?v=' + (\n          MAAS_config.files_version)),\n      link: function(scope, element, attrs) {\n        // Statuses that should show spinner.\n        var SPINNER_STATUSES = [\n          1,   // commissioning\n          9,   // deploying\n          12,  // releasing\n          14,  // disk erasing\n          17,  // entering rescue mode\n          19,  // exiting rescue mode\n          21   // testing\n        ];\n\n        // Scope variables.\n        scope.table = {\n          column: 'fqdn',\n          predicate: 'fqdn',\n          reverse: false,\n          allViewableChecked: false,\n          switches: SwitchesManager.getItems(),\n          filteredSwitches: [],\n          osinfo: GeneralManager.getData(\"osinfo\")\n        };\n\n        // Ensures that the checkbox for select all is the correct value.\n        scope.updateAllChecked = function() {\n          // Not checked when the filtered switches are empty.\n          if(scope.table.filteredSwitches.length === 0) {\n              scope.table.allViewableChecked = false;\n              return;\n          }\n\n          // Loop through all filtered switches and see if all are checked.\n          var i;\n          for(i = 0; i < scope.table.filteredSwitches.length; i++) {\n              if(!scope.table.filteredSwitches[i].$selected) {\n                  scope.table.allViewableChecked = false;\n                  return;\n              }\n          }\n          scope.table.allViewableChecked = true;\n        };\n\n        // Selects and deselects visible switches.\n        scope.toggleCheckAll = function() {\n          if(scope.table.allViewableChecked) {\n            angular.forEach(\n              scope.table.filteredSwitches, function(switch_) {\n                SwitchesManager.unselectItem(switch_.system_id);\n              });\n          } else {\n            angular.forEach(\n              scope.table.filteredSwitches, function(switch_) {\n                SwitchesManager.selectItem(switch_.system_id);\n              });\n          }\n          scope.updateAllChecked();\n          scope.onCheckAll();\n        };\n\n        // Selects and unselects switch.\n        scope.toggleChecked = function(switch_) {\n          if(SwitchesManager.isSelected(switch_.system_id)) {\n            SwitchesManager.unselectItem(switch_.system_id);\n          } else {\n            SwitchesManager.selectItem(switch_.system_id);\n          }\n          scope.updateAllChecked();\n          scope.onCheck({$switch_: switch_});\n        };\n\n        // Sorts the table by predicate.\n        scope.sortTable = function(predicate) {\n            scope.table.predicate = predicate;\n            scope.table.reverse = !scope.table.reverse;\n        };\n\n        // Sets the viewable column or sorts.\n        scope.selectColumnOrSort = function(predicate) {\n            if(scope.table.column !== predicate) {\n                scope.table.column = predicate;\n            } else {\n                scope.sortTable(predicate);\n            }\n        };\n\n        // Return true if spinner should be shown.\n        scope.showSpinner = function(switch_) {\n          return SPINNER_STATUSES.indexOf(switch_.status_code) > -1;\n        };\n\n        // Returns the release title from osinfo.\n        scope.getReleaseTitle = function(os_release) {\n          if(angular.isArray(scope.table.osinfo.releases)) {\n            for(i = 0; i < scope.table.osinfo.releases.length; i++) {\n              var release = scope.table.osinfo.releases[i];\n              if(release[0] === os_release) {\n                return release[1];\n              }\n            }\n          }\n          return os_release;\n        };\n\n        // Returns the status text to show.\n        scope.getStatusText = function(switch_) {\n          var showRelease = ['Deploying', 'Deployed'];\n          if(showRelease.indexOf(switch_.status) === -1) {\n            return switch_.status;\n          } else {\n            var releaseTitle = scope.getReleaseTitle(\n              switch_.osystem + '/' + switch_.distro_series);\n            if(switch_.osystem === \"ubuntu\") {\n              releaseTitle = releaseTitle.split('\"')[0].trim();\n            }\n            if(switch_.status === \"Deployed\") {\n              return releaseTitle;\n            }\n            if(switch_.status === \"Deploying\") {\n              return switch_.status + ' ' + releaseTitle;\n            }\n          }\n        };\n\n        // When the list of filtered switches change update the all checkbox.\n        scope.$watchCollection(\"table.filteredSwitches\", function() {\n          scope.updateAllChecked();\n          scope.onListingChange({$switches: scope.table.filteredSwitches});\n        });\n\n        // Load the required managers and start polling for osinfo.\n        ManagerHelperService.loadManagers(\n          scope, [SwitchesManager, GeneralManager]).then(function() {\n            GeneralManager.startPolling(scope, \"osinfo\");\n          });\n\n        // Stop polling when the scope is destroyed.\n        scope.$on(\"$destroy\", function() {\n          GeneralManager.stopPolling(scope, \"osinfo\");\n        });\n      }\n    };\n}]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Toggle control.\n */\n\nangular.module('MAAS').directive('toggleCtrl',[\n    '$document',\n    function($document) {\n        return {\n            restrict: 'A',\n            link: function($scope, $element, $attr){\n\n                $scope.isToggled = false;\n                $scope.toggleMenu = function() {\n                  $scope.isToggled = !$scope.isToggled;\n                };\n\n                var clickHandler = function(event) {\n                    if ($element.find(event.target).length > 0) {\n                        return;\n                    }\n                    $scope.$apply(function() {\n                        $scope.isToggled = false;\n                    });\n                };\n\n                $document.on('click', clickHandler);\n                $scope.$on('$destroy', function() {\n                    $document.off('click', clickHandler);\n                });\n            }\n        };\n}]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Type directive.\n */\n\nangular.module('MAAS').directive('ngType', function() {\n    return {\n        restrict: \"A\",\n        scope: {\n            ngType: \"=\"\n        },\n        link: function(scope, element, attrs) {\n            scope.$watch('ngType', function() {\n                valid_types = [\n                    'button',\n                    'checkbox',\n                    'color',\n                    'date ',\n                    'datetime ',\n                    'datetime-local ',\n                    'email ',\n                    'file',\n                    'hidden',\n                    'image',\n                    'month ',\n                    'number ',\n                    'password',\n                    'radio',\n                    'range ',\n                    'reset',\n                    'search',\n                    'submit',\n                    'tel',\n                    'text',\n                    'time ',\n                    'url',\n                    'week'\n                ];\n                if(valid_types.indexOf(scope.ngType) !== -1) {\n                    element[0].type = scope.ngType;\n                }\n                else {\n                    throw new Error(\"Invalid input type: \" + scope.ngType);\n                }\n\n            });\n        }\n    };\n});","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Version reloader.\n *\n * Watches the version reported by the GeneralManager if it changes then\n * the entire page is reloaded by-passing the local browser cache.\n */\n\n\nangular.module('MAAS').directive('maasVersionReloader', [\n    '$window', 'GeneralManager', 'ManagerHelperService', 'LogService',\n    function($window, GeneralManager, ManagerHelperService, LogService) {\n        return {\n            restrict: \"A\",\n            controller: function($scope) {\n                $scope.version = GeneralManager.getData(\"version\");\n\n                // Reload the page by-passing the browser cache.\n                $scope.reloadPage = function() {\n                    // Force cache reload by passing true.\n                    $window.location.reload(true);\n                };\n\n                ManagerHelperService.loadManager($scope, GeneralManager).then(\n                    function() {\n                        GeneralManager.enableAutoReload(true);\n                        LogService.info(\n                            'Version reloader: Monitoring MAAS \"' +\n                            $scope.site + '\"; version', $scope.version.text,\n                            \"via\", $window.location.href);\n                        $scope.$watch(\"version.text\",\n                            function(newValue, oldValue) {\n                                if(newValue !== oldValue) {\n                                    LogService.info(\n                                        \"MAAS version changed from '\" +\n                                        oldValue + \"' to '\" + newValue +\n                                        \"'; forcing reload.\");\n                                    $scope.reloadPage();\n                                }\n                            });\n                    });\n            }\n        };\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Window Width.\n *\n * Watches the window width and calculates what the inner width of the window.\n * Applying the attribute window-wdith on the parent element and calling\n * data-ng-if=\"width > 768\" you can use this to hide / show elements for mobile\n * development.\n *\n */\n\n\nangular.module('MAAS').directive('windowWidth', [\n    '$window',\n    function ($window) {\n        return {\n            restrict: 'A',\n            link: function($scope, element, attrs){\n                $scope.windowWidth = $window.innerWidth;\n                function onResize(){\n                    // uncomment for only fire when $window.innerWidth change\n                    if ($scope.windowWidth !== $window.innerWidth) {\n                        $scope.windowWidth = $window.innerWidth;\n                        $scope.$apply(function () {\n                            $scope.message = \"Timeout called!\";\n                        });\n                    }\n                }\n\n                function cleanUp() {\n                    angular.element($window).off('resize', onResize);\n                }\n\n                angular.element($window).on('resize', onResize);\n                $scope.$on('$destroy', cleanUp);\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS BootResource Manager\n *\n * Manager for the boot resources. This manager is unique from all the other\n * managers because it uses polling instead of having the region push the\n * information.\n *\n * Why is it polling?\n * The boot resource information is split between the region controller and\n * all rack controllers. The region controller does not cache any information\n * about a rack controllers images it contacts the rack as its source of truth.\n * This means that the client needs to use polling so the region controller\n * can ask each rack controller what is the status of your images.\n */\n\nangular.module('MAAS').factory(\n    'BootResourcesManager',\n    ['$q', '$timeout', 'RegionConnection', 'ErrorService',\n    function($q, $timeout, RegionConnection, ErrorService) {\n\n        // Constructor\n        function BootResourcesManager() {\n            // Set true once been loaded the first time.\n            this._loaded = false;\n\n            // Holds the data recieved from polling.\n            this._data = {};\n\n            // Set to true when polling has been enabled.\n            this._polling = false;\n\n            // The next promise for the polling interval.\n            this._nextPromise = null;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data.\n            this._pollTimeout = 10000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when an error occurs.\n            this._pollErrorTimeout = 500;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when the retrieved data is empty.\n            this._pollEmptyTimeout = 3000;\n        }\n\n        // Return the data.\n        BootResourcesManager.prototype.getData = function() {\n            return this._data;\n        };\n\n        // Return true when data has been loaded.\n        BootResourcesManager.prototype.isLoaded = function() {\n            return this._loaded;\n        };\n\n        // Returns true when currently polling.\n        BootResourcesManager.prototype.isPolling = function() {\n            return this._polling;\n        };\n\n        // Starts the polling for data.\n        BootResourcesManager.prototype.startPolling = function() {\n            if(!this._polling) {\n                this._polling = true;\n                return this._poll();\n            } else {\n                return this._nextPromise;\n            }\n        };\n\n        // Stops the polling for data.\n        BootResourcesManager.prototype.stopPolling = function() {\n            this._polling = false;\n            if(angular.isObject(this._nextPromise)) {\n                $timeout.cancel(this._nextPromise);\n                this._nextPromise = null;\n            }\n        };\n\n        // Load the data from the region.\n        BootResourcesManager.prototype._loadData = function(raiseError) {\n            raiseError = raiseError || false;\n            var self = this;\n            return RegionConnection.callMethod(\"bootresource.poll\").then(\n                function(newData) {\n                    angular.copy(angular.fromJson(newData), self._data);\n                    self._loaded = true;\n                    return self._data;\n                }, function(error) {\n                    if(raiseError) {\n                        ErrorService.raiseError(error);\n                    }\n                });\n        };\n\n        // Registers the next polling attempt.\n        BootResourcesManager.prototype._pollAgain = function(timeout) {\n            var self = this;\n            this._nextPromise = $timeout(function() {\n                self._poll();\n            }, timeout);\n            return this._nextPromise;\n        };\n\n        // Polls for the data from the region.\n        BootResourcesManager.prototype._poll = function() {\n            var self = this;\n\n            // Can only poll if connected.\n            if(!RegionConnection.isConnected()) {\n                return this._pollAgain(this._pollErrorTimeout);\n            }\n\n            return this._loadData(false).then(function(newData) {\n                var pollTimeout = self._pollTimeout;\n                if(!angular.isObject(newData) ||\n                    newData.connection_error ||\n                    !angular.isArray(newData.resources) ||\n                    newData.resources.length === 0) {\n                    pollTimeout = self._pollEmptyTimeout;\n                }\n                self._pollAgain(pollTimeout);\n                return newData;\n            }, function(error) {\n                // Don't raise the error, just log it and try again.\n                console.log(error);\n                self._pollAgain(self._pollErrorTimeout);\n            });\n        };\n\n        // Loads the resources. This implemented so the ManagerHelperService\n        // can work on this manager just like all the rest.\n        BootResourcesManager.prototype.loadItems = function() {\n            var defer = $q.defer();\n            this._loadData(true).then(function() {\n                defer.resolve();\n            });\n            return defer.promise;\n        };\n\n        // Does nothing. This implemented so the ManagerHelperService\n        // can work on this manager just like all the rest.\n        BootResourcesManager.prototype.enableAutoReload = function() { };\n\n        // Stop the running image import process.\n        BootResourcesManager.prototype.stopImport = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.stop_import\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Save the ubuntu options and start the import process.\n        BootResourcesManager.prototype.saveUbuntu = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.save_ubuntu\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Save the Ubuntu Core images and start the import process.\n        BootResourcesManager.prototype.saveUbuntuCore = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.save_ubuntu_core\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Save the other images and start the import process.\n        BootResourcesManager.prototype.saveOther = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.save_other\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        // Fetch the releases and arches from the provided source.\n        BootResourcesManager.prototype.fetch = function(source) {\n            return RegionConnection.callMethod(\"bootresource.fetch\", source);\n        };\n\n        // Delete an image.\n        BootResourcesManager.prototype.deleteImage = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"bootresource.delete_image\", params).then(\n                    function(newData) {\n                        angular.copy(angular.fromJson(newData), self._data);\n                        self._loaded = true;\n                        return self._data;\n                    });\n        };\n\n        return new BootResourcesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Configs Manager\n *\n * Manages all of the config values in the browser. This manager is used for\n * the first-user journey and the settings page.\n */\n\n angular.module('MAAS').factory(\n     'ConfigsManager',\n     ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n             $q, $rootScope, RegionConnection, Manager) {\n\n         function ConfigsManager() {\n             Manager.call(this);\n\n             this._pk = \"name\";\n             this._handler = \"config\";\n\n             // Listen for notify events for the config object.\n             var self = this;\n             RegionConnection.registerNotifier(\"config\",\n                 function(action, data) {\n                     self.onNotify(action, data);\n                 });\n         }\n\n         ConfigsManager.prototype = new Manager();\n\n         return new ConfigsManager();\n     }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Controllers Manager\n *\n * Manages all of the controllers in the browser. This manager is used for the\n * controller listing and view pages. The manager is a subclass of\n * NodesManager.\n */\n\nangular.module('MAAS').factory(\n    'ControllersManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', 'ServicesManager',\n            function($q, $rootScope, RegionConnection, NodesManager,\n            ServicesManager) {\n\n        function ControllersManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"controller\";\n\n            // Listen for notify events for the controller object.\n            var self = this;\n            RegionConnection.registerNotifier(\"controller\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n        ControllersManager.prototype = new NodesManager();\n\n        ControllersManager.prototype.getServices = function(controller) {\n            var services = [];\n            angular.forEach(controller.service_ids, function(service_id) {\n                var service = ServicesManager.getItemFromList(service_id);\n                if(angular.isObject(service)) {\n                    services.push(service);\n                }\n            });\n            return services;\n        };\n\n        // Check the boot image import status.\n        ControllersManager.prototype.checkImageStates = function(controllers) {\n            return RegionConnection.callMethod(\n                this._handler + \".check_images\", controllers);\n        };\n\n        return new ControllersManager();\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Devices Manager\n *\n * Manages all of the devices in the browser. This manager is used for the\n * device listing and the device view page. The manager uses the\n * RegionConnection to load the devices, update the devices, and listen for\n * notification events about devices.\n */\n\nangular.module('MAAS').factory(\n    'DevicesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', function(\n            $q, $rootScope, RegionConnection, NodesManager) {\n\n        function DevicesManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"device\";\n            this._metadataAttributes = {\n                \"owner\": null,\n                \"subnets\": null,\n                \"tags\": null,\n                \"zone\": function(device) {\n                    return device.zone.name;\n                }\n            };\n\n            // Listen for notify events for the device object.\n            var self = this;\n            RegionConnection.registerNotifier(\"device\", function(action, data) {\n                self.onNotify(action, data);\n            });\n        }\n\n        DevicesManager.prototype = new NodesManager();\n\n        // Create a device.\n        DevicesManager.prototype.create = function(node) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the device to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"device.create\", node);\n        };\n\n        // Create an interface on device.\n        DevicesManager.prototype.createInterface = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"device.create_interface\", params).then(function(device) {\n                    self._replaceItem(device);\n                    return device;\n                });\n        };\n\n        // Perform the action on the device.\n        DevicesManager.prototype.performAction = function(\n            device, action, extra) {\n\n            if(!angular.isObject(extra)) {\n                extra = {};\n            }\n            return RegionConnection.callMethod(\"device.action\", {\n                \"system_id\": device.system_id,\n                \"action\": action,\n                \"extra\": extra\n                });\n        };\n\n        return new DevicesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS DHCPSnippet Manager\n *\n * Manages all of the DHCPSnippets in the browser. The manager uses the\n * RegionConnection to load the DHCPSnippets, update the DHCPSnippets, and\n * listen for notification events about DHCPSnippets.\n */\n\nangular.module('MAAS').factory(\n    'DHCPSnippetsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function DHCPSnippetsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"dhcpsnippet\";\n\n            // Listen for notify events for the DHCPSnippet object.\n            var self = this;\n            RegionConnection.registerNotifier(\"dhcpsnippet\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        DHCPSnippetsManager.prototype = new Manager();\n\n        // Create the snippet.\n        DHCPSnippetsManager.prototype.create = function(snippet) {\n            return RegionConnection.callMethod(\n                this._handler + \".create\", snippet, true);\n        };\n\n        return new DHCPSnippetsManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Discovery Manager\n *\n * A Discovery is a MAC, IP binding with an optional hostname that MAAS\n * believes it has discovered. It is associated with a particular fabric and\n * VLAN, and is aware of which rack or region interface most recently\n * discovered it.\n *\n * This class manages all of the discoveries in the browser. It uses the\n * RegionConnection to load the discoveries and listen for notification events\n * about discoveries.\n */\n\nangular.module('MAAS').factory(\n    'DiscoveriesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'PollingManager',\n    function($q, $rootScope, RegionConnection, PollingManager) {\n\n        function DiscoveriesManager() {\n            PollingManager.call(this);\n\n            this._pk = \"first_seen\";\n            this._batchKey = \"first_seen\";\n            this._handler = \"discovery\";\n\n            // Poll every 10 seconds when its empty as its okay for\n            // this to be empty.\n            this._pollEmptyTimeout = 5000;\n        }\n\n        DiscoveriesManager.prototype = new PollingManager();\n\n        return new DiscoveriesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Domain Manager\n *\n * Manages all of the domains in the browser. The manager uses the\n * RegionConnection to load the domains, update the domains, and listen for\n * notification events about domains.\n */\n\nangular.module('MAAS').factory(\n    'DomainsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function DomainsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"domain\";\n\n            // Listen for notify events for the domain object.\n            var self = this;\n            RegionConnection.registerNotifier(\"domain\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        DomainsManager.prototype = new Manager();\n\n        // Create a domain.\n        DomainsManager.prototype.create = function(domain) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"domain.create\", domain);\n        };\n\n        // Delete the domain.\n        DomainsManager.prototype.deleteDomain = function(domain) {\n            return RegionConnection.callMethod(\"domain.delete\", domain);\n        };\n\n        DomainsManager.prototype.getDefaultDomain = function() {\n            if(this._items.length === 0) {\n                return null;\n            } else {\n                var i;\n                for(i=0;i<this._items.length;i++) {\n                    if(this._items[i].id === 0) {\n                        return this._items[i];\n                    }\n                }\n            }\n            return this._items[0];\n        };\n\n        DomainsManager.prototype.getDomainByName = function(name) {\n            if(this._items.length > 0) {\n                var i;\n                for(i=0;i<this._items.length;i++) {\n                    if(this._items[i].name === name) {\n                        return this._items[i];\n                    }\n                }\n            }\n            return null;\n        };\n\n        return new DomainsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Event Manager Factory\n *\n * Manages all of the events for a node in the browser. The manager uses the\n * RegionConnection to load the events and listen for event notifications.\n */\n\nangular.module('MAAS').factory(\n    'EventsManagerFactory',\n    ['RegionConnection', 'Manager', 'ErrorService',\n    function(RegionConnection, Manager, ErrorService) {\n\n        function EventsManager(nodeId, factory) {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"event\";\n            this._nodeId = nodeId;\n            this._factory = factory;\n            this._maxDays = 1;\n        }\n\n        EventsManager.prototype = new Manager();\n\n        // Return the initial batch parameters with the id of the node\n        // and the maximum number of days to load.\n        EventsManager.prototype._initBatchLoadParameters = function() {\n            return {\n                \"node_id\": this._nodeId,\n                \"max_days\": this._maxDays\n            };\n        };\n\n        // Destroys its self. Removes self from the EventsManagerFactory.\n        EventsManager.prototype.destroy = function(){\n            this._factory.destroyManager(this);\n\n            // If this manager has ever loaded then the region is sending\n            // events about this node. Tell the RegionConnection not to\n            // stop sending notification for events from this node.\n            if(this.isLoaded()) {\n                RegionConnection.callMethod(\"event.clear\", {\n                    node_id: this._nodeId\n                });\n            }\n        };\n\n        // Get the maximum number of days the manager will load.\n        EventsManager.prototype.getMaximumDays = function() {\n            return this._maxDays;\n        };\n\n        // Changes the maximum number of days to load and loads the items.\n        EventsManager.prototype.loadMaximumDays = function(days) {\n            var self = this;\n            var setMaximumDays = function() {\n                self._maxDays = days;\n                self.loadItems();\n            };\n\n            if(this.isLoading()) {\n                // Call loadItems to get an extra defer to know when\n                // the loading is done.\n                this.loadItems().then(function() {\n                    setMaximumDays();\n                });\n            } else {\n                setMaximumDays();\n            }\n        };\n\n        // Factory that holds all created EventsManagers.\n        function EventsManagerFactory() {\n            // Holds a list of all EventsManager that have been created.\n            this._managers = [];\n\n            // Listen for notify events for the event object.\n            var self = this;\n            RegionConnection.registerNotifier(\"event\", function(action, data) {\n                self.onNotify(action, data);\n            });\n        }\n\n        // Gets the EventManager for the nodes with node_id.\n        EventsManagerFactory.prototype._getManager = function(nodeId) {\n            var i;\n            for(i = 0; i < this._managers.length; i++) {\n                if(this._managers[i]._nodeId === nodeId) {\n                    return this._managers[i];\n                }\n            }\n            return null;\n        };\n\n        // Gets the EventManager for the nodes node_id. Creates a new manager\n        // if one does not exist.\n        EventsManagerFactory.prototype.getManager = function(nodeId) {\n            var manager = this._getManager(nodeId);\n            if(!angular.isObject(manager)) {\n                // Not created so create it.\n                manager = new EventsManager(nodeId, this);\n                this._managers.push(manager);\n                return manager;\n            }\n            return manager;\n        };\n\n        // Destroy the EventManager.\n        EventsManagerFactory.prototype.destroyManager = function(manager) {\n            var idx = this._managers.indexOf(manager);\n            if(idx >= 0) {\n                this._managers.splice(idx, 1);\n            }\n        };\n\n        // Called when the RegionConnection gets a notification for an event.\n        EventsManagerFactory.prototype.onNotify = function(action, data) {\n            if(action === \"delete\") {\n                // Send all delete actions to all managers. Only one will\n                // remove the event with the given id.\n                angular.forEach(this._managers, function(manager) {\n                    manager.onNotify(action, data);\n                });\n            } else if (action === \"create\" || action === \"update\") {\n                // Get the manager based on the node_id in data, and send\n                // it the notification.\n                var manager = this._getManager(data.node_id);\n                if(angular.isObject(manager)) {\n                    manager.onNotify(action, data);\n                }\n            }\n        };\n\n        return new EventsManagerFactory();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Fabric Manager\n *\n * Manages all of the fabrics in the browser. The manager uses the\n * RegionConnection to load the fabrics, update the fabrics, and listen for\n * notification events about fabrics.\n */\n\nangular.module('MAAS').factory(\n    'FabricsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', 'VLANsManager',\n    function(\n    $q, $rootScope, RegionConnection, Manager, VLANsManager) {\n\n        function FabricsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"fabric\";\n\n            // Listen for notify events for the fabric object.\n            var self = this;\n            RegionConnection.registerNotifier(\"fabric\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        FabricsManager.prototype = new Manager();\n\n        // Given a Fabric object, returns its display name.\n        FabricsManager.prototype.getName = function(fabric) {\n            if(!angular.isObject(fabric)) {\n                return;\n            }\n            if(angular.isString(fabric.name)) {\n                return fabric.name;\n            } else {\n                return this._handler + \"-\" + fabric[this._pk];\n            }\n        };\n\n        // Delete the Fabric.\n        FabricsManager.prototype.deleteFabric = function(fabric) {\n            return RegionConnection.callMethod(\n                \"fabric.delete\", { \"id\": fabric.id }, true);\n        };\n\n        // Create a Fabric.\n        FabricsManager.prototype.create = function(fabric) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"fabric.create\", fabric);\n        };\n\n\n        return new FabricsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS General Manager\n *\n * Manager for general information from the region. The general handler on the\n * region side does not push information to the client. This manager uses\n * polling to grab this data periodically from the region.\n *\n * This manage provides different pieces of data and is structure differently\n * than extending the Manager service. It still provides the Manager service\n * interface allowing the ManagerHelperService to load this manager.\n */\n\nangular.module('MAAS').factory(\n    'GeneralManager',\n    ['$q', '$timeout', 'RegionConnection', 'ErrorService',\n    function($q, $timeout, RegionConnection, ErrorService) {\n\n        // Constructor\n        function GeneralManager() {\n            // Holds the available endpoints and its data.\n            this._data = {\n                machine_actions: {\n                    method: \"general.machine_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                device_actions: {\n                    method: \"general.device_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                region_controller_actions: {\n                    method: \"general.region_controller_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                rack_controller_actions: {\n                    method: \"general.rack_controller_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                region_and_rack_controller_actions: {\n                    method: \"general.region_and_rack_controller_actions\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                architectures: {\n                    method: \"general.architectures\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                known_architectures: {\n                    method: \"general.known_architectures\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                pockets_to_disable: {\n                    method: \"general.pockets_to_disable\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                components_to_disable: {\n                    method: \"general.components_to_disable\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                hwe_kernels: {\n                    method: \"general.hwe_kernels\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                min_hwe_kernels: {\n                    method: \"general.min_hwe_kernels\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null\n                },\n                default_min_hwe_kernel: {\n                    method: \"general.default_min_hwe_kernel\",\n                    data: { text: '' },\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        oldData.text = newData;\n                    }\n                },\n                osinfo: {\n                    method: \"general.osinfo\",\n                    data: {},\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    isEmpty: function(data) {\n                        var osystems = data.osystems;\n                        return (angular.isUndefined(osystems) ||\n                            osystems.length === 0);\n                    },\n                    replaceData: function(oldData, newData) {\n                        angular.copy(newData, oldData);\n                    }\n                },\n                bond_options: {\n                    method: \"general.bond_options\",\n                    data: {},\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        angular.copy(newData, oldData);\n                    }\n                },\n                version: {\n                    method: \"general.version\",\n                    data: { text: null },\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        oldData.text = newData;\n                    }\n                },\n                power_types: {\n                    method: \"general.power_types\",\n                    data: [],\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        // Add new power types.\n                        var i, j, newPowerType, oldPowerType;\n                        for(i = 0; i < newData.length; i++) {\n                            newPowerType = newData[i];\n                            var newItem = true;\n                            for(j = 0; j < oldData.length; j++) {\n                                oldPowerType = oldData[j];\n                                if(newPowerType.name === oldPowerType.name) {\n                                    newItem = false;\n                                    break;\n                                }\n                            }\n\n                            // Item was previously not in the list so it is\n                            // inserted into the array.\n                            if(newItem) {\n                                oldData.push(newPowerType);\n                            }\n                        }\n\n                        // Remove any power types that are not included in\n                        // the newData.\n                        for(i = oldData.length - 1; i >= 0; i--) {\n                            oldPowerType = oldData[i];\n                            var found = false;\n                            for(j = 0; j < newData.length; j++) {\n                                newPowerType = newData[j];\n                                if(newPowerType.name === oldPowerType.name) {\n                                    found = true;\n                                    break;\n                                }\n                            }\n\n                            // Item was previously not in the list so it is\n                            // inserted into the array.\n                            if(!found) {\n                                oldData.splice(i, 1);\n                            }\n                        }\n                    }\n                },\n                release_options: {\n                    method: \"general.release_options\",\n                    data: {},\n                    loaded: false,\n                    polling: [],\n                    nextPromise: null,\n                    replaceData: function(oldData, newData) {\n                        angular.copy(newData, oldData);\n                    }\n                }\n            };\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data.\n            this._pollTimeout = 10000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when an error occurs.\n            this._pollErrorTimeout = 3000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when the retrieved data is empty.\n            this._pollEmptyTimeout = 3000;\n\n            // Set to true when the items list should reload upon re-connection\n            // to the region.\n            this._autoReload = false;\n\n            // Use the same notify type as a default manager.\n            this._type = 'notify';\n\n            // The scopes that have loaded this manager.\n            this._scopes = [];\n        }\n\n        GeneralManager.prototype._getInternalData = function(name) {\n            var data = this._data[name];\n            if(angular.isUndefined(data)) {\n                throw new Error(\"Unknown data: \" + name);\n            }\n            return data;\n        };\n\n        // Return loaded data.\n        GeneralManager.prototype.getData = function(name) {\n            return this._getInternalData(name).data;\n        };\n\n        // Return true when all data has been loaded.\n        GeneralManager.prototype.isLoaded = function() {\n            var loaded = true;\n            angular.forEach(this._data, function(data) {\n                if(!data.loaded) {\n                    loaded = false;\n                }\n            });\n            return loaded;\n        };\n\n        // Return true when data has been loaded.\n        GeneralManager.prototype.isDataLoaded = function(name) {\n            return this._getInternalData(name).loaded;\n        };\n\n        // Returns true when the manager is currently polling.\n        GeneralManager.prototype.isPolling = function() {\n            var polling = false;\n            angular.forEach(this._data, function(data) {\n                if(data.polling.length > 0) {\n                    polling = true;\n                }\n            });\n            return polling;\n        };\n\n        // Returns true when the manager is currently polling for that data.\n        GeneralManager.prototype.isDataPolling = function(name) {\n            return this._getInternalData(name).polling;\n        };\n\n        // Starts the manager polling for data.\n        GeneralManager.prototype.startPolling = function(scope, name) {\n            var data = this._getInternalData(name);\n            var idx = data.polling.indexOf(scope);\n            if(idx === -1) {\n                data.polling.push(scope);\n                if(data.polling.length === 1) {\n                    // Polling needs to be started. This is the first scope\n                    // that is requesting for polling to be performed.\n                    this._poll(data);\n                }\n            }\n        };\n\n        // Stops the manager polling for data.\n        GeneralManager.prototype.stopPolling = function(scope, name) {\n            var data = this._getInternalData(name);\n            var idx = data.polling.indexOf(scope);\n            if(idx >= 0) {\n                data.polling.splice(idx, 1);\n            }\n            if(data.polling.length === 0 &&\n                angular.isObject(data.nextPromise)) {\n                $timeout.cancel(data.nextPromise);\n                data.nextPromise = null;\n            }\n        };\n\n        // Load the data from the region.\n        GeneralManager.prototype._loadData = function(data, raiseError) {\n            var replaceData = data.replaceData;\n            raiseError = raiseError || false;\n\n            // Set default replaceData function if data doesn't provide its\n            // own function.\n            if(angular.isUndefined(replaceData)) {\n                replaceData = function(oldData, newData) {\n                    oldData.length = 0;\n                    oldData.push.apply(oldData, newData);\n                };\n            }\n\n            return RegionConnection.callMethod(data.method).then(\n                function(newData) {\n                    replaceData(data.data, newData);\n                    data.loaded = true;\n                    return data.data;\n                }, function(error) {\n                    if(raiseError) {\n                        ErrorService.raiseError(error);\n                    }\n                    return error;\n                });\n        };\n\n        GeneralManager.prototype._pollAgain = function(data, timeout) {\n            var self = this;\n            data.nextPromise = $timeout(function() {\n                self._poll(data);\n            }, timeout);\n        };\n\n        // Polls for the data from the region.\n        GeneralManager.prototype._poll = function(data) {\n            var self = this;\n            var isEmpty = data.isEmpty;\n\n            // Set default isEmpty function if data doesn't provide its\n            // own function.\n            if(angular.isUndefined(isEmpty)) {\n                isEmpty = function(data) {\n                    return data.length === 0;\n                };\n            }\n\n            // Can only poll if connected.\n            if(!RegionConnection.isConnected()) {\n                this._pollAgain(data, this._pollErrorTimeout);\n                return;\n            }\n\n            return this._loadData(data, false).then(function(newData) {\n                var pollTimeout = self._pollTimeout;\n                if(isEmpty(data.data)) {\n                    pollTimeout = self._pollEmptyTimeout;\n                }\n                self._pollAgain(data, pollTimeout);\n                return newData;\n            }, function(error) {\n                // Don't raise the error, just log it and try again.\n                console.log(error);\n                self._pollAgain(data, self._pollErrorTimeout);\n            });\n        };\n\n        // Loads all the items. This implemented so the ManagerHelperService\n        // can work on this manager just like all the rest.\n        GeneralManager.prototype.loadItems = function() {\n            var self = this;\n            var defer = $q.defer();\n            var waitingCount = Object.keys(this._data).length;\n            var done = function() {\n                waitingCount -= 1;\n                if(waitingCount === 0) {\n                    defer.resolve();\n                }\n            };\n\n            angular.forEach(this._data, function(data) {\n                self._loadData(data, true).then(function() {\n                    done();\n                });\n            });\n\n            return defer.promise;\n        };\n\n        // Enables auto reloading of the item list on connection to region.\n        GeneralManager.prototype.enableAutoReload = function() {\n            if(!this._autoReload) {\n                this._autoReload = true;\n                var self = this;\n                this._reloadFunc = function() {\n                    self.loadItems();\n                };\n                RegionConnection.registerHandler(\"open\", this._reloadFunc);\n            }\n        };\n\n        // Disable auto reloading of the item list on connection to region.\n        GeneralManager.prototype.disableAutoReload = function() {\n            if(this._autoReload) {\n                RegionConnection.unregisterHandler(\"open\", this._reloadFunc);\n                this._reloadFunc = null;\n                this._autoReload = false;\n            }\n        };\n\n        return new GeneralManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS IPRange Manager\n *\n * Manages all of the IPRanges in the browser. The manager uses the\n * RegionConnection to load the IPRanges, update the IPRanges, and listen for\n * notification events about IPRanges.\n */\n\nangular.module('MAAS').factory(\n    'IPRangesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function IPRangesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"iprange\";\n\n            // Listen for notify events for the iprange object.\n            var self = this;\n            RegionConnection.registerNotifier(\"iprange\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        IPRangesManager.prototype = new Manager();\n\n        return new IPRangesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Machines Manager\n *\n * Manages all of the machines in the browser. This manager is used for the\n * machine listing and view pages. The manager is a subclass of NodesManager.\n */\n\nangular.module('MAAS').factory(\n    'MachinesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', function(\n            $q, $rootScope, RegionConnection, NodesManager) {\n\n        function MachinesManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"machine\";\n\n            this._metadataAttributes = {\n                \"architecture\": null,\n                \"status\": null,\n                \"owner\": null,\n                \"tags\": null,\n                \"pod\": function(machine) {\n                    return (machine.pod === undefined) ? '' :machine.pod.name;\n                },\n                \"zone\": function(machine) {\n                    return machine.zone.name;\n                },\n                \"subnets\": null,\n                \"fabrics\": null,\n                \"spaces\": null,\n                \"storage_tags\": null,\n                \"release\": function(machine) {\n                    if(machine.status_code === 6 || machine.status_code === 9) {\n                        return machine.osystem + \"/\" + machine.distro_series;\n                    } else {\n                        return '';\n                    }\n                }\n            };\n\n            // Listen for notify events for the machine object.\n            var self = this;\n            RegionConnection.registerNotifier(\"machine\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n\n        }\n        MachinesManager.prototype = new NodesManager();\n\n        MachinesManager.prototype.mountSpecialFilesystem =\n            function(machine, fstype, mount_point, mount_options) {\n                var method = this._handler + \".mount_special\";\n                var params = {\n                    system_id: machine.system_id,\n                    fstype: fstype,\n                    mount_point: mount_point,\n                    mount_options: mount_options\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        MachinesManager.prototype.unmountSpecialFilesystem =\n            function(machine, mount_point) {\n                var method = this._handler + \".unmount_special\";\n                var params = {\n                    system_id: machine.system_id,\n                    mount_point: mount_point\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        return new MachinesManager();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS NodeResultsManager Manager\n *\n * Manages all of the NodeResults in the browser. The manager uses the\n * RegionConnection to load the NodeResults, and listen for\n * notification events about NodeResults.\n */\n\nangular.module('MAAS').factory(\n    'NodeResultsManagerFactory', ['RegionConnection', 'Manager',\n    function(RegionConnection, Manager) {\n\n        function NodeResultsManager(node, factory) {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"noderesult\";\n            this._node = node;\n            this._factory = factory;\n\n            // Store as an array to preserve order.\n            this.commissioning_results = [\n                {\n                    title: null,\n                    hardware_type: 0,\n                    results: {}\n                },\n                {\n                    title: \"CPU\",\n                    hardware_type: 1,\n                    results: {}\n                },\n                {\n                    title: \"Memory\",\n                    hardware_type: 2,\n                    results: {}\n                },\n                {\n                    title: \"Storage\",\n                    hardware_type: 3,\n                    results: {}\n                }\n            ];\n            this.testing_results = [\n                {\n                    title: \"CPU\",\n                    hardware_type: 1,\n                    results: {}\n                },\n                {\n                    title: \"Memory\",\n                    hardware_type: 2,\n                    results: {}\n                },\n                {\n                    title: \"Storage\",\n                    hardware_type: 3,\n                    results: {}\n                },\n                {\n                    title: \"Other Results\",\n                    hardware_type: 0,\n                    results: {}\n                }\n            ];\n            this.installation_results = [];\n\n            // Listen for notify events for the ScriptResult object.\n            // This is noderesult instead of scriptresult because the\n            // class name is NodeResultHandler.\n            var self = this;\n            RegionConnection.registerNotifier(\"noderesult\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        NodeResultsManager.prototype = new Manager();\n\n        NodeResultsManager.prototype._getStorageSubtext = function(disk) {\n            var deviceinfo = '';\n            if(disk.model !== '') {\n                deviceinfo += \"Model: \" + disk.model;\n            }\n            if(disk.serial !== '') {\n                if(deviceinfo !== '') {\n                    deviceinfo += ', ';\n                }\n                deviceinfo += \"Serial: \" + disk.serial;\n            }\n            if(deviceinfo !== '') {\n                return '/dev/' + disk.name + ' (' + deviceinfo + ')';\n            }else{\n                return '/dev/' + disk.name;\n            }\n        };\n\n        NodeResultsManager.prototype._updateObject = function(\n            existing, updated) {\n            angular.forEach(updated, function(value, key) {\n                if(existing[key] !== value && key !== 'showing_results' &&\n                   key !== 'showing_history' && key !== 'showing_menu' &&\n                   key !== '$selected') {\n                    existing[key] = value;\n                }\n            });\n        };\n\n        NodeResultsManager.prototype._addOrReplace = function(results, result) {\n            var i;\n            for(i = 0; i < results.length; i++) {\n                if(results[i].name === result.name) {\n                    // Object already exists, update fields.\n                    result.$selected = results[i].$selected;\n                    result.showing_results = results[i].showing_results;\n                    result.showing_history = results[i].showing_history;\n                    result.showing_menu = results[i].showing_menu;\n                    angular.copy(result, results[i]);\n                    return;\n                }\n            }\n            // No result with the same name exists, add it to the sorted list.\n            for(i = 0; i < results.length; i++) {\n                if(results[i].name > result.name) {\n                    results.splice(i, 0, result);\n                    return;\n                }\n            }\n            results.push(result);\n        };\n\n        NodeResultsManager.prototype._processItem = function(result) {\n            var results;\n            result.showing_results = false;\n            result.showing_history = false;\n            result.showing_menu = false;\n            result.result_section = \"scripts\";\n\n            if(result.result_type === 0) {\n                results = this.commissioning_results;\n            } else if(result.result_type === 1) {\n                // Installation results are not split into hardware types or\n                // have subtext labels.\n                this._addOrReplace(this.installation_results, result);\n                return;\n            } else {\n                // Store all remaining result types as test results in case\n                // another result type is ever added.\n                results = this.testing_results;\n                result.result_section = \"tests\";\n            }\n            var i;\n            // Fallback to storing results in other results incase a new type\n            // is added\n            var hardware_type_results = results[3];\n            for(i = 0; i < results.length; i++) {\n                if(results[i].hardware_type === result.hardware_type) {\n                    hardware_type_results = results[i].results;\n                    break;\n                }\n            }\n\n            if(result.hardware_type === 3 &&\n               result.physical_blockdevice !== null) {\n                // Storage results are split into individual components.\n                var disk, subtext;\n                // If the storage result is associated with a specific\n                // component generate subtext for that component.\n                for(i = 0; i < this._node.disks.length; i++) {\n                    disk = this._node.disks[i];\n                    if(disk.id === result.physical_blockdevice) {\n                        subtext = this._getStorageSubtext(disk);\n                        if(!angular.isArray(\n                            hardware_type_results[subtext])) {\n                                hardware_type_results[subtext] = [];\n                        }\n                        this._addOrReplace(\n                            hardware_type_results[subtext], result);\n                        break;\n                    }\n                }\n            } else {\n                // Other hardware types are not split into individual\n                // components.\n                if(!angular.isArray(hardware_type_results[null])) {\n                    hardware_type_results[null] = [];\n                }\n                this._addOrReplace(hardware_type_results[null], result);\n            }\n        };\n\n        NodeResultsManager.prototype._removeItem = function(result) {\n            var idx = this._getIndexOfItem(this._items, result.id);\n            if(idx >= 0) {\n                this._updateMetadata(this._items[idx], \"delete\");\n            }\n            this._removeItemByIdFromArray(this._items, result.id);\n            this._removeItemByIdFromArray(this._selectedItems, result.id);\n\n            var self = this;\n            angular.forEach(this.commissioning_results, function(hw_type) {\n                angular.forEach(hw_type.results, function(results, subtext) {\n                    self._removeItemByIdFromArray(results, result.id);\n                    if(results.length === 0)\n                    {\n                        delete hw_type.results[subtext];\n                    }\n                });\n            });\n            angular.forEach(this.testing_results, function(hw_type) {\n                angular.forEach(hw_type.results, function(results, subtext) {\n                    self._removeItemByIdFromArray(results, result.id);\n                    if(results.length === 0)\n                    {\n                        delete hw_type.results[subtext];\n                    }\n                });\n            });\n            this._removeItemByIdFromArray(this.installation_results, result.id);\n        };\n\n        // Return the list of ScriptResults for the given node when retrieving\n        // the initial list.\n        NodeResultsManager.prototype._initBatchLoadParameters = function() {\n            var ret = {\n                \"system_id\": this._node.system_id\n            };\n            // Limit the results returned to what can be viewed.\n            if(this._area === \"summary\") {\n                ret.has_surfaced = true;\n                ret.result_type = 2;\n            }else if(this._area === \"testing\") {\n                ret.result_type = 2;\n            }else if(this._area === \"commissioning\") {\n                ret.result_type = 0;\n            }else if(this._area === \"logs\") {\n                ret.result_type = 1;\n            }\n            return ret;\n        };\n\n        // Destroys itself. Removes self from the NodeResultsManagerFactory.\n        NodeResultsManager.prototype.destroy = function() {\n            this._factory.destroyManager(this);\n\n            // If this manager has ever loaded then the region is sending\n            // results from this node. Tell the RegionConnection to stop.\n            if(this.isLoaded()) {\n                var method = this._handler + \".clear\";\n                RegionConnection.callMethod(method, {\n                    system_id: this._node.system_id\n                });\n            }\n        };\n\n        // Get result data.\n        NodeResultsManager.prototype.get_result_data = function(\n            script_id, data_type) {\n            var method = this._handler + \".get_result_data\";\n            var params = {\n                id: script_id,\n                data_type: data_type\n            };\n            return RegionConnection.callMethod(method, params);\n        };\n\n        // Factory that holds all created NodeResultsManagers.\n        function NodeResultsManagerFactory() {\n            // Holds a list of all NodeResultsManagers that have been created.\n            this._managers = [];\n        }\n\n        // Gets the NodeResultsManager for the nodes with node_system_id.\n        NodeResultsManagerFactory.prototype._getManager = function(node) {\n            var i;\n            for(i = 0; i < this._managers.length; i++) {\n                if(this._managers[i]._node.system_id === node.system_id) {\n                    return this._managers[i];\n                }\n            }\n            return null;\n        };\n\n        // Gets the NodeResultsManager for the nodes system_id. Creates a new\n        // manager if one does not exist.\n        NodeResultsManagerFactory.prototype.getManager = function(\n            node, area) {\n            var manager = this._getManager(node);\n            if(!angular.isObject(manager)) {\n                // Not created so create it.\n                manager = new NodeResultsManager(node, this);\n                this._managers.push(manager);\n            }\n            manager._area = area;\n            if(area === \"commissioning\") {\n                manager.results = manager.commissioning_results;\n            }else if(area === \"logs\") {\n                manager.results = manager.installation_results;\n            }else{\n                manager.results = manager.testing_results;\n            }\n            return manager;\n        };\n\n        // Destroy the NodeResultsManager.\n        NodeResultsManagerFactory.prototype.destroyManager = function(manager) {\n            var idx = this._managers.indexOf(manager);\n            if(idx >= 0) {\n                this._managers.splice(idx, 1);\n            }\n        };\n\n        return new NodeResultsManagerFactory();\n    }]);\n","/* Copyright 2015-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes Manager\n *\n * Manages all of the nodes in the browser. This manager is used for the\n * machine and controller listing and view pages (as machines and controllers\n * are both Nodes).  The manager uses the RegionConnection to load the nodes,\n * update the nodes, and listen for notification events about nodes.\n */\n\nangular.module('MAAS').service(\n    'NodesManager',\n    ['$q', '$rootScope', '$timeout', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, $timeout, RegionConnection, Manager) {\n\n        function NodesManager() {\n            Manager.call(this);\n        }\n\n        NodesManager.prototype = new Manager();\n\n        // Create a node.\n        NodesManager.prototype.create = function(node) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the node to the list. Adding it here will cause angular\n            // to complain because the same object exist in the list.\n            return RegionConnection.callMethod(\n                this._handler + \".create\", node);\n        };\n\n        // Perform the action on the node.\n        NodesManager.prototype.performAction = function(\n            node, action, extra) {\n            if(!angular.isObject(extra)) {\n                extra = {};\n            }\n            return RegionConnection.callMethod(this._handler + \".action\", {\n                \"system_id\": node.system_id,\n                \"action\": action,\n                \"extra\": extra\n                });\n        };\n\n        // Check the power state for the node.\n        NodesManager.prototype.checkPowerState = function(node) {\n            return RegionConnection.callMethod(this._handler + \".check_power\", {\n                \"system_id\": node.system_id\n                }).then(function(state) {\n                    node.power_state = state;\n                    return state;\n                }, function(error) {\n                    node.power_state = \"error\";\n\n                    // Already been logged server side, but log it client\n                    // side so if they really care they can see why.\n                    console.log(error);\n\n                    // Return the state as error to the remaining callbacks.\n                    return \"error\";\n                });\n        };\n\n        // Create the physical interface on the node.\n        NodesManager.prototype.createPhysicalInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_physical\", params);\n            };\n\n        // Create the VLAN interface on the node.\n        NodesManager.prototype.createVLANInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_vlan\", params);\n            };\n\n        // Create the bond interface on the node.\n        NodesManager.prototype.createBondInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_bond\", params);\n            };\n\n        // Create the bridge interface on the node.\n        NodesManager.prototype.createBridgeInterface = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_bridge\", params);\n            };\n\n        // Update the interface for the node.\n        NodesManager.prototype.updateInterface = function(\n            node, interface_id, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                params.interface_id = interface_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".update_interface\", params);\n            };\n\n        // Update an interface from a maas-obj-form.\n        NodesManager.prototype.updateInterfaceForm = function(\n            params) {\n                return RegionConnection.callMethod(\n                    this._handler + \".update_interface\", params);\n            };\n\n        // Delete the interface for the node.\n        NodesManager.prototype.deleteInterface = function(\n            node, interface_id) {\n                var params = {\n                    system_id: node.system_id,\n                    interface_id: interface_id\n                };\n                return RegionConnection.callMethod(\n                    this._handler + \".delete_interface\", params);\n            };\n\n        // Create or update the link to the subnet for the interface.\n        NodesManager.prototype.linkSubnet = function(\n            node, interface_id, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                params.interface_id = interface_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".link_subnet\", params);\n            };\n\n        // Remove the link to the subnet for the interface.\n        NodesManager.prototype.unlinkSubnet = function(\n            node, interface_id, link_id) {\n                var params = {\n                    system_id: node.system_id,\n                    interface_id: interface_id,\n                    link_id: link_id\n                };\n                return RegionConnection.callMethod(\n                    this._handler + \".unlink_subnet\", params);\n            };\n\n        // Send the update information to the region.\n        NodesManager.prototype.updateFilesystem = function(\n            node, block_id, partition_id, fstype, mount_point, mount_options,\n            tags) {\n                var self = this;\n                var method = this._handler + \".update_filesystem\";\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id,\n                    partition_id: partition_id,\n                    fstype: fstype,\n                    mount_point: mount_point,\n                    mount_options: mount_options,\n                    tags: tags\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete the disk.\n        NodesManager.prototype.deleteDisk = function(\n            node, block_id) {\n                var self = this;\n                var method = this._handler + \".delete_disk\";\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete the partition.\n        NodesManager.prototype.deletePartition = function(\n            node, partition_id) {\n                var self = this;\n                var method = this._handler + \".delete_partition\";\n                var params = {\n                    system_id: node.system_id,\n                    partition_id: partition_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete the disk or partition.\n        NodesManager.prototype.deleteVolumeGroup = function(\n            node, volume_group_id) {\n                var self = this;\n                var method = this._handler + \".delete_volume_group\";\n                var params = {\n                    system_id: node.system_id,\n                    volume_group_id: volume_group_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete a cache set.\n        NodesManager.prototype.deleteCacheSet = function(\n            node, cache_set_id) {\n                var self = this;\n                var method = this._handler + \".delete_cache_set\";\n                var params = {\n                    system_id: node.system_id,\n                    cache_set_id: cache_set_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Delete a filesystem.\n        NodesManager.prototype.deleteFilesystem = function(\n            node, blockdevice_id, partition_id, filesystem_id) {\n                var self = this;\n                var method = this._handler + \".delete_filesystem\";\n                var params = {\n                    system_id: node.system_id,\n                    blockdevice_id: blockdevice_id,\n                    partition_id: partition_id,\n                    filesystem_id: filesystem_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Create a new partition.\n        NodesManager.prototype.createPartition = function(\n            node, block_id, size, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                var self = this;\n                var method = this._handler + \".create_partition\";\n                params.system_id = node.system_id;\n                params.block_id = block_id;\n                params.partition_size = size;\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Create a new cache set.\n        NodesManager.prototype.createCacheSet = function(\n            node, block_id, partition_id) {\n                var self = this;\n                var method = this._handler + \".create_cache_set\";\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id,\n                    partition_id: partition_id\n                };\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Create a new bcache device.\n        NodesManager.prototype.createBcache = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_bcache\", params);\n            };\n\n        // Create a new RAID device.\n        NodesManager.prototype.createRAID = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_raid\", params);\n            };\n\n        // Create a new volume group.\n        NodesManager.prototype.createVolumeGroup = function(\n            node, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".create_volume_group\", params);\n            };\n\n        // Create a new logical volume.\n        NodesManager.prototype.createLogicalVolume = function(\n            node, volume_group_id, name, size, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                var self = this;\n                var method = this._handler + \".create_logical_volume\";\n                params.system_id = node.system_id;\n                params.volume_group_id = volume_group_id;\n                params.name = name;\n                params.size = size;\n                return RegionConnection.callMethod(method, params);\n            };\n\n        // Update a disk.\n        NodesManager.prototype.updateDisk = function(\n            node, block_id, params) {\n                if(!angular.isObject(params)) {\n                    params = {};\n                }\n                params.system_id = node.system_id;\n                params.block_id = block_id;\n                return RegionConnection.callMethod(\n                    this._handler + \".update_disk\", params);\n            };\n\n        // Set disk as the boot disk.\n        NodesManager.prototype.setBootDisk = function(\n            node, block_id) {\n                var params = {\n                    system_id: node.system_id,\n                    block_id: block_id\n                };\n                return RegionConnection.callMethod(\n                    this._handler + \".set_boot_disk\", params);\n            };\n\n        NodesManager.prototype.getSummaryXML = function(node) {\n            return RegionConnection.callMethod(\n                this._handler + \".get_summary_xml\",\n                {\"system_id\": node.system_id});\n        };\n\n        NodesManager.prototype.getSummaryYAML = function(node) {\n            return RegionConnection.callMethod(\n                this._handler + \".get_summary_yaml\",\n                {\"system_id\": node.system_id});\n        };\n\n        return NodesManager;\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Notifications Manager.\n *\n * Manages notifications in the browser. Uses RegionConnection to load\n * notifications, await new, updated, and deleted notifications, and to\n * dismiss them.\n */\n\nangular.module('MAAS').factory(\n    'NotificationsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n     function($q, $rootScope, RegionConnection, Manager) {\n\n        function NotificationsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"notification\";\n\n            // Listen for notify events for the notification object.\n            RegionConnection.registerNotifier(\n                \"notification\", angular.bind(this, this.onNotify));\n        }\n\n        NotificationsManager.prototype = new Manager();\n        NotificationsManager.prototype.dismiss = function(notification) {\n            return RegionConnection.callMethod(\n                \"notification.dismiss\", {id: notification.id});\n        };\n\n        return new NotificationsManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS PackageRepositories Manager\n *\n * Manages all of the PackageRepositories in the browser. The manager uses the\n * RegionConnection to load the PackageRepositories, update them, and listen\n * for notification events about them.\n */\n\nangular.module('MAAS').factory(\n    'PackageRepositoriesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function PackageRepositoriesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"packagerepository\";\n\n            // Listen for notify events for the PackageRepository object.\n            var self = this;\n            RegionConnection.registerNotifier(\"packagerepository\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        PackageRepositoriesManager.prototype = new Manager();\n\n        // Create the repository.\n        PackageRepositoriesManager.prototype.create = function(repository) {\n            return RegionConnection.callMethod(\n                this._handler + \".create\", repository, true);\n        };\n\n        return new PackageRepositoriesManager();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Pods Manager\n *\n * Manages all of the pods in the browser. The manager uses the\n * RegionConnection to load the pods, update the pods, and listen for\n * notification events about pods.\n */\n\nangular.module('MAAS').service(\n    'PodsManager',\n    ['$q', '$rootScope', '$timeout', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, $timeout, RegionConnection, Manager) {\n\n        function PodsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"pod\";\n\n            // Listen for notify events for the pod object.\n            var self = this;\n            RegionConnection.registerNotifier(\"pod\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        PodsManager.prototype = new Manager();\n\n        // Refresh the pod information\n        PodsManager.prototype.refresh = function(pod) {\n            var self = this;\n            return RegionConnection.callMethod(\"pod.refresh\", pod).then(\n                function(pod) {\n                    self._replaceItem(pod);\n                    return pod;\n                });\n        };\n\n        // Compose a machine in the pod.\n        PodsManager.prototype.compose = function(params) {\n            var self = this;\n            return RegionConnection.callMethod(\"pod.compose\", params).then(\n                function(pod) {\n                    self._replaceItem(pod);\n                    return pod;\n                });\n        };\n\n        return new PodsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Region Connection\n *\n * Provides the websocket connection between the client and the MAAS regiond\n * service.\n */\n\nangular.module('MAAS').factory(\n    'RegionConnection',\n    ['$q', '$rootScope', '$timeout', '$window', '$cookies', function(\n        $q, $rootScope, $timeout, $window, $cookies) {\n\n        // Message types\n        var MSG_TYPE = {\n            REQUEST: 0,\n            RESPONSE: 1,\n            NOTIFY: 2\n        };\n\n        // Response types\n        var RESPONSE_TYPE = {\n            SUCCESS: 0,\n            ERROR: 1\n        };\n\n        // Constructor\n        function RegionConnection() {\n            this.callbacks = {};\n            this.requests = {};\n            this.requestId = 0;\n            this.url = null;\n            this.websocket = null;\n            this.connected = false;\n            this.autoReconnect = true;\n            this.retryTimeout = 5000;\n            this.error = null;\n\n            // Defer used for defaultConnect. If defaultConnect is called\n            // quickly only the first one will start the connection. The\n            // remaining will recieve this defer.\n            this.defaultConnectDefer = null;\n\n            // List of functions to call when a WebSocket event occurs. Each\n            // function will get the WebSocket event passed to it.\n            this.handlers = {\n                open: [],\n                error: [],\n                close: []\n            };\n\n            // Object containing a fields with list of functions. When\n            // a NOTIFY message is received it will match the name to a field\n            // in this object. If the field exists in the object the list\n            // of functions will be called with the action and obj_id.\n            this.notifiers = {};\n        }\n\n        // Return a new request id.\n        RegionConnection.prototype.newRequestId = function() {\n            this.requestId += 1;\n            return this.requestId;\n        };\n\n        // Register event handler.\n        RegionConnection.prototype.registerHandler = function (name, func) {\n            if(!angular.isDefined(this.handlers[name])) {\n                throw new Error(\"Invalid handler: \" + name);\n            }\n            if(!angular.isFunction(func)) {\n                throw new Error(\"Requires a function to register a handler.\");\n            }\n            this.handlers[name].push(func);\n        };\n\n        // Unregister event handler.\n        RegionConnection.prototype.unregisterHandler = function (name, func) {\n            if(!angular.isDefined(this.handlers[name])) {\n                throw new Error(\"Invalid handler: \" + name);\n            }\n            var idx = this.handlers[name].indexOf(func);\n            if(idx >= 0) {\n                this.handlers[name].splice(idx, 1);\n            }\n        };\n\n        // Register notification handler.\n        RegionConnection.prototype.registerNotifier = function(name, func) {\n            if(!angular.isFunction(func)) {\n                throw new Error(\"Requires a function to register a notifier.\");\n            }\n            if(angular.isUndefined(this.notifiers[name])) {\n                this.notifiers[name] = [];\n            }\n            this.notifiers[name].push(func);\n        };\n\n        // Unregister notification handler.\n        RegionConnection.prototype.unregisterNotifier = function(name, func) {\n            if(angular.isUndefined(this.notifiers[name])) {\n                return;\n            }\n            var idx = this.notifiers[name].indexOf(func);\n            if(idx >= 0) {\n                this.notifiers[name].splice(idx, 1);\n            }\n        };\n\n        // Return True if currently connected to region.\n        RegionConnection.prototype.isConnected = function() {\n            return this.connected;\n        };\n\n        // Builds the websocket connection.\n        RegionConnection.prototype.buildSocket = function(url) {\n            return new WebSocket(url);\n        };\n\n        // Opens the websocket connection.\n        RegionConnection.prototype.connect = function() {\n            this.url = this._buildUrl();\n            this.autoReconnect = true;\n            this.websocket = this.buildSocket(this.url);\n\n            var self = this;\n            this.websocket.onopen = function(evt) {\n                self.connected = true;\n                angular.forEach(self.handlers.open, function(func) {\n                    func(evt);\n                });\n            };\n            this.websocket.onerror = function(evt) {\n                angular.forEach(self.handlers.error, function(func) {\n                    func(evt);\n                });\n            };\n            this.websocket.onclose = function(evt) {\n                self.connected = false;\n                self.error = \"Unable to connect to: \" + self.url.split(\"?\")[0];\n                angular.forEach(self.handlers.close, function(func) {\n                    func(evt);\n                });\n                if(self.autoReconnect) {\n                    $timeout(function() {\n                        self.connect();\n                    }, self.retryTimeout);\n                }\n            };\n            this.websocket.onmessage = function(evt) {\n                self.onMessage(angular.fromJson(evt.data));\n            };\n        };\n\n        // Closes the websocket connection.\n        RegionConnection.prototype.close = function() {\n            this.autoReconnect = false;\n            this.websocket.close();\n            this.websocket = null;\n        };\n\n        // Return the protocol used for the websocket connection.\n        RegionConnection.prototype._getProtocol = function() {\n            return $window.location.protocol;\n        };\n\n        // Return connection url to websocket from current location and\n        // html options.\n        RegionConnection.prototype._buildUrl = function() {\n            var host = $window.location.hostname;\n            var port = $window.location.port;\n            var path = $window.location.pathname;\n            var proto = 'ws';\n            if (this._getProtocol() === 'https:') {\n                proto = 'wss';\n            }\n\n            // Path and port can be overridden by href and data-websocket-port\n            // in the base element respectively.\n            var base = angular.element(\"base\");\n            if(angular.isDefined(base)) {\n                var newPath = base.attr(\"href\");\n                if(angular.isDefined(newPath)) {\n                    path = newPath;\n                }\n                var newPort = base.data(\"websocket-port\");\n                if(angular.isDefined(newPort)) {\n                    port = newPort;\n                }\n            }\n\n            // Append final '/' if missing from end of path.\n            if(path[path.length - 1] !== '/') {\n                path += '/';\n            }\n\n            // Build the URL. Include the :port only if it has a value.\n            url = proto + \"://\" + host;\n            if(angular.isString(port) && port.length > 0){\n                url += \":\" + port;\n            }\n            url += path + \"ws\";\n\n            // Include the csrftoken in the URL if it's defined.\n            var csrftoken;\n            if(angular.isFunction($cookies.get)) {\n                csrftoken = $cookies.get('csrftoken');\n            } else {\n                csrftoken = $cookies.csrftoken;\n            }\n            if(angular.isDefined(csrftoken)) {\n                url += '?csrftoken=' + encodeURIComponent(csrftoken);\n            }\n\n            return url;\n        };\n\n        // Opens the default websocket connection.\n        RegionConnection.prototype.defaultConnect = function() {\n            // Already been called but the connection has not been completed.\n            if(angular.isObject(this.defaultConnectDefer)) {\n                return this.defaultConnectDefer.promise;\n            }\n\n            // Already connected.\n            var defer;\n            if(this.isConnected()) {\n                // Create a new defer as the defaultConnectDefer would\n                // have already been resolved.\n                defer = $q.defer();\n\n                // Cannot resolve the defer inline as it hasn't been given\n                // back to the caller. It will be called in the next loop.\n                $timeout(defer.resolve);\n                return defer.promise;\n            }\n\n            // Start the connection.\n            var self = this, opened, errored;\n            defer = this.defaultConnectDefer = $q.defer();\n            opened = function(evt) {\n                this.defaultConnectDefer = null;\n                self.unregisterHandler(\"open\", opened);\n                self.unregisterHandler(\"error\", errored);\n                $rootScope.$apply(defer.resolve(evt));\n            };\n            errored = function(evt) {\n                this.defaultConnectDefer = null;\n                self.unregisterHandler(\"open\", opened);\n                self.unregisterHandler(\"error\", errored);\n                $rootScope.$apply(defer.reject(evt));\n            };\n            this.registerHandler(\"open\", opened);\n            this.registerHandler(\"error\", errored);\n            this.connect();\n            return defer.promise;\n        };\n\n        // Called when a message is received.\n        RegionConnection.prototype.onMessage = function(msg) {\n            // Response\n            if(msg.type === MSG_TYPE.RESPONSE) {\n                this.onResponse(msg);\n            // Notify\n            } else if(msg.type === MSG_TYPE.NOTIFY) {\n                this.onNotify(msg);\n            }\n        };\n\n        // Called when a response message is recieved.\n        RegionConnection.prototype.onResponse = function(msg) {\n            // Grab the registered defer from the callbacks list.\n            var defer = this.callbacks[msg.request_id];\n            var remembered_request = this.requests[msg.request_id];\n            if(angular.isDefined(defer)) {\n                if(msg.rtype === RESPONSE_TYPE.SUCCESS) {\n                    // Resolve the defer inside of the digest cycle, so any\n                    // update to an object or collection will trigger a\n                    // watcher.\n                    $rootScope.$apply(defer.resolve(msg.result));\n                } else if(msg.rtype === RESPONSE_TYPE.ERROR) {\n                    // Reject the defer since an error occurred.\n                    if(angular.isObject(remembered_request)) {\n                        $rootScope.$apply(defer.reject({\n                            \"error\": msg.error,\n                            \"request\": remembered_request\n                        }));\n                    } else {\n                        $rootScope.$apply(defer.reject(msg.error));\n                    }\n                }\n                // Remove the defer from the callback list.\n                delete this.callbacks[msg.request_id];\n                delete this.requests[msg.request_id];\n            }\n        };\n\n        // Called when a notify response is recieved.\n        RegionConnection.prototype.onNotify = function(msg) {\n            var handlers = this.notifiers[msg.name];\n            if(angular.isArray(handlers)) {\n                angular.forEach(handlers, function(handler) {\n                    handler(msg.action, msg.data);\n                });\n            }\n        };\n\n        // Call method on the region.\n        RegionConnection.prototype.callMethod = function(\n                method, params, remember) {\n            var defer = $q.defer();\n            var request_id = this.newRequestId();\n            var request = {\n                type: MSG_TYPE.REQUEST,\n                request_id: request_id,\n                method: method,\n                params: params\n            };\n            this.callbacks[request_id] = defer;\n            // If requested, remember what the details of the request were,\n            // so that the controller can refresh its memory.\n            if (remember) {\n                this.requests[request_id] = request;\n            }\n            this.websocket.send(angular.toJson(request));\n            return defer.promise;\n        };\n\n        return new RegionConnection();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS ScriptsManager Manager\n *\n * Manages all of the Scripts in the browser. The manager uses the\n * RegionConnection to load the Scripts, and listen for notification\n * events about Scripts.\n */\n\nangular.module('MAAS').factory(\n    'ScriptsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function ScriptsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"script\";\n\n            // Listen for notify events for the Script object.\n            var self = this;\n            RegionConnection.registerNotifier(\"script\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        ScriptsManager.prototype = new Manager();\n\n        return new ScriptsManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Service Manager\n *\n * Manages all of the services for a node in the browser. The manager uses the\n * RegionConnection to load the services and listen for service notifications.\n */\n\nangular.module('MAAS').factory(\n    'ServicesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function ServicesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"service\";\n\n            // Listen for notify events for the service object.\n            var self = this;\n            RegionConnection.registerNotifier(\"service\",\n                function(action, data) {\n                    self.onNotify(action, data);\n            });\n        }\n\n        ServicesManager.prototype = new Manager();\n\n        return new ServicesManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Space Manager\n *\n * Manages all of the spaces in the browser. The manager uses the\n * RegionConnection to load the spaces, update the spaces, and listen for\n * notification events about spaces.\n */\n\nangular.module('MAAS').factory(\n    'SpacesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', 'SubnetsManager',\n    function($q, $rootScope, RegionConnection, Manager, SubnetsManager) {\n\n        function SpacesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"space\";\n\n            // Listen for notify events for the space object.\n            var self = this;\n            RegionConnection.registerNotifier(\"space\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        SpacesManager.prototype = new Manager();\n\n        // Create a space.\n        SpacesManager.prototype.create = function(space) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"space.create\", space);\n        };\n\n\n        // Delete the space.\n        SpacesManager.prototype.deleteSpace = function(space) {\n            return RegionConnection.callMethod(\"space.delete\", space);\n        };\n\n        return new SpacesManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS SSHKey Manager\n *\n * Manages all of the SSHKeys in the browser. The manager uses the\n * RegionConnection to load the SSHKeys, update the SSHKeys, and\n * listen for notification events about SSHKeys.\n */\n\nangular.module('MAAS').factory(\n    'SSHKeysManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function SSHKeysManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"sshkey\";\n\n            // Listen for notify events for the sshkey object.\n            var self = this;\n            RegionConnection.registerNotifier(\"sshkey\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        SSHKeysManager.prototype = new Manager();\n\n        // Imports SSH keys from a launchpad and github.\n        SSHKeysManager.prototype.importKeys = function(params) {\n            // We don't add the results to the list because a NOTIFY event will\n            // add the ssh key to the list. Adding it here will cause angular\n            // to complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"sshkey.import_keys\", params);\n        };\n\n        return new SSHKeysManager();\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS StaticRoute Manager\n *\n * Manages all of the StaticRoutes in the browser. The manager uses the\n * RegionConnection to load the StaticRoutes, update the StaticRoutes, and\n * listen for notification events about StaticRoutes.\n */\n\nangular.module('MAAS').factory(\n    'StaticRoutesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager',\n    function($q, $rootScope, RegionConnection, Manager) {\n\n        function StaticRoutesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"staticroute\";\n\n            // Listen for notify events for the staticroute object.\n            var self = this;\n            RegionConnection.registerNotifier(\"staticroute\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        StaticRoutesManager.prototype = new Manager();\n\n        return new StaticRoutesManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Subnet Manager\n *\n * Manages all of the subnets in the browser. The manager uses the\n * RegionConnection to load the subnets, update the subnets, and listen for\n * notification events about subnets.\n */\n\nangular.module('MAAS').factory(\n    'SubnetsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function SubnetsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"subnet\";\n\n            // Listen for notify events for the subnet object.\n            var self = this;\n            RegionConnection.registerNotifier(\"subnet\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        SubnetsManager.prototype = new Manager();\n\n        // Return the name of the subnet. Will include the name of the subnet\n        // in '(', ')' if it exists and not the same as the cidr.\n        SubnetsManager.prototype.getName = function(subnet) {\n            if(!angular.isObject(subnet)) {\n                return \"\";\n            }\n\n            var name = subnet.cidr;\n            if(angular.isString(subnet.name) &&\n                subnet.name !== \"\" &&\n                subnet.name !== subnet.cidr) {\n                name += \" (\" + subnet.name + \")\";\n            }\n            return name;\n        };\n\n        SubnetsManager.prototype.getLargestRange = function(subnet) {\n            var largest_range = {num_addresses: 0, start: \"\", end: \"\"};\n            angular.forEach(subnet.statistics.ranges, function(iprange) {\n                if(angular.equals(iprange.purpose, [\"unused\"]) &&\n                        iprange.num_addresses > largest_range.num_addresses) {\n                    largest_range = iprange;\n                }\n            });\n            return largest_range;\n        };\n\n        SubnetsManager.prototype.hasDynamicRange = function(subnet) {\n            var i;\n            for(i = 0; i < subnet.statistics.ranges.length ; i++) {\n                var iprange = subnet.statistics.ranges[i];\n                if(iprange.purpose.indexOf(\"dynamic\") !== -1) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        // Create a subnet.\n        SubnetsManager.prototype.create = function(subnet) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"subnet.create\", subnet);\n        };\n\n        // Delete the subnet.\n        SubnetsManager.prototype.deleteSubnet = function(subnet) {\n            return RegionConnection.callMethod(\"subnet.delete\", {\n                \"id\": subnet.id\n            });\n        };\n\n        // Perform a neighbour discovery scan on the subnet.\n        SubnetsManager.prototype.scanSubnet = function(subnet) {\n            return RegionConnection.callMethod(\"subnet.scan\", {\n                \"id\": subnet.id\n            });\n        };\n\n        return new SubnetsManager();\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Switches Manager\n *\n * Manages all of the switches in the browser. This manager is used for the\n * switches listing and the switches view page. The manager uses the\n * RegionConnection to load the switches, update the switches, and listen for\n * notification events about switches.\n */\n\nangular.module('MAAS').factory(\n    'SwitchesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'NodesManager', function(\n            $q, $rootScope, RegionConnection, NodesManager) {\n\n        function SwitchesManager() {\n            NodesManager.call(this);\n\n            this._pk = \"system_id\";\n            this._handler = \"switch\";\n            this._metadataAttributes = {\n                \"owner\": null,\n                \"subnets\": null,\n                \"tags\": null,\n                \"zone\": function(device) {\n                    return device.zone.name;\n                }\n            };\n\n            // Listen for notify events for the switch object.\n            var self = this;\n            RegionConnection.registerNotifier(\"switch\", function(action, data) {\n                self.onNotify(action, data);\n            });\n        }\n\n        SwitchesManager.prototype = new NodesManager();\n\n        // Create a switch.\n        SwitchesManager.prototype.create = function(node) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the device to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"switch.create\", node);\n        };\n\n        // Perform the action on the switch.\n        SwitchesManager.prototype.performAction = function(\n            device, action, extra) {\n\n            if(!angular.isObject(extra)) {\n                extra = {};\n            }\n            return RegionConnection.callMethod(\"switch.action\", {\n                \"system_id\": device.system_id,\n                \"action\": action,\n                \"extra\": extra\n                });\n        };\n\n        return new SwitchesManager();\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Tag Manager\n *\n * Manages all of the tags in the browser. The manager uses the\n * RegionConnection to load the tags, update the tags, and listen for\n * notification events about tags.\n */\n\nangular.module('MAAS').factory(\n    'TagsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function TagsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"tag\";\n\n            // Listen for notify events for the tag object.\n            var self = this;\n            RegionConnection.registerNotifier(\"tag\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        TagsManager.prototype = new Manager();\n\n        // Helper for autocomplete that will return a string of tags that\n        // contain the query text.\n        TagsManager.prototype.autocomplete = function(query) {\n            var matching = [];\n            angular.forEach(this._items, function(item) {\n                if(item.name.indexOf(query) > -1) {\n                    matching.push(item.name);\n                }\n            });\n            return matching;\n        };\n\n        return new TagsManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS User Manager\n *\n * Manages all of the users in the browser. The manager uses the\n * RegionConnection to load the users, update the users, and listen for\n * notification events about users.\n */\n\nangular.module('MAAS').factory(\n    'UsersManager',\n    ['RegionConnection', 'Manager', 'ErrorService',\n    function(RegionConnection, Manager, ErrorService) {\n\n        function UsersManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"user\";\n\n            // Holds the authenticated user for the connection.\n            this._authUser = null;\n\n            // Listen for notify events for the user object.\n            var self = this;\n            RegionConnection.registerNotifier(\"user\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        UsersManager.prototype = new Manager();\n\n        // Get the authenticated user for the connection.\n        UsersManager.prototype.getAuthUser = function() {\n            return this._authUser;\n        };\n\n        // Return true if the authenticated user is super user.\n        UsersManager.prototype.isSuperUser = function() {\n            var authUser = this.getAuthUser();\n            if(!angular.isObject(authUser)) {\n                return false;\n            }\n            return authUser.is_superuser;\n        };\n\n        // Return true if the authenticated user has uploaded at\n        // least one SSH key.\n        UsersManager.prototype.getSSHKeyCount = function() {\n            authuser = this._authUser;\n            if(!angular.isObject(authuser)) {\n                return 0;\n            }\n            return authuser.sshkeys_count;\n        };\n\n        // Load the authenticated user.\n        UsersManager.prototype._loadAuthUser = function() {\n            var self = this;\n            return RegionConnection.callMethod(\"user.auth_user\", {}).then(\n                function(user) {\n                    if(angular.isObject(self._authUser)) {\n                        // Copy the user into the authUser. This keeps the\n                        // reference the same, not requiring another call to\n                        // getAuthUser.\n                        angular.copy(user, self._authUser);\n                    } else {\n                        self._authUser = user;\n                    }\n                    return self._authUser;\n                }, function(error) {\n                    ErrorService.raiseError(error);\n                });\n        };\n\n        UsersManager.prototype._replaceItem = function(item) {\n            Manager.prototype._replaceItem.call(this, item);\n\n            // Update the authenticated user if updated item has the\n            // same primary key.\n            if(angular.isObject(this._authUser) &&\n                this._authUser[this._pk] === item[this._pk]) {\n                // Copy the item into the authUser. This keeps the reference\n                // the same, not requiring another call to getAuthUser.\n                angular.copy(item, this._authUser);\n            }\n        };\n\n        UsersManager.prototype.loadItems = function() {\n            // Load the auth user when all the items are loaded as well.\n            this._loadAuthUser();\n            return Manager.prototype.loadItems.call(this);\n        };\n\n        UsersManager.prototype.reloadItems = function() {\n            // Load the auth user when all the items are reloaded as well.\n            this._loadAuthUser();\n            return Manager.prototype.reloadItems.call(this);\n        };\n\n        // Mark the user as completed the intro.\n        UsersManager.prototype.markIntroComplete = function() {\n            var self = this;\n            return RegionConnection.callMethod(\n                \"user.mark_intro_complete\", {}).then(\n                    function(user) {\n                        if(angular.isObject(self._authUser)) {\n                            // Copy the user into the authUser. This keeps the\n                            // reference the same, not requiring another call\n                            // to getAuthUser.\n                            angular.copy(user, self._authUser);\n                        } else {\n                            self._authUser = user;\n                        }\n                        return self._authUser;\n                    }, function(error) {\n                        ErrorService.raiseError(error);\n                    });\n        };\n\n        return new UsersManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS VLAN Manager\n *\n * Manages all of the VLANs in the browser. The manager uses the\n * RegionConnection to load the VLANs, update the VLANs, and listen for\n * notification events about VLANs.\n */\n\nangular.module('MAAS').factory(\n    'VLANsManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', 'SubnetsManager',\n    function($q, $rootScope, RegionConnection, Manager, SubnetsManager) {\n\n        function VLANsManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"vlan\";\n\n            // Listen for notify events for the vlan object.\n            var self = this;\n            RegionConnection.registerNotifier(\"vlan\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        VLANsManager.prototype = new Manager();\n\n        VLANsManager.prototype.getName = function(vlan) {\n            var name = vlan.vid;\n            if(vlan.vid === 0) {\n                name = \"untagged\";\n            } else if(angular.isString(vlan.name) && vlan.name !== \"\") {\n                name += \" (\" + vlan.name + \")\";\n            }\n            return name;\n        };\n\n        // Delete the VLAN.\n        VLANsManager.prototype.deleteVLAN = function(vlan) {\n            return RegionConnection.callMethod(\n                \"vlan.delete\", { \"id\": vlan.id }, true);\n        };\n\n        // This is needed for testing: in the normal course of things,\n        // rack_sids is generated entirely by the websocket handler.\n        VLANsManager.prototype.addRackController = function(vlan, rack) {\n            vlan.rack_sids.push(rack.system_id);\n        };\n\n        // Configure DHCP on the VLAN\n        VLANsManager.prototype.configureDHCP = function(\n           vlan, controllers, extra, relay_vlan) {\n           var params = {\n               \"id\": vlan.id,\n               \"controllers\": controllers,\n               \"extra\": extra\n           };\n           if(relay_vlan === null || angular.isNumber(relay_vlan)) {\n              params.relay_vlan = relay_vlan;\n           }\n           return RegionConnection.callMethod(\n                \"vlan.configure_dhcp\", params, true);\n        };\n\n        // Disable DHCP on the VLAN\n        VLANsManager.prototype.disableDHCP = function(vlan) {\n            return RegionConnection.callMethod(\n                \"vlan.configure_dhcp\", {\n                    \"id\": vlan.id,\n                    \"controllers\": [],\n                    \"relay_vlan\": null\n                }, true);\n        };\n\n        // Create a VLAN.\n        VLANsManager.prototype.create = function(vlan) {\n            // We don't add the item to the list because a NOTIFY event will\n            // add the domain to the list. Adding it here will cause angular to\n            // complain because the same object exist in the list.\n            return RegionConnection.callMethod(\"vlan.create\", vlan);\n        };\n\n        return new VLANsManager();\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Zone Manager\n *\n * Manages all of the zones in the browser. The manager uses the\n * RegionConnection to load the zones, update the zones, and listen for\n * notification events about zones.\n */\n\nangular.module('MAAS').factory(\n    'ZonesManager',\n    ['$q', '$rootScope', 'RegionConnection', 'Manager', function(\n            $q, $rootScope, RegionConnection, Manager) {\n\n        function ZonesManager() {\n            Manager.call(this);\n\n            this._pk = \"id\";\n            this._handler = \"zone\";\n\n            // Listen for notify events for the zone object.\n            var self = this;\n            RegionConnection.registerNotifier(\"zone\",\n                function(action, data) {\n                    self.onNotify(action, data);\n                });\n        }\n\n        ZonesManager.prototype = new Manager();\n\n        // Return the default zone.\n        ZonesManager.prototype.getDefaultZone = function() {\n            if(this._items.length === 0) {\n                return null;\n            } else {\n                var i;\n                for(i=0;i<this._items.length;i++) {\n                    if(this._items[i].id === 0) {\n                        return this._items[i];\n                    }\n                }\n            }\n            return this._items[0];\n        };\n\n        return new ZonesManager();\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter VLANs by Fabric.\n */\n\nangular.module('MAAS').filter('filterByFabric', function() {\n    return function(vlans, fabric) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(fabric)) {\n            id = fabric.id;\n        } else if(angular.isNumber(fabric)) {\n            id = fabric;\n        } else {\n            return filtered;\n        }\n        angular.forEach(vlans, function(vlan) {\n            if(vlan.fabric === id) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter Subnets by Space.\n */\n\nangular.module('MAAS').filter('filterBySpace', function() {\n    return function(objects, space) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(space)) {\n            id = space.id;\n        } else if(angular.isNumber(space)) {\n            id = space;\n        } else {\n            return filtered;\n        }\n        angular.forEach(objects, function(object) {\n            if(object.space === id) {\n                filtered.push(object);\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').filter('filterByNullSpace', function() {\n    return function(objects) {\n        var filtered = [];\n        angular.forEach(objects, function(object) {\n            if(object.space === null) {\n                filtered.push(object);\n            }\n        });\n        return filtered;\n    };\n});","/* Copyright 2016-2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Filter objects with subnet foreign key references by a particular subnet.\n */\n\nangular.module('MAAS').filter('filterBySubnet', function() {\n    return function(foreign_objects, subnet, key) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(subnet)) {\n            id = subnet.id;\n        } else if(angular.isNumber(subnet)) {\n            id = subnet;\n        } else {\n            return filtered;\n        }\n        if(angular.isUndefined(key)) {\n            key = 'subnet';\n        }\n        angular.forEach(foreign_objects, function(obj) {\n            if(obj[key] === id) {\n                filtered.push(obj);\n            }\n        });\n        return filtered;\n    };\n});\n\n// Filters by subnet, unless the subnet is not defined. If the subnet is not\n// defined, filters by VLAN.\nangular.module('MAAS').filter('filterBySubnetOrVlan', function() {\n    return function(foreign_objects, subnet, vlan) {\n        var filtered = [];\n        var id;\n        var key = null;\n        if(angular.isDefined(subnet) && subnet !== null) {\n            key = 'subnet';\n            if(angular.isObject(subnet)) {\n                id = subnet.id;\n            } else if(angular.isNumber(subnet)) {\n                id = subnet;\n            }\n        } else if(angular.isDefined(vlan) && vlan !== null) {\n            key = 'vlan';\n            if(angular.isObject(vlan)) {\n                id = vlan.id;\n            } else if(angular.isNumber(vlan)) {\n                id = vlan;\n            }\n        } else {\n            return filtered;\n        }\n        angular.forEach(foreign_objects, function(obj) {\n            if(obj[key] === id) {\n                filtered.push(obj);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter Subnets by VLAN.\n */\n\nangular.module('MAAS').filter('filterByVLAN', function() {\n    return function(subnets, vlan) {\n        var filtered = [];\n        var id;\n        if(angular.isObject(vlan)) {\n            id = vlan.id;\n        } else if(angular.isNumber(vlan)) {\n            id = vlan;\n        } else {\n            return filtered;\n        }\n        angular.forEach(subnets, function(subnet) {\n            if(subnet.vlan === id) {\n                filtered.push(subnet);\n            }\n        });\n        return filtered;\n    };\n});\n\nangular.module('MAAS').filter('filterControllersByVLAN', function() {\n    return function(controllers, vlan) {\n        var filtered = [];\n        if(!angular.isObject(vlan)) {\n            return filtered;\n        }\n        angular.forEach(controllers, function(controller) {\n            // XXX mpontillo disable VLAN check until VLAN is populated\n            // on the rack controller's interfaces.\n            // if(controller.vlan_ids.indexOf(vlan.id) != -1) {\n\n            // XXX mpontillo 2016-02-22 this is a hack to prevent too many\n            // nodes from being sent through the filter; we have a bug which\n            // sends nodes in which are not controllers.\n            if(controller.node_type === 2 || controller.node_type === 4) {\n                filtered.push(controller);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes Filter\n */\n\nangular.module('MAAS').filter('nodesFilter', ['$filter', 'SearchService',\n    function($filter, SearchService) {\n\n        // Default filter built-in angular. Used on all extra filters that do\n        // not specify a specific type.\n        var standardFilter = $filter('filter');\n\n        // Helpers that convert the pseudo field on node to an actual\n        // value from the node.\n        var mappings = {\n            cpu: function(node) {\n                return node.cpu_count;\n            },\n            cores: function(node) {\n                return node.cpu_count;\n            },\n            ram: function(node) {\n                return node.memory;\n            },\n            mac: function(node) {\n                macs = [];\n                macs.push(node.pxe_mac);\n                macs.push.apply(macs, node.extra_macs);\n                return macs;\n            },\n            zone: function(node) {\n                return node.zone.name;\n            },\n            pod: function(node) {\n                return (node.pod === undefined) ? undefined : node.pod.name;\n            },\n            'pod-id': function(node) {\n                return (node.pod === undefined) ? undefined : node.pod.id;\n            },\n            power: function(node) {\n                return node.power_state;\n            },\n            release: function(node) {\n                if(node.status_code === 6 || node.status_code === 9) {\n                    return node.osystem + \"/\" + node.distro_series;\n                } else {\n                    return '';\n                }\n            }\n        };\n\n        // Return true when value is an integer.\n        function isInteger(value) {\n            // +1 done to silence js-lint.\n            return value % +1 === 0;\n        }\n\n        // Return true when lowercase value contains the already\n        // lowercased lowerTerm.\n        function _matches(value, lowerTerm, exact) {\n            if(angular.isNumber(value)) {\n                if(exact) {\n                    if(isInteger(value)) {\n                        return value === parseInt(lowerTerm, 10);\n                    } else {\n                        return value === parseFloat(lowerTerm);\n                    }\n                } else {\n                    if(isInteger(value)) {\n                        return value >= parseInt(lowerTerm, 10);\n                    } else {\n                        return value >= parseFloat(lowerTerm);\n                    }\n                }\n            } else if(angular.isString(value)) {\n                if(exact) {\n                    return value.toLowerCase() === lowerTerm;\n                } else {\n                    return value.toLowerCase().indexOf(lowerTerm) >= 0;\n                }\n            } else {\n                return value === lowerTerm;\n            }\n        }\n\n        // Return true if value matches lowerTerm, unless negate is true then\n        // return false if matches.\n        function matches(value, lowerTerm, exact, negate) {\n            var match = _matches(value, lowerTerm, exact);\n            if(negate) {\n                return !match;\n            }\n            return match;\n        }\n\n        return function(nodes, search) {\n            if(angular.isUndefined(nodes) ||\n                angular.isUndefined(search) ||\n                nodes.length === 0) {\n                return nodes;\n            }\n\n            var filtered = nodes;\n            var filters = SearchService.getCurrentFilters(search);\n            angular.forEach(filters, function(terms, attr) {\n                if(attr === '_') {\n                    // Use the standard filter on terms that do not specify\n                    // an attribute.\n                    angular.forEach(terms, function(term) {\n                        filtered = standardFilter(filtered, term);\n                    });\n                } else if(attr === 'in') {\n                    // \"in:\" is used to filter the nodes by those that are\n                    // currently selected.\n                    angular.forEach(terms, function(term) {\n                        var matched = [];\n                        angular.forEach(filtered, function(node) {\n                            if(node.$selected &&\n                                term.toLowerCase() === \"selected\") {\n                                matched.push(node);\n                            } else if(!node.$selected &&\n                                term.toLowerCase() === \"!selected\") {\n                                matched.push(node);\n                            }\n                        });\n                        filtered = matched;\n                    });\n                } else {\n                    // Mapping function for the attribute.\n                    var mapFunc = mappings[attr];\n\n                    // Loop through each item and only select the matching.\n                    var matched = [];\n                    angular.forEach(filtered, function(node) {\n                        var value;\n                        if(angular.isFunction(mapFunc)) {\n                            value = mapFunc(node);\n                        } else if(node.hasOwnProperty(attr)) {\n                            value = node[attr];\n                        }\n\n                        // Unable to get value for this node. So skip it.\n                        if(angular.isUndefined(value)) {\n                            return;\n                        }\n\n                        var i, j;\n                        for(i = 0; i < terms.length; i++) {\n                            var term = terms[i].toLowerCase();\n                            var exact = false, negate = false;\n\n                            // '!' at the beginning means the term is negated.\n                            while(term.indexOf('!') === 0) {\n                                negate = !negate;\n                                term = term.substring(1);\n                            }\n\n                            // '=' at the beginning means to match exactly.\n                            if(term.indexOf('=') === 0) {\n                                exact = true;\n                                term = term.substring(1);\n                            }\n\n                            // Allow '!' after the '=' as well.\n                            while(term.indexOf('!') === 0) {\n                                negate = !negate;\n                                term = term.substring(1);\n                            }\n\n                            if(angular.isArray(value)) {\n                                // If value is an array check if the\n                                // term matches any value in the\n                                // array. If negated, check whether no\n                                // value in the array matches.\n                                if(negate) {\n                                    // Push to matched only if no value in\n                                    // the array matches term.\n                                    var no_match = true;\n                                    for(j = 0; j < value.length; j++) {\n                                        if(matches(\n                                            value[j], term, exact, false)) {\n                                            no_match = false;\n                                            break; // Skip remaining tests.\n                                        }\n                                    }\n                                    if(no_match) {\n                                        matched.push(node);\n                                        return;\n                                    }\n                                } else {\n                                    for(j = 0; j < value.length; j++) {\n                                        if(matches(\n                                            value[j], term, exact, false)) {\n                                            matched.push(node);\n                                            return;\n                                        }\n                                    }\n                                }\n                            } else {\n                                // Standard value check that it matches the\n                                // term.\n                                if(matches(value, term, exact, negate)) {\n                                    matched.push(node);\n                                    return;\n                                }\n                            }\n                        }\n                    });\n                    filtered = matched;\n                }\n            });\n            return filtered;\n        };\n    }]);\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter Subnets by VLAN.\n */\n\nangular.module('MAAS').filter('orderByDate', function() {\n    return function(items, field, field2) {\n        var sorted = items.slice();\n        sorted.sort(function(a, b) {\n            aDate = new Date(a[field]);\n            bDate = new Date(b[field]);\n\n            // Sort by ID as well if equal.\n            if(angular.isString(field2) &&\n                aDate.getTime() === bDate.getTime()) {\n                return (\n                    a[field2] > b[field2] ? -1 : a[field2] < b[field2] ? 1 : 0);\n            } else {\n              return aDate > bDate ? -1 : aDate < bDate ? 1 : 0;\n            }\n        });\n        return sorted;\n    };\n});\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Filter to remove the default VLAN as an option.\n */\n\nangular.module('MAAS').filter('removeDefaultVLAN', function() {\n    return function(vlans) {\n        var filtered = [];\n        angular.forEach(vlans, function(vlan) {\n            if(vlan.vid !== 0) {\n                filtered.push(vlan);\n            }\n        });\n        return filtered;\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Module\n *\n * Initializes the MAAS module with its required dependencies and sets up\n * the interpolater to use '{$' and '$}' instead of '{{' and '}}' as this\n * conflicts with Django templates.\n */\n\nangular.module('MAAS',\n    ['ngRoute', 'ngCookies', 'ngSanitize', 'ngTagsInput', 'vs-repeat']).config(\n    function($interpolateProvider, $routeProvider, $httpProvider) {\n        $interpolateProvider.startSymbol('{$');\n        $interpolateProvider.endSymbol('$}');\n\n        // Set the $httpProvider to send the csrftoken in the header of any\n        // http request.\n        $httpProvider.defaults.xsrfCookieName = 'csrftoken';\n        $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';\n\n        // Helper that wrappers the templateUrl to append the files version\n        // to the path. Used to override client cache.\n        function versionedPath(path) {\n            return path + \"?v=\" + MAAS_config.files_version;\n        }\n\n        // Setup routes only for the index page, all remaining pages should\n        // not use routes. Once all pages are converted to using Angular this\n        // will go away. Causing the page to never have to reload.\n        var href = angular.element(\"base\").attr('href');\n        var path = document.location.pathname;\n        if(path[path.length - 1] !== '/') {\n            path += '/';\n        }\n        if(path === href) {\n            var routes = $routeProvider.\n                when('/intro', {\n                    templateUrl: versionedPath(\n                        'static/partials/intro.html'),\n                    controller: 'IntroController'\n                }).\n                when('/intro/user', {\n                    templateUrl: versionedPath(\n                        'static/partials/intro-user.html'),\n                    controller: 'IntroUserController'\n                }).\n                when('/nodes', {\n                    templateUrl: versionedPath(\n                        'static/partials/nodes-list.html'),\n                    controller: 'NodesListController'\n                }).\n                when('/node/:type/:system_id/:result_type/:id', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-result.html'),\n                    controller: 'NodeResultController'\n                }).\n                when('/node/:type/:system_id/events', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-events.html'),\n                    controller: 'NodeEventsController'\n                }).\n                when('/node/:system_id/events', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-events.html'),\n                    controller: 'NodeEventsController'\n                }).\n                when('/node/:type/:system_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-details.html'),\n                    controller: 'NodeDetailsController'\n                }).\n                when('/node/:system_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/node-details.html'),\n                    controller: 'NodeDetailsController'\n                }).\n                when('/pods', {\n                    templateUrl: versionedPath(\n                        'static/partials/pods-list.html'),\n                    controller: 'PodsListController'\n                }).\n                when('/pod/:id', {\n                    templateUrl: versionedPath(\n                        'static/partials/pod-details.html'),\n                    controller: 'PodDetailsController'\n                }).\n                when('/images', {\n                    templateUrl: versionedPath(\n                        'static/partials/images.html'),\n                    controller: 'ImagesController'\n                }).\n                when('/domains', {\n                    templateUrl: versionedPath(\n                        'static/partials/domains-list.html'),\n                    controller: 'DomainsListController'\n                }).\n                when('/domain/:domain_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/domain-details.html'),\n                    controller: 'DomainDetailsController'\n                }).\n                when('/space/:space_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/space-details.html'),\n                    controller: 'SpaceDetailsController'\n                }).\n                when('/fabric/:fabric_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/fabric-details.html'),\n                    controller: 'FabricDetailsController'\n                }).\n                when('/subnets', {\n                    redirectTo: '/networks?by=fabric'\n                }).\n                when('/networks', {\n                    templateUrl: versionedPath(\n                        'static/partials/networks-list.html'),\n                    controller: 'NetworksListController',\n                    reloadOnSearch: false\n                }).\n                when('/subnet/:subnet_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/subnet-details.html'),\n                    controller: 'SubnetDetailsController'\n                }).\n                when('/vlan/:vlan_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/vlan-details.html'),\n                    controller: 'VLANDetailsController',\n                    controllerAs: 'vlanDetails'\n                }).\n                when('/settings/:section', {\n                    templateUrl: versionedPath(\n                        'static/partials/settings.html'),\n                    controller: 'SettingsController'\n                }).\n                when('/zone/:zone_id', {\n                    templateUrl: versionedPath(\n                        'static/partials/zone-details.html'),\n                    controller: 'ZoneDetailsController'\n                }).\n                when('/zones', {\n                    templateUrl: versionedPath(\n                        'static/partials/zones-list.html'),\n                    controller: 'ZonesListController',\n                    reloadOnSearch: false\n                });\n            if(MAAS_config.superuser) {\n                // Only superuser's can access the dashboard at the moment.\n                routes = routes.when('/dashboard', {\n                    templateUrl: versionedPath(\n                        'static/partials/dashboard.html'),\n                    controller: 'DashboardController'\n                }).\n                otherwise({\n                    redirectTo: '/dashboard'\n                });\n            } else {\n                routes = routes.otherwise({\n                    redirectTo: '/nodes'\n                });\n            }\n        }\n    });\n\n// Force users to #/intro when it has not been completed.\nangular.module('MAAS').run(['$rootScope', '$location',\n    function ($rootScope, $location) {\n        $rootScope.$on('$routeChangeStart', function(event, next, current) {\n            if(!MAAS_config.completed_intro) {\n                if(next.controller !== 'IntroController') {\n                    $location.path('/intro');\n                }\n            } else if (!MAAS_config.user_completed_intro) {\n                if(next.controller !== 'IntroUserController') {\n                    $location.path('/intro/user');\n                }\n            }\n        });\n    }]);\n\n// Send pageview to Google Anayltics when the route has changed.\nangular.module('MAAS').run(['$rootScope',\n    function ($rootScope) {\n        window.ga = window.ga || function() {\n            (window.ga.q = window.ga.q || []).push(arguments);\n        };\n        window.ga.l = +new Date();\n        window.ga('create', 'UA-1018242-63', 'auto', {\n          userId: MAAS_config.analytics_user_id\n        });\n        window.ga('set', 'dimension1', MAAS_config.version);\n        window.ga('set', 'dimension2', MAAS_config.uuid);\n        $rootScope.$on('$routeChangeSuccess', function() {\n            var path = window.location.pathname + window.location.hash;\n            window.ga('send', 'pageview', path);\n        });\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Browser Service\n *\n * Detects the browser used by the client. This is very simple case, because\n * at the moment we really only care about if the browser is Firefox. This\n * could be improved for other browsers, but this should only be used as a\n * last resort to prevent something bad happening on a misbehaving browser.\n */\n\nangular.module('MAAS').service('BrowserService', ['$window',\n    function($window) {\n\n        // The first items in the array will be matched first. So if the user\n        // agent for the browser contains both you need to make the more\n        // specific one first. E.g. Chrome contains both \"Chrome\" and \"Safari\"\n        // in its user-agent string. Since \"Safari\" does not chrome comes first\n        // so it matches that browser more specifically.\n        var BROWSERS = [\n            {\n                name: \"chrome\",\n                regex: /chrome/i\n            },\n            {\n                name: \"safari\",\n                regex: /safari/i\n            },\n            {\n                name: \"firefox\",\n                regex: /firefox/i\n            },\n            {\n                name: \"ie\",\n                regex: /MSIE/\n            }\n        ];\n\n        this.browser = \"other\";\n\n        // Set the browser if a regex matches. The first to match wins.\n        var self = this;\n        angular.forEach(BROWSERS, function(matcher) {\n            if(matcher.regex.test($window.navigator.userAgent) &&\n                self.browser === \"other\") {\n                self.browser = matcher.name;\n            }\n        });\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Converter Service\n *\n * Used by controllers to convert user inputs.\n */\n\nangular.module('MAAS').service('ConverterService', function() {\n\n        // Case is important: 1kB is 1000 bytes, whereas 1KB is 1024 bytes.\n        // See https://en.wikipedia.org/wiki/Byte#Unit_symbol\n        var UNITS = ['bytes', 'kB', 'MB', 'GB', 'TB'];\n\n        var KILOBYTE = 1000.0;\n        var MEGABYTE = 1000.0 * 1000.0;\n        var GIGABYTE = 1000.0 * 1000.0 * 1000.0;\n        var TERABYTE = 1000.0 * 1000.0 * 1000.0 * 1000.0;\n\n        // Convert the bytes to a unit.\n        this.bytesToUnits = function(bytes) {\n            // Support string being passed.\n            if(angular.isString(bytes)) {\n                bytes = parseInt(bytes, 10);\n            }\n\n            var i, unit, converted = bytes;\n            for(i = 0; i < UNITS.length; i++) {\n                unit = UNITS[i];\n                if(Math.abs(converted) < 1000.0 || unit === 'TB') {\n                    var string = converted.toFixed(1) + \" \" + unit;\n                    if(unit === 'bytes') {\n                        string = converted + \" \" + unit;\n                    }\n                    return {\n                        original: bytes,\n                        converted: converted,\n                        units: unit,\n                        string: string\n                    };\n                }\n                converted /= 1000.0;\n            }\n        };\n\n        // Convert the data based on the unit to bytes.\n        this.unitsToBytes = function(data, unit) {\n            // Support string being passed.\n            if(angular.isString(data)) {\n                data = parseFloat(data);\n            }\n            if(unit === 'bytes') {\n                return Math.floor(data);\n            } else if(unit === 'kB') {\n                return Math.floor(data * KILOBYTE);\n            } else if(unit === 'MB') {\n                return Math.floor(data * MEGABYTE);\n            } else if(unit === 'GB') {\n                return Math.floor(data * GIGABYTE);\n            } else if(unit === 'TB') {\n                return Math.floor(data * TERABYTE);\n            }\n        };\n\n        // Convert the data based on unit down to the lowest tolerance to still\n        // be the same value in that unit.\n        this.roundUnits = function(data, unit) {\n            // Support string being passed.\n            if(angular.isString(data)) {\n                data = parseFloat(data);\n            }\n            if(unit === 'bytes') {\n                return Math.floor(data);\n            } else if(unit === 'kB') {\n                return Math.floor(data * KILOBYTE) - (0.05 * KILOBYTE);\n            } else if(unit === 'MB') {\n                return Math.floor(data * MEGABYTE) - (0.05 * MEGABYTE);\n            } else if(unit === 'GB') {\n                return Math.floor(data * GIGABYTE) - (0.05 * GIGABYTE);\n            } else if(unit === 'TB') {\n                return Math.floor(data * TERABYTE) - (0.05 * TERABYTE);\n            }\n        };\n\n        // Round the bytes down to size based on the block size.\n        this.roundByBlockSize = function(bytes, block_size) {\n            return block_size * Math.floor(bytes / block_size);\n        };\n\n        // Convert string ipv4 address into octets array.\n        this.ipv4ToOctets = function(ipAddress) {\n            var parts = ipAddress.split('.');\n            var octets = [];\n            angular.forEach(parts, function(part) {\n                octets.push(parseInt(part, 10));\n            });\n            return octets;\n        };\n\n        // Convert string ipv4 address into integer.\n        this.ipv4ToInteger = function(ipAddress) {\n            var octets = this.ipv4ToOctets(ipAddress);\n            return (\n                (octets[0] * Math.pow(256,3)) +\n                (octets[1] * Math.pow(256,2)) +\n                (octets[2] * 256) + octets[3]);\n        };\n\n        // Convert ipv6 address to a full ipv6 address, removing the\n        // '::' shortcut and padding each group with zeros.\n        this.ipv6Expand = function(ipAddress) {\n            var i, expandedAddress = ipAddress;\n            if(expandedAddress.indexOf(\"::\") !== -1) {\n                // '::' is present so replace it with the required\n                // number of '0000:' based on its location in the string.\n                var split = ipAddress.split(\"::\");\n                var groups = 0;\n                for(i = 0; i < split.length; i++) {\n                    groups += split[i].split(\":\").length;\n                }\n                expandedAddress = split[0] + \":\";\n                for(i = 0; i < 8 - groups; i++) {\n                    expandedAddress += \"0000:\";\n                }\n                expandedAddress += split[1];\n            }\n            // Pad the output of each part with zeros.\n            var output = [], parts = expandedAddress.split(\":\");\n            angular.forEach(parts, function(part) {\n                output.push(\"0000\".substr(part.length) + part);\n            });\n            return output.join(\":\");\n        };\n\n        // Convert string ipv6 into groups array.\n        this.ipv6ToGroups = function(ipAddress) {\n            var groups = [];\n            var parts = this.ipv6Expand(ipAddress).split(\":\");\n            angular.forEach(parts, function(part) {\n                groups.push(parseInt(part, 16));\n            });\n            return groups;\n        };\n    });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Error Service\n */\n\nangular.module('MAAS').service('ErrorService', function() {\n\n        // Holds the client error.\n        this._error = null;\n\n        // Raise this error in the UI.\n        this.raiseError = function(error) {\n            // Possible that this method is called more than once.\n            // Only take the first error.\n            if(!angular.isString(this._error)) {\n                this._error = error;\n            }\n        };\n    });\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS JSON Service\n *\n * Used by controllers to parse JSON.\n */\n\nangular.module('MAAS').service('JSONService', function() {\n\n    // Return the JSON for the string or null if it cannot be parsed.\n    this.tryParse = function(jsonString) {\n        try {\n            var obj = JSON.parse(jsonString);\n            // JSON.parse(false) or JSON.parse(1234) will throw errors, but\n            // JSON.parse(null) returns 'null', and typeof null === \"object\".\n            if (obj && typeof obj === \"object\" && obj !== null) {\n                return obj;\n            }\n        }\n        catch (e) { }\n        return null;\n    };\n});\n","/* Copyright 2017 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Log Service\n *\n * Allows logging to be enabled or disabled, and allows a particular log level\n * to be set, which will allow logs of a specified importance (or more) to be\n * seen.\n *\n * Also appends a time index (in seconds, accurate to milliseconds) to the\n * beginning of the log string.\n */\n\nangular.module('MAAS').service('LogService', [\n    '$window', function($window) {\n        var self = this;\n\n        // Global enable/disable for MAAS logging. If set to `false`, this\n        // value takes precedence over the logLevel.\n        self.logging = true;\n\n        // Specifies the log level.\n        // Level 1: error() logging\n        // Level 2: error() and warn() logging\n        // Level 3: all of the above, plus info()\n        // Level 4: all of the above, plus log()\n        // Level 5: all of the above, plus debug()\n        self.logLevel = 5;\n\n        // Returns a monotonic time (in milliseconds) since page load.\n        self.now = function() {\n            return $window.performance ? $window.performance.now() : 0;\n        };\n\n        // Standard logging functions.\n        self._debug = console.debug;\n        self._log = console.log;\n        self._info = console.info;\n        self._warn = console.warn;\n        self._error = console.error;\n\n        // Formats the specified time (in milliseconds) in seconds.\n        this.formatMilliseconds = function(milliseconds) {\n            return parseFloat(milliseconds / 1000.0).toFixed(3);\n        };\n\n        // Internal function to log using the specified destination, with the\n        // specified list of arguments.\n        this.__log = function(destination, args) {\n            if(self.logging === true) {\n                // Add time index to the beginning of the log.\n                Array.prototype.unshift.call(args,\n                    \"[\" + self.formatMilliseconds(self.now()) + \"]\");\n                destination.apply(self, args);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._debug().\n        this.debug = function() {\n            if(self.logLevel >= 5) {\n                self.__log(self._debug, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._log().\n        this.log = function() {\n            if(self.logLevel >= 4) {\n                self.__log(self._log, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._info().\n        this.info = function() {\n            if(self.logLevel >= 3) {\n                self.__log(self._info, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._warn().\n        this.warn = function() {\n            if(self.logLevel >= 2) {\n                self.__log(self._warn, arguments);\n            }\n        };\n\n        // Wrapper to check the log level and then call self._err().\n        this.error = function() {\n            if(self.logLevel >= 1) {\n                self.__log(self._error, arguments);\n            }\n        };\n    }\n]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Base Manager\n *\n * Manages a collection of items from the websocket in the browser. The manager\n * uses the RegionConnection to load the items, update the items, and listen\n * for notification events about the items.\n */\n\nangular.module('MAAS').service(\n    'Manager',\n    ['$q', '$rootScope', '$timeout', 'RegionConnection', function(\n            $q, $rootScope, $timeout, RegionConnection) {\n\n        // Actions that are used to update the statuses metadata.\n        var METADATA_ACTIONS = {\n            CREATE: \"create\",\n            UPDATE: \"update\",\n            DELETE: \"delete\"\n        };\n\n        // Constructor\n        function Manager() {\n            // Primary key on the items in the list. Used to match items.\n            this._pk = \"id\";\n\n            // Key used when loading batches. Typically the same as _pk\n            // but not always.\n            this._batchKey = \"id\";\n\n            // The field from which to get a human-readable name.\n            this._name_field = \"name\";\n\n            // Handler on the region to call to list, create, update, delete,\n            // and listen for notifications. Must be set by overriding manager.\n            this._handler = null;\n\n            // Holds all items in the system. This list must always be the same\n            // object.\n            this._items = [];\n\n            // The way this manager recieves its updated information. 'notify'\n            // means this manager recieved notify messages from the websocket.\n            // See PollingManager for the other possible type. This is only\n            // used by the `ManagerHelperService` to identify how updating\n            // the data should be handled.\n            this._type = 'notify';\n\n            // Holds list of scopes that currently have this manager loaded.\n            this._scopes = [];\n\n            // True when all of the items have been loaded. This is done on\n            // intial connection to the region.\n            this._loaded = false;\n\n            // True when the items list is currently being loaded or reloaded.\n            // Actions will not be processed while this is false.\n            this._isLoading = false;\n\n            // Holds list of defers that need to be called once the loading of\n            // items has finished. This is used when a caller calls loadItems\n            // when its already loading.\n            this._extraLoadDefers = [];\n\n            // Holds list of defers that need to be called once the reloading\n            // of items has finished. This is used when a caller calls\n            // reloadItems when its already reloading.\n            this._extraReloadDefers = [];\n\n            // Holds all of the notify actions that need to be processed. This\n            // is used to hold the actions while the items are being loaded.\n            // Once all of the items are loaded the queue will be processed.\n            this._actionQueue = [];\n\n            // Holds list of all of the currently selected items. This is held\n            // in a seperate list to remove the need to loop through the full\n            // listing to grab the selected items.\n            this._selectedItems = [];\n\n            // Set to true when the items list should reload upon re-connection\n            // to the region.\n            this._autoReload = false;\n\n            // Holds the item that is currenly being viewed. This object will\n            // be updated if any notify events are recieved for it. This allows\n            // the ability of not having to keep pulling the item out of the\n            // items list.\n            this._activeItem = null;\n\n            // Holds metadata information that is used to helper filtering.\n            this._metadata = {};\n\n            // List of attributes to track on the loaded items. Each attribute\n            // in this list will be placed in _metadata to track its currect\n            // values and the number of items with that value.\n            this._metadataAttributes = [];\n        }\n\n        // Return index of the item in the given array.\n        Manager.prototype._getIndexOfItem = function(array, pk_value) {\n            var i;\n            for(i = 0, len = array.length; i < len; i++) {\n                if(array[i][this._pk] === pk_value) {\n                    return i;\n                }\n            }\n            return -1;\n        };\n\n        // Replace the item in the array at the same index.\n        Manager.prototype._replaceItemInArray = function(array, item) {\n            var idx = this._getIndexOfItem(array, item[this._pk]);\n            if(idx >= 0) {\n                // Keep the current selection on the item.\n                item.$selected = array[idx].$selected;\n                angular.copy(item, array[idx]);\n            }\n        };\n\n        // Remove the item from the array.\n        Manager.prototype._removeItemByIdFromArray = function(\n            array, pk_value) {\n            var idx = this._getIndexOfItem(array, pk_value);\n            if(idx >= 0) {\n                array.splice(idx, 1);\n            }\n        };\n\n        // Return the parameters that should be used for the batch load\n        // request. Should be used by subclass that want to add extra\n        // parameters to the batch request. By default it returns an empty\n        // object.\n        Manager.prototype._initBatchLoadParameters = function() {\n            return {};\n        };\n\n        // Batch load items from the region in groups of 50.\n        Manager.prototype._batchLoadItems = function(array, extra_func) {\n            var self = this;\n            var defer = $q.defer();\n            var method = this._handler + \".list\";\n            function callLoad() {\n                var params = self._initBatchLoadParameters();\n                params.limit = 50;\n\n                // Get the last batchKey in the list so the region knows to\n                // start at that offset.\n                if(array.length > 0) {\n                    params.start = array[array.length-1][self._batchKey];\n                }\n                RegionConnection.callMethod(\n                    method, params).then(function(items) {\n                        // Pass each item to extra_func function if given.\n                        if(angular.isFunction(extra_func)) {\n                            angular.forEach(items, function(item) {\n                                extra_func(item);\n                            });\n                        }\n\n                        array.push.apply(array, items);\n                        if(items.length === 50) {\n                            // Could be more items, request the next 50.\n                            callLoad(array);\n                        } else {\n                            defer.resolve(array);\n                        }\n                    }, defer.reject);\n            }\n            callLoad();\n            return defer.promise;\n        };\n\n        // Resolves array of defers with item.\n        Manager.prototype._resolveDefers = function(defersArray, item) {\n            angular.forEach(defersArray, function(defer) {\n                defer.resolve(item);\n            });\n        };\n\n        // Rejects array of defers with error.\n        Manager.prototype._rejectDefers = function(defersArray, error) {\n            angular.forEach(defersArray, function(defer) {\n                defer.reject(error);\n            });\n        };\n\n        // Return list of items.\n        Manager.prototype.getItems = function() {\n            return this._items;\n        };\n\n        // Clears the currect state of the manager.\n        Manager.prototype.clear = function() {\n            this._loaded = false;\n            this._items.length = 0;\n            this._actionQueue.length = 0;\n            this._selectedItems.length = 0;\n            this._activeItem = null;\n            this._metadata = {};\n            this._metadataAttributes.length = 0;\n        };\n\n        // Load all the items.\n        Manager.prototype.loadItems = function() {\n            // If the items have already been loaded then, we need to\n            // reload the items list not load the initial list.\n            if(this._loaded) {\n                return this.reloadItems();\n            }\n\n            // If its already loading then the caller just needs to be informed\n            // of when it has finished loading.\n            if(this._isLoading) {\n                var defer = $q.defer();\n                this._extraLoadDefers.push(defer);\n                return defer.promise;\n            }\n\n            var self = this;\n            this._isLoading = true;\n            return this._batchLoadItems(this._items, function(item) {\n                item.$selected = false;\n                self._updateMetadata(item, METADATA_ACTIONS.CREATE);\n                self._processItem(item);\n            }).then(function() {\n                self._loaded = true;\n                self._isLoading = false;\n                self.processActions();\n                self._resolveDefers(self._extraLoadDefers, self._items);\n                self._extraLoadDefers = [];\n                return self._items;\n            }, function(error) {\n                self._rejectDefers(self._extraLoadDefers, error);\n                self._extraLoadDefers = [];\n                return $q.reject(error);\n            });\n        };\n\n        // Reload the items list.\n        Manager.prototype.reloadItems = function() {\n            // If the items have not been loaded then, we need to\n            // load the initial list.\n            if(!this._loaded) {\n                return this.loadItems();\n            }\n\n            // If its already reloading then the caller just needs to be\n            // informed of when it has refinished loading.\n            if(this._isLoading) {\n                var defer = $q.defer();\n                this._extraReloadDefers.push(defer);\n                return defer.promise;\n            }\n\n            // Updates the items list with the reloaded items.\n            var self = this;\n            function updateItems(items) {\n                // Iterate in reverse so we can remove items inline, without\n                // having to adjust the index.\n                var i = self._items.length;\n                while(i--) {\n                    var item = self._items[i];\n                    var updatedIdx = self._getIndexOfItem(\n                        items, item[self._pk]);\n                    if(updatedIdx === -1) {\n                        self._updateMetadata(item, METADATA_ACTIONS.DELETE);\n                        self._items.splice(i, 1);\n                        self._removeItemByIdFromArray(\n                            self._selectedItems, item[self._pk]);\n                    } else {\n                        var updatedItem = items[updatedIdx];\n                        self._updateMetadata(\n                            updatedItem, METADATA_ACTIONS.UPDATE);\n                        updatedItem.$selected = item.$selected;\n                        angular.copy(items[updatedIdx], item);\n                        items.splice(updatedIdx, 1);\n                    }\n                }\n\n                // The remain items in items array are the new items.\n                angular.forEach(items, function(item) {\n                    self._items.push(item);\n                    self._processItem(item);\n                });\n            }\n\n            // The reload action loads all of the items into this list\n            // instead of the items list. This list will then be used to\n            // update the items list.\n            var currentItems = [];\n\n            // Start the reload process and once complete call updateItems.\n            self._isLoading = true;\n            return this._batchLoadItems(currentItems).then(function(items) {\n                updateItems(items);\n                self._isLoading = false;\n                self.processActions();\n\n                // Set the activeItem again so the region knows that its\n                // the active item.\n                if(angular.isObject(self._activeItem)) {\n                    self.setActiveItem(self._activeItem[self._pk]);\n                }\n\n                self._resolveDefers(self._extraReloadDefers, self._items);\n                self._extraReloadDefers = [];\n                return self._items;\n            }, function(error) {\n                self._rejectDefers(self._extraReloadDefers, error);\n                self._extraReloadDefers = [];\n                return $q.reject(error);\n            });\n        };\n\n        // Enables auto reloading of the item list on connection to region.\n        Manager.prototype.enableAutoReload = function() {\n            if(!this._autoReload) {\n                this._autoReload = true;\n                var self = this;\n                this._reloadFunc = function() {\n                    self.reloadItems();\n                };\n                RegionConnection.registerHandler(\"open\", this._reloadFunc);\n            }\n        };\n\n        // Disable auto reloading of the item list on connection to region.\n        Manager.prototype.disableAutoReload = function() {\n            if(this._autoReload) {\n                RegionConnection.unregisterHandler(\"open\", this._reloadFunc);\n                this._reloadFunc = null;\n                this._autoReload = false;\n            }\n        };\n\n        // True when the initial item list has finished loading.\n        Manager.prototype.isLoaded = function() {\n            return this._loaded;\n        };\n\n        // True when the item list is currently being loaded or reloaded.\n        Manager.prototype.isLoading = function() {\n            return this._isLoading;\n        };\n\n        // Allow for extra processing of items as they are added or updated.\n        Manager.prototype._processItem = function(item) {\n        };\n\n        // Replace item in the items and selectedItems list.\n        Manager.prototype._replaceItem = function(item) {\n            this._updateMetadata(item, METADATA_ACTIONS.UPDATE);\n            this._replaceItemInArray(this._items, item);\n        };\n\n        // Remove item in the items and selectedItems list.\n        Manager.prototype._removeItem = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx >= 0) {\n                this._updateMetadata(this._items[idx], METADATA_ACTIONS.DELETE);\n            }\n            this._removeItemByIdFromArray(this._items, pk_value);\n            this._removeItemByIdFromArray(this._selectedItems, pk_value);\n        };\n\n        // Get the item from the list. Does not make a get request to the\n        // region to load more data.\n        Manager.prototype.getItemFromList = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx >= 0) {\n                return this._items[idx];\n            } else {\n                return null;\n            }\n        };\n\n        // Get the item from the region.\n        Manager.prototype.getItem = function(pk_value) {\n            var self = this;\n            var method = this._handler + \".get\";\n            var params = {};\n            params[this._pk] = pk_value;\n            return RegionConnection.callMethod(\n                method, params).then(function(item) {\n                    self._replaceItem(item);\n                    return item;\n                });\n        };\n\n        // Send the create information to the region.\n        Manager.prototype.createItem = function(item) {\n            var self = this;\n            var method = this._handler + \".create\";\n            item = angular.copy(item);\n            delete item.$selected;\n            return RegionConnection.callMethod(\n                method, item).then(function(item) {\n                    self._replaceItem(item);\n                    return item;\n                });\n        };\n\n        // Send the update information to the region.\n        Manager.prototype.updateItem = function(item) {\n            var self = this;\n            var method = this._handler + \".update\";\n            item = angular.copy(item);\n            delete item.$selected;\n            return RegionConnection.callMethod(\n                method, item).then(function(item) {\n                    self._replaceItem(item);\n                    return item;\n                });\n        };\n\n        // Send the delete call for item to the region.\n        Manager.prototype.deleteItem = function(item) {\n            var self = this;\n            var method = this._handler + \".delete\";\n            var params = {};\n            params[this._pk] = item[this._pk];\n            return RegionConnection.callMethod(\n                method, params).then(function() {\n                    self._removeItem(item[self._pk]);\n                });\n        };\n\n        // Return the active item.\n        Manager.prototype.getActiveItem = function() {\n            return this._activeItem;\n        };\n\n        // Set the active item.\n        Manager.prototype.setActiveItem = function(pk_value) {\n            if(!this._loaded) {\n                throw new Error(\n                    \"Cannot set active item unless the manager is loaded.\");\n            }\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                this._activeItem = null;\n                // Item with pk_value does not exists. Reject the returned\n                // deferred.\n                var defer = $q.defer();\n                $timeout(function() {\n                    defer.reject(\"No item with pk: \" + pk_value);\n                });\n                return defer.promise;\n            } else {\n                this._activeItem = this._items[idx];\n                // Data that is loaded from the list call is limited and\n                // doesn't contain all of the needed data for an activeItem.\n                // Call set_active on the handler for the region to know\n                // this item needs all information when updated.\n                var self = this;\n                var method = this._handler + \".set_active\";\n                var params = {};\n                params[this._pk] = pk_value;\n                return RegionConnection.callMethod(\n                    method, params).then(function(item) {\n                        self._replaceItem(item);\n                        return self._activeItem;\n                    });\n            }\n        };\n\n        // Clears the active item.\n        Manager.prototype.clearActiveItem = function() {\n            this._activeItem = null;\n        };\n\n        // True when the item list is stable and not being loaded or reloaded.\n        Manager.prototype.canProcessActions = function() {\n            return !this._isLoading;\n        };\n\n        // Handle notify from RegionConnection about an item.\n        Manager.prototype.onNotify = function(action, data) {\n            // Place the notification in the action queue.\n            this._actionQueue.push({\n                action: action,\n                data: data\n            });\n            // Processing incoming actions is enabled. Otherwise they\n            // will be queued until processActions is called.\n            if(this.canProcessActions()) {\n               $rootScope.$apply(this.processActions());\n            }\n        };\n\n        // Process all actions to keep the item information up-to-date.\n        Manager.prototype.processActions = function() {\n            while(this._actionQueue.length > 0) {\n                var action = this._actionQueue.shift();\n                if(action.action === \"create\") {\n                    // Check that the received data doesn't already exists\n                    // in the _items list. If it does then this is actually\n                    // an update action not a create action.\n                    var idx = this._getIndexOfItem(\n                        this._items, action.data[this._pk]);\n                    if(idx >= 0) {\n                        // Actually this is an update action not a create\n                        // action. So replace the item instead of adding it.\n                        this._replaceItem(action.data);\n                    } else {\n                        action.data.$selected = false;\n                        this._updateMetadata(\n                            action.data, METADATA_ACTIONS.CREATE);\n                        this._items.push(action.data);\n                    }\n                    this._processItem(action.data);\n                } else if(action.action === \"update\") {\n                    this._replaceItem(action.data);\n                    this._processItem(action.data);\n                } else if(action.action === \"delete\") {\n                    this._removeItem(action.data);\n                }\n            }\n        };\n\n        // Return list of selected items.\n        Manager.prototype.getSelectedItems = function() {\n            return this._selectedItems;\n        };\n\n        // Mark the given item as selected.\n        Manager.prototype.selectItem = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                console.log(\n                    \"WARN: selection of \" + this._handler + \"(\" + pk_value +\n                    \") failed because its missing in the items list.\");\n                return;\n            }\n\n            var item = this._items[idx];\n            item.$selected = true;\n\n            idx = this._selectedItems.indexOf(item);\n            if(idx === -1) {\n                this._selectedItems.push(item);\n            }\n        };\n\n        // Mark the given item as unselected.\n        Manager.prototype.unselectItem = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                console.log(\n                    \"WARN: de-selection of \" + this._handler + \"(\" +\n                    pk_value + \") failed because its missing in the \" +\n                    \"nodes list.\");\n                return;\n            }\n\n            var item = this._items[idx];\n            item.$selected = false;\n\n            idx = this._selectedItems.indexOf(item);\n            if(idx >= 0) {\n                this._selectedItems.splice(idx, 1);\n            }\n        };\n\n        // Determine if a item is selected.\n        Manager.prototype.isSelected = function(pk_value) {\n            var idx = this._getIndexOfItem(this._items, pk_value);\n            if(idx === -1) {\n                console.log(\n                    \"WARN: unable to determine if \" + this._handler + \"(\" +\n                    pk_value + \") is selected because its missing in the \" +\n                    \"nodes list.\");\n                return false;\n            }\n\n            return this._items[idx].$selected === true;\n        };\n\n        // Return the metadata object value from `metadatas` matching `name`.\n        Manager.prototype._getMetadataValue = function(metadatas, name) {\n            var i;\n            for(i = 0; i < metadatas.length; i++) {\n                if(metadatas[i].name === name) {\n                    return metadatas[i];\n                }\n            }\n            return null;\n        };\n\n        // Add new value to metadatas if it doesnt exists or increment the\n        // count if it already does.\n        Manager.prototype._addMetadataValue = function(metadatas, value) {\n            var metadata = this._getMetadataValue(metadatas, value);\n            if(metadata) {\n                metadata.count += 1;\n            } else {\n                metadata = {\n                    name: value,\n                    count: 1\n                };\n                metadatas.push(metadata);\n            }\n        };\n\n        // Remove value from metadatas.\n        Manager.prototype._removeMetadataValue = function(metadatas, value) {\n            var metadata = this._getMetadataValue(metadatas, value);\n            if(metadata) {\n                metadata.count -= 1;\n                if(metadata.count <= 0) {\n                    metadatas.splice(metadatas.indexOf(metadata), 1);\n                }\n            }\n        };\n\n        // Update the metadata entry in `metadatas` for the array value and\n        // based on the action.\n        Manager.prototype._updateMetadataArrayEntry = function(\n                metadatas, newValue, action, oldValue) {\n            var self = this;\n\n            if(action === METADATA_ACTIONS.CREATE) {\n                angular.forEach(newValue, function(value) {\n                    // On create ignore empty values.\n                    if(value === '') {\n                        return;\n                    }\n                    self._addMetadataValue(metadatas, value);\n                });\n            } else if(action === METADATA_ACTIONS.DELETE) {\n                angular.forEach(newValue, function(value) {\n                    self._removeMetadataValue(metadatas, value);\n                });\n            } else if(action === METADATA_ACTIONS.UPDATE &&\n                angular.isDefined(oldValue)) {\n                // Any values in added are new on the item, and any values left\n                // in oldArray have been removed.\n                var added = [];\n                var oldArray = angular.copy(oldValue);\n                angular.forEach(newValue, function(value) {\n                    var idx = oldArray.indexOf(value);\n                    if(idx === -1) {\n                        // Value not in oldArray so it has been added.\n                        added.push(value);\n                    } else {\n                        // Value already in oldArray so its already tracked.\n                        oldArray.splice(idx, 1);\n                    }\n                });\n\n                // Add the new values.\n                angular.forEach(added, function(value) {\n                    self._addMetadataValue(metadatas, value);\n                });\n\n                // Remove the old values.\n                angular.forEach(oldArray, function(value) {\n                    self._removeMetadataValue(metadatas, value);\n                });\n            }\n        };\n\n        // Update the metadata entry in `metadatas` for the newValue and based\n        // on the action. Method does not work with array values, use\n        // _updateMetadataArrayEntry for values that are arrays.\n        Manager.prototype._updateMetadataValueEntry = function(\n                metadatas, newValue, action, oldValue) {\n            if(action === METADATA_ACTIONS.CREATE) {\n                // On create ignore empty values.\n                if(newValue === '') {\n                    return;\n                }\n                this._addMetadataValue(metadatas, newValue);\n            } else if(action === METADATA_ACTIONS.DELETE) {\n                this._removeMetadataValue(metadatas, newValue);\n            } else if(action === METADATA_ACTIONS.UPDATE &&\n                angular.isDefined(oldValue)) {\n                if(oldValue !== newValue) {\n                    if(oldValue !== \"\") {\n                        // Decrement the old value\n                        this._removeMetadataValue(metadatas, oldValue);\n                    }\n\n                    // Increment the new value with the \"create\"\n                    // operation.\n                    this._updateMetadataEntry(\n                        metadatas, newValue, METADATA_ACTIONS.CREATE, oldValue);\n                }\n            }\n        };\n\n        // Update the metadata entry in `metadatas` with the newValue and based\n        // on the action. Update action will use the oldValue to remove it from\n        // the metadata.\n        Manager.prototype._updateMetadataEntry = function(\n                metadatas, newValue, action, oldValue) {\n            if(angular.isArray(newValue)) {\n                this._updateMetadataArrayEntry(\n                    metadatas, newValue, action, oldValue);\n            } else {\n                this._updateMetadataValueEntry(\n                    metadatas, newValue, action, oldValue);\n            }\n        };\n\n        // Return the metadata object.\n        Manager.prototype.getMetadata = function() {\n            return this._metadata;\n        };\n\n        // Update the metadata objects based on the given item and action.\n        Manager.prototype._updateMetadata = function(item, action) {\n            var self = this;\n            var oldItem, idx;\n            if(action === METADATA_ACTIONS.UPDATE) {\n                // Update actions require the oldItem if it exist in the\n                // current item listing.\n                idx = this._getIndexOfItem(this._items, item[this._pk]);\n                if(idx >= 0) {\n                    oldItem = this._items[idx];\n                }\n            }\n            angular.forEach(this._metadataAttributes, function(func, attr) {\n                if(angular.isUndefined(self._metadata[attr])) {\n                    self._metadata[attr] = [];\n                }\n                var newValue, oldValue;\n                if(angular.isFunction(func)) {\n                    newValue = func(item);\n                    if(angular.isObject(oldItem)) {\n                        oldValue = func(oldItem);\n                    }\n                } else {\n                    newValue = item[attr];\n                    if(angular.isObject(oldItem)) {\n                        oldValue = oldItem[attr];\n                    }\n                }\n                self._updateMetadataEntry(\n                    self._metadata[attr], newValue, action, oldValue);\n            });\n        };\n\n        // Default implementation of getName(): returns the default name for\n        // this object, if it exists.\n        Manager.prototype.getName = function(obj) {\n            if(!angular.isObject(obj)) {\n                return;\n            }\n            if(angular.isString(obj[this._name_field])) {\n                return obj[this._name_field];\n            }\n        };\n\n        return Manager;\n    }]);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Manager Helper Service\n *\n * Used by controllers to load managers. It helps the initialization of\n * managers and makes sure that all items in the manager are loaded\n * before resolving the defer.\n */\n\nangular.module('MAAS').service('ManagerHelperService', [\n    '$q', '$timeout', 'ErrorService', 'RegionConnection',\n    function($q, $timeout, ErrorService, RegionConnection) {\n\n        // Loads the manager.\n        this.loadManager = function(scope, manager) {\n            var defer = $q.defer();\n\n            // If the manager already has this scope loaded then nothing needs\n            // to be done.\n            if(manager._scopes.indexOf(scope) > -1) {\n                $timeout(function() {\n                    defer.resolve(manager);\n                });\n                return defer.promise;\n            }\n\n            // Do this entire operation with in the context of the region\n            // connection is connected.\n            RegionConnection.defaultConnect().then(function() {\n                if(manager._type === 'notify') {\n                    if(manager.isLoaded()) {\n                        $timeout(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        });\n                    } else {\n                        manager.loadItems().then(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                    }\n                    // Always enable auto reload. This will make sure the items\n                    // are reloaded if the connection goes down.\n                    manager.enableAutoReload();\n\n                    // Remove the scope for the loaded scopes for the manager.\n                    scope.$on(\"$destroy\", function() {\n                        var idx = manager._scopes.indexOf(scope);\n                        if(idx > -1) {\n                            manager._scopes.splice(idx, 1);\n                        }\n                    });\n                } else if(manager._type === 'poll') {\n                    if(manager.isPolling()) {\n                        $timeout(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        });\n                    } else {\n                        manager.startPolling().then(function() {\n                            manager._scopes.push(scope);\n                            defer.resolve(manager);\n                        }, function(error) {\n                            ErrorService.raiseError(error);\n                        });\n                    }\n\n                    // Stop the polling when the scope is destroyed and its\n                    // not in use by any other scopes.\n                    scope.$on(\"$destroy\", function() {\n                        var idx = manager._scopes.indexOf(scope);\n                        if(idx > -1) {\n                            manager._scopes.splice(idx, 1);\n                        }\n                        if(manager._scopes.length === 0) {\n                            manager.stopPolling();\n                        }\n                    });\n                } else {\n                    throw new Error(\"Unknown manager type: \" + manager._type);\n                }\n            });\n            return defer.promise;\n        };\n\n        // Gets the list of managers.\n        this.loadManagers = function(scope, managers) {\n            var defer = $q.defer();\n            var loadedManagers = [];\n\n            // Resolves the defer if all managers are loaded.\n            var resolveAllLoaded = function() {\n                if(loadedManagers.length === managers.length) {\n                    defer.resolve(managers);\n                }\n            };\n\n            var self = this;\n            angular.forEach(managers, function(manager) {\n                self.loadManager(scope, manager).then(function(loadedManager) {\n                    loadedManagers.push(loadedManager);\n                    resolveAllLoaded();\n                });\n            });\n            return defer.promise;\n        };\n\n        // Tries to parse the specified string as JSON. If parsing fails,\n        // returns the original string. (This is useful since some manager\n        // calls return an error that could be either plain text, or JSON.)\n        this.tryParsingJSON = function(string) {\n            var error;\n            try {\n                error = JSON.parse(string);\n            } catch(e) {\n                if (e instanceof SyntaxError) {\n                    return string;\n                } else {\n                    throw e;\n                }\n            }\n            return error;\n        };\n\n        // Returns a printable version of the specified dictionary (useful\n        // for displaying an error to the user).\n        this.getPrintableString = function(dict, showNames) {\n            var result = '';\n            angular.forEach(dict, function(value, key) {\n                var error = dict[key];\n                if(showNames === true) {\n                    result += key + \": \";\n                }\n                if(angular.isString(error) || angular.isNumber(error)) {\n                    result += error + \"  \";\n                } else if(angular.isObject(error)) {\n                    angular.forEach(error, function(error) {\n                        result += error + \"  \";\n                    });\n                }\n                result = result.trim() + \"\\n\";\n            });\n            return result.trim();\n        };\n\n        // Convert the Python dict error message to displayed message.\n        // We know it's probably a form ValidationError dictionary, so just use\n        // it as such, and recover if that doesn't parse as JSON.\n        this.parseValidationError = function(error, showNames) {\n            error = this.tryParsingJSON(error);\n            if(!angular.isObject(error)) {\n                return error;\n            } else {\n                return this.getPrintableString(error, showNames);\n            }\n        };\n    }]);\n","/* Copyright 2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Space Manager\n *\n * Manages all of the spaces in the browser. The manager uses the\n * RegionConnection to load the spaces, update the spaces, and listen for\n * notification events about spaces.\n */\n\nangular.module('MAAS').factory(\n    'PollingManager',\n    ['$q', '$timeout', 'RegionConnection', 'Manager',\n    function($q, $timeout, RegionConnection, Manager) {\n\n        function PollingManager() {\n            Manager.call(this);\n\n            // The way this manager recieves its updated information. 'poll'\n            // means this manager periodicly polls for new data from the\n            // websocket.\n            this._type = 'poll';\n\n            // Set to true when polling has been enabled.\n            this._polling = false;\n\n            // The next promise for the polling interval.\n            this._nextPromise = null;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data.\n            this._pollTimeout = 10000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when an error occurs.\n            this._pollErrorTimeout = 3000;\n\n            // Amount of time in milliseconds the manager should wait to poll\n            // for new data when the retrieved data is empty.\n            this._pollEmptyTimeout = 3000;\n        }\n\n        PollingManager.prototype = new Manager();\n\n        // Returns true when currently polling.\n        PollingManager.prototype.isPolling = function() {\n            return this._polling;\n        };\n\n        // Starts the polling.\n        PollingManager.prototype.startPolling = function() {\n            if(!this._polling) {\n                this._polling = true;\n                return this._poll();\n            } else {\n                return this._nextPromise;\n            }\n        };\n\n        // Stops the polling.\n        PollingManager.prototype.stopPolling = function() {\n            this._polling = false;\n            if(angular.isObject(this._nextPromise)) {\n                $timeout.cancel(this._nextPromise);\n                this._nextPromise = null;\n            }\n        };\n\n        // Registers the next polling attempt.\n        PollingManager.prototype._pollAgain = function(timeout) {\n            var self = this;\n            this._nextPromise = $timeout(function() {\n                self._poll();\n            }, timeout);\n            return this._nextPromise;\n        };\n\n        // Polls for the data from the region.\n        PollingManager.prototype._poll = function() {\n            var self = this;\n            return this.reloadItems().then(function(items) {\n                var pollTimeout = self._pollTimeout;\n                if(items.length === 0) {\n                    pollTimeout = self._pollEmptyTimeout;\n                }\n                self._pollAgain(pollTimeout);\n                return items;\n            }, function(error) {\n                self._pollAgain(self._pollErrorTimeout);\n                return $q.reject(error);\n            });\n        };\n\n        return PollingManager;\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Nodes Search Services\n */\n\nangular.module('MAAS').service('SearchService', function() {\n\n    // Holds an empty filter object.\n    var emptyFilter = { _: [] };\n\n    // Return a new empty filter;\n    this.getEmptyFilter = function() {\n        return angular.copy(emptyFilter);\n    };\n\n    // Splits the search string into different terms based on white space.\n    // This handles the ability for whitespace to be inside of '(', ')'.\n    //\n    // XXX blake_r 28-01-15: This could be improved with a regex, but was\n    // unable to come up with one that would allow me to validate the end\n    // ')' in the string.\n    this.getSplitSearch = function(search) {\n        var terms = search.split(' ');\n        var fixedTerms = [];\n        var spanningParentheses = false;\n        angular.forEach(terms, function(term, idx) {\n            if(spanningParentheses) {\n                // Previous term had an opening '(' but not a ')'. This\n                // term should join that previous term.\n                fixedTerms[fixedTerms.length - 1] += ' ' + term;\n\n                // If the term contains the ending ')' then its the last\n                // in the group.\n                if(term.indexOf(')') !== -1) {\n                    spanningParentheses = false;\n                }\n            } else {\n                // Term is not part of a previous '(' span.\n                fixedTerms.push(term);\n\n                var startIdx = term.indexOf('(');\n                if(startIdx !== -1) {\n                    if(term.indexOf(')', startIdx) === -1) {\n                        // Contains a starting '(' but not a ending ')'.\n                        spanningParentheses = true;\n                    }\n                }\n            }\n        });\n\n        if(spanningParentheses) {\n            // Missing ending parentheses so error with terms.\n            return null;\n        }\n        return fixedTerms;\n    };\n\n    // Return all of the currently active filters for the given search.\n    this.getCurrentFilters = function(search) {\n        var filters = this.getEmptyFilter();\n        if(search.length === 0) {\n            return filters;\n        }\n        var searchTerms = this.getSplitSearch(search);\n        if(!searchTerms) {\n            return null;\n        }\n        angular.forEach(searchTerms, function(terms) {\n            terms = terms.split(':');\n            if(terms.length === 1) {\n                // Search term is not specifing a specific field. Gets\n                // add to the '_' section of the filters.\n                if(filters._.indexOf(terms[0]) === -1) {\n                    filters._.push(terms[0]);\n                }\n            } else {\n                var field = terms.shift();\n                var values = terms.join(\":\");\n\n                // Remove the starting '(' and ending ')'.\n                values = values.replace('(', '');\n                values = values.replace(')', '');\n\n                // If empty values then do nothing.\n                if(values.length === 0) {\n                    return;\n                }\n\n                // Split the values based on comma.\n                values = values.split(',');\n\n                // Add the values to filters.\n                if(angular.isUndefined(filters[field])) {\n                    filters[field] = [];\n                }\n                angular.forEach(values, function(value) {\n                    if(filters[field].indexOf(value) === -1) {\n                        filters[field].push(value);\n                    }\n                });\n            }\n        });\n        return filters;\n    };\n\n    // Convert \"filters\" into a search string.\n    this.filtersToString = function(filters) {\n        var search = \"\";\n        angular.forEach(filters, function(terms, type) {\n            // Skip empty and skip \"_\" as it gets appended at the\n            // beginning of the search.\n            if(terms.length === 0 || type === \"_\") {\n                return;\n            }\n            search += type + \":(\" + terms.join(\",\") + \") \";\n        });\n        if(filters._.length > 0) {\n            search = filters._.join(\" \") + \" \" + search;\n        }\n        return search.trim();\n    };\n\n    // Return the index of the value in the type for the filter.\n    this._getFilterValueIndex = function(filters, type, value) {\n        var values = filters[type];\n        if(angular.isUndefined(values)) {\n            return -1;\n        }\n        var lowerValues = values.map(function(value) {\n            return value.toLowerCase();\n        });\n        return lowerValues.indexOf(value.toLowerCase());\n    };\n\n    // Return true if the type and value are in the filters.\n    this.isFilterActive = function(filters, type, value, exact) {\n        var values = filters[type];\n        if(angular.isUndefined(values)) {\n            return false;\n        }\n        if(angular.isUndefined(exact)) {\n            exact = false;\n        }\n        if(exact) {\n            value = \"=\" + value;\n        }\n        return this._getFilterValueIndex(filters, type, value) !== -1;\n    };\n\n    // Toggles a filter on or off based on type and value.\n    this.toggleFilter = function(filters, type, value, exact) {\n        if(angular.isUndefined(filters[type])) {\n            filters[type] = [];\n        }\n        if(exact) {\n            value = \"=\" + value;\n        }\n        var idx = this._getFilterValueIndex(filters, type, value);\n        if(idx === -1) {\n            filters[type].push(value);\n        } else {\n            filters[type].splice(idx, 1);\n        }\n        return filters;\n    };\n\n    // Holds all stored filters.\n    var storedFilters = {};\n\n    // Store a filter for later.\n    this.storeFilters = function(name, filters) {\n        storedFilters[name] = filters;\n    };\n\n    // Retrieve a stored fitler.\n    this.retrieveFilters = function(name) {\n        return storedFilters[name];\n    };\n});\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * MAAS Validation Service\n *\n * Used by controllers to validate user inputs.\n */\n\nangular.module('MAAS').service('ValidationService', [\n    'ConverterService', function(ConverterService) {\n\n        // Pattern that matches a domainname.\n        // XXX 2016-02-24 lamont: This also matches \"example.com.\",\n        // which is wrong.\n        var domainnamePattern =\n            /^([a-z\\d]|[a-z\\d][a-z\\d-.]*[a-z\\d])*$/i;\n\n        // Pattern that matches a hostname.\n        var hostnamePattern =\n            /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])*$/;\n\n        // Pattern that matches a MAC.\n        var macPattern = /^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$/;\n\n        // Pattern used to match IPv4.\n        var ipv4Pattern = new RegExp([\n            '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.',\n            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.',\n            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.',\n            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'\n            ].join(''));\n\n        // Returns true if the octets in one equal two with the cidr mask in\n        // bits applied to both.\n        function cidrMatcher(one, two, size, bits) {\n            var part = 0;\n            while(bits > 0) {\n                var shift = size - bits;\n                if(shift < 0) {\n                    shift = 0;\n                }\n\n                var oneShift = one[part] >> shift;\n                var twoShift = two[part] >> shift;\n                if(oneShift !== twoShift) {\n                    return false;\n                }\n                bits -= size;\n                part += 1;\n            }\n            return true;\n        }\n\n        // Return true if the domainname is valid, false otherwise.\n        this.validateDomainName = function(domainname) {\n            // Invalid if the domain is not a string, empty, or more than\n            // 253 characters.\n            if(!angular.isString(domainname) ||\n                domainname.length === 0 || domainname.length > 253) {\n                return false;\n            }\n            return domainnamePattern.test(domainname);\n        };\n\n        // Return true if the hostname is valid, false otherwise.\n        this.validateHostname = function(hostname) {\n            // Invalid if the hostname is not a string, empty, or more than\n            // 63 characters.\n            if(!angular.isString(hostname) ||\n                hostname.length === 0 || hostname.length > 63) {\n                return false;\n            }\n            return hostnamePattern.test(hostname);\n        };\n\n        // Return true if the MAC is valid, false otherwise.\n        this.validateMAC = function(macAddress) {\n            // Invalid if the macAddress is not a string.\n            if(!angular.isString(macAddress)) {\n                return false;\n            }\n            return macPattern.test(macAddress.trim());\n        };\n\n        // Return true if the IP is valid IPv4 address, false otherwise.\n        this.validateIPv4 = function(ipAddress) {\n            // Invalid if the ipAddress is not a string or empty.\n            if(!angular.isString(ipAddress) || ipAddress.length === 0) {\n                return false;\n            }\n            return ipv4Pattern.test(ipAddress);\n        };\n\n        // Return true if the IP is valid IPv6 address, false otherwise.\n        this.validateIPv6 = function(ipAddress) {\n            // Invalid if the ipAddress is not a string, empty, or missing\n            // at least one ':'.\n            if(!angular.isString(ipAddress) ||\n                ipAddress.length === 0 ||\n                ipAddress.indexOf(':') === -1) {\n                return false;\n            }\n            var expandedAddress = ConverterService.ipv6Expand(ipAddress);\n            var octets = ConverterService.ipv6ToGroups(expandedAddress);\n            if(octets.length !== 8) {\n                return false;\n            }\n\n            // Make sure all octets are in range.\n            var i;\n            for(i = 0; i < 8; i++) {\n                if(isNaN(octets[i]) || octets[i] < 0 || octets[i] > 0xffff) {\n                    // Out of range.\n                    return false;\n                }\n            }\n\n            // Don't allow unspecified, loopback, multicast, link-local\n            // unicast, or anything out of range.\n            if(octets[0] < 1 ||\n                octets[0] === 0xff00 ||\n                octets[0] === 0xfe80) {\n                return false;\n            }\n            return true;\n        };\n\n        // Return true if the IP is valid, false otherwise.\n        this.validateIP = function(ipAddress) {\n            return (\n                this.validateIPv4(ipAddress) || this.validateIPv6(ipAddress));\n        };\n\n        // Return true if the ipAddress is in the network.\n        this.validateIPInNetwork = function(ipAddress, network) {\n            var networkSplit = network.split('/');\n            var networkAddress = networkSplit[0];\n            var cidrBits = parseInt(networkSplit[1], 10);\n\n            if(this.validateIPv4(ipAddress) &&\n                this.validateIPv4(networkAddress)) {\n                return cidrMatcher(\n                    ConverterService.ipv4ToOctets(ipAddress),\n                    ConverterService.ipv4ToOctets(networkAddress),\n                    8, cidrBits);\n            } else if(this.validateIPv6(ipAddress) &&\n                this.validateIPv6(networkAddress)) {\n                return cidrMatcher(\n                    ConverterService.ipv6ToGroups(ipAddress),\n                    ConverterService.ipv6ToGroups(networkAddress),\n                    16, cidrBits);\n            }\n            return false;\n        };\n\n        // Return true if the ipAddress is in the network and between the\n        // lowAddress and highAddress inclusive.\n        this.validateIPInRange = function(\n            ipAddress, network, lowAddress, highAddress) {\n            // If the ip address is not even in the network then its\n            // not in the range.\n            if(!this.validateIPInNetwork(ipAddress, network)) {\n                return false;\n            }\n\n            var i, ipOctets, lowOctets, highOctets;\n            if(this.validateIPv4(ipAddress) &&\n                this.validateIPv4(lowAddress) &&\n                this.validateIPv4(highAddress)) {\n\n                // Check that each octet is of the ip address is more or equal\n                // to the low address and less or equal to the high address.\n                ipOctets = ConverterService.ipv4ToOctets(ipAddress);\n                lowOctets = ConverterService.ipv4ToOctets(lowAddress);\n                highOctets = ConverterService.ipv4ToOctets(highAddress);\n                for(i = 0; i < 4; i++) {\n                    if(ipOctets[i] > highOctets[i] ||\n                        ipOctets[i] < lowOctets[i]) {\n                        return false;\n                    }\n                }\n                return true;\n            } else if(this.validateIPv6(ipAddress) &&\n                this.validateIPv6(lowAddress) &&\n                this.validateIPv6(highAddress)) {\n\n                // Check that each octet is of the ip address is more or equal\n                // to the low address and less or equal to the high address.\n                ipOctets = ConverterService.ipv6ToGroups(ipAddress);\n                lowOctets = ConverterService.ipv6ToGroups(lowAddress);\n                highOctets = ConverterService.ipv6ToGroups(highAddress);\n                for(i = 0; i < 8; i++) {\n                    if(ipOctets[i] > highOctets[i] ||\n                        ipOctets[i] < lowOctets[i]) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return false;\n        };\n    }]);\n","/* Copyright 2015 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * IO module.\n *\n */\n\nYUI.add('maas.io', function(Y) {\n\nY.log('loading maas.io');\n\nvar module = Y.namespace('maas.io');\n\n/**\n * Return a Y.IO object to talk to the MAAS website.\n *\n * @method getIO\n */\nmodule.getIO = function() {\n    var io = new Y.IO();\n    // Populate the header used by Django for CSRF protection.\n    Y.io.header('X-CSRFTOKEN', Y.Cookie.get(\"csrftoken\"));\n    return io;\n};\n\n}, '0.1', {'requires': ['cookie', 'io-base']}\n);\n","/* Copyright 2015-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * OS/Release seletion utilities.\n *\n * @module Y.maas.power_parameter\n */\n\nYUI.add('maas.os_distro_select', function(Y) {\n\nY.log('loading maas.os_distro_select');\nvar module = Y.namespace('maas.os_distro_select');\n\n// Only used to mockup io in tests.\nmodule._io = new Y.maas.io.getIO();\n\nvar OSReleaseWidget;\n\n/**\n * A widget class that modifies the viewable options of the release\n * field, based on the selected operating system field.\n *\n */\nOSReleaseWidget = function() {\n    OSReleaseWidget.superclass.constructor.apply(this, arguments);\n};\n\nOSReleaseWidget.NAME = 'os-release-widget';\n\nY.extend(OSReleaseWidget, Y.Widget, {\n\n   /**\n    * Initialize the widget.\n    * - cfg.srcNode is the node which will be updated when the selected\n    *   value of the 'os node' will change.\n    * - cfg.osNode is the node containing a 'select' element.  When\n    *   the selected element will change, the srcNode HTML will be\n    *   updated.\n    *\n    * @method initializer\n    */\n    initializer: function(cfg) {\n        this.initialSkip = true;\n    },\n\n   /**\n    * Bind the widget to events (to name 'event_name') generated by the given\n    * 'osNode'.\n    *\n    * @method bindTo\n    */\n    bindTo: function(osNode, event_name) {\n        var self = this;\n        if (!osNode) {\n            return;\n        }\n        Y.one(osNode).on(event_name, function(e) {\n            var osValue = e.currentTarget.get('value');\n            self.switchTo(osValue);\n        });\n        var osValue = Y.one(osNode).get('value');\n        self.switchTo(osValue);\n    },\n\n   /**\n    * React to a new value of the os node: update the HTML of\n    * 'srcNode'.\n    *\n    * @method switchTo\n    */\n    switchTo: function(newOSValue) {\n        var srcNode = this.get('srcNode');\n        var options = srcNode.all('option');\n        var selected = false;\n        options.each(function(option) {\n            var sel = this.modifyOption(option, newOSValue);\n            if (selected === false) {\n                selected = sel;\n            }\n        }, this);\n\n        // We skip selection on first load, as Django will already\n        // provide the users, current selection. Without this the\n        // current selection will be clobered.\n        if (this.initialSkip === true) {\n            this.initialSkip = false;\n            return;\n        }\n\n        // See if a selection was made, if not then we need\n        // to select the first visible as a default is not\n        // present.\n        if(!selected) {\n            this.selectVisableOption(options);\n        }\n    },\n\n   /**\n    * Modify an option to make it visible or hidden. Returns true\n    * if the method also make the selection active.\n    *\n    * @method modifyOption\n    */\n    modifyOption: function(option, newOSValue) {\n        var selected = false;\n        var value = option.get('value');\n        var split_value = value.split(\"/\");\n\n        // If \"Default OS\" is selected, then\n        // only show \"Default OS Release\".\n        if(newOSValue === '') {\n            if(value === '') {\n                option.removeClass('hidden');\n                option.set('selected', 'selected');\n            }\n            else {\n                option.addClass('hidden');\n            }\n        }\n        else {\n            if(split_value[0] === newOSValue) {\n                option.removeClass('hidden');\n                if(split_value[1] === '' && !this.initialSkip) {\n                    selected = true;\n                    option.set('selected', 'selected');\n                }\n            }\n            else {\n                option.addClass('hidden');\n            }\n        }\n        return selected;\n    },\n\n   /**\n    * Selected the first option that is not hidden.\n    *\n    * @method selectVisableOption\n    */\n    selectVisableOption: function(options) {\n        var first_option = null;\n        Y.Array.each(options, function(option) {\n            if(!option.hasClass('hidden')) {\n                if(first_option === null) {\n                    first_option = option;\n                }\n            }\n        });\n        if(first_option !== null) {\n            first_option.set('selected', 'selected');\n        }\n    }\n});\n\nmodule.OSReleaseWidget = OSReleaseWidget;\n\n}, '0.1', {'requires': ['widget', 'maas.io']}\n);\n\nYUI().use(\n  'maas.os_distro_select',\n  function (Y) {\n  Y.on('load', function() {\n    // Create OSDistroWidget so that the release field will be\n    // updated each time the value of the os field changes.\n    var releaseWidget = new Y.maas.os_distro_select.OSReleaseWidget({\n        srcNode: '#id_deploy-default_distro_series'\n        });\n    releaseWidget.bindTo(Y.one('#id_deploy-default_osystem'), 'change');\n    releaseWidget.render();\n  });\n});\n","/* Copyright 2012-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Utilities for the user preferences page.\n *\n * @module Y.maas.prefs\n */\n\nYUI.add('maas.prefs', function(Y) {\n\nY.log('loading maas.prefs');\nvar module = Y.namespace('maas.prefs');\n\n// Only used to mockup io in tests.\nmodule._io = new Y.maas.io.getIO();\n\nvar TokenWidget;\n\nTokenWidget = function() {\n    TokenWidget.superclass.constructor.apply(this, arguments);\n};\n\nTokenWidget.NAME = 'profile-widget';\n\nTokenWidget.ATTRS = {\n    // The number of tokens displayed.\n    nb_tokens: {\n        readOnly: true,\n        getter: function() {\n            return this.get('srcNode').all('.js-bundle').size();\n        }\n    }\n};\n\nY.extend(TokenWidget, Y.Widget, {\n\n    displayError: function(message) {\n        this.status_node.set('text', message);\n    },\n\n    initializer: function(cfg) {\n        this.create_link = Y.Node.create('<a />')\n            .set('href', '#')\n            .set('id','create_token')\n            .addClass('p-button--neutral')\n            .addClass('u-float--right')\n            .set('text', \"Generate MAAS key\");\n        this.status_node = Y.Node.create('<div />')\n            .set('id','create_error');\n        this.spinnerNode = Y.Node.create('<img />')\n            .addClass('u-animation--spin')\n            .addClass('icon')\n            .addClass('icon--loading');\n        this.get('srcNode').one('#token_creation_placeholder')\n            .append(this.create_link)\n            .append(this.status_node);\n    },\n\n    confirm: function(message) {\n        return confirm(message);\n    },\n\n    bindDeleteRow: function(row) {\n        var self = this;\n        var delete_link = row.one('a.js-delete-link');\n        delete_link.on('click', function(e) {\n            e.preventDefault();\n            if (self.confirm(\"Are you sure you want to delete this key?\")) {\n                self.deleteToken(row);\n            }\n        });\n    },\n\n    bindUI: function() {\n        var self = this;\n        this.create_link.on('click', function(e) {\n            e.preventDefault();\n            self.requestKeys();\n        });\n        Y.each(this.get('srcNode').all('.js-bundle'), function(row) {\n            self.bindDeleteRow(row);\n        });\n    },\n\n   /**\n    * Delete the token contained in the provided row.\n    * Call the API to delete the token and then remove the table row.\n    *\n    * @method deleteToken\n    */\n    deleteToken: function(row) {\n        var token_key = row.one('input').get('id');\n        var self = this;\n        var cfg = {\n            method: 'POST',\n            data: Y.QueryString.stringify({\n                op: 'delete_authorisation_token',\n                token_key: token_key\n                }),\n            sync: false,\n            on: {\n                start: Y.bind(self.showSpinner, self),\n                end: Y.bind(self.hideSpinner, self),\n                success: function(id, out) {\n                    row.remove();\n                 },\n                failure: function(id, out) {\n                    Y.log(out);\n                    if (out.status === 404) {\n                        self.displayError(\"The key has already been deleted.\");\n                    }\n                    else {\n                        self.displayError(\"Unable to delete the key.\");\n                    }\n                }\n            }\n        };\n        var request = module._io.send(\n            MAAS_config.uris.account_handler, cfg);\n    },\n\n    showSpinner: function() {\n        this.displayError('');\n        this.status_node.insert(this.spinnerNode, 'after');\n    },\n\n    hideSpinner: function() {\n        this.spinnerNode.remove();\n    },\n\n   /**\n    * Create a single string token from a key set.\n    *\n    * A key set is composed of 3 keys: consumer_key, token_key, token_secret.\n    * For an easy copy and paste experience, the string handed over to the\n    * user is a colon separated concatenation of these keys called 'token'.\n    *\n    * @method createTokenFromKeys\n    */\n    createTokenFromKeys: function(consumer_key, token_key, token_secret) {\n        return consumer_key + ':' + token_key + ':' + token_secret;\n    },\n\n   /**\n    * Add a token to the list of tokens.\n    *\n    * @method addToken\n    */\n    addToken: function(token, token_key) {\n        var list = this.get('srcNode').one('ul');\n        var row = Y.Node.create('<li />')\n            .addClass('js-bundle')\n            .addClass('u-equal-height')\n            .append(Y.Node.create('<div />')\n                .addClass('col-8')\n                .addClass('p-code-snippet')\n                    .append(Y.Node.create('<input />')\n                        .set('type', 'text')\n                        .addClass('p-code-snippet__input')\n                        .set('id', token_key)\n                        .set('value', token)))\n            .append(Y.Node.create(\n                '<div class=\"col-1 u-vertically-center\">' +\n                '<a class=\"p-tooltip p-tooltip--top-center js-delete-link\">' +\n                '<i class=\"p-icon--delete\"></i>' +\n                '<span class=\"p-tooltip__message\" role=\"tooltip\">' +\n                'Delete API key</span></a></div>'))\n       list.append(row);\n       this.bindDeleteRow(row);\n    },\n\n   /**\n    * Request a new OAuth key set from the API.\n    *\n    * @method requestKeys\n    */\n    requestKeys: function() {\n        var self = this;\n        var cfg = {\n            method: 'POST',\n            data: 'op=create_authorisation_token',\n            sync: false,\n            on: {\n                start: Y.bind(self.showSpinner, self),\n                end: Y.bind(self.hideSpinner, self),\n                success: function(id, out) {\n                    var keys;\n                    try {\n                        keys = JSON.parse(out.response);\n                    }\n                    catch(e) {\n                        // Parsing error.\n                        self.displayError('Unable to create a new token.');\n                    }\n                    // Generate a token from the keys.\n                    var token = self.createTokenFromKeys(\n                        keys.consumer_key, keys.token_key,\n                        keys.token_secret);\n                    // Add the new token to the list of tokens.\n                    self.addToken(token, keys.token_key);\n                 },\n                failure: function(id, out) {\n                    self.displayError('Unable to create a new token.');\n                }\n            }\n        };\n        var request = module._io.send(\n            MAAS_config.uris.account_handler, cfg);\n    }\n});\n\nmodule.TokenWidget = TokenWidget;\n\n}, '0.1', {'requires': ['widget', 'maas.io']}\n);\n","/* Copyright 2012-2014 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * Widget to expand (make visible) or fold (make invisible) a content div,\n * in response to clicks on a button link.\n *\n * Write your initial HTML for the visible state.  If the client does not\n * execute the script, the content div will be visible.  Upon initialization,\n * the widget immediately goes into its \"hidden\" state.\n *\n * Once the widget is set up, its reveal() method will toggle it between its\n * visible and invisible states.  The transition is animated with a sliding\n * effect.\n *\n * The widget fires a \"hiding\" event before hiding, and \"hidden\" after.\n * Similarly, it fires \"revealing\" before revealing and \"revealed\" after.\n *\n * Synonyms: expander, collapsible, foldable.\n *\n * @module Y.maas.reveal\n */\n\nYUI.add('maas.reveal', function(Y) {\n\nY.log('loading maas.reveal');\n\nvar module = Y.namespace('maas.reveal');\n\nvar Reveal;\n\nReveal = function(config) {\n    Reveal.superclass.constructor.apply(this, arguments);\n};\n\nReveal.NAME = 'reveal';\n\nReveal.ATTRS = {\n    /**\n     * DOM node for the content div.  This is the div that will be hidden\n     * or revealed.  It must contain exactly one tag.\n     *\n     * The widget will add the \"slider\" class to this node, and the \"content\"\n     * class to its child node.\n     *\n     * Hiding the content is done by setting the target node's height to zero;\n     * it's child node keeps its original size but becomes invisible.\n     *\n     * @attribute targetNode\n     * @type node\n     */\n    targetNode: {\n        value: null\n    },\n\n    /**\n     * DOM node for the button link that triggers the reveal.\n     *\n     * @attribute linkNode\n     * @type node\n     */\n    linkNode: {\n        value: null\n    },\n\n    /**\n     * The text the button link should contain when the content div is\n     * visible.\n     *\n     * @attribute hideText\n     * @type string\n     */\n    hideText: {\n        value: null\n    },\n\n    /**\n     * The text the button link should contain when the content div is hidden.\n     *\n     * @attribute showText\n     * @type string\n     */\n    showText: {\n        value: null\n    },\n\n    /**\n     * Skip animations?\n     *\n     * Use this when testing, to avoid wasting time on delays.\n     *\n     * @attribute quick\n     * @type bool\n     */\n    quick: {\n        value: false\n    }\n};\n\n\n// Return a style attribute for a node, as an int.\n// Any suffix to the number, such as the typical \"px,\" is ignored.\nfunction get_style_int(node, attribute) {\n    return parseInt(node.getStyle(attribute), 10);\n}\n\n\nY.extend(Reveal, Y.Widget, {\n    /**\n     * Standard YUI hook: prepare the DOM for the widget.\n     *\n     * @method renderUI\n     */\n    renderUI: function() {\n        var target = this.get('targetNode');\n        target.addClass('slider');\n        target.get('children').addClass('content');\n    },\n\n    /**\n     * Standard YUI hook: install event listeners for the widget.\n     *\n     * @method bindUI\n     */\n    bindUI: function() {\n        var self = this;\n        this.get('linkNode').on('click', function(e) {\n            e.preventDefault();\n            self.reveal();\n        });\n    },\n\n    /**\n     * Standard YUI hook: update UI to match the widget's state at the time\n     * it is rendered.\n     *\n     * The HTML is written in an expanded state, but during rendering, the\n     * widget immediately (and without animation) goes into its hidden state.\n     *\n     * @method syncUI\n     */\n    syncUI: function() {\n        this.fire(\"hiding\");\n        this.get('targetNode').setStyle('height', 0);\n        this.set_hidden_link(this.get('linkNode'));\n        this.fire(\"hidden\");\n    },\n\n    /**\n     * Is this widget currently in its visible state?\n     *\n     * @method is_visible\n     */\n    is_visible: function() {\n        return get_style_int(this.get('targetNode'), 'height') > 0;\n    },\n\n    /**\n     * Set link to its \"hidden\" state.\n     *\n     * @method set_hidden_link\n     */\n    set_hidden_link: function(link) {\n        var new_text = this.get('showText');\n        if (new_text !== null && new_text !== undefined) {\n            link.set('text', new_text);\n        }\n    },\n\n    /**\n     * Set link to its \"visible\" state.\n     *\n     * @method set_visible_link\n     */\n    set_visible_link: function(link) {\n        var new_text = this.get('hideText');\n        if (new_text !== null && new_text !== undefined) {\n            link.set('text', new_text);\n        }\n    },\n\n    /**\n     * Get the desired duration for an animation.\n     *\n     * Returns the suggested duration, unless the \"quick\" attribute is set\n     * in which case it returns a very brief duration.\n     *\n     * @method get_animation_duration\n     */\n    get_animation_duration: function(suggested_duration) {\n        if (this.get('quick')) {\n            return 0.01;\n        }\n        else {\n            return suggested_duration;\n        }\n    },\n\n    /**\n     * Create the animation for sliding in the content div.\n     *\n     * @method create_slide_in\n     */\n    create_slide_in: function(node, publisher) {\n        var anim = new Y.Anim({\n            node: node,\n            duration: this.get_animation_duration(0.3),\n            to: {height: 0}\n        });\n        anim.on('end', function() {\n            publisher.fire('hidden');\n        });\n        return anim;\n    },\n\n    /**\n     * Create the animation for sliding out the content div.\n     *\n     * @method create_slide_out\n     */\n    create_slide_out: function(node, publisher) {\n        // The target node contains exactly one node of content.  Its height\n        // is constant.  We calculate the appropriate expanded height for the\n        // target node from the height of the content node, plus marings and\n        // padding.\n        var content_node = node.one('.content');\n        var new_height = (\n            get_style_int(content_node, 'height') +\n            get_style_int(content_node, 'paddingTop') +\n            get_style_int(content_node, 'paddingBottom') +\n            get_style_int(content_node, 'marginTop') +\n            get_style_int(content_node, 'marginBottom'));\n        var anim = new Y.Anim({\n            node: node,\n            duration: this.get_animation_duration(0.2),\n            to: {height: new_height}\n        });\n        anim.on('end', function() {\n            publisher.fire('revealed');\n        });\n        return anim;\n    },\n\n    /**\n     * Toggle between the hidden and revealed states.\n     *\n     * @method reveal\n     */\n    reveal: function() {\n        var target = this.get('targetNode');\n        var link = this.get('linkNode');\n        if (this.is_visible()) {\n            this.fire('hiding');\n            this.create_slide_in(target, this).run();\n            this.set_hidden_link(link);\n        }\n        else {\n            this.fire('revealing');\n            this.create_slide_out(target, this).run();\n            this.set_visible_link(link);\n        }\n    }\n});\n\nmodule.Reveal = Reveal;\n\n}, '0.1', {'requires': ['widget', 'node', 'event', 'anim']});\n\nYUI().use('maas.reveal', function (Y) {\n  Y.on('domready', function() {\n    Y.all('.p-script-expander').each(function (script_entry) {\n      var script_expander = new Y.maas.reveal.Reveal({\n        targetNode: script_entry.one('.p-script-expander__content'),\n        linkNode: script_entry.one('.p-script-expander__trigger')\n        });\n      script_expander.render();\n    });\n  });\n});\n","/* Copyright 2014-2016 Canonical Ltd.  This software is licensed under the\n * GNU Affero General Public License version 3 (see the file LICENSE).\n *\n * The shortpoll module provides the functionality to deal with updating\n * in-browser data by polling the server.\n *\n * @module shortpoll\n */\nYUI.add('maas.shortpoll', function(Y) {\n\nvar namespace = Y.namespace('maas.shortpoll');\n\n// Event fired when the short-polling request starts.\nnamespace.shortpoll_start_event = 'maas.shortpoll.start';\n\n// Event fired each time the short-polling request fails (to connect or\n// to parse the returned result).\nnamespace.shortpoll_fail_event = 'maas.shortpoll.failure';\n\n// After MAX_SHORT_DELAY_FAILED_ATTEMPTS failed connections (real failed\n// connections or connection getting an invalid return) separated\n// by SHORT_DELAY (millisec), wait LONG_DELAY (millisec) between\n// each failed connection.\nnamespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS = 5;\nnamespace.SHORT_DELAY = 15 * 1000;  // 15 seconds.\nnamespace.LONG_DELAY = 3 * 60 * 1000;  // 3 minutes.\n\n// Ugly hack for tests, to prevent repolling.\nnamespace._repoll = true;\n\n// Overridden by tests.\nnamespace._io = new Y.maas.io.getIO();\n\n/**\n *\n * A ShortPollManager creates and manages a polling connection to the server\n * to fetch objects.\n *\n * @class ShortPollManager\n */\nfunction ShortPollManager(config) {\n    ShortPollManager.superclass.constructor.apply(this, arguments);\n}\n\nShortPollManager.NAME = \"shortPollManager\";\n\nShortPollManager.ATTRS = {\n    /**\n     * The URI to poll.\n     *\n     * @attribute uri\n     * @type string\n     */\n    uri: {\n        value: \"\"\n    },\n\n    /**\n     * The key with which to publish polled responses.\n     *\n     * @attribute eventKey\n     * @type string\n     */\n    eventKey: {\n        valueFn: function() {\n            return Y.guid(\"shortpoll_\");\n        }\n    },\n\n    /**\n     * The IO instance used.\n     *\n     * @attribute io\n     * @type Y.IO\n     */\n    io: {\n        readOnly: true,\n        getter: function() {\n            return namespace._io;\n        }\n    }\n};\n\nY.extend(ShortPollManager, Y.Base, {\n    initializer : function(cfg) {\n        this._started = false;\n        this._failed_attempts = 0;\n        this._sequence = 0;\n    },\n\n    successPoll : function (id, response) {\n        try {\n            var eventKey = this.get(\"eventKey\");\n            var data = Y.JSON.parse(response.responseText);\n            Y.fire(eventKey, data);\n            return true;\n        }\n        catch (e) {\n            Y.fire(namespace.shortpoll_fail_event, e);\n            return false;\n        }\n    },\n\n    failurePoll : function () {\n        Y.fire(namespace.shortpoll_fail_event);\n    },\n\n    /**\n     * Return the delay (milliseconds) to wait before trying to reconnect\n     * again after a failed connection.\n     *\n     * The rationale here is that:\n     * 1. We should not try to reconnect instantaneously after a failed\n     *    connection.\n     * 2. After a certain number of failed connections, we should set the\n     *    delay between two failed connection to a bigger number because the\n     *    server may be having problems.\n     *\n     * @method _pollDelay\n     */\n    _pollDelay : function() {\n        if (this._failed_attempts >=\n                namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS) {\n            return namespace.LONG_DELAY;\n        }\n        else {\n            return namespace.SHORT_DELAY;\n        }\n    },\n\n    /**\n     * Relaunch a connection to the server after a successful or\n     * a failed connection.\n     *\n     * @method repoll\n     * @param {Boolean} failed: whether or not the previous connection\n     *     has failed.\n     */\n    repoll : function(failed) {\n        if (failed) {\n            this._failed_attempts += 1;\n        }\n        else {\n            this._failed_attempts = 0;\n        }\n        if (namespace._repoll) {\n            var delay = this._pollDelay();\n            Y.later(delay, this, this.poll);\n            return delay;\n        }\n        else {\n            return this._pollDelay();\n        }\n    },\n\n    poll : function() {\n        var that = this;\n        var config = {\n            method: \"GET\",\n            sync: false,\n            on: {\n                failure: function(id, response) {\n                    if (Y.Lang.isValue(response) &&\n                        Y.Lang.isValue(response.status) &&\n                        (response.status === 408 ||\n                         response.status === 504)) {\n                        // If the error code is:\n                        // - 408 Request timeout\n                        // - 504 Gateway timeout\n                        // Then ignore the error and start\n                        // polling again.\n                        that.repoll(false);\n                    }\n                    else {\n                        that.failurePoll();\n                        that.repoll(true);\n                    }\n                },\n                success: function(id, response) {\n                    var success = that.successPoll(id, response);\n                    that.repoll(!success);\n                }\n            }\n        };\n        this._sequence = this._sequence + 1;\n        var poll_uri = this.get(\"uri\");\n        if (poll_uri.indexOf(\"?\") >= 0) {\n            poll_uri += \"&sequence=\" + this._sequence;\n        }\n        else {\n            poll_uri += \"?sequence=\" + this._sequence;\n        }\n        if (!this._started) {\n            Y.fire(namespace.shortpoll_start_event);\n            this._started = true;\n        }\n        this.get(\"io\").send(poll_uri, config);\n    }\n});\n\nnamespace.ShortPollManager = ShortPollManager;\n\n}, \"0.1\", {\"requires\":[\"base\", \"event\", \"json\", \"maas.io\"]});\n","var MAASUI = MAASUI || {};\n\n/**\n * A set of framework-agnostic JavaScript utilities for the MAAS UI\n * @namespace MAASUI.utils\n * @return {Object} public methods\n */\nMAASUI.utils = (function() {\n  /**\n   * Run the supplied function when page content is loaded\n   * @namespace MAASUI.utils\n   * @method ready\n   * @param {Object} fn - the function to run\n   */\n  var ready = function(fn) {\n    if (document.attachEvent ? document.readyState === \"complete\" :\n        document.readyState !== \"loading\") {\n      fn();\n    } else {\n      document.addEventListener('DOMContentLoaded', fn);\n    }\n  };\n\n  /**\n   * Toggle a specified class on the provided element\n   * @namespace MAASUI.utils\n   * @method toggleClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to toggle\n   * @return {bool} true for success or false if incorrect params are given\n   */\n  var toggleClass = function(el, className) {\n    if (typeof(el) != 'undefined' && el != null) {\n      if (el.classList) {\n        el.classList.toggle(className);\n      } else {\n        var classes = el.className.split(' ');\n        var existingIndex = classes.indexOf(className);\n        if (existingIndex >= 0) {\n          classes.splice(existingIndex, 1);\n        } else {\n          classes.push(className);\n        }\n        el.className = classes.join(' ');\n      }\n    } else {\n      return false;\n    }\n    return true;\n  };\n\n  /**\n   * Remove a specified class from the provided element\n   * @namespace MAASUI.utils\n   * @method removeClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to remove\n   * @return {bool} true for success or false if incorrect params are given\n   */\n  var removeClass = function(el, className) {\n    if (typeof(el) != 'undefined' && el != null) {\n      if (el.classList) {\n        el.classList.remove(className);\n      } else {\n        el.className = el.className.replace(new RegExp(\n          '(^|\\\\b)' + className.split(' ').join('|') + '(\\\\b|$)', 'gi'), ' ');\n      }\n    } else {\n      return false;\n    }\n    return true;\n  };\n\n  /**\n   * Check if a DOM element has a class\n   * @namespace MAASUI.utils\n   * @method hasClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to check\n   * @return {bool} is the class present\n   */\n  var hasClass = function(el, className) {\n    var hasClass = false;\n\n    if (el.classList) {\n      hasClass = el.classList.contains(className);\n    } else {\n      hasClass = new RegExp(\n        '(^| )' + className + '( |$)', 'gi').test(el.className);\n    }\n\n    return hasClass;\n  };\n\n  /**\n   * Remove a specified class from the provided element\n   * @namespace MAASUI.utils\n   * @method addClass\n   * @param {Object} el - a DOM element\n   * @param {String} className - the class name to add\n   */\n  var addClass = function(el, className) {\n    if (!hasClass(el, className)) {\n      if (el.classList) {\n        el.classList.add(className);\n      } else {\n        el.className += ' ' + className;\n      }\n    }\n  };\n\n  return {\n    ready: ready,\n    toggleClass: toggleClass,\n    removeClass: removeClass,\n    hasClass: hasClass,\n    addClass: addClass\n  };\n})();\n\n/**\n * A handler for toggleable menus\n * @namespace MAASUI.dropdown\n */\nMAASUI.dropdown = (function() {\n  var wrapperClassname = \"p-dropdown\";\n  var toggleClassName = \"p-dropdown__toggle\";\n  var menuClassName = \"p-dropdown__menu\";\n  var menuItemClassName =\"p-dropdown__item\";\n  var activeClassName = \"active\"\n  var dropdowns;\n\n  /**\n   * Initialise the menu and toggle events\n   * @namespace MAASUI.dropdown\n   * @method init\n   */\n  var init = function() {\n    dropdowns = document.querySelectorAll('.' + wrapperClassname);\n\n    Array.prototype.forEach.call(dropdowns, function(dropdown, i) {\n      // Add click event for dropdown toggling.\n      dropdown.addEventListener(\"click\", click);\n\n      // Add click event to all dropdown links to close menus.\n      var sublinks = dropdown.querySelectorAll('.' + menuItemClassName);\n      Array.prototype.forEach.call(sublinks, function(link, i) {\n        link.addEventListener(\"click\", closeAllMenus);\n      });\n\n      // Add click event for whole document to close all menus when\n      // anything else is clicked.\n      document.addEventListener('click', function(event) {\n        var isClickInside = dropdown.contains(event.target);\n        if (!isClickInside) {\n          closeAllMenus();\n        }\n      });\n    });\n\n    return true;\n  }\n\n  /**\n   * A handler for a toggle menu click (intended for use on click events)\n   * @namespace MAASUI.dropdown\n   * @method click\n   * @param {Object} event - a click event\n   */\n  var click = function(event) {\n    if (MAASUI.utils.hasClass(this, activeClassName)) {\n      closeAllMenus();\n    } else {\n      openMenu(this);\n    }\n    event.stopPropagation();\n  }\n\n  /**\n   * Opens the menu for the provided dropdown element\n   * @namespace MAASUI.dropdown\n   * @method openMenu\n   * @param {Object} el - the dropdown element\n   */\n  var openMenu = function(el) {\n    closeAllMenus();\n    MAASUI.utils.addClass(el, activeClassName);\n  }\n\n  /**\n   * Closes all open menus and deactivates all toggles\n   * @namespace MAASUI.dropdown\n   * @method closeAllMenus\n   * @param {Object} event - a click event (optional)\n   */\n  var closeAllMenus = function(event) {\n    Array.prototype.forEach.call(dropdowns, function(dropdown, i) {\n      //Deactive all toggle buttons\n      MAASUI.utils.removeClass(dropdown, activeClassName);\n    });\n\n    if (typeof event != 'undefined') {\n      event.stopPropagation();\n    }\n  }\n\n  return {\n    init: init\n  };\n})();\n\nMAASUI.utils.ready(MAASUI.dropdown.init);\n"],"sourceRoot":""}
 
 
b'\\ No newline at end of file'