content: Sub ParseAutoplayCommon(setupParams as object, setup_sync as object)
    
    setupParams.version = setup_sync.LookupMetadata("client", "version")
  
    setupParams.base = setup_sync.LookupMetadata("client", "base")
    setupParams.recoveryHandler = setup_sync.LookupMetadata("client", "recoveryHandler")
    setupParams.recoverySetup = setup_sync.LookupMetadata("client", "recoverySetup")
    setupParams.next = setup_sync.LookupMetadata("client", "next")
    setupParams.event = setup_sync.LookupMetadata("client", "event")
    setupParams.error = setup_sync.LookupMetadata("client", "error")
    setupParams.deviceError = setup_sync.LookupMetadata("client", "deviceError")
    setupParams.deviceDownload = setup_sync.LookupMetadata("client", "deviceDownload")
    setupParams.deviceDownloadProgress = setup_sync.LookupMetadata("client", "deviceDownloadProgress")
    setupParams.trafficDownload = setup_sync.LookupMetadata("client", "trafficDownload")
    setupParams.uploadLogs = setup_sync.LookupMetadata("client", "uploadLogs")
    setupParams.batteryCharger = setup_sync.LookupMetadata("client", "batteryCharger")
    
    setupParams.account = setup_sync.LookupMetadata("server", "account")
    setupParams.bsnRegistrationToken = setup_sync.LookupMetadata("server", "bsnRegistrationToken")
    setupParams.user = setup_sync.LookupMetadata("server", "user")
    setupParams.password = setup_sync.LookupMetadata("server", "password")
    setupParams.group = setup_sync.LookupMetadata("server", "group")
    setupParams.enableUnsafeAuthentication = setup_sync.LookupMetadata("server", "enableUnsafeAuthentication")
    
    setupParams.endpoints_s3Url = setup_sync.LookupMetadata("server", "endpoints_s3Url")
    setupParams.endpoints_provisionServer = setup_sync.LookupMetadata("server", "endpoints_provisionServer")
    setupParams.endpoints_bsnServer = setup_sync.LookupMetadata("server", "endpoints_bsnServer")
    setupParams.endpoints_websocketsDWS = setup_sync.LookupMetadata("server", "endpoints_websocketsDWS")
    setupParams.endpoints_bsnApiServer = setup_sync.LookupMetadata("server", "endpoints_bsnApiServer")
    setupParams.endpoints_certsServer = setup_sync.LookupMetadata("server", "endpoints_certsServer")
  
    setupParams.partnerUrl = setup_sync.LookupMetadata("server", "partnerUrl")
    
    setupParams.unitName$ = setup_sync.LookupMetadata("client", "unitName")
    setupParams.unitNamingMethod$ = setup_sync.LookupMetadata("client", "unitNamingMethod")
    setupParams.unitDescription$ = setup_sync.LookupMetadata("client", "unitDescription")
    setupParams.timezone$ = setup_sync.LookupMetadata("client", "timeZone")
    setupParams.timeServer$ = setup_sync.LookupMetadata("client", "timeServer")
    
    setupParams.remoteDwsEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "remoteDwsEnabled"))
    
    setupParams.dwsEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "dwsEnabled"))
    
    'NOTE: Using GetMetadata() for "dwsPassword" because LookupMetadata() returns "" for null
    setupParams.dwsPassword$ = setup_sync.GetMetadata("client").dwsPassword
    
    setupParams.lwsConfig$ = setup_sync.LookupMetadata("client", "lwsConfig")
    setupParams.lwsEnableUpdateNotifications = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "lwsEnableUpdateNotifications"))
    setupParams.lwsUserName$ = setup_sync.LookupMetadata("client", "lwsUserName")
    setupParams.lwsPassword$ = setup_sync.LookupMetadata("client", "lwsPassword")
    
    setupParams.bsnCloudEnabled = IsTruthy(setup_sync.LookupMetadata("client", "bsnCloudEnabled"))  
    
    ParseJsonLogging(setupParams, setup_sync)
    
    setupParams.enableRemoteSnapshot = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "deviceScreenShotsEnabled"))
    setupParams.remoteSnapshotInterval% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "deviceScreenShotsInterval"))
    setupParams.remoteSnapshotMaxImages% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "deviceScreenShotsCountLimit"))
    setupParams.remoteSnapshotJpegQualityLevel% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "deviceScreenShotsQuality"))
    setupParams.remoteSnapshotOrientation = setup_sync.LookupMetadata("client", "deviceScreenShotsOrientation")
    
    setupParams.useDHCP = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "useDHCP"))
    setupParams.rateLimitModeOutsideWindow = setup_sync.LookupMetadata("client", "rateLimitModeOutsideWindow")
    setupParams.rateLimitRateOutsideWindow = setup_sync.LookupMetadata("client", "rateLimitRateOutsideWindow")
    setupParams.rateLimitModeInWindow = setup_sync.LookupMetadata("client", "rateLimitModeInWindow")
    setupParams.rateLimitRateInWindow = setup_sync.LookupMetadata("client", "rateLimitRateInWindow")
    setupParams.rateLimitModeInitialDownloads = setup_sync.LookupMetadata("client", "rateLimitModeInitialDownloads")
    setupParams.rateLimitRateInitialDownloads = setup_sync.LookupMetadata("client", "rateLimitRateInitialDownloads")
    setupParams.uploadLogFilesAtBoot = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "uploadLogFilesAtBoot"))
    setupParams.uploadLogFilesAtSpecificTime = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "uploadLogFilesAtSpecificTime"))
    setupParams.uploadLogFilesTime% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "uploadLogFilesTime"))
    setupParams.idleScreenColor$ = setup_sync.LookupMetadata("client", "idleScreenColor")
    setupParams.lwsUserName$ = setup_sync.LookupMetadata("client", "lwsUserName")
    setupParams.lwsPassword$ = setup_sync.LookupMetadata("client", "lwsPassword")
    
    setupParams.specifyHostname = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "specifyHostname"))
    setupParams.hostName$ = setup_sync.LookupMetadata("client", "hostname")
    
    setupParams.useWireless = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "useWireless"))
    setupParams.ssid$ = setup_sync.LookupMetadata("client", "ssid")
    setupParams.passphrase$ = setup_sync.LookupMetadata("client", "passphrase")
    
    setupParams.useProxy = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "useProxy"))
    setupParams.proxy$ = setup_sync.LookupMetadata("client", "proxy")
    setupParams.proxySpec$ = setupParams.proxy$
  
    if (setup_sync.GetMetadata("client").networkHosts <> invalid)
      setupParams.networkHosts = setup_sync.GetMetadata("client").networkHosts
    else
      setupParams.networkHosts = []
    end if
    
    setupParams.networkConnectionPriorityWired% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "networkConnectionPriorityWired"))
    setupParams.networkConnectionPriorityWireless% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "networkConnectionPriorityWireless"))
    setupParams.contentDataTypeEnabledWired = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "contentDataTypeEnabledWired"))
    setupParams.textFeedsDataTypeEnabledWired = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "textFeedsDataTypeEnabledWired"))
    setupParams.healthDataTypeEnabledWired = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "healthDataTypeEnabledWired"))
    setupParams.mediaFeedsDataTypeEnabledWired = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "mediaFeedsDataTypeEnabledWired"))
    setupParams.logUploadsXfersEnabledWired = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "logUploadsXfersEnabledWired"))
    setupParams.contentDataTypeEnabledWireless = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "contentDataTypeEnabledWireless"))
    setupParams.textFeedsDataTypeEnabledWireless = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "textFeedsDataTypeEnabledWireless"))
    setupParams.healthDataTypeEnabledWireless = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "healthDataTypeEnabledWireless"))
    setupParams.mediaFeedsDataTypeEnabledWireless = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "mediaFeedsDataTypeEnabledWireless"))
    setupParams.logUploadsXfersEnabledWireless = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "logUploadsXfersEnabledWireless"))
    setupParams.networkDiagnosticsEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "networkDiagnosticsEnabled"))
    setupParams.testEthernetEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "testEthernetEnabled"))
    setupParams.testWirelessEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "testWirelessEnabled"))
    setupParams.testInternetEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "testInternetEnabled"))
    setupParams.useCustomSplashScreen = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "useCustomSplashScreen"))
    
    setupParams.configVersion$ = setup_sync.LookupMetadata("client", "configVersion")
    
    setupParams.timeBetweenNetConnects% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "timeBetweenNetConnects"))
    
    setupParams.staticIPAddress = setup_sync.LookupMetadata("client", "staticIPAddress")
    setupParams.subnetMask = setup_sync.LookupMetadata("client", "subnetMask")
    setupParams.gateway = setup_sync.LookupMetadata("client", "gateway")
    setupParams.dns1 = setup_sync.LookupMetadata("client", "dns1")
    setupParams.dns2 = setup_sync.LookupMetadata("client", "dns2")
    setupParams.dns3 = setup_sync.LookupMetadata("client", "dns3")
    
    'WPA/802.1X Authentication Parameters
    if type(setup_sync.GetMetadata("client").wpaSettings) = "roAssociativeArray" then
      wpaSettings = setup_sync.GetMetadata("client").wpaSettings
      setupParams.enableWPAEnterpriseAuthentication = wpaSettings.enableWPAEnterpriseAuthentication
      setupParams.wpaEnterpriseVariant = wpaSettings.wpaEnterpriseVariant
      setupParams.eapCertificateType = wpaSettings.eapCertificateType
      setupParams.eapCertificatePassphrase = wpaSettings.eapCertificatePassphrase
      setupParams.peapUsername = wpaSettings.peapUsername
      setupParams.peapPassphrase = wpaSettings.peapPassphrase
      
      setupParams.eapCertificateFileName = ""
      setupParams.eapPemOrDerKeyFileName = ""
      setupParams.caCertificateFileName = ""
  
      if IsString(wpaSettings.eapCertificateFileName) and wpaSettings.eapCertificateFileName <> "" then
        setupParams.eapCertificateFileName = wpaSettings.eapCertificateFileName
      endif
  
      if IsString(wpaSettings.eapPemOrDerKeyFileName) and wpaSettings.eapPemOrDerKeyFileName <> "" then
        setupParams.eapPemOrDerKeyFileName = wpaSettings.eapPemOrDerKeyFileName
      endif
  
      if IsString(wpaSettings.caCertificateFileName) and wpaSettings.caCertificateFileName <> "" then
        setupParams.caCertificateFileName = wpaSettings.caCertificateFileName
      endif
  
    else
      setupParams.enableWPAEnterpriseAuthentication = false
    endif
  
    setupParams.useDHCP_2 = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "useDHCP_2"))
    
    setupParams.staticIPAddress_2 = setup_sync.LookupMetadata("client", "staticIPAddress_2")
    setupParams.subnetMask_2 = setup_sync.LookupMetadata("client", "subnetMask_2")
    setupParams.gateway_2 = setup_sync.LookupMetadata("client", "gateway_2")
    setupParams.dns1_2 = setup_sync.LookupMetadata("client", "dns1_2")
    setupParams.dns2_2 = setup_sync.LookupMetadata("client", "dns2_2")
    setupParams.dns3_2 = setup_sync.LookupMetadata("client", "dns3_2")
    
    'WPA/802.1X Authentication Parameters
    if type(setup_sync.GetMetadata("client").wpaSettings_2) = "roAssociativeArray" then
      wpaSettings = setup_sync.GetMetadata("client").wpaSettings_2
      setupParams.enableWPAEnterpriseAuthentication_2 = wpaSettings.enableWPAEnterpriseAuthentication
      setupParams.wpaEnterpriseVariant_2 = wpaSettings.wpaEnterpriseVariant
      setupParams.eapCertificateType_2 = wpaSettings.eapCertificateType
      setupParams.eapCertificatePassphrase_2 = wpaSettings.eapCertificatePassphrase
      setupParams.peapUsername_2 = wpaSettings.peapUsername
      setupParams.peapPassphrase_2 = wpaSettings.peapPassphrase
      
      setupParams.eapCertificateFileName_2 = ""
      setupParams.eapPemOrDerKeyFileName_2 = ""
      setupParams.caCertificateFileName_2 = ""
  
      if IsString(wpaSettings.eapCertificateFileName) and wpaSettings.eapCertificateFileName <> "" then
        setupParams.eapCertificateFileName_2 = wpaSettings.eapCertificateFileName
      endif
  
      if IsString(wpaSettings.eapPemOrDerKeyFileName) and wpaSettings.eapPemOrDerKeyFileName <> "" then
        setupParams.eapPemOrDerKeyFileName_2 = wpaSettings.eapPemOrDerKeyFileName
      endif
  
      if IsString(wpaSettings.caCertificateFileName) and wpaSettings.caCertificateFileName <> "" then
        setupParams.caCertificateFileName_2 = wpaSettings.caCertificateFileName
      endif
  
    else
      setupParams.enableWPAEnterpriseAuthentication_2 = false
    endif
  
    setupParams.rateLimitModeOutsideWindow_2 = setup_sync.LookupMetadata("client", "rateLimitModeOutsideWindow_2")
    setupParams.rateLimitRateOutsideWindow_2 = setup_sync.LookupMetadata("client", "rateLimitRateOutsideWindow_2")
    setupParams.rateLimitModeInWindow_2 = setup_sync.LookupMetadata("client", "rateLimitModeInWindow_2")
    setupParams.rateLimitRateInWindow_2 = setup_sync.LookupMetadata("client", "rateLimitRateInWindow_2")
    setupParams.rateLimitModeInitialDownloads_2 = setup_sync.LookupMetadata("client", "rateLimitModeInitialDownloads_2")
    setupParams.rateLimitRateInitialDownloads_2 = setup_sync.LookupMetadata("client", "rateLimitRateInitialDownloads_2")
  
    setupParams.uploadLogs = setup_sync.LookupMetadata("client", "uploadLogs")
    setupParams.uploadSnapshots = setup_sync.LookupMetadata("client", "uploadSnapshots")
    setupParams.contentDownloadsRestricted = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "contentDownloadsRestricted"))
    setupParams.contentDownloadRangeStart% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "contentDownloadRangeStart"))
    setupParams.contentDownloadRangeLength% = GetNumberFromNumericString(setup_sync.LookupMetadata("client", "contentDownloadRangeLength"))
    setupParams.usbUpdatePassword$ = setup_sync.LookupMetadata("client", "usbUpdatePassword")
    setupParams.brightWallName = setup_sync.LookupMetadata("client", "BrightWallName")
    setupParams.brightWallScreenNumber = setup_sync.LookupMetadata("client", "BrightWallScreenNumber")
  
    ' Set lower case setup type
    setupParams.setupType = lcase(setup_sync.LookupMetadata("client", "setupType"))
  
    ' BCN-6317. If inheritNetworkProperties is true, do not apply network settings
    setupParams.inheritNetworkProperties = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "inheritNetworkProperties"))
    
  end sub
  
  
  Sub CreateApplicationConnection(setupParams as object, msgPort as object, networkingRegistrySection as object)
    ' If we have a new enough system, use the control cloud access method for IPC
    ccloud = CreateObject("roControlCloud")
    if ccloud <> invalid then
      ccloud.SetUserData("bootstrap")
      ccloud.SetPort(msgPort)
      ' commented the follow as SendStatusPayload always called immediate after this function,
      ' which works as indicator to use application port as communication channel.
      ' if the order changed/function removed, we need to send an empty object.
      ' send an empty message indicate we'll use application port
      ' ccloud.SendMessage({})
      setupParams.ccloud = ccloud
    else 
      setupParams.dgSocket = CreateDatagramSocket(setupParams, msgPort, networkingRegistrySection)
    end if
  
    ' Maintain socket port to accept incoming udp message from bootstrap
    setupParams.wsUdpSocketPort$ = networkingRegistrySection.Read("wsUdpSocketPort")
    if setupParams.wsUdpSocketPort$ = "" then
      setupParams.wsUdpSocketPort% = 9999
    else
      setupParams.wsUdpSocketPort% = int(val(setupParams.wsUdpSocketPort$))
    end if
  
  end sub
  
  
  Function CreateDatagramSocket(setupParams as object, msgPort as object, networkingRegistrySection as object)
    ' open datagramSocket for setup scripts and bootstrap to communicate
    ' create object for bootstrap udp messages
    dgSocket = CreateObject("roDatagramSocket")
    setupParams.daUdpSocketPort$ = networkingRegistrySection.Read("daUdpSocketPort")
    
    if setupParams.daUdpSocketPort$ = "" then
      setupParams.daUdpSocketPort% = 8888
    else
      setupParams.daUdpSocketPort% = int(val(setupParams.daUdpSocketPort$))
    end if
  
    dgSocket.BindToLocalPort(setupParams.daUdpSocketPort%)
    dgSocket.SetUserData("bootstrap")
    dgSocket.SetPort(msgPort)
  
    return dgSocket
  
  end function
  
  
  Sub SendStatusPayload(setupParams as object, version as string)
  
    if setupParams.ccloud <> invalid then
      jsonArray = ConstructStatusPayload(version)
      result = setupParams.ccloud.SendMessage(jsonArray)
  
    else if setupParams.dgSocket <> invalid then
      jsonArray = ConstructStatusPayload(version)
      jsonString = FormatJson(jsonArray)
      result = setupParams.dgSocket.SendTo("127.0.0.1", setupParams.wsUdpSocketPort%, jsonString)
    end if
  
  end sub
  
  
  Function ConstructStatusPayload(version as string)
  
    ' use the same format as websocket messages
      ' Constructing jsonArray.payload.body.script
      script = CreateObject("roAssociativeArray")
      script.AddReplace("type", "Setup")
      script.AddReplace("version", version)
  
      ' Constructing jsonArray.payload.body
      body = CreateObject("roAssociativeArray")
      body.AddReplace("script", script)
  
      ' Constructing jsonArray.payload
      payload = CreateObject("roAssociativeArray")
      payload.AddReplace("route", "/v1/script-status")
      payload.AddReplace("body", body)
      
      ' Constructing jsonArray
      jsonArray = CreateObject("roAssociativeArray")
      jsonArray.AddReplace("payload", payload)
  
      return jsonArray
  
  end function
  
  
  Sub ParseJsonLogging(setupParams as object, setup_sync as object)
    
    setupParams.playbackLoggingEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "playbackLoggingEnabled"))
    setupParams.stateLoggingEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "stateLoggingEnabled"))
    setupParams.eventLoggingEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "eventLoggingEnabled"))
    setupParams.diagnosticLoggingEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "diagnosticLoggingEnabled"))
    setupParams.variableLoggingEnabled = GetBoolFromNumericString(setup_sync.LookupMetadata("client", "variableLoggingEnabled"))
    
  end sub
  
  
  Sub CheckStorageDeviceIsWritable()
    
    ' determine if the storage device is writable
    tmpFileName$ = "bs~69-96.txt"
    WriteAsciiFile(tmpFileName$, "1")
    readValue$ = ReadAsciiFile(tmpFileName$)
    if len(readValue$) = 1 and readValue$ = "1" then
      DeleteFile(tmpFileName$)
    else
      ' only display message if device supports video
      videoMode = CreateObject("roVideoMode")
      if type(videoMode) = "roVideoMode" then
        resX = videoMode.GetResX()
        resY = videoMode.GetResY()
        videoMode = invalid
        
        r = CreateObject("roRectangle", 0, 0, resX, resY)
        twParams = CreateObject("roAssociativeArray")
        twParams.LineCount = 1
        twParams.TextMode = 2
        twParams.Rotation = 0
        twParams.Alignment = 1
        tw = CreateObject("roTextWidget", r, 1, 2, twParams)
        tw.PushString("")
        tw.Show()
        
        r = CreateObject("roRectangle", 0, resY / 2 - resY / 32, resX, resY / 32)
        tw = CreateObject("roTextWidget", r, 1, 2, twParams)
        tw.PushString("The attached storage device is write protected.")
        tw.Show()
        
        r2 = CreateObject("roRectangle", 0, resY / 2, resX, resY / 32)
        tw2 = CreateObject("roTextWidget", r2, 1, 2, twParams)
        tw2.PushString("Remove it, enable writing, and reboot the device.")
        tw2.Show()
      end if
      
      msgPort = CreateObject("roMessagePort")
      msg = wait(0, msgPort)
    end if
    
  end sub
  
  
  ' Note that the check only needed for series 4 and older models
  ' Series 5 and newer models should always support BSN.cloud so no need to check
  Sub CheckFirmwareVersion()
    
    modelObject = CreateObject("roDeviceInfo")
    
    ' check to see whether or not the current firmware meets the minimum compatibility requirements
    ' note that the return value for the GetVersionNumber() method does not include any additional version numbers after the first three
    ' the calculation is major*65536 + minor*256 + build
    versionNumber% = modelObject.GetVersionNumber()
    
    if modelObject.GetFamily() = "pantera" then
      minVersionNumber% = 524407
      minVersion$ = "8.0.119"
    else if modelObject.GetFamily() = "pagani" then
      minVersionNumber% = 524407
      minVersion$ = "8.0.119"
    else if modelObject.GetFamily() = "impala" then
      minVersionNumber% = 524407
      minVersion$ = "8.0.119"
    else if modelObject.GetFamily() = "malibu" then
      minVersionNumber% = 524407
      minVersion$ = "8.0.119"
    else if modelObject.GetFamily() = "tiger" then
      minVersionNumber% = 524407
      minVersion$ = "8.0.119"
    else ' no supported devices should hit this else
      minVersionNumber% = 524407
      minVersion$ = "8.0.119"
    end if
    
    if versionNumber% < minVersionNumber% then
      osUpgradeMsg$ = "Firmware needs to be upgraded to " + minVersion$ + " or greater"
      ' only display message if device supports video
      videoMode = CreateObject("roVideoMode")
      if type(videoMode) = "roVideoMode" then
        resX = videoMode.GetResX()
        resY = videoMode.GetResY()
        videoMode = invalid
        r = CreateObject("roRectangle", 0, resY / 2 - resY / 64, resX, resY / 32)
        twParams = CreateObject("roAssociativeArray")
        twParams.LineCount = 1
        twParams.TextMode = 2
        twParams.Rotation = 0
        twParams.Alignment = 1
        tw = CreateObject("roTextWidget", r, 1, 2, twParams)
        tw.PushString(osUpgradeMsg$)
        tw.Show()
      else
        ' for a model that doesn't support video, print the message instead
        systemLog = CreateObject("roSystemLog")
        systemLog.SendLine(osUpgradeMsg$)
      end if
      msgPort = CreateObject("roMessagePort")
      gpioPort = CreateObject("roGpioControlPort")
      gpioPort.SetPort(msgPort)
      while true
        msg = wait(0, msgPort)
        if type(msg) = "roGpioButton" and msg.GetInt() = 12 then
          stop
        end if
      end while
    end if
    
  end sub
  
  
  Sub ClearRegistryKeys(registrySection as object)
    
    ' Clear legacy registry keys
    registrySection.Delete("next")
    registrySection.Delete("event")
    registrySection.Delete("error")
    registrySection.Delete("deviceerror")
    registrySection.Delete("devicedownload")
    registrySection.Delete("recurl")
    registrySection.Delete("timezone")
    registrySection.Delete("unitName")
    registrySection.Delete("unitNamingMethod")
    registrySection.Delete("unitDescription")
    registrySection.Delete("timeBetweenNetConnects")
    registrySection.Delete("contentDownloadsRestricted")
    registrySection.Delete("contentDownloadRangeStart")
    registrySection.Delete("contentDownloadRangeLength")
    registrySection.Delete("useDHCP")
    registrySection.Delete("staticIPAddress")
    registrySection.Delete("subnetMask")
    registrySection.Delete("gateway")
    registrySection.Delete("broadcast")
    registrySection.Delete("dns1")
    registrySection.Delete("dns2")
    registrySection.Delete("dns3")
    registrySection.Delete("timeServer")
    registrySection.Delete("account")
    registrySection.Delete("user")
    registrySection.Delete("password")
    registrySection.Delete("group")
    
    ' Clear other keys in case they're no longer used
    ' If user specifies to inherit network properties,
    ' we do not delete previous network settings
    registrySection.Delete("uup")
    registrySection.Delete("cfv")
    
    registrySection.Delete("brightWallName")
    registrySection.Delete("brightWallScreenNumber")
    
    registrySection.Delete("beacon1")
    registrySection.Delete("beacon2")
    
    registrySection.Delete("susse")
  
    registrySection.Delete("su")
  
    'BCN-7431: prevent unexpected LFN setup workflow error, but still allow LFN support application setup
    registrySection.Delete("ru")
  end sub
  
  
  Sub ClearNetworkRegistryKeys(registrySection as object, inp as boolean)
  
    if not inp then
  
      registrySection.Delete("up")
      registrySection.Delete("ps")
      registrySection.Delete("bph")
      registrySection.Delete("ts")
  
      registrySection.Delete("wifi")
      registrySection.Delete("ss")
      registrySection.Delete("pp")
  
      registrySection.Delete("ncp")
      registrySection.Delete("ncp2")
  
      registrySection.Delete("cwr")
      registrySection.Delete("twr")
      registrySection.Delete("mwr")
      registrySection.Delete("hwr")
      registrySection.Delete("lwr")
  
      registrySection.Delete("cwf")
      registrySection.Delete("twf")
      registrySection.Delete("mwf")
      registrySection.Delete("hwf")
      registrySection.Delete("lwf")
  
      registrySection.Delete("sip")
      registrySection.Delete("sm")
      registrySection.Delete("gw")
      registrySection.Delete("d1")
      registrySection.Delete("d2")
      registrySection.Delete("d3")
  
      registrySection.Delete("sip2")
      registrySection.Delete("sm2")
      registrySection.Delete("gw2")
      registrySection.Delete("d12")
      registrySection.Delete("d22")
      registrySection.Delete("d32")
  
      registrySection.Delete("rlmid")
      registrySection.Delete("rlrid")
      registrySection.Delete("rlmow")
      registrySection.Delete("rlrow")
      registrySection.Delete("rlmiw")
      registrySection.Delete("rlriw")
  
      registrySection.Delete("rlmid2")
      registrySection.Delete("rlrid2")
      registrySection.Delete("rlmow2")
      registrySection.Delete("rlrow2")
      registrySection.Delete("rlmiw2")
      registrySection.Delete("rlriw2")
  
      registrySection.Delete("inp")
      registrySection.Delete("networkjson")
  
      registrySection.Delete("cdrs")
      registrySection.Delete("cdrl")
  
      'WPA Enterprise parameters
      registrySection.Delete("enableWPAEnterpriseAuthentication")
      registrySection.Delete("wpaEnterpriseVariant")
      registrySection.Delete("eapCertificateType")
      registrySection.Delete("eapCertificate")
      registrySection.Delete("eapPassphrase")
      registrySection.Delete("eapPemOrDerKey")
      registrySection.Delete("peapUsername")
      registrySection.Delete("peapPassphrase")
      registrySection.Delete("caCertificate")
      registrySection.Delete("enableWPAEnterpriseAuthentication2")
      registrySection.Delete("wpaEnterpriseVariant2")
      registrySection.Delete("eapCertificateType2")
      registrySection.Delete("eapCertificate2")
      registrySection.Delete("eapPassphrase2")
      registrySection.Delete("eapPemOrDerKey2")
      registrySection.Delete("peapUsername2")
      registrySection.Delete("peapPassphrase2")
      registrySection.Delete("caCertificate2")
  
    end if
  
  end sub
  
  
  Function RegistrationReset(registrySection as object)
  
    registration_flag = registrySection.Read("registered_with_bsn")
    registration_in_progress = registrySection.Read("registration_in_progress")
  
    ' if found registration flag set and it's the first time setup script rebooted
    ' means flag was left over from previous setup
    ' delete registered_with_bsn flag so that player can re-register
    if (IsTruthy(registration_flag) = true) and (not (IsTruthy(registration_in_progress) = true)) then
      registrySection.Delete("registered_with_bsn")
      registrySection.Delete("access_token")
      registrySection.Delete("access_token_expiration")
      registrySection.Delete("refresh_token")
      registrySection.Delete("bsnrt")
      registrySection.Delete("a")
      registrySection.Write("registration_in_progress", "yes")
      registrySection.Flush()
      return true
    end if
  
    return false
  
  end function
  
  
  Sub WriteRegistryVersion(registrySection as object, version as string)
  
    registrySection.Write("version", version)
  
  End sub
  
  
  Function GetRateLimits(setupParams as object, rateLimitModeKey$ as string, rateLimitRateKey$ as string)
    
    rateLimitModeSpec$ = setupParams[rateLimitModeKey$]
    
    rateLimitMode$ = "default"
    rateLimitRate$ = "0"
    rateLimitRate% = -1
    
    if rateLimitModeSpec$ = "unlimited" then
      rateLimitMode$ = "unlimited"
      rateLimitRate% = 0
    else if rateLimitModeSpec$ = "specified" then
      rateLimitMode$ = "specified"
      rateLimitRate$ = setupParams[rateLimitRateKey$]
      rateLimitRate% = int(val(rateLimitRate$))
    end if
    
    rateLimits = { }
    rateLimits.rateLimitMode$ = rateLimitMode$
    rateLimits.rateLimitRate$ = rateLimitRate$
    rateLimits.rateLimitRate% = rateLimitRate%
    
    return rateLimits
    
  end function
  
  
  Function SetNetworkConfiguration(interfaceNum% as integer, setupParams as object, registrySection as object, keySuffix$ as string, registrySuffix$ as string)
    
    networkingParameters = { }
    if setupParams.inheritNetworkProperties then
      nc = CreateObject("roNetworkConfiguration", interfaceNum%)
  
      useDHCP = true
      if type(nc) = "roNetworkConfiguration" then
        ' GetCurrentConfig().dhcp is of type roBoolean
        ' Doc: https://docs.brightsign.biz/display/DOC/roNetworkConfiguration#roNetworkConfiguration-GetCurrentConfig()AsObject
        useDHCP = nc.GetCurrentConfig().dhcp
      end if
  
      if useDHCP = false then
        currentConfig = nc.GetCurrentConfig()
        registrySection.Write("dhcp" + registrySuffix$, "no")
        registrySection.Write("sip" + registrySuffix$, currentConfig.ip4_address)
        registrySection.Write("sm" + registrySuffix$, currentConfig.ip4_netmask)
        registrySection.Write("gw" + registrySuffix$, currentConfig.ip4_gateway)
        ' dns_servers is an roArray of Strings
        dnsServers = currentConfig.dns_servers
        for i = 1 to 3
          currentDns = dnsServers[i-1]
          if IsString(currentDns) then
            registrySection.Write("d"+StripLeadingSpaces(stri(i))+registrySuffix$, currentDns)
          else
            registrySection.Write("d"+StripLeadingSpaces(stri(i))+registrySuffix$, "")
          end if
        next
      else
        registrySection.Write("dhcp" + registrySuffix$, "yes")
      end if
  
    else
      networkingParameters.useDHCP = setupParams["useDHCP" + keySuffix$]
      
      if not networkingParameters.useDHCP then
        networkingParameters.staticIPAddress$ = setupParams["staticIPAddress" + keySuffix$]
        networkingParameters.subnetMask$ = setupParams["subnetMask" + keySuffix$]
        networkingParameters.gateway$ = setupParams["gateway" + keySuffix$]
        networkingParameters.dns1$ = setupParams["dns1" + keySuffix$]
        networkingParameters.dns2$ = setupParams["dns2" + keySuffix$]
        networkingParameters.dns3$ = setupParams["dns3" + keySuffix$]
        
        registrySection.Write("dhcp" + registrySuffix$, "no")
        registrySection.Write("sip" + registrySuffix$, networkingParameters.staticIPAddress$)
        registrySection.Write("sm" + registrySuffix$, networkingParameters.subnetMask$)
        registrySection.Write("gw" + registrySuffix$, networkingParameters.gateway$)
        registrySection.Write("d1" + registrySuffix$, networkingParameters.dns1$)
        registrySection.Write("d2" + registrySuffix$, networkingParameters.dns2$)
        registrySection.Write("d3" + registrySuffix$, networkingParameters.dns3$)
      else
        registrySection.Write("dhcp" + registrySuffix$, "yes")
      end if
    end if
    
    rateLimits = GetRateLimits(setupParams, "rateLimitModeOutsideWindow" + keySuffix$, "rateLimitRateOutsideWindow" + keySuffix$)
    rlmow$ = rateLimits.rateLimitMode$
    rlrow$ = rateLimits.rateLimitRate$
    
    rateLimits = GetRateLimits(setupParams, "rateLimitModeInWindow" + keySuffix$, "rateLimitRateInWindow" + keySuffix$)
    rlmiw$ = rateLimits.rateLimitMode$
    rlriw$ = rateLimits.rateLimitRate$
    
    rateLimits = GetRateLimits(setupParams, "rateLimitModeInitialDownloads" + keySuffix$, "rateLimitRateInitialDownloads" + keySuffix$)
    rlmid$ = rateLimits.rateLimitMode$
    rlrid$ = rateLimits.rateLimitRate$
    networkingParameters.rl% = rateLimits.rateLimitRate%
    
    registrySection.Write("rlmow" + registrySuffix$, rlmow$)
    registrySection.Write("rlrow" + registrySuffix$, rlrow$)
    registrySection.Write("rlmiw" + registrySuffix$, rlmiw$)
    registrySection.Write("rlriw" + registrySuffix$, rlriw$)
    registrySection.Write("rlmid" + registrySuffix$, rlmid$)
    registrySection.Write("rlrid" + registrySuffix$, rlrid$)
    
    'WPA/802.1X Authentication Configuration
    networkingParameters.enableWPAEnterpriseAuthentication = setupParams["enableWPAEnterpriseAuthentication" + keySuffix$]
    registrySection.Write("enableWPAEnterpriseAuthentication" + registrySuffix$ , GetTrueFalseFromBoolean(networkingParameters.enableWPAEnterpriseAuthentication))
  	  
    if networkingParameters.enableWPAEnterpriseAuthentication then
  
      networkingParameters.wpaEnterpriseVariant$ = setupParams["wpaEnterpriseVariant" + keySuffix$]
      registrySection.Write("wpaEnterpriseVariant" + registrySuffix$, networkingParameters.wpaEnterpriseVariant$)
  		
      if networkingParameters.wpaEnterpriseVariant$ = "WPAEnterpriseEapTls" then
        networkingParameters.eapCertificateType$ = setupParams["eapCertificateType" + keySuffix$]
        registrySection.Write("eapCertificateType" + registrySuffix$, networkingParameters.eapCertificateType$)
        
        networkingParameters.eapCertificate = CreateObject("roByteArray")
        ok = networkingParameters.eapCertificate.ReadFile(setupParams["eapCertificateFileName" + keySuffix$])
        if ok then
          fileContents$ = networkingParameters.eapCertificate.ToBase64String()
          registrySection.Write("eapCertificate" + registrySuffix$, fileContents$)
        endif
  
        if networkingParameters.eapCertificateType$ = "WPAEapTlsPEMorDER" then
          networkingParameters.eapPemOrDerKey = CreateObject("roByteArray")
          ok = networkingParameters.eapPemOrDerKey.ReadFile(setupParams["eapPemOrDerKeyFileName" + keySuffix$])
          if ok then
            fileContents$ = networkingParameters.eapPemOrDerKey.ToBase64String()
            registrySection.Write("eapPemOrDerKey" + registrySuffix$, fileContents$)
          endif
        endif
  
        networkingParameters.eapPassphrase$ = setupParams["eapCertificatePassphrase" + keySuffix$]
        registrySection.Write("eapPassphrase" + registrySuffix$, networkingParameters.eapPassphrase$)
  			
      else if networkingParameters.wpaEnterpriseVariant$ = "WPAEnterprisePeap" then
        networkingParameters.peapUsername$ = setupParams["peapUsername" + keySuffix$]
        networkingParameters.peapPassphrase$ = setupParams["peapPassphrase" + keySuffix$]
        registrySection.Write("peapUsername" + registrySuffix$, networkingParameters.peapUsername$)
        registrySection.Write("peapPassphrase" + registrySuffix$, networkingParameters.peapPassphrase$)
      endif
  		
      networkingParameters.isCaCertificate = false
      networkingParameters.caCertificate = CreateObject("roByteArray")
      ok = networkingParameters.caCertificate.ReadFile(setupParams["caCertificateFileName" + keySuffix$])
  
      if ok then
        fileContents$ = networkingParameters.caCertificate.ToBase64String()
        if len(fileContents$) > 0 then
          registrySection.Write("caCertificate" + registrySuffix$, fileContents$)
          networkingParameters.isCaCertificate = true
        endif
      endif
  
      if networkingParameters.isCaCertificate then
        registrySection.Write("isCaCertificate" + registrySuffix$, "True")
      else
        registrySection.Write("isCaCertificate" + registrySuffix$, "False")
      endif
  
    endif
    
    return networkingParameters
    
  end function
  
  
  Sub SetLogging(setupParams as object, registrySection as object)
    
    if type(registrySection) = "roRegistrySection" then
      registrySection.Write("ple", GetYesNoFromBoolean(setupParams.playbackLoggingEnabled))
      registrySection.Write("ele", GetYesNoFromBoolean(setupParams.eventLoggingEnabled))
      registrySection.Write("sle", GetYesNoFromBoolean(setupParams.stateLoggingEnabled))
      registrySection.Write("dle", GetYesNoFromBoolean(setupParams.diagnosticLoggingEnabled))
      registrySection.Write("vle", GetYesNoFromBoolean(setupParams.variableLoggingEnabled))
      registrySection.Write("uab", GetYesNoFromBoolean(setupParams.uploadLogFilesAtBoot))
      registrySection.Write("uat", GetYesNoFromBoolean(setupParams.uploadLogFilesAtSpecificTime))
      registrySection.Write("ut", GetNumericStringFromNumber(setupParams.uploadLogFilesTime%))
    end if
    
  end sub
  
  
  Function GetModelSupportsWifi()
    
    modelSupportsWifi = false
    nc = CreateObject("roNetworkConfiguration", 1)
    if type(nc) = "roNetworkConfiguration" then
      currentConfig = nc.GetCurrentConfig()
      if type(currentConfig) = "roAssociativeArray" then
        modelSupportsWifi = true
      end if
    end if
    nc = invalid
    return modelSupportsWifi
    
  end function
  
  
  Sub SetLWS(setupParams as object, registrySection as object)
    
    ' delete obsolete lws keys
    registrySection.Delete("lws")
    registrySection.Delete("lwsu")
    registrySection.Delete("lwsp")
    
    ' local web server
    if setupParams.lwsConfig$ = "content" or setupParams.lwsConfig$ = "status" then
      registrySection.Write("nlws", Left(setupParams.lwsConfig$, 1))
      registrySection.Write("nlwsu", setupParams.lwsUserName$)
      registrySection.Write("nlwsp", setupParams.lwsPassword$)
      registrySection.Write("nlwseun", GetYesNoFromBoolean(setupParams.lwsEnableUpdateNotifications))
    else
      registrySection.Delete("nlws")
      registrySection.Delete("nlwsu")
      registrySection.Delete("nlwsp")
      registrySection.Delete("nlwseun")
    end if
    
  end sub
  
  
  Sub SetHostname(specifyHostname as boolean, hostname$ as string)
    
    if specifyHostname then
      
      nc = CreateObject("roNetworkConfiguration", 0)
      
      if type(nc) <> "roNetworkConfiguration" then
        nc = CreateObject("roNetworkConfiguration", 1)
      end if
      
      if type(nc) = "roNetworkConfiguration" then
        ok = nc.SetHostname(hostname$)
        if ok then 
          nc.Apply()
        endif
        nc = invalid
      end if
    end if
    
  end sub
  
  
  Sub SetDWS(setupParams as object, registrySection as object)
    
    ' diagnostic web server
    
    dwsAA = CreateObject("roAssociativeArray")
    di = CreateObject("roDeviceInfo")
    deviceSerial$ = di.GetDeviceUniqueId()
    if setupParams.dwsEnabled or setupParams.remoteDwsEnabled then
      dwsAA["port"] = "80"
      if setupParams.dwsPassword$ = "§default" then
        ' Using "open" parameter here since serial is not encrypted.
        ' See https://brightsign.atlassian.net/wiki/spaces/DOC/pages/370673153/roNetworkConfiguration#roNetworkConfiguration-SetupDWS(settingsAsroAssociativeArray)AsBoolean
        ' for details.
        dwsAA["open"] = deviceSerial$
      else
        dwsAA["password"] = setupParams.dwsPassword$ 'also covers "" case
      end if
    else
      dwsAA["port"] = 0
    end if
    
    ' Set the old registry to see if dws or remotedws values are switched
    dwseRegistry = registrySection.Read("dwse")
    rdwseRegistry = registrySection.Read("rdwse")
    
    registrySection.Write("rdwse", GetYesNoFromBoolean(setupParams.remoteDwsEnabled))
    registrySection.Write("dwse", GetYesNoFromBoolean(setupParams.dwsEnabled))
  
    if setupParams.dwsPassword$ = "§default" then
      registrySection.Write("dwsp", deviceSerial$)
    else
      registrySection.Write("dwsp", setupParams.dwsPassword$)
    end if
    
    ' set DWS on device
    nc = CreateObject("roNetworkConfiguration", 0)
    
    if type(nc) <> "roNetworkConfiguration" then
      nc = CreateObject("roNetworkConfiguration", 1)
    end if
    
    if type(nc) = "roNetworkConfiguration" then
      restartRequired = nc.SetupDWS(dwsAA)
      ' Will put a RestartApplication() at the end of setup if setupParams.restartRequired = true.
      ' Unnecessary reboot for BSN/LFN/SFN. Refactor reboot throughout autorun for device setup
      if restartRequired then setupParams.restartRequired = true
      if dwseRegistry <> GetYesNoFromBoolean(setupParams.dwsEnabled) or rdwseRegistry <> GetYesNoFromBoolean(setupParams.remoteDwsEnabled) then
        setupParams.restartRequired = true
      end if
    end if
    
  end sub
  
  
  Sub ConfigureEthernet(ethernetNetworkingParameters as object, networkConnectionPriorityWired% as integer, timeServer$ as string, proxySpec$ as string, bypassProxyHosts as object, featureMinRevs as object)
    nc = CreateObject("roNetworkConfiguration", 0)
    if type(nc) = "roNetworkConfiguration" then
      nc.ResetInterfaceSettings()
      ConfigureNetwork(nc, ethernetNetworkingParameters, networkConnectionPriorityWired%, timeServer$, proxySpec$, bypassProxyHosts, featureMinRevs)
    else
      print "Unable to create roNetworkConfiguration - index = 0"
    end if
  end sub
  
  
  Sub ConfigureWifi(wifiNetworkingParameters as object, ssid$ as string, passphrase$ as string, networkConnectionPriorityWireless% as integer, timeServer$ as string, proxySpec$ as string, bypassProxyHosts as object, featureMinRevs as object)
  
    nc = CreateObject("roNetworkConfiguration", 1)
    if type(nc) = "roNetworkConfiguration" then
      nc.ResetInterfaceSettings()
      nc.SetWiFiESSID(ssid$)
      nc.SetObfuscatedWifiPassphrase(passphrase$)
      ConfigureNetwork(nc, wifiNetworkingParameters, networkConnectionPriorityWireless%, timeServer$, proxySpec$, bypassProxyHosts, featureMinRevs)
    else
      print "Unable to create roNetworkConfiguration - index = 1"
    end if
  end sub
  
  
  Sub ConfigureNetwork(nc as object, networkingParameters as object, networkConnectionPriority% as integer, timeServer$ as string, proxySpec$ as string, bypassProxyHosts as object, featureMinRevs as object)
    
    if not networkingParameters.useDHCP then
      nc.SetIP4Address(networkingParameters.staticIPAddress$)
      nc.SetIP4Netmask(networkingParameters.subnetMask$)
      nc.SetIP4Gateway(networkingParameters.gateway$)
      if networkingParameters.dns1$ <> "" then nc.AddDNSServer(networkingParameters.dns1$)
      if networkingParameters.dns2$ <> "" then nc.AddDNSServer(networkingParameters.dns2$)
      if networkingParameters.dns3$ <> "" then nc.AddDNSServer(networkingParameters.dns3$)
    else
      nc.SetDHCP()
    end if
    
    nc.SetRoutingMetric(networkConnectionPriority%)
    nc.SetTimeServer(timeServer$)
    nc.SetProxy(proxySpec$)
    
    ok = nc.SetProxyBypass(bypassProxyHosts)
    
    nc.SetInboundShaperRate(networkingParameters.rl%)
  
    success = nc.Apply()
    
    ConfigureWPANetwork(nc, networkingParameters)
  
  end sub
  
  
  Sub ConfigureEthernetWPA(ethernetNetworkingParameters as object)
  
    nc = CreateObject("roNetworkConfiguration", 0)
    if type(nc) = "roNetworkConfiguration" then
      ConfigureWPANetwork(nc, ethernetNetworkingParameters)
    else
      print "Unable to create roNetworkConfiguration - index = 0"
    end if
  
  end sub
  
  
  Sub ConfigureWifiWPA(wifiNetworkingParameters as object)
  
    nc = CreateObject("roNetworkConfiguration", 1)
    if type(nc) = "roNetworkConfiguration" then
      ConfigureWPANetwork(nc, wifiNetworkingParameters)
    else
      print "Unable to create roNetworkConfiguration - index = 1"
    end if
  
  end sub
  
  
  Sub ConfigureWPANetwork(nc as object, networkingParameters as object)
  
    if networkingParameters.enableWPAEnterpriseAuthentication then
    
      if networkingParameters.wpaEnterpriseVariant$ = "WPAEnterpriseEapTls" then
  
        'EAP-TLS
        if networkingParameters.eapCertificateType$ = "WPAEapTlsPKCS" then
          'PKCS#12
          ok = nc.SetWiFiClientCertificate("")
          ok = nc.SetWiFiPrivateKey(networkingParameters.eapCertificate)
        else if networkingParameters.eapCertificateType$ = "WPAEapTlsPEMorDER" then
          'X.509
          ok = nc.SetWiFiClientCertificate(networkingParameters.eapCertificate)
          ok = nc.SetWiFiPrivateKey(networkingParameters.eapPemOrDerKey)
        endif
        'optional passphrase for any of the above certificates
        if networkingParameters.eapPassphrase$ <> "" then
          nc.SetObfuscatedWiFiPassphrase(networkingParameters.eapPassphrase$)
        endif
      else if networkingParameters.wpaEnterpriseVariant$ = "WPAEnterprisePeap" then
        'PEAP
        nc.SetWiFiIdentity(networkingParameters.peapUsername$)
        if networkingParameters.peapPassphrase$ <> "" then
          nc.SetObfuscatedWiFiPassphrase(networkingParameters.peapPassphrase$)
        endif
      endif
  
      if networkingParameters.isCaCertificate = true then
        'CA
        nc.SetWiFiCACertificates(networkingParameters.caCertificate)
      endif
  
      success = nc.Apply()
  
    endif
  
  end sub
  
  
  Sub DisableWireless()
    nc = CreateObject("roNetworkConfiguration", 1)
    if type(nc) = "roNetworkConfiguration" then
      nc.SetDHCP()
      nc.SetWiFiESSID("")
      nc.SetObfuscatedWifiPassphrase("")
      nc.SetWiFiIdentity("")
      nc.SetWiFiCaCertificates("")
      nc.SetWiFiClientCertificate("")
      nc.SetWiFiPrivateKey("")
      nc.SetWiFiPassphrase("")
      nc.Apply()
    end if
  end sub
  
  
  Sub SetWiredParameters(setupParams as object, registrySection as object, useWireless as boolean)
    
    if useWireless then
      if setupParams.inheritNetworkProperties then
        ' get wired priority from OS
        nc0 = CreateObject("roNetworkConfiguration", 0)
        if type(nc0) = "roNetworkConfiguration" then
          registrySection.Write("ncp", GetNumericStringFromNumber(nc0.GetCurrentConfig().metric))
          ' Content data types enabled keep previous settings
        end if
      else
        registrySection.Write("ncp", GetNumericStringFromNumber(setupParams.networkConnectionPriorityWired%))
        registrySection.Write("cwr", GetTrueFalseFromBoolean(setupParams.contentDataTypeEnabledWired))
        registrySection.Write("twr", GetTrueFalseFromBoolean(setupParams.textFeedsDataTypeEnabledWired))
        registrySection.Write("hwr", GetTrueFalseFromBoolean(setupParams.healthDataTypeEnabledWired))
        registrySection.Write("mwr", GetTrueFalseFromBoolean(setupParams.mediaFeedsDataTypeEnabledWired))
        registrySection.Write("lwr", GetTrueFalseFromBoolean(setupParams.logUploadsXfersEnabledWired))
      end if
    else
      registrySection.Write("ncp", "0")
      registrySection.Write("cwr", "True")
      registrySection.Write("twr", "True")
      registrySection.Write("hwr", "True")
      registrySection.Write("mwr", "True")
      registrySection.Write("lwr", "True")
    end if
    
  end sub
  
  
  Function SetWirelessParameters(setupParams as object, registrySection as object, modelSupportsWifi as boolean) as boolean
  
    if setupParams.useWireless and modelSupportsWifi then
      registrySection.Write("wifi", "yes")
      registrySection.Write("ss", setupParams.ssid$)
      registrySection.Write("pp", setupParams.passphrase$)
      
      registrySection.Write("ncp2", GetNumericStringFromNumber(setupParams.networkConnectionPriorityWireless%))
      registrySection.Write("cwf", GetTrueFalseFromBoolean(setupParams.contentDataTypeEnabledWireless))
      registrySection.Write("twf", GetTrueFalseFromBoolean(setupParams.textFeedsDataTypeEnabledWireless))
      registrySection.Write("hwf", GetTrueFalseFromBoolean(setupParams.healthDataTypeEnabledWireless))
      registrySection.Write("mwf", GetTrueFalseFromBoolean(setupParams.mediaFeedsDataTypeEnabledWireless))
      registrySection.Write("lwf", GetTrueFalseFromBoolean(setupParams.logUploadsXfersEnabledWireless))
      return true
    end if
  
    registrySection.Write("wifi", "no")
    return false
    
  end function
  
  Function GetWirelessParametersInheritNetworkProperties(setupParams as object, registrySection as object, modelSupportsWifi as boolean, checkINPWifiConnectionTimerCount as integer) as string
    
    setupParams.useWireless = IsWifiConnected()
  
    if modelSupportsWifi and checkINPWifiConnectionTimerCount < 3 then
      if setupParams.useWireless then
        registrySection.Write("wifi", "yes")
  
        ' get wireless priority from OS
        nc1 = CreateObject("roNetworkConfiguration", 1)
        if type(nc1) = "roNetworkConfiguration" then
          ' TODO: overwrite wifi ssid and passpharse in registry once OS-11064 is ready to return wifi passphrase
          ' registrySection.Write("ss", nc1.GetWiFiESSID())
          ' registrySection.Write("pp", nc1.??())
          registrySection.Write("ncp2", GetNumericStringFromNumber(nc1.GetCurrentConfig().metric))
        end if
        ' Content data types enabled keep previous settings
        return "wifiConnected"
      else
        wifiPreviouslySet = registrySection.read("wifi")
        ssidPreviouslySet = registrySection.read("ss")
        if wifiPreviouslySet = "yes" and ssidPreviouslySet <> "" then
          return "wifiConnectionPending"
        end if
      end if
    end if
    print "Unable to inherit Wifi configuration, disabling Wifi"
    registrySection.Write("wifi", "no")
    return "wifiCantConnect"
  
  End Function
  
  Function IsWifiConnected() as boolean
      ' Wifi interface
      wifiAvailable = false
      nc1 = CreateObject("roNetworkConfiguration", 1)
  
      if type(nc1) = "roNetworkConfiguration" then
  
        wifiConfig = nc1.GetCurrentConfig()
        if (wifiConfig.DoesExist("ip4_address")) then
          wifiIpAddressAvailable = (wifiConfig.Lookup("ip4_address") <> "")
        else
          wifiIpAddressAvailable = false
        end if
  
        if (wifiConfig.DoesExist("link")) then
          wifiLinkAvailable = wifiConfig.Lookup("link")
        end if
  
        wifiAvailable = (wifiIpAddressAvailable and wifiLinkAvailable)
      end if
  
      return wifiAvailable
  
  end function
  
  
  Function SetNetworkConfigurationInterfaces(setupParams as object, registrySection as object, useWireless as boolean, modelSupportsWifi as boolean)
    
    networkConfigurationInterfaces = {}
  
    ' Network configurations
    if useWireless then
      if modelSupportsWifi then
        networkConfigurationInterfaces.wifiNetworkingParameters = SetNetworkConfiguration(1, setupParams, registrySection, "", "")
        networkConfigurationInterfaces. ethernetNetworkingParameters = SetNetworkConfiguration(0, setupParams, registrySection, "_2", "2")
      else
        ' if the user specified wireless but the system doesn't support it, use the parameters specified for wired (the secondary parameters)
        networkConfigurationInterfaces.ethernetNetworkingParameters = SetNetworkConfiguration(0, setupParams, registrySection, "_2", "")
      end if
    else
      networkConfigurationInterfaces.ethernetNetworkingParameters = SetNetworkConfiguration(0, setupParams, registrySection, "", "")
    end if
  
    ' registry writes complete - flush it
    registrySection.Flush()
  
    return networkConfigurationInterfaces
  
  End Function
  
  
  ' B-Deploy use case: recovery url might be present for non-BSN setup types
  Sub SetRecoveryHandlerUrl(setupParams as object, registrySection as object)
    if IsString(setupParams.recoveryHandler) and setupParams.recoveryHandler <> "" then
      registrySection.Write("ru", setupParams.recoveryHandler)
    end if
  End Sub
  
  
  Function GetProxy(setupParams as object, registrySection as object) as string
    
    proxySpec$ = ""
    if setupParams.inheritNetworkProperties then
  
      nc = CreateObject("roNetworkConfiguration", 0)
      if type(nc) = "roNetworkConfiguration" then
        proxySpec$ = nc.GetProxy()
        if IsString(proxySpec$) and proxySpec$ <> "" then
          registrySection.Write("up", "yes")
          registrySection.Write("ps", proxySpec$)
          return proxySpec$
        end if
      end if
  
    else
      if setupParams.useProxy then
        
        proxySpec$ = ""
        registrySection.Write("up", "yes")
        registrySection.Write("ps", setupParams.proxySpec$)
        
        return setupParams.proxySpec$
        
      end if
    
    end if
    
    registrySection.Write("up", "no")
    return ""
    
  end function
  
  
  Function GetBypassProxyHosts(proxySpec$ as string, setupParams as object) as object
    
    bypassProxyHosts = []
    
    if proxySpec$ <> "" then
      
      for each networkHost in setupParams.networkHosts
        ParseProxyBypass(bypassProxyHosts, networkHost)
      next
      
    end if
    
    return bypassProxyHosts
    
  end function
  
  
  Sub ParseProxyBypass(bypassProxyHosts as object, networkHost as object)
    
    if networkHost.BypassProxy then
      hostName$ = networkHost.HostName
      if hostName$ <> "" then
        bypassProxyHosts.push(hostName$)
      end if
    end if
    
  end sub
  
  
  Sub WriteTimeServer(setupParams as object, registrySection as object)
    if setupParams.inheritNetworkProperties then
      ' Time server
      nc = CreateObject("roNetworkConfiguration", 0)
      if type(nc) = "roNetworkConfiguration" then
        timeServer = nc.GetTimeServer()
        if IsString(timeServer) and timeServer <> "" then
          ' apply time server in the case after factory reset
          if timeServer = "default://" then
            timeServer = "ntp://time.brightsignnetwork.com"
            nc.SetTimeServer(timeServer)
            nc.Apply()
          end if
          registrySection.Write("ts", timeServer)
          print "time server in setup script = ";timeServer
        end if
      end if
    else
      registrySection.Write("ts", setupParams.timeServer$)
      print "time server in setup script = ";setupParams.timeServer$
    end if
  end sub
  
  
  Function GetBinding(wiredTransferEnabled as boolean, wirelessTransferEnabled as boolean) as integer
    
    binding% = -1
    if wiredTransferEnabled <> wirelessTransferEnabled then
      if wiredTransferEnabled then
        binding% = 0
      else
        binding% = 1
      end if
    end if
    
    return binding%
    
  end function
  
  
  ' Check not invalid, then check either true/false
  Function IsTruthy(value)
    valueType = type(value)
    if valueType = "Boolean" or valueType = "roBoolean" then
      if value = true or value = True then
        return true
      else if value = false or value = False then
        return false
      end if
    else if valueType = "String" or valueType = "roString" then
      if value = "true" or value = "True" or value = "1" or value = "on" or value = "On" or value = "yes" or value = "Yes" then
        return true
      else if value = "false" or value = "False" or value = "0" or value = "off" or value = "Off" or value = "no" or value = "No" then
        return false
      end if
    else if valueType = "Integer" or valueType = "roInteger" then
      if value = 1 then
        return true
      else if value = 0 then
        return false
      end if
    end if
    return invalid
  end function
  
  
  Function GetBoolFromNumericString(value$ as string) as boolean
    if value$ = "1" then return true
    return false
  end function
  
  
  Function GetNumberFromNumericString(value$ as string) as integer
    return int(val(value$))
  end function
  
  
  Function GetYesNoFromBoolean(value as boolean) as string
    if value then return "yes"
    return "no"
  end function
  
  
  Function GetTrueFalseFromBoolean(value as boolean) as string
    if value then return "True"
    return "False"
  end function
  
  
  Function GetNumericStringFromNumber(value% as integer) as string
    return stri(value%)
  end function
  
  
  Function StripLeadingSpaces(inputString$ as string) as string
    
    while true
      if left(inputString$, 1) <> " " then return inputString$
      inputString$ = right(inputString$, len(inputString$) - 1)
    end while
    
    return inputString$
    
  end function
  
  
  ' The pair function syncSpecValueFalse can be found in autoxml.brs
  ' only add this function because only it is being used in autorun-setup-simple-networking.brs
  Function syncSpecValueTrue(syncSpecValue$) as boolean
    if lcase(syncSpecValue$) = "yes" or syncSpecValue$ = "1" or lcase(syncSpecValue$) = "true" then
      return true
    end if
    return false
  end function
  
  Sub ClearBsnce(supervisorRegistrySection As Object, bsnCloudEnabled)
    if IsTruthy(bsnCloudEnabled) = invalid or IsTruthy(bsnCloudEnabled) <> false then
      supervisorRegistrySection.Delete("bsnce")
    end if
  end sub
  
  
  Sub SetRemoteSnapshot(setupParams as object, registrySection as object)
    
    registrySection.Write("enableRemoteSnapshot", GetYesNoFromBoolean(setupParams.enableRemoteSnapshot))
    
    if setupParams.enableRemoteSnapshot then
      registrySection.Write("remoteSnapshotInterval", GetNumericStringFromNumber(setupParams.remoteSnapshotInterval%))
      registrySection.Write("remoteSnapshotMaxImages", GetNumericStringFromNumber(setupParams.remoteSnapshotMaxImages%))
      registrySection.Write("remoteSnapshotJpegQualityLevel", GetNumericStringFromNumber(setupParams.remoteSnapshotJpegQualityLevel%))
  
      ' remoteSnapshotDisplayPortrait changed to remoteSnapshotOrientation for BCN-6961
      orientation = setupParams.remoteSnapshotOrientation
      ' if remote snapshot orientation is not found in sync spec, use the default value "Landscape"
      if IsString(orientation) and orientation <> "" then
        registrySection.Write("remoteSnapshotOrientation", orientation)
      else
        registrySection.Write("remoteSnapshotOrientation", "Landscape")
      end if
    end if
    
  end sub
  
  
  Sub SetIdleColor(setupParams as object, registrySection as object)
    
    registrySection.Write("isc", setupParams.idleScreenColor$)
    
  end sub
  
  
  Function CreateDeviceSetupSplashScreen(headervalue as string, messagevalue as string, msgPort as object)
    
    filepath = ""
      
    filepath = "sys:/web-client/postDeviceSetupSplashScreen/dist/index.html"
    
    file = CreateObject("roReadFile", filepath)
    
    if file <> invalid then
      filepath = "file:/" + filepath
      
      videoMode = CreateObject("roVideoMode")
      resX = videoMode.GetResX()
      resY = videoMode.GetResY()
      r = CreateObject("roRectangle", 0, 0, resX, resY)
      config = {
        url: filepath
        brightsign_js_objects_enabled: true
        nodejs_enabled: true
      }
      htmlWidget = CreateObject("roHtmlWidget", r, config)
      if type(htmlWidget) = "roHtmlWidget" then
        htmlWidget.SetPort(msgPort)
        htmlWidget.AllowJavascriptUrls({ all: "*" })
        htmlWidget.EnableJavascript(true)
        sleep(5000)
        
        htmlWidget.PostJSMessage({
          htmlcommand: "setupsplashscreenmessage",
          headermsg: headervalue,
          message: messagevalue
        })
        htmlWidget.Show()
        sleep(5000)
        return htmlWidget
      else
        stop
      end if
    end if
    'endif
    
    return invalid
    
  end function
  
  
  Function UpdateSplashScreenMessage(headervalue as string, messagevalue as string, htmlWidget as object)
    htmlWidget.PostJSMessage({
      htmlcommand: "setupsplashscreenmessage",
      headermsg: headervalue,
      message: messagevalue
    })
  
    return htmlWidget
  end function
  
  
  Function SetDeviceSplashScreenMessageByType(deviceSplashScreen as object, msgType as string, msgPort as object)
    headervalue = ""
    messagevalue = ""
    if msgType = "sfn_complete" then
      headervalue = "Congratulations, your BrightSign player is set up!"
      messagevalue = "Use BrightAuthor:connected to publish content via the Web Folder mode."
    else if msgType = "sfn_error"
      headervalue = "Failed to connect to the Web Folder."
      messagevalue = "Please confirm that the Web Folder is accessible and that the Web Folder URL was correctly entered during player setup."
    else if msgType = "standalone_complete" then
      headervalue = "Congratulations, your BrightSign player is set up!"
      messagevalue = "Use BrightAuthor:connected to publish content to a MicroSD card. Then, insert the card into the player."
    else if msgType = "no_application_url" then
      headervalue = "Cannot find the App URL while setting up the Partner App."
      messagevalue = "Please confirm that the App URL was correctly entered during player setup."
    else if msgType = "network_setup_failure" then
      headervalue = "Network setup failure"
      messagevalue = "Please visit support.brightsign.biz to contact BrightSign Tech Support."
    else if (msgType.left(12) = "unknown_type") then
      setupType = msgType.right(msgType.len()-13)
      headervalue = "Unknown setup type"
      messagevalue = "Cannot recognize the setup type: "+setupType
    else if (msgType.right(10) = "initialize") then
      setupType = msgType.left(msgType.len()-11)
      if setupType = "bsn" then
        headervalue = "BSN.cloud setup is in progress..."
      else if setupType = "sfn" then
        headervalue = "Web Folder setup is in progress..."
      else if setupType = "lfn" then
        headervalue = "Local Network setup is in progress..."
      else if setupType = "standalone" then
        headervalue = "Standalone setup is in progress..."
      else if setupType = "partnerapplication"
        headervalue = "Partner App setup is in progress..."
      else
        headervalue = "Player setup is in progress..."
      end if
      messagevalue = "Please wait for the player setup to finish. Do not unplug or reboot the player."
    end if
  
    if headervalue <> "" and messagevalue <> "" then
      if deviceSplashScreen = invalid then
        return CreateDeviceSetupSplashScreen(headervalue, messagevalue, msgPort)
      else
        return UpdateSplashScreenMessage(headervalue, messagevalue, deviceSplashScreen)
      end if
    else
      return invalid
    end if
  
  end function
  
  
  Sub SetCustomSplashScreen(setupParams as object, registrySection as object, featureMinRevs as object)
    
    deviceCustomization = CreateObject("roDeviceCustomization")
    
    if setupParams.useCustomSplashScreen then
      ok = deviceCustomization.WriteSplashScreen("customSplashScreen")
    else
      ok = deviceCustomization.WriteSplashScreen("")
    end if
    
  end sub
  
  
  Sub SetBeacons(spec as object, registrySection as object, featureMinRevs as object)
    
    return
    
    ''		for n = 1 to 2
    ''			key$ = "beacon" + Mid(stri(n),2)
    ''			beaconJson = GetEntry(spec, key$)
    ''			if Len(beaconJson) > 0 then
    ''				registrySection.Write(key$, beaconJson)
    ''			endif
    ''		next
    
  end sub
  
  
  Function ParseFeatureMinRevs() as object
    
    featureMinRevs = { }
    
    path$ = "featureMinRevs.json"
    featureMinRevs$ = ReadAsciiFile(path$)
    
    if len(featureMinRevs$) > 0 then
      
      publishedFeatureMinRevs = ParseJson(featureMinRevs$)
      
      ' verify that this is a valid FeatureMinRevs Json file
      if type(publishedFeatureMinRevs.FeatureMinRevs) <> "roAssociativeArray" then print "Invalid FeatureMinRevs JSON file - name not FeatureMinRevs" : stop
      if not IsString(publishedFeatureMinRevs.FeatureMinRevs.version) then print "Invalid FeatureMinRevs JSON file - version not found" : stop
      
      for each featureAA in publishedFeatureMinRevs.FeatureMinRevs.features
        featureName$ = featureAA.name
        minRev$ = featureAA.minFWRev
        featureMinRevs.AddReplace(featureName$, minRev$)
      next
      
    end if
    
    return featureMinRevs
    
  end function
  
  
  Function IsFeatureSupported(featureName$ as string, featureMinRevs as object) as boolean
    
    modelObject = CreateObject("roDeviceInfo")
    fwVersion$ = modelObject.GetVersion()
    
    featureExists = featureMinRevs.DoesExist(featureName$)
    if featureExists then
      featureMinFWRev = featureMinRevs[featureName$]
      featureMinFWRevVSFWVersion% = CompareFirmwareVersions(featureMinFWRev, fwVersion$)
      if featureMinFWRevVSFWVersion% <= 0 then
        return true
      end if
    end if
    
    return false
    
  end function
  
  
  Function CompareFirmwareVersions(a$ as string, b$ as string) as integer
    
    start_a% = 0
    start_b% = 0
    
    while true
      
      if start_a% >= len(a$) then
        if start_b% >= len(b$) then
          return 0
        else
          return -1
        end if
      else if start_b% >= len(b$) then
        return 1
      end if
      
      aChar$ = mid(a$, start_a% + 1, 1)
      a_digit = IsDigit(aChar$)
      
      bChar$ = mid(b$, start_b% + 1, 1)
      b_digit = IsDigit(bChar$)
      
      if a_digit and b_digit then
        
        ' Now we need to find the end of each of the sequences of digits.
        aa = { }
        aa.index = start_a%
        a_number% = ReadDigits(a$, aa)
        start_a% = aa.index
        
        bb = { }
        bb.index = start_b%
        b_number% = ReadDigits(b$, bb)
        start_b% = bb.index
        
        if a_number% < b_number% then
          return -1
        else if a_number% > b_number% then
          return 1
        end if
      else if a_digit then
        ' The first string has a digit but the second one has a
        ' non-digit so it must be greater.
        return 1
      else if b_digit then
        return -1
      else
        aChar$ = mid(a$, start_a% + 1, 1)
        bChar$ = mid(b$, start_b% + 1, 1)
        
        if asc(aChar$) < asc(bChar$) then
          return -1
        else if asc(aChar$) > asc(bChar$)
          return 1
        end if
        
        ' Otherwise we've dealt with this character
        start_a% = start_a% + 1
        start_b% = start_b% + 1
      end if
    end while
    
  end function
  
  
  Function IsDigit(a$ as string) as boolean
    
    if asc(a$) >= 48 and asc(a$) <= 57 then
      return true
    else
      return false
    end if
    
  end function
  
  
  Function ReadDigits(s$ as string, aa as object) as integer
    
    value% = 0
    
    index% = aa.index
    
    sChar$ = mid(s$, index% + 1, 1)
    
    while index% < len(s$) and IsDigit(sChar$)
      
      new_value% = value% * 10 + asc(sChar$) - asc("0")
      index% = index% + 1
      
      value% = new_value%
      
      if len(s$) > index% then
        sChar$ = mid(s$, index% + 1, 1)
      end if
      
    end while
    
    aa.index = index%
    return value%
    
  end function
  
  
  Sub SetBsnCloudParameters(setupParams as object, registrySection as object)
  
    if setupParams.account <> "" and setupParams.group <> "" and setupParams.bsnRegistrationToken <> "" then
      registrySection.Write("a", setupParams.account)
      registrySection.Write("g", setupParams.group)
      registrySection.Write("bsnrt", setupParams.bsnRegistrationToken)
      registrySection.Write("endpoints_s3Url", setupParams.endpoints_s3Url)
      registrySection.Write("endpoints_provisionServer", setupParams.endpoints_provisionServer)
      registrySection.Write("endpoints_bsnServer", setupParams.endpoints_bsnServer)
      registrySection.Write("endpoints_websocketsDWS", setupParams.endpoints_websocketsDWS)
      registrySection.Write("endpoints_bsnApiServer", setupParams.endpoints_bsnApiServer)
      registrySection.Write("endpoints_certsServer", setupParams.endpoints_certsServer)
    end if
  
  end sub
  
  
  Sub RestartIfNecessary(setupParams as object, restartScript as boolean)
  
    if setupParams.restartRequired <> invalid and setupParams.restartRequired = true then
      a = RestartApplication()
      stop
    else
      if restartScript then
        a = RestartScript()
        stop
      end if
    end if
  
  end sub
  
  
  Sub WaitRegistrationMessage(timerIntervalInSeconds as integer, proceedSignal as boolean, msgPort as object, port as integer)
    registrationResponseTimer= CreateObject("roTimer")
    registrationResponseTimer.SetPort(msgPort)
    ' Wait for reigstration response for a min
    registrationResponseTimer.SetElapsed(timerIntervalInSeconds, 0)
    registrationResponseTimer.Start()
  
    proceedAfterRegistrationProcessComplete = false
    ' ProceedSignal will be true when registered_with_bsn flag is set to yes
    if proceedSignal = true then
      proceedAfterRegistrationProcessComplete = true
    end if
  
    ' Registration process may be complete by:
    ' 1. a successful registration(flag is set or get udp/application message from supervisor) 
    ' 2. timeout occurring prior to receiving a successful message from the supervisor
    while not proceedAfterRegistrationProcessComplete
      msg = wait(0, msgPort)
      if type(msg) = "roTimerEvent" then
        if stri(msg.GetSourceIdentity()) = stri(registrationResponseTimer.GetIdentity()) then
          proceedAfterRegistrationProcessComplete = true
        end if
      else if type(msg) = "roDatagramEvent" and msg.GetSourcePort() = port and IsString(msg.GetUserData()) and msg.GetUserData() = "bootstrap" then
        payload = ParseJson(msg.GetString())
        if payload <> invalid and payload.message <> invalid and payload.message = "sync.registration.complete" then
          proceedAfterRegistrationProcessComplete = true
        end if
      else if type(msg) = "roControlCloudMessageEvent" and IsString(msg.GetUserData()) and msg.GetUserData() = "bootstrap" then
        jsonobject = ParseJson(msg.GetData())
        if jsonobject <> invalid and jsonobject.message <> invalid and jsonobject.message = "sync.registration.complete" then
          proceedAfterRegistrationProcessComplete = true
        end if
      end if
    end while
  
  end sub
  
  
  Function GetSupervisorSupportsConfigureNetwork(msgPort as object) as boolean
  
    url = CreateObject("roUrlTransfer")
    bootstrapRestBase = "http://127.0.0.1"
    registrationRequestUrl = bootstrapRestBase + "/api/v1/system/supervisor/registration"
  
    url.SetUrl(registrationRequestUrl)
    url.SetPort(msgPort)
    url.SetProxyBypass(["127.0.0.1", "localhost"]) ' BCN-8732
  
    result = url.GetToString()
    if result <> "" then
      payload = ParseJson(result)
      if type(payload) = "roAssociativeArray" and type(payload.data) = "roAssociativeArray" and type(payload.data.result) = "roAssociativeArray" then
        if type(payload.data.result.setupSupport) = "roAssociativeArray" and IsBoolean(payload.data.result.setupSupport.network) and payload.data.result.setupSupport.network then
          return true
        endif
      endif
    endif
  
    return false
  
  end function
  
  
  Function TriggerRegistrationRequest(registrySection as object, msgPort as object) as string
  
    url = CreateObject("roUrlTransfer")
    bootstrapRestBase = "http://127.0.0.1"
    registrationRequestUrl = bootstrapRestBase + "/api/v1/system/supervisor/registration"
  
    url.SetUrl(registrationRequestUrl)
    url.SetPort(msgPort)
    url.SetProxyBypass(["127.0.0.1", "localhost"]) ' BCN-8732
  
    aa = {}
    aa.method = "PUT"
    aa.request_body_string = ""
    aa.response_body_string = true
    
    registrationUrlEvent = url.SyncMethod(aa)
    rc = registrationUrlEvent.getResponseCode()
  
    if rc = 404 then
      ' 404 means endpoint does not exist
      ' we are probably talking to an old OS
      ' restart supervisor to trigger a registration request
      RestartApplication()
      stop
    endif
  
    if rc = 200 then
  
      result = registrationUrlEvent.getString()
      payload = ParseJson(result)
      if type(payload) = "roAssociativeArray" and type(payload.data) = "roAssociativeArray" and type(payload.data.result) = "roAssociativeArray" and type(payload.data.result.setup) = "roAssociativeArray" and type(payload.data.result.setup.network) = "roAssociativeArray" and IsBoolean(payload.data.result.setup.network.success) then
        
        if payload.data.result.setup.network.success then
          return "networkSetupSuccess"
        else
          return "networkSetupFailure"
        endif
  
      endif
  
      return "networkSetupNotFound"
  
    else
  
      ' BCN-8430 if failed to trigger a registration request, restart application
      print "Failed to trigger registration request. Error code:";ok
      RestartApplication()
      stop
  
    endif
  
  end function
  
  
  Function EnableDebugging(filePath$) as object
    
    debugParams = { }
    
    debugParams.serialDebugOn = false
    debugParams.systemLogDebugOn = false
    
    syncSpec = CreateObject("roSyncSpec")
    
    if syncSpec.ReadFromFile(filePath$) then
      if syncSpecValueTrue(syncSpec.LookupMetadata("client", "enableSerialDebugging")) then
        debugParams.serialDebugOn = true
      end if
      if syncSpecValueTrue(syncSpec.LookupMetadata("client", "enableSystemLogDebugging")) then
        debugParams.systemLogDebugOn = true
      end if
    end if
    
    syncSpec = invalid
    
    return debugParams
    
  end function
  
  
  REM *******************************************************
  REM *******************************************************
  REM ***************                    ********************
  REM *************** DIAGNOSTICS OBJECT ********************
  REM ***************                    ********************
  REM *******************************************************
  REM *******************************************************
  
  REM
  REM construct a new diagnostics BrightScript object
  REM
  Function newDiagnostics(sysFlags as object) as object
    
    diagnostics = { }
    
    diagnostics.debug = sysFlags.debugOn
    diagnostics.systemLogDebug = sysFlags.systemLogDebugOn
  
    if diagnostics.systemLogDebug then
      diagnostics.systemLog = CreateObject("roSystemLog")
    end if
  
    diagnostics.setupVersion$ = "unknown"
    diagnostics.deviceFWVersion$ = "unknown"
    diagnostics.systemTime = CreateObject("roSystemTime")
    
    diagnostics.PrintDebug = PrintDebug
    diagnostics.PrintTimestamp = PrintTimestamp
    diagnostics.SetSystemInfo = SetSystemInfo
    diagnostics.TurnDebugOn = TurnDebugOn
      
    return diagnostics
    
  end function
  
  
  Sub PrintDebug(debugStr$ as string)
    
    if type(m) <> "roAssociativeArray" then stop
    
    if m.debug then    
      print debugStr$
    end if
    
    if m.systemLogDebug then
      m.systemLog.SendLine(debugStr$)
    end if
    
  end sub
  
  
  Sub PrintTimestamp()
    
    eventDateTime = m.systemTime.GetLocalDateTime()
    if m.debug then print eventDateTime.GetString()
    if m.systemLogDebug then m.systemLog.SendLine(eventDateTime.GetString())
    
  end sub
  
  
  Sub SetSystemInfo(sysInfo as object, diagnosticCodes as object)
    
    m.setupVersion$ = sysInfo.setupVersion$
    m.deviceFWVersion$ = sysInfo.deviceFWVersion$
    m.deviceUniqueID$ = sysInfo.deviceUniqueID$
    m.deviceModel$ = sysInfo.deviceModel$
    m.deviceFamily$ = sysInfo.deviceFamily$
    m.deviceFWVersionNumber% = sysInfo.deviceFWVersionNumber%
    
    m.diagnosticCodes = diagnosticCodes
    
  end sub
  
  
  Sub TurnDebugOn()
    
    m.debug = true
    
    return
    
  end sub
  
  
  Function IsBoolean(inputVariable as object) as boolean
  
    if type(inputVariable) = "roBoolean" or type(inputVariable) = "boolean" then return true
    return false
  
  end function
  
  
  Function IsString(inputVariable as object) as boolean
    
    if type(inputVariable) = "roString" or type(inputVariable) = "String" then return true
    return false
    
  end function
  