text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

struct NetworkWatchersApi <: SwaggerApi
    client::Swagger.Client
end

"""

Verifies the possibility of establishing a direct TCP connection from a virtual machine to a given endpoint including another VM or an arbitrary remote server.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::ConnectivityParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: ConnectivityInformation
"""
function _swaggerinternal_networkWatchersCheckConnectivity(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", ConnectivityInformation, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/connectivityCheck", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersCheckConnectivity(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersCheckConnectivity(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersCheckConnectivity(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersCheckConnectivity(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Creates or updates a network watcher in the specified resource group.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::NetworkWatcher (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NetworkWatcher
"""
function _swaggerinternal_networkWatchersCreateOrUpdate(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "PUT", NetworkWatcher, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersCreateOrUpdate(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersCreateOrUpdate(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersCreateOrUpdate(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersCreateOrUpdate(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Deletes the specified network watcher resource.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Nothing
"""
function _swaggerinternal_networkWatchersDelete(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "DELETE", Nothing, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersDelete(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersDelete(_api, resourceGroupName, networkWatcherName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersDelete(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersDelete(_api, resourceGroupName, networkWatcherName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets the specified network watcher by resource group.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NetworkWatcher
"""
function _swaggerinternal_networkWatchersGet(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", NetworkWatcher, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGet(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGet(_api, resourceGroupName, networkWatcherName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGet(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGet(_api, resourceGroupName, networkWatcherName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

NOTE: This feature is currently in preview and still being tested for stability. Gets the relative latency score for internet service providers from a specified location to Azure regions.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::AzureReachabilityReportParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: AzureReachabilityReport
"""
function _swaggerinternal_networkWatchersGetAzureReachabilityReport(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", AzureReachabilityReport, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/azureReachabilityReport", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetAzureReachabilityReport(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetAzureReachabilityReport(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetAzureReachabilityReport(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetAzureReachabilityReport(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Queries status of flow log and traffic analytics (optional) on a specified resource.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::FlowLogStatusParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: FlowLogInformation
"""
function _swaggerinternal_networkWatchersGetFlowLogStatus(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", FlowLogInformation, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/queryFlowLogStatus", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetFlowLogStatus(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetFlowLogStatus(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetFlowLogStatus(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetFlowLogStatus(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets Network Configuration Diagnostic data to help customers understand and debug network behavior. It provides detailed information on what security rules were applied to a specified traffic flow and the result of evaluating these rules. Customers must provide details of a flow like source, destination, protocol, etc. The API returns whether traffic was allowed or denied, the rules evaluated for the specified flow and the evaluation results.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::NetworkConfigurationDiagnosticParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NetworkConfigurationDiagnosticResponse
"""
function _swaggerinternal_networkWatchersGetNetworkConfigurationDiagnostic(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", NetworkConfigurationDiagnosticResponse, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/networkConfigurationDiagnostic", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetNetworkConfigurationDiagnostic(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetNetworkConfigurationDiagnostic(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetNetworkConfigurationDiagnostic(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetNetworkConfigurationDiagnostic(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets the next hop from the specified VM.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::NextHopParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NextHopResult
"""
function _swaggerinternal_networkWatchersGetNextHop(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", NextHopResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/nextHop", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetNextHop(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetNextHop(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetNextHop(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetNextHop(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets the current network topology by resource group.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::TopologyParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Topology
"""
function _swaggerinternal_networkWatchersGetTopology(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", Topology, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/topology", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetTopology(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetTopology(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetTopology(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetTopology(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Initiate troubleshooting on a specified resource.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::TroubleshootingParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: TroubleshootingResult
"""
function _swaggerinternal_networkWatchersGetTroubleshooting(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", TroubleshootingResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/troubleshoot", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetTroubleshooting(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetTroubleshooting(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetTroubleshooting(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetTroubleshooting(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Get the last completed troubleshooting result on a specified resource.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::QueryTroubleshootingParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: TroubleshootingResult
"""
function _swaggerinternal_networkWatchersGetTroubleshootingResult(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", TroubleshootingResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/queryTroubleshootResult", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetTroubleshootingResult(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetTroubleshootingResult(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetTroubleshootingResult(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetTroubleshootingResult(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets the configured and effective security group rules on the specified VM.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::SecurityGroupViewParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: SecurityGroupViewResult
"""
function _swaggerinternal_networkWatchersGetVMSecurityRules(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", SecurityGroupViewResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/securityGroupView", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersGetVMSecurityRules(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetVMSecurityRules(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersGetVMSecurityRules(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersGetVMSecurityRules(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets all network watchers by resource group.
Param: resourceGroupName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NetworkWatcherListResult
"""
function _swaggerinternal_networkWatchersList(_api::NetworkWatchersApi, resourceGroupName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", NetworkWatcherListResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers", ["azure_auth"])
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersList(_api::NetworkWatchersApi, resourceGroupName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersList(_api, resourceGroupName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersList(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersList(_api, resourceGroupName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets all network watchers by subscription.
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NetworkWatcherListResult
"""
function _swaggerinternal_networkWatchersListAll(_api::NetworkWatchersApi, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", NetworkWatcherListResult, "/subscriptions/{subscriptionId}/providers/Microsoft.Network/networkWatchers", ["azure_auth"])
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersListAll(_api::NetworkWatchersApi, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersListAll(_api, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersListAll(_api::NetworkWatchersApi, response_stream::Channel, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersListAll(_api, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

NOTE: This feature is currently in preview and still being tested for stability. Lists all available internet service providers for a specified Azure region.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::AvailableProvidersListParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: AvailableProvidersList
"""
function _swaggerinternal_networkWatchersListAvailableProviders(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", AvailableProvidersList, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/availableProvidersList", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersListAvailableProviders(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersListAvailableProviders(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersListAvailableProviders(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersListAvailableProviders(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Configures flow log and traffic analytics (optional) on a specified resource.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::FlowLogInformation (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: FlowLogInformation
"""
function _swaggerinternal_networkWatchersSetFlowLogConfiguration(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", FlowLogInformation, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/configureFlowLog", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersSetFlowLogConfiguration(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersSetFlowLogConfiguration(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersSetFlowLogConfiguration(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersSetFlowLogConfiguration(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Updates a network watcher tags.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::TagsObject (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: NetworkWatcher
"""
function _swaggerinternal_networkWatchersUpdateTags(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "PATCH", NetworkWatcher, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersUpdateTags(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersUpdateTags(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersUpdateTags(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersUpdateTags(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Verify IP flow from the specified VM to a location given the currently configured NSG rules.
Param: resourceGroupName::String (required)
Param: networkWatcherName::String (required)
Param: parameters::VerificationIPFlowParameters (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: VerificationIPFlowResult
"""
function _swaggerinternal_networkWatchersVerifyIPFlow(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", VerificationIPFlowResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkWatchers/{networkWatcherName}/ipFlowVerify", ["azure_auth"], parameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "networkWatcherName", networkWatcherName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function networkWatchersVerifyIPFlow(_api::NetworkWatchersApi, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersVerifyIPFlow(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function networkWatchersVerifyIPFlow(_api::NetworkWatchersApi, response_stream::Channel, resourceGroupName::String, networkWatcherName::String, parameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_networkWatchersVerifyIPFlow(_api, resourceGroupName, networkWatcherName, parameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

export networkWatchersCheckConnectivity, networkWatchersCreateOrUpdate, networkWatchersDelete, networkWatchersGet, networkWatchersGetAzureReachabilityReport, networkWatchersGetFlowLogStatus, networkWatchersGetNetworkConfigurationDiagnostic, networkWatchersGetNextHop, networkWatchersGetTopology, networkWatchersGetTroubleshooting, networkWatchersGetTroubleshootingResult, networkWatchersGetVMSecurityRules, networkWatchersList, networkWatchersListAll, networkWatchersListAvailableProviders, networkWatchersSetFlowLogConfiguration, networkWatchersUpdateTags, networkWatchersVerifyIPFlow


text:
module sif

function image(encoding::Array{Int,1}, width::Int, height::Int)
    layers = div(div(length(encoding), width), height)
    return reshape(encoding, (width, height, layers))
end

function resolve(img::Array{Int,3})
    (width, height, layers) = size(img)
    result = zeros(Int, (width, height))
    for i in 1:width, j in 1:height
        for k in 1:layers
            if img[i,j,k] == 2
                continue
            elseif img[i,j,k] == 0
                result[i,j] = 0
                break
            elseif img[i,j,k] == 1
                result[i,j] = 1
                break
            end
        end
    end
    return result
end

function checksum(img::Array{Int,3})
    (_, _, layers) = size(img)
    _, idx = findmin(map(layer -> count(x -> x == 0, img[:,:,layer]), 1:layers))
    ones = count(x -> x == 1, img[:,:,idx])
    twos = count(x -> x == 2, img[:,:,idx])
    return ones * twos
end

end

ext: jl


text:
module A1O2R2
export GameEnv, GameSpec
include("game.jl")
end


text:
module WizardsChess

  using Revise
  using Blink
  using Chess

  Chess.square(string::AbstractString) = Chess.square(String(string))

  include("structs.jl")
  include("valid_moves.jl")

  characters = [
  "a", "b", "c", "d",
  "e", "f", "g", "h"
  ]

  algebraic_notation = function (row,col)
      characters[col] * string(row)
  end

  export start

  function run_turn(player)
    game = player.game

    cur_rand = rand()

    if game.halfmove_clock <= 5
      depth = 2
    elseif game.halfmove_clock <= 20
      if cur_rand < 0.25
        depth = 1
      elseif cur_rand < 0.75
        depth = 2
      else
        depth = 3
      end
    elseif game.halfmove_clock < 35
      if cur_rand < 0.2
        depth = 0
      elseif cur_rand < 0.4
        depth = 1
      elseif cur_rand < 0.6
        depth = 2
      elseif cur_rand < 0.8
        depth = 3
      else
        depth = 4
      end
    end

    cur_move = Chess.long_algebraic_format(
      Chess.best_move_search(
        Chess.read_fen(fen(game)), depth
      )[2]
    )

    if length(cur_move) == 5
      cur_move, piece_char = cur_move[1:4], cur_move[5:5]
      @assert piece_char in ["q", "n", "b", "r"]
      if piece_char == "q"
        piece_class_name = "Queen"
      elseif piece_char == "n"
        piece_class_name = "Knight"
      elseif piece_char == "b"
        piece_class_name = "Bishop"
      else
        @assert piece_char == "r"
        piece_class_name = "Rook"
      end
    else
      piece_char = ""
    end

    @assert length(cur_move) == 4
    @assert !isnothing(match(r"[a-h]\d[a-h]\d", cur_move))

    beg_col, beg_row, end_col, end_row = split(cur_move, "")

    beg_col = findfirst(tmp_char -> tmp_char == beg_col, characters)
    end_col = findfirst(tmp_char -> tmp_char == end_col, characters)

    beg_row = parse(Int,beg_row)
    end_row = parse(Int,end_row)

    piece = game.board[beg_row,beg_col]
    piece_name = lowercase(last(split(string(typeof(piece)),".")))

    if piece_name == "king" && abs( beg_col - end_col ) > 1
      @assert !piece.player.has_castled

      @assert abs( beg_col - end_col ) == 2
      @assert beg_col == 5
      @assert beg_row == end_row
      @assert beg_row == 1 || beg_row == 8

      if end_col > beg_col
        @assert piece.player.can_castle_right
        end_col = 8
      else
        @assert piece.player.can_castle_left
        end_col = 1
      end

      end_col, end_row, beg_col, beg_row =
        beg_col, beg_row, end_col, end_row
    end

    cur_string = Blink.JSString("""
      var delayedFunction = function() {

        \$("#js-row__$(beg_row) #js-col__$(beg_col) .svg-inline--fa").css("pointer-events", "auto");
        \$("#js-row__$(beg_row) #js-col__$(beg_col) .svg-inline--fa").click();

        var subDelayedFunction = function() {
          var checkExist = setInterval(function() {
             if ( \$("#js-row__$(end_row) #js-col__$(end_col) .cs-overlay").hasClass("disabled") ) {
                \$("#js-row__$(end_row) #js-col__$(end_col) .cs-overlay").removeClass("disabled");
                \$("#js-row__$(end_row) #js-col__$(end_col) .cs-overlay").click();
                clearInterval(checkExist);
      """ *
      (
        piece_char == "" ? "" : "Blink.msg('select_piece', ['$(piece_class_name)'])"
      ) *
      """
             }
          }, 100);
        }

        setTimeout(subDelayedFunction,500);

      }

      setTimeout(delayedFunction,250);
    """)

    @js_(game.window, $cur_string)

  end

  function build_board!(game)
    work_string = "";
    work_string *= "\$('.cs-overlay').removeClass('active');"
    work_string *= "\$('.cs-overlay').removeClass('disabled');"
    work_string *= "\$('.cs-overlay').removeClass('cs-capture');"
    work_string *= "\$('.cs-overlay').removeClass('cs-castle');"
    work_string *= "\$('.cs-overlay').removeClass('js-auto');"
    work_string *= "\$('#js-table .svg-inline--fa').remove();"

    for i in 1:8
      for j in 1:8
        isnothing(game.board[i,j]) && continue

        piece = game.board[i,j]
        piece_name = lowercase(last(split(string(typeof(piece)),".")))
        piece_color = piece.player.is_white ? "white" : "black"

        cur_style = ( piece.player.is_human ) ? "" : "pointer-events: none;"

        work_string *= """
          \$("#js-row__$(i) #js-col__$(j)").prepend('');
        """
      end
    end

    for player in game.players
      isnothing(player.anti_pawn) && continue
      piece_color = player.is_white ? "white" : "black"

      work_string *= """
        \$("#js-row__$(player.anti_pawn.row) #js-col__$(player.anti_pawn.col)").prepend('');
      """
    end

    cur_string = Blink.JSString(work_string)
    @js_(game.window, $cur_string)
  end

  function fen(game::Game)
    fen = ""

    string_array = []
    for row in 8:-1:1
      push!(string_array, "")
      white_space = 0
      for col in 1:8
        tmp_piece = game.board[row,col]

        if isnothing(tmp_piece)
          white_space += 1
          continue
        end

        if white_space > 0
          string_array[end] *= string(white_space)
          white_space = 0
        end

        tmp_piece_name = lowercase(last(split(string(typeof(tmp_piece)),".")))
        piece_char = tmp_piece_name == "knight" ? "n" : tmp_piece_name[1]
        piece_char = ( tmp_piece.player.is_white ) ? uppercase(piece_char) : lowercase(piece_char)

        string_array[end] *= piece_char
      end
      ( white_space > 0 ) && ( string_array[end] *= string(white_space) )
    end

    fen *= join(string_array, "/")

    fen *= game.is_whites_turn ? " w" : " b"

    white = filter(player -> player.is_white, game.players)[1]
    black = filter(player -> !player.is_white, game.players)[1]

    castling_string = ""

    white.can_castle_right && ( castling_string *= "K" )
    white.can_castle_left && ( castling_string *= "Q" )
    black.can_castle_right && ( castling_string *= "k" )
    black.can_castle_left && ( castling_string *= "q" )

    ( castling_string == "" ) && ( castling_string = "-" )

    fen *= " " * castling_string * " "

    if game.is_whites_turn
      fen *= isnothing(black.anti_pawn) ? "-" : algebraic_notation(black.anti_pawn.row,black.anti_pawn.col)
    else
      fen *= isnothing(white.anti_pawn) ? "-" : algebraic_notation(white.anti_pawn.row,white.anti_pawn.col)
    end

    fen *= " " * string(game.halfmove_clock)

    fen *= " " * string(game.fullmove_number)

    fen
  end

  function upgrade_pawn!(game, piece_class)
    pawns = filter(piece -> isa(piece,Pawn), vcat(map(player -> player.pieces, game.players)...))

    filter!(pawn -> ( pawn.row == 1 || pawn.row == 8 ), pawns)
    @assert length(pawns) == 1

    pawn = pawns[1]

    filter!(tmp_piece -> tmp_piece != pawn, pawn.player.pieces)

    piece = piece_class(pawn.player, pawn.row, pawn.col)
    push!(pawn.player.pieces, piece)

    game.board[pawn.row,pawn.col] = piece
  end

  function start()

    window = Window(async=false)
    size(window, (size(window)*1.5)...)

    js_pipeline = [
      ["core", "jquery.min.js"],
      ["core", "popper.min.js"],
      ["init.js"],
      ["bootstrap-material-design.js"],
      ["plugins", "moment.min.js"],
      ["plugins", "bootstrap-selectpicker.js"],
      ["plugins", "bootstrap-tagsinput.js"],
      ["plugins", "jasny-bootstrap.min.js"],
      ["plugins", "nouislider.min.js"],
      ["material-kit.js"],
      ["font-awesome.js"]
    ]

    for asset in js_pipeline
      load!(window, abspath(@__DIR__,"..", "assets", "js", asset...),async=false)
    end

    css_pipeline = [
      ["material-kit.css"]
    ]

    for asset in css_pipeline
      load!(window, abspath(@__DIR__,"..", "assets", "css", asset...),async=false)
    end

    loadcss!(window, "https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Roboto+Slab:400,700|Material+Icons")
    # loadjs!(window, "https://kit.fontawesome.com/fd1fd9f86d.js")

    load!(window, abspath(@__DIR__,"..", "assets", "app.css"), async=false)
    body!(window, String(read(abspath(@__DIR__,"..", "assets", "app.html"))), async=false)
    load!(window, abspath(@__DIR__,"..", "assets", "app.js"), async=false)

    game = Game(window, player_1_is_human=false)

    build_board!(game)

    handle(window, "click_piece") do args
      row, col = map(arg -> parse(Int,arg),args)
      piece = game.board[row,col]

      ( piece.player.is_white == game.is_whites_turn ) || return

      moves = valid_moves(piece)

      work_string = """
        var thisIsWhite = \$("#js-row__$(row) #js-col__$(col) .svg-inline--fa").hasClass("cs-white");
        var thatIsWhite = false;
        var usedClass = "";
      """

      work_string *= "\$('.cs-overlay').removeClass('active');"
      work_string *= "\$('.cs-overlay').removeClass('disabled');"
      work_string *= "\$('.cs-overlay').removeClass('cs-capture');"
      work_string *= "\$('.cs-overlay').removeClass('cs-castle');"
      work_string *= "\$('.cs-overlay').removeClass('js-auto');"

      if piece.player.is_human
        castle_class = "cs-castle"
      else
        castle_class = "cs-castle js-auto"
      end

      for (i,j) in moves
        work_string *= """
          \$("#js-row__$(i) #js-col__$(j) .cs-overlay").addClass('active');

          thatIsWhite = \$("#js-row__$(i) #js-col__$(j) .svg-inline--fa").hasClass("cs-white");

          if ( thisIsWhite == thatIsWhite ) {
            usedClass = '$(castle_class)';
          } else {
            usedClass = 'cs-capture';
          }

          if ( \$("#js-row__$(i) #js-col__$(j) .svg-inline--fa").length > 0 ) {
            \$("#js-row__$(i) #js-col__$(j) .cs-overlay").addClass(usedClass);
          }
        """

        if !piece.player.is_human
          work_string *= """
            \$("#js-row__$(i) #js-col__$(j) .cs-overlay").addClass("disabled");
          """
        end
      end

      cur_string = Blink.JSString(work_string)
      @js_(window, $cur_string)
    end

    handle(window, "click_overlay") do args
      game.halfmove_clock += 1

      piece_row, piece_col, overlay_row, overlay_col = map(arg -> parse(Int,arg),args)
      piece = game.board[piece_row,piece_col]

      @assert piece.player.is_white == game.is_whites_turn

      moves = valid_moves(piece)
      @assert [overlay_row,overlay_col] in moves

      piece.row = overlay_row
      piece.col = overlay_col

      piece.player.anti_pawn = nothing
      game.board[piece_row,piece_col] = nothing

      piece_name = lowercase(last(split(string(typeof(piece)),".")))
      other_piece = game.board[overlay_row,overlay_col]
      if isnothing(other_piece)
        game.board[overlay_row,overlay_col] = piece
      else
        other_piece_name = lowercase(last(split(string(typeof(other_piece)),".")))
        if piece.player == other_piece.player
          @assert piece_name == "rook"
          @assert other_piece_name == "king"
          @assert piece_col == 1 || piece_col == 8

          game.board[piece.row,piece.col] = nothing
          game.board[other_piece.row,other_piece.col] = nothing

          if piece_col == 1
            @assert piece.player.can_castle_left
            other_piece.col = 3
            piece.col = 4
          elseif piece_col == 8
            @assert piece.player.can_castle_right
            other_piece.col = 7
            piece.col = 6
          end

          game.board[piece.row,piece.col] = piece
          game.board[other_piece.row,other_piece.col] = other_piece

          piece.player.has_castled = true
          piece.player.can_castle_left = false
          piece.player.can_castle_right = false
        else
          filter!(tmp_piece -> tmp_piece != other_piece, other_piece.player.pieces)
          game.board[overlay_row,overlay_col] = piece
          game.halfmove_clock = 0
        end
      end

      if piece_name == "pawn"
        game.halfmove_clock = 0
        if piece.player.is_human && ( piece.row == 1 || piece.row == 8 )
          cur_string = Blink.JSString("\$('#exampleModal').modal({show: true})")
          @js_(game.window, $cur_string)
        end

        is_white = piece.player.is_white

        is_init = (
          ( is_white && piece_row == 2 ) ||
          ( !is_white && piece_row == 7 )
        )

        if is_init && abs(piece_row - overlay_row) > 1
          @assert piece_col == overlay_col
          @assert abs(piece_row - overlay_row) == 2
          piece.player.anti_pawn = AntiPawn(
            piece.player, Int((piece_row+overlay_row)/2), piece.col
          )
        end

        other_player = filter(tmp_player -> tmp_player != piece.player, game.players)[1]

        anti_pawn = other_player.anti_pawn
        if !isnothing(anti_pawn) && piece.row == anti_pawn.row && piece.col == anti_pawn.col
          if piece.player.is_white
            @assert piece.row == 6
            captured_pawn = game.board[piece_row,piece.col]
            @assert !isnothing(captured_pawn)

            captured_pawn_name = lowercase(last(split(string(typeof(captured_pawn)),".")))
            @assert captured_pawn_name == "pawn"
            @assert captured_pawn.player == other_player

            game.board[captured_pawn.row,captured_pawn.col] = nothing
            filter!(tmp_piece -> tmp_piece != captured_pawn_name, other_player.pieces)
          else
            @assert piece.row == 3
          end
        end
      end

      if piece_name == "king"
        piece.player.can_castle_left = false
        piece.player.can_castle_right = false
      end

      if piece_name == "rook"
        if piece.player.can_castle_left && piece_col == 1
          piece.player.can_castle_left = false
        elseif piece.player.can_castle_right && piece_col == 8
          piece.player.can_castle_right = false
        end
      end

      if piece.player.is_white
        game.is_whites_turn = false

        black = filter(player -> !player.is_white, game.players)[1]
        black.anti_pawn = nothing

        build_board!(game)
        black.is_human || run_turn(black)
      else
        game.fullmove_number += 1
        game.is_whites_turn = true

        white = filter(player -> player.is_white, game.players)[1]
        white.anti_pawn = nothing

        build_board!(game)
        white.is_human || run_turn(white)
      end

    end

    handle(window, "select_piece") do args
      @assert length(args) == 1
      piece_class = getfield(WizardsChess, Symbol(args[1]))

      upgrade_pawn!(game, piece_class)
      build_board!(game)

      cur_string = Blink.JSString("\$('#exampleModal').modal('hide')")
      @js_(game.window, $cur_string)
    end

    handle(window, "new_game") do args
      game = Game(window)

      build_board!(game)

      white = filter(player -> player.is_white, game.players)[1]
      white.is_human || run_turn(white)
    end

    white = filter(player -> player.is_white, game.players)[1]
    white.is_human || run_turn(white)

    game

  end

end


text:
"""
Collect cmd line args for processing and file access
Return: 2 file handles
"""

function getfilenames()
	if sizeof(ARGS) > 0

		rdname = ARGS[1]
		wrname = ARGS[2]
	else
		println("2 file names required. Exiting.")
		exit(-1)
  end

		x = open(rdname, "r")
		y = open(wrname, "w")
    return x, y
end

##############################################################################
# Call to format the REMI GDP table to csv
#
##############################################################################
function newstr(fhobj, fileout)
  for line in eachline(fhobj)
	  if line == "\n"
			continue
		end

    # Convert each line of text to a comma separated string
    # Filter out Dollar format ($ with , in number) and other characters
		fltr = Regex("(\\\$|,|\(|\)|\\n|)") # Nifty regex filter
		line = replace(line, fltr, "")  # Remove unwanted characters

    # Separate the text only string in first column
    textStrObj = match(r"[a-z-; ]+\s+"i, line )
		textStr = textStrObj.match  # access and store substring
		textStr = strip(textStr) # Remove the trailing white space

    # Now process the numeric values in vector
    numStrObj = match(r"([+-]?\d+\s+){4,}", line ) # Match up to 4 number fields
		numStr = numStrObj.match  # access and store substring
		numStr = strip(numStr) # Remove the trailing white space
		numStr = replace(numStr, r"\s+", ",") # Comma separate the number fields
    newStr = string(textStr, ",", numStr, "\n") # Rejoin fields w/ comma sep
		print(fileout, newStr)  # Write String to file
	end
  close(fileout)
  close(fhobj)
return
end

##############################################################################
#  CSV file format import to DataFrame
#
##############################################################################
function dataframeload(x)
  dfhandle = open(x, "r")
	df = readtable(dfhandle)
	#println(df)
	#in_dollars = df * 1000000
	#println(in_dollars)
return
end

##############################################################################
# Main Program
##############################################################################

function main()
  x, y = getfilenames()
	newstr(x, y)
	dfhandle = open("tmp1.txt", "r")
	col_names=[symbol("Sector"),symbol("2020"), symbol("2025"), symbol("2030"), symbol("2035")]
	df = readtable(dfhandle, header=false, names=col_names)
  #println(head(df,4))
	#println(head(df[:Sector]))
	#println(tail(df, 3))
end
##############################################################################
#
##############################################################################
using DataFrames
#using Debug

#dataframeload(ARGS[2])
main()
exit(0)

max_stars_repo_name: mnatale/column-filter

max_issues_repo_name: mnatale/column-filter

max_forks_repo_name: mnatale/column-filter


text:
#!/usr/bin/env julia

using Luxor

using Test

using Random
Random.seed!(42)

CAIRO_PATH_MOVE_TO = 0
CAIRO_PATH_LINE_TO = 1
CAIRO_PATH_CURVE_TO = 2
CAIRO_PATH_CLOSE_PATH = 3

function get_path_flat(str)
    sethue("blue")
    setopacity(.7)
    setline(0.5)
    p = textpath(str)
    o = getpathflat()
    strokepath()
    sethue("red")
    x, y = 0, 0
    for e in o
        if e.element_type == CAIRO_PATH_MOVE_TO
            (x, y) = e.points
            move(x, y)
        elseif e.element_type == CAIRO_PATH_LINE_TO
            (x, y) = e.points
            # straight lines
            line(x, y)
            strokepath()
            circle(x, y, 1, :stroke)
        elseif e.element_type == CAIRO_PATH_CURVE_TO
            (x1, y1, x2, y2, x3, y3) = e.points
            # show bezier control lines
            circle(x1, y1, 1, :stroke)
            circle(x2, y2, 1, :stroke)
            circle(x3, y3, 1, :stroke)
            move(x, y)
            curve(x1, y1, x2, y2, x3, y3)
            strokepath()
            (x, y) = (x3, y3) # update current point
        elseif e.element_type == CAIRO_PATH_CLOSE_PATH
            closepath()
        else
            error("unknown CairoPathEntry " * repr(e.element_type))
            error("unknown CairoPathEntry " * repr(e.points))
        end
    end
end

function get_path_flat_test(fname)
    Drawing(500, 500, fname)
    origin()
    fontsize(80)
    get_path_flat("Luxor")
    @test finish() == true
    println("...finished test: output in $(fname)")
end

get_path_flat_test("get-path-flat-test.pdf")


text:
# To run this script, `cd` to the `./test/fixtures` directory and then, from the Julia terminal, `include("./runner.jl")`.

import JSON

# Small values:
x = linspace( 1e-36, 1e-38, 1007 )

y = Array( Any, length(x) )
z = Array( Any, length(x) )
for i in eachindex(x)
	# Mimic implicit type promotion in JavaScript where we need to cast a Float64 to a Float32 before deriving a bit sequence:
	f32 = convert( Float32, x[i] )
    y[i] = bits( f32 )
    z[i] = convert( Float64, f32 )
end

data = Dict([
	("x", z),
	("expected", y)
])

outfile = open("bits_1e-36_1e-38.json", "w")
write( outfile, JSON.json(data) )
close( outfile );

# Medium values:
x = linspace( -1e3, 1e3, 1007 )

y = Array( Any, length(x) )
z = Array( Any, length(x) )
for i in eachindex(x)
	# Mimic implicit type promotion in JavaScript where we need to cast a Float64 to a Float32 before deriving a bit sequence:
	f32 = convert( Float32, x[i] )
    y[i] = bits( f32 )
    z[i] = convert( Float64, f32 )
end

data = Dict([
	("x", z),
	("expected", y)
])

outfile = open("bits_-1e3_1e3.json", "w")
write( outfile, JSON.json(data) )
close( outfile );

# Large values:
x = linspace( 1e36, 1e38, 1007 )

y = Array( Any, length(x) )
z = Array( Any, length(x) )
for i in eachindex(x)
	# Mimic implicit type promotion in JavaScript where we need to cast a Float64 to a Float32 before deriving a bit sequence:
	f32 = convert( Float32, x[i] )
    y[i] = bits( f32 )
    z[i] = convert( Float64, f32 )
end

data = Dict([
	("x", z),
	("expected", y)
])

outfile = open("bits_1e36_1e38.json", "w")
write( outfile, JSON.json(data) )
close( outfile );

# Subnormal values:
x = linspace( 1e-39, 1e-45, 1007 )

y = Array( Any, length(x) )
z = Array( Any, length(x) )
for i in eachindex(x)
	# Mimic implicit type promotion in JavaScript where we need to cast a Float64 to a Float32 before deriving a bit sequence:
	f32 = convert( Float32, x[i] )
    y[i] = bits( f32 )
    z[i] = convert( Float64, f32 )
end

data = Dict([
	("x", z),
	("expected", y)
])

outfile = open("bits_1e-39_1e-45.json", "w")
write( outfile, JSON.json(data) )
close( outfile );


text:
"""
Extract all the reference meshes from the opf file, format them to [`HomogenousMesh`] and return a `Dict`
out of them. The keys of the `Dict` are named after the mesh `id`.

# Notes
In OPF files, the reference meshes are used as a basis to build each component, and then transformed (scaled, rotated...)
using a transformation matrix located in the topology to fit the dimensions and spatial positionning of the component.

# Exemples
> opf= read_opf("simple_OPF_shapes.opf")
> extract_opf_ref_meshes(opf)
"""
function extract_opf_ref_meshes(opf, MeshType::Type{MT} = GLNormalMesh) where {MT <: AbstractMesh}
    meshes = Dict{Int32, Any}()
    for i in opf["meshBDD"]["mesh"]
        push!(meshes, parse(Int32,i[:Id]) => extract_opf_ref_mesh(i,MeshType))
    end
    return meshes
end

"""
Parse a mesh in opf format to [`HomogenousMesh`]
"""
function extract_opf_ref_mesh(opf_mesh, MeshType::Type{MT} = GLNormalMesh) where {MT <: AbstractMesh}
    # Tv,Tn,Tuv,Tf = vertextype(MeshType), normaltype(MeshType), TextureCoordinate(MeshType), facetype(MeshType)
    Tv,Tn,Tuv,Tf = vertextype(MeshType), normaltype(MeshType), UV{Float32}, facetype(MeshType)
    v,n,uv,f     = Tv[], Tn[], Tuv[], Tf[]
    attr = Dict{Symbol, Any}()
    id= Int32[]
    # Faces:
    mesh_faces= [a[""] for a in opf_mesh["faces"]["face"]]
    for opf_mesh in mesh_faces
        append!(f, decompose(Tf, Face{3, UInt32}(opf_mesh .+ 1)))
    end
    # NB: +1 because decompose tries to transform 1-based to 0-based index, but
    # the faces already are 0-based indices.

    # vertices:
    for p in 1:3:length(opf_mesh["points"])
        push!(v, Point{3, Float32}(opf_mesh["points"][p:(p+2)]))
    end

    # normals:
    for p in 1:3:length(opf_mesh["normals"])
        push!(n, Point{3, Float32}(opf_mesh["normals"][p:(p+2)]))
    end

    # textures coordinates:
    if "textureCoords" in keys(opf_mesh)
        for p in 1:2:length(opf_mesh["textureCoords"])
            push!(uv, UV{Float32}(opf_mesh["textureCoords"][p:(p+1)]))
        end
    end

    # attribute_id
    push!(id, parse(Int32,opf_mesh[:Id]))

    attr[:faces]= f
    attr[:vertices]= v
    attr[:normals]= n
    attr[:texturecoordinates]= uv
    attr[:attributes]= id

    return MT(GeometryTypes.homogenousmesh(attr))::MT
end

"""
Make a Dict of meshes from the reference meshes (from `[extract_opf_ref_meshes]`) and the topology (using transformation matrices).
These meshes can then be used for 3D graphics purposes.
"""
function meshes_from_topology(opf)
    meshes = Dict{Int32,HomogenousMesh}() # A dict with the meshes
    attr = Dict() # A dict with the attributes (change Dict() to  Dict{Type, Any}())
    ref_meshes= extract_opf_ref_meshes(opf)
    shapes= extract_opf_shapes(opf)
    attrTypes= attr_type(opf["attributeBDD"])
    mesh_from_topology!(opf,meshes,ref_meshes,shapes,attr,attrTypes)

    return Dict("mesh" => meshes, "attributes" => attr) # The whole item (mesh + attributes)
end

"""
Compute meshes from topology and reference mesh iteratively for the whole topology. This function is called
    by [`meshes_from_topology`].

# Arguments
* node: parent node with all its childs (e.g. opf).
* meshes: a Dict with the previously computed meshes (Dict{Int32,HomogenousMesh}()). The function will recursively push to it.
* ref_meshes: the meshes used as a reference. A transformation matrix is used on them to build the object's meshes.
* shapes: shapes from the opf, i.e. the mesh index, the material index and its name.
* attr: an empty Dict that is filled recursively with the attributes of each node.
* attrType: the attributes type, read from the opf.
* child: the name of the node of interest.

# Returns
Increments `meshes` and `attr` in-place recursively for all childs in the node.
"""
function mesh_from_topology!(node,meshes,ref_meshes,shapes,attr,attrType,child= "topology")

    attr_mesh= Dict{String,Any}()
    # Getting the attributes:
    for i in intersect(collect(keys(attrType)), collect(keys(node[child])))
        push!(attr_mesh, i => node[child][i])
    end
    # Add the scale as an attribute:
    push!(attr_mesh, "scale" => node[child][:scale])

    id= node[child][:id]

    # Get the geometry (transformation matrix and dUp and dDwn):
    geom= try node[child]["geometry"] catch nothing end
    # Try to get the shape index if any:
    shapeIndex= try parse(Int32,geom["shapeIndex"]) catch nothing end

    if geom != nothing
        # Add w to the transformation matrix:
        m= vcat(geom["mat"], [0 0 0 1])
    else
        m= I # identity matrix from LinearAlgebra package (lazy)
    end

    if shapeIndex != nothing
        shape= shapes[shapeIndex]
        # Add the material index as an attribute:
        push!(attr_mesh, "materialIndex" => shape["materialIndex"])

        # Get the reference mesh and taper it in z and y (the principal axis is following x already):
        ref_mesh_scaled= taper( ref_meshes[shape["meshIndex"]].vertices,geom["dUp"],geom["dDwn"])

        # Transform the vertices:
        transformed_vertices= map(x -> Point{3,Float32}((m*vcat(x, 1.0))[1:3]),ref_mesh_scaled)
        # NB: using vcat to add w (1) on the vector.
        # NB2: the order for the matrices products is important.

        mesh_1= HomogenousMesh(faces= ref_meshes[shape["meshIndex"]].faces,
                                vertices= transformed_vertices,
                                normals= ref_meshes[shape["meshIndex"]].normals)
        push!(meshes, id => mesh_1)
    end

    # Add the resulting attributes to the main attr object:
    push!(attr, id => attr_mesh)
    # Make the function recursive for each component:
    for i in intersect(collect(keys(node[child])), ["decomp", "branch","follow"])
        # If it is an Array (several "follow" are represented as an Array under only
        # one "follow" to avoid several same key names in a Dict), then do it for each:
        if isa(node[child][i], Array)
            for j in 1:length(node[child][i])
                mesh_from_topology!(node[child][i],meshes,ref_meshes,shapes,attr,attrType,j)
            end
        else
            mesh_from_topology!(node[child],meshes,ref_meshes,shapes,attr,attrType,i)
        end
    end
end

"""
Merge the meshes returned from [`meshes_from_topology`] into one [`HomogenousMesh`] for plotting purposes.
"""
function merge_meshes(meshes::Dict{Int32,HomogenousMesh})
    mesh_ids= collect(keys(meshes))
    all_meshes= [(meshes[mesh_ids[1]])]

    for i in mesh_ids[2:end]
        all_meshes[1]= merge(all_meshes[1], meshes[i])
    end

    return all_meshes[1]
end

"""
Transform a reference mesh using dDwn and dUp from the geometry of a mesh. The tapering
helps to transform the reference mesh into a more tapered (i.e. pointy) or enlarged object, e.g.
make a cone from a cylinder.
"""
function taper(mesh,dUp,dDwn)
    delta = dDwn - dUp
    Xs= map(x -> x[1], mesh)
    xmin= minimum(Xs) ; xmax= maximum(Xs)
    deltaX = xmax - xmin

    scaled_mesh= Array{Point{3,Float32}}(undef, length(mesh))
    for i in 1:length(mesh)
        dX = (mesh[i][1] - xmin)
        factor = dDwn - delta * (dX / deltaX)
        scaled_mesh[i]= Point{3,Float32}(mesh[i][1],mesh[i][2] * factor,mesh[i][3] * factor)
    end

    return scaled_mesh
end


text:
using StochasticDiffEq, DiffEqDevTools, Test, Random
using DiffEqProblemLibrary.SDEProblemLibrary: importsdeproblems; importsdeproblems()
import DiffEqProblemLibrary.SDEProblemLibrary: prob_sde_additive, prob_sde_additivesystem
Random.seed!(100)

println("Bunch of additive solves")

f_bm(u,p,t) = 0.0
f_bm(::Type{Val{:analytic}},u0,p,t,W) = W
g_bm(u,p,t) = 1.0
prob = SDEProblem(f_bm,g_bm,0.0,(0.0,1.0))
sol1 = solve(prob,SRA1(),dt=1/2^(3),adaptive=false)
sol2 = solve(prob,SOSRA(),dt=1/2^(3),adaptive=false)
sol3 = solve(prob,SKenCarp(),dt=1/2^(3),adaptive=false)
@test sol1.errors[:l2] ≈ 0.0 atol = 1e-14
@test sol2.errors[:l2] ≈ 0.0 atol = 1e-14
@test sol3.errors[:l2] ≈ 0.0 atol = 1e-14

prob = prob_sde_additive

# Test error in stepping and seeding simultaniously
sol  = solve(prob,SRA(StochasticDiffEq.constructSOSRA()),dt=1/2^(3),seed=1)
sol2 = solve(prob,SOSRA(),dt=1/2^(3),seed=1)
@test sol.t ≈ sol2.t

sol =solve(prob,SRA1(),dt=1/2^(3))
sol =solve(prob,SRA2(),dt=1/2^(3))
sol =solve(prob,SRA3(),dt=1/2^(3))
sol =solve(prob,SOSRA(),dt=1/2^(3))
sol =solve(prob,SOSRA2(),dt=1/2^(3))
sol =solve(prob,SKenCarp(),dt=1/2^(3))
sol =solve(prob,SKenCarp(nlsolve=StochasticDiffEq.NLNewton(min_iter=5)),dt=1/2^(3))

prob = prob_sde_additivesystem

sol =solve(prob,SRA(),dt=1/2^(3))
sol =solve(prob,SRA1(),dt=1/2^(3))
sol =solve(prob,SRA2(),dt=1/2^(3))
sol =solve(prob,SRA3(),dt=1/2^(3))
sol =solve(prob,SOSRA(),dt=1/2^(3))
sol =solve(prob,SOSRA2(),dt=1/2^(3))
sol =solve(prob,SKenCarp(),dt=1/2^(3))

## Convergence Testing
println("Convergence Test on MultiDimAdditive")
dts = (1/2) .^ (7:-1:4) #14->7 good plot

sim = test_convergence(dts,prob,SRA(),numMonte=5)
@test abs(sim.𝒪est[:l2]-2) < 0.1
sim2 = test_convergence(dts,prob,SRA1(),numMonte=5)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!
sim2 = test_convergence(dts,prob,SRA2(),numMonte=5)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!
sim2 = test_convergence(dts,prob,SRA3(),numMonte=5)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!
sim2 = test_convergence(dts,prob,SOSRA(),numMonte=10)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!
sim2 = test_convergence(dts,prob,SOSRA2(),numMonte=5)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!
dts = (1/2) .^ (11:-1:7) #14->7 good plot
Random.seed!(100)
sim2 = test_convergence(dts,prob,SKenCarp(),numMonte=20)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!
sim2 = test_convergence(dts,prob,SKenCarp(nlsolve=StochasticDiffEq.NLNewton(min_iter=3)),numMonte=20)
@test abs(sim2.𝒪est[:l∞]-2) <.1 #High tolerance since low dts for testing!


text:
"""
    pixelspacing(img) -> (sx, sy, ...)

Return a tuple representing the separation between adjacent pixels
along each axis of the image.  Defaults to (1,1,...).  Use
ImagesAxes for images with anisotropic spacing or to encode the
spacing using physical units.
"""
pixelspacing{T,N}(img::AbstractArray{T,N}) = ntuple(d->1, Val{N})

"""
    spacedirections(img) -> (axis1, axis2, ...)

Return a tuple-of-tuples, each `axis[i]` representing the displacement
vector between adjacent pixels along spatial axis `i` of the image
array, relative to some external coordinate system ("physical
coordinates").

By default this is computed from `pixelspacing`, but you can set this
manually using ImagesMeta.
"""
spacedirections(img::AbstractArray) = _spacedirections(pixelspacing(img))
function _spacedirections{N}(ps::NTuple{N})
    ntuple(i->ntuple(d->d==i ? ps[d] : zero(ps[d]), Val{N}), Val{N})
end

"""
    sdims(img)

Return the number of spatial dimensions in the image. Defaults to the
same as `ndims`, but with ImagesAxes you can specify that some axes
correspond to other quantities (e.g., time) and thus not included by
`sdims`.
"""
sdims(img::AbstractArray) = length(coords_spatial(img))

"""
   coords_spatial(img)

Return a tuple listing the spatial dimensions of `img`.

Note that a better strategy may be to use ImagesAxes and take slices along the time axis.
"""
coords_spatial{T,N}(img::AbstractArray{T,N}) = ntuple(identity, Val{N})

"""
    nimages(img)

Return the number of time-points in the image array. Defaults to
1. Use ImagesAxes if you want to use an explicit time dimension.
"""
nimages(img::AbstractArray) = 1

"""
    size_spatial(img)

Return a tuple listing the sizes of the spatial dimensions of the
image. Defaults to the same as `size`, but using ImagesAxes you can
mark some axes as being non-spatial.
"""
size_spatial(img) = size(img)

"""
    indices_spatial(img)

Return a tuple with the indices of the spatial dimensions of the
image. Defaults to the same as `indices`, but using ImagesAxes you can
mark some axes as being non-spatial.
"""
indices_spatial(img) = indices(img)

#### Utilities for writing "simple algorithms" safely ####
# If you don't feel like supporting multiple representations, call these

"""
    assert_timedim_last(img)

Throw an error if the image has a time dimension that is not the last
dimension.
"""
assert_timedim_last(img::AbstractArray) = nothing

#### Permutations over dimensions ####

# TODO: decide about the default storage order!!
widthheight(img::AbstractArray) = size(img,1), size(img,2)

width(img::AbstractArray) = widthheight(img)[1]
height(img::AbstractArray) = widthheight(img)[2]

#### Low-level utilities ####
"""
    permutation(to, from) -> p

Calculate the permutation of labels in `from` to produce the order in
`to`. Any entries in `to` that are missing in `from` will receive an
index of 0. Any entries in `from` that are missing in `to` will have
their indices appended to the end of the permutation. Consequently,
the length of `p` is equal to the longer of `to` and `from`.
"""
function permutation(to, from)
    n = length(to)
    nf = length(from)
    li = linearindices(from)
    d = Dict(from[i]=>i for i in li)
    covered = similar(dims->falses(length(li)), li)
    ind = Array(Int, max(n, nf))
    for (i,toi) in enumerate(to)
        j = get(d, toi, 0)
        ind[i] = j
        if j != 0
            covered[j] = true
        end
    end
    k = n
    for i in li
        if !covered[i]
            d[from[i]] != i && throw(ArgumentError("no duplicates in from allowed"))
            k += 1
            k > nf && throw(ArgumentError("no incomplete containment allowed in $to and $from"))
            ind[k] = i
        end
    end
    ind
end


text:
# MIT license
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE in the project root for full license information.

""" Computes the location of the optical center of the lens that will project the centroid of the display to the centroid of the eyebox. Normally the display centroid will be aligned with the geometric centroid of the lens, rather than the optical center of the lens."""
function compute_optical_center(eyeboxcentroid,displaycenter,lensplane)
    v = displaycenter - eyeboxcentroid
    r = Ray(eyeboxcentroid,v)
    return closestintersection(surfaceintersection(lensplane))
end

function subdivide_fov(eyeboxpolygon)
end

""" eyebox rectangle represented as a 3x4 SMatrix with x,y,z coordinates in rows 1,2,3 respectively."""
function eyeboxpolygon(xsize,ysize)
    xext,yext = (xsize,ysize) ./ 2.0 #divide by 2 to get min and max extensions
    return SMatrix{3,4}([xext;yext;0.0 ;; xext;-yext;0.0 ;; -xext;-yext;0.0 ;; -xext;yext;0.0])
end

subpoints(pts::AbstractVector,subdivisions) = reshape(collect(range(extrema(pts)...,subdivisions)),1,subdivisions)
export subpoints

subdivide(poly::AbstractMatrix,xsubdivisions,ysubdivisions) = subdivide(SMatrix{3,4}(poly),xsubdivisions,ysubdivisions)

"""poly is a two dimensional rectangle represented as a 3x4 SMatrix with x values in row 1 and y values in row 2. Returns a vector of length xsubdivisions*ysubdivisions containing all the subdivided rectangles."""
function subdivide(poly::T, xsubdivisions, ysubdivisions) where{T<:SMatrix{3,4}}
    result = Vector{T}(undef,0) #efficiency not an issue here so don't need to preallocate vector

    x = subpoints(poly[1,:],xsubdivisions+1) #range function makes one less subdivision that people will be expecting, e.g., collect(range(1,3,2)) returns [1,3]
    y = subpoints(poly[2,:],ysubdivisions+1)

    for i in 1:length(x) -1
        for j in 1:length(y) -1
            push!(result,T([x[i];y[j];0.0 ;; x[i+1];y[j];0.0 ;; x[i+1];y[j+1];0.0 ;; x[i];y[j+1];0.0]))
        end
    end
    return result
end
export subdivide

function setup_system(subdivisions::NTuple{2,Int})
    eyeballframe = Transform(I(4)) #This establishes the global coordinate frame for the systems. Positive Z axis is assumed to be the forward direction, the default direction of the eye's optical axis when looking directly ahead.
    corneavertex = OpticSim.HumanEye.cornea_to_eyecenter()

    eyeboxframe = eyeballframe*OpticSim.translation(0.0,0.0,ustrip(mm,corneavertex))  #unfortunately can't use unitful values in transforms because the rotation and translation components would have different types which is not allowed in a Matrix.

    println(typeof(eyeboxframe))
    eyeboxpoly =  eyeboxpolygon(10mm,9mm) #four corners of the eyebox frame which is assumed centered around the positive Z axis. Transformed to the eyeballframe.
    println(typeof(subdivide(eyeboxpoly,subdivisions...)[1]))
    subdivided_eyeboxpolys = map(x-> eyeboxframe .* x, subdivide(eyeboxpoly,subdivisions...))
end
export setup_system


text:
# This file is a part of Julia. License is MIT: http://julialang.org/license

@testset "libgit2-online" begin

#########
# TESTS #
#########
# init & clone
mktempdir() do dir
    repo_url = "https://github.com/JuliaLang/Example.jl"
    @testset "Cloning repository" begin
        @testset "with 'https' protocol" begin
            repo_path = joinpath(dir, "Example1")
            repo = LibGit2.clone(repo_url, repo_path)
            try
                @test isdir(repo_path)
                @test isdir(joinpath(repo_path, ".git"))
            finally
                close(repo)
            end
        end

        @testset "with incorrect url" begin
            try
                repo_path = joinpath(dir, "Example2")
                # credentials are required because github tries to authenticate on unknown repo
                cred = LibGit2.UserPasswordCredentials("","") # empty credentials cause authentication error
                LibGit2.clone(repo_url*randstring(10), repo_path, payload=Nullable(cred))
                error("unexpected")
            catch ex
                @test isa(ex, LibGit2.Error.GitError)
                @test ex.code == LibGit2.Error.EAUTH
            end
        end
    end
end

end


text:
using CSV, DataFrames, DecisionTree, Distributions, Gurobi, JuMP, LightGraphs, Parameters, SparseArrays, Statistics, ArgParse, Random

include("oracles/portfolio_oracle.jl")
include("solver/util.jl")
include("solver/sgd.jl")
include("solver/reformulation.jl")
include("solver/random_forests_po.jl")
include("solver/validation_set.jl")
include("experiments/replication_functions.jl")

"""
Test to run one instance of the portfolio optimization experiment.
Using the reformulation approach (spo+ formulation). (reformulation.jl)
replication_functions.jl : Functions for generating a single replication of a particular experiment
		(Dependencies: util.jl, sgd.jl, reformulation.jl, random_forests_po.jl, validation_set.jl)
		To change validation loss , will need to adjust: util.jl
		To change data generation method , will need to adjust: util.jl
		To change training loss algorithm (currently spo+), will need to adjust: util.jl, sgd.jl, validation_set.jl

Above dependencies from SPO repository:
https://github.com/paulgrigas/SmartPredictThenOptimize

"""

#environment
envOracle = setup_gurobi_env(method_type = :default, use_time_limit = false)
envReform = setup_gurobi_env(method_type = :method3, use_time_limit = false)

# Fixed parameter settings (these never change)
num_assets = 50
num_factors = 4
n_train = 100

holdout_percent = 0.25
n_holdout = round(Int, holdout_percent*n_train)

n_test = 10000
p_features = 5
n_sigmoid_polydegree = 4
noise_multiplier_tau = 1

rng_seed = 2128
Random.seed!(rng_seed)

port_results = portfolio_replication(num_assets, num_factors, n_train, n_holdout, n_test, p_features,
        n_sigmoid_polydegree, noise_multiplier_tau;
        num_lambda = 10, lambda_max = 100.0, lambda_min_ratio = 10.0^(-6),
        gurobiEnvOracle = envOracle, gurobiEnvReform = envReform, different_validation_losses = false,
        data_type = :poly_kernel)

max_stars_repo_name: katerinagiannoutsou/dso-coding-project

max_issues_repo_name: katerinagiannoutsou/dso-coding-project

max_forks_repo_name: katerinagiannoutsou/dso-coding-project


text:
@testset "Update CN0 Estimator" begin

    cn0_estimator = MomentsCN0Estimator(20)
    @test @inferred(Tracking.get_prompt_buffer(cn0_estimator)) == zero(SVector{20, ComplexF64})
    @test @inferred(Tracking.get_current_index(cn0_estimator)) == 0
    @test @inferred(Tracking.length(cn0_estimator)) == 0

    next_cn0_estimator = @inferred Tracking.update(cn0_estimator, 1 + 2im)
    @test @inferred(Tracking.get_prompt_buffer(next_cn0_estimator))[1] == 1 + 2im
    @test @inferred(Tracking.get_current_index(next_cn0_estimator)) == 1
    @test @inferred(Tracking.length(next_cn0_estimator)) == 1

    cn0_estimator = MomentsCN0Estimator(ones(SVector{20, ComplexF64}), 20, 20)
    next_cn0_estimator = @inferred Tracking.update(cn0_estimator, 1 + 2im)
    @test @inferred(Tracking.get_prompt_buffer(next_cn0_estimator))[1] == 1 + 2im
    @test @inferred(Tracking.get_current_index(next_cn0_estimator)) == 1
    @test @inferred(Tracking.length(next_cn0_estimator)) == 20

    cn0_estimator = MomentsCN0Estimator(ones(SVector{20, ComplexF64}), 19, 20)
    @test @inferred(Tracking.get_current_index(cn0_estimator)) == 19
    @test @inferred(Tracking.length(cn0_estimator)) == 20

    @test @allocated(Tracking.update(MomentsCN0Estimator(20), 1 + 2im)) == 0
end

@testset "CN0 estimation" begin

    Random.seed!(1234)
    carrier_doppler = 0Hz
    start_code_phase = 0
    code_frequency = 1023kHz
    sampling_frequency = 4MHz
    prn = 1
    range = 0:3999
    start_carrier_phase = π / 2
    cn0_estimator = MomentsCN0Estimator(20)
    correlator_sample_shifts = SVector(-2, 0, 2)
    start_sample = 1
    num_samples = 4000
    gpsl1 = GPSL1()

    for i = 1:20
        signal = get_code.(
                gpsl1,
                code_frequency .* range ./ sampling_frequency .+ start_code_phase,
                prn
            ) .* 10^(45 / 20) .+
            randn(ComplexF64, length(range)) .* sqrt(4e6)
        code = get_code.(
            gpsl1,
            code_frequency .* (-2:4001) ./ sampling_frequency .+ start_code_phase,
            prn
        )
        correlator = EarlyPromptLateCorrelator()
        signal_struct = StructArray(signal)
        correlator = Tracking.correlate(
            correlator,
            signal_struct,
            code,
            correlator_sample_shifts,
            start_sample,
            num_samples,
        )
        cn0_estimator = Tracking.update(
            cn0_estimator,
            get_prompt(correlator, correlator_sample_shifts)
        )
    end
    @test @inferred(Tracking.get_current_index(cn0_estimator)) == 20
    @test @inferred(Tracking.length(cn0_estimator)) == 20
    cn0_estimate = @inferred Tracking.estimate_cn0(cn0_estimator, 1ms)

    @test cn0_estimate ≈ 45dBHz atol = 2.05dBHz

end


text:
"""
Show all out put in julia.
See https://stackoverflow.com/questions/37107133/how-to-show-all-output-in-julia
"""
function show_all(x)
    show(stdout, "text/plain", x)
end


text:
### CONVENIENCE FUNCTIONS ###

# Tensorial calculus related functions
δ(i,j) = i == j ? 1.0 : 0.0
Isym_func(i,j,k,l) = 0.5*(δ(i,k)*δ(j,l) + δ(i,l)*δ(j,k))
Isymdev_func(i,j,k,l) = 0.5*(δ(i,k)*δ(j,l) + δ(i,l)*δ(j,k)) - 1.0/3.0*δ(i,j)*δ(k,l)
get_3D_func(i,j,tensor2D) = (i<=2) && (j<=2) ? tensor2D[i,j] : 0.0

# elastic moduli relations :
E_from_Gν(G,ν) = 2G*(1 + ν)
E_from_KG(K,G) = 9*K*G / (3K + G)
ν_from_KG(K,G) = (3K - 2G) / (2*(3K + G))
G_from_Eν(E,ν) = E / 2(1 + ν)
G_from_Kν(K,ν) = 3K*(1 - 2ν) / (2*(1+ν))
G_from_λν(λ,ν) = λ*(1 - 2ν) / (2ν)
G_from_EK(E,K) = 3K*E / (9K - E)
K_from_Eν(E,ν) = E / 3(1 - 2ν)
K_from_Gν(G,ν) = 2G*(1 + ν) / (3*(1 - 2ν))
λ_from_Eν(E,ν) = E*ν / ((1+ν)*(1-2ν))
λ_from_KG(K,G) = K - (2/3)*G
λ_from_Gν(G,ν) = 2G*ν / (1 - 2ν)

Dᵉ_func(i,j,k,l,G,λ) = λ*(δ(i,j)*δ(k,l)) + G*(δ(i,k)*δ(j,l) + δ(i,l)*δ(j,k))
Cᵉ_func(i,j,k,l,G,λ) = (λ/(2G*(3λ + 2G)))*(δ(i,j)*δ(k,l)) + (1/2G)*(δ(i,k)*δ(j,l) + δ(i,l)*δ(j,k))


text:
module DimensionalPlotRecipes

using RecipesBase
using LinearAlgebra

# Splits a complex matrix to its real and complex parts
# Reals defaults solid, imaginary defaults dashed
# Label defaults are changed to match the real-imaginary reference / indexing
@recipe function f(x::AbstractArray{T},y::Array{Complex{T2}};
                   transformation=:split3D) where {T<:Real,T2<:Number}
  if transformation==:split2D
    A = real.(y)
    B = imag.(y)
    _y = [!iseven(i) ? A[:,i÷2+1] : B[:,i÷2] for i in 1:2size(A,2)]
    linestyle --> reshape([!iseven(i) ? :solid : :dash for i in 1:2size(A,2)],1,2size(A,2))
    label --> reshape([!iseven(i) ? "Re(y$(i÷2+1))" : "Im(y$(i÷2))" for i in 1:2size(A,2)],1,2size(A,2))
    seriescolor --> reshape([!iseven(i) ? i÷2+1 : i÷2 for i in 1:2size(A,2)],1,2size(A,2))
    retval = (x,_y)
  elseif transformation==:split3D
    A = real.(y)
    B = imag.(y)
    ylabel --> "Re(y)"
    zlabel --> "Im(y)"
    retval = (x,A,B)
  elseif transformation==:modulus
    _y = norm.(y)
    label --> reshape(["||y$(i)||" for i in 1:size(_y,2)],1,size(_y,2))
    retval = (x,_y)
  elseif transformation==:modulus2
    _y = abs2.(y)
    label --> reshape(["|y$(i)|^2" for i in 1:size(_y,2)],1,size(_y,2))
    retval = (x,_y)
  else
    error("Transformation unknown. Please use :split2D, :split3D, :modulus, or :modulus2")
  end
  (retval...,)
end

end # module


text:
"""
    AbstractDistance

Distance function used to evaluate the distance from a point to a set.
New subtypes of `AbstractDistance` must implement fallbacks for sets they don't cover and implement
`distance_to_set(::Distance, v, s::S)` for sets they override the distance for.
"""
abstract type AbstractDistance end

"""
    DefaultDistance

Default distance function, implemented for all sets.
"""
struct DefaultDistance <: AbstractDistance end

"""
    distance_to_set(distance_definition, v, s)

Compute the distance of a value to a set.
When `v ∈ s`, the distance is zero (or all individual distances are zero).

Each set `S` implements at least `distance_to_set(d::DefaultDistance, v::T, s::S)`
with `T` of appropriate type for members of the set.
"""
function distance_to_set end

distance_to_set(::AbstractDistance, v, s) = distance_to_set(DefaultDistance(), v, s)

"""
    EpigraphViolationDistance

Distance used when `v ∈ s` can be expressed as a single scalar function `f(v) ≤ 0`.
The distance is expressed as `max(f(v), 0)`.
"""
struct EpigraphViolationDistance <: AbstractDistance end

"""
    NormedEpigraphDistance{p}

Distance used when `v ∈ s` can be expressed as the intersection of level sets `f_i(v) ≤ 0 ∀ i ∈ I`.
The distance is expressed as `norm([max(f_i(v), 0) ∀ i ∈ I], n)` with `p` a norm value accepted by `LinearAlgebra.norm`.
"""
struct NormedEpigraphDistance{p} <: AbstractDistance end

"""
    projection_on_set(distance_definition, v, s)

Compute the projection of a vector `v` on a set `s`.

Each set `S` implements at least `projection_on_set(d::DefaultDistance, v::T, s::S)`
with `T` of appropriate type for members of the set.
"""
function projection_on_set end

"""
    projection_gradient_on_set(distance_definition, v, s)

Compute the gradient of projection of a vector `v` on a set `s`.

Each set `S` implements at least `projection_gradient_on_set(d::DefaultDistance, v::T, s::S)`
with `T` of appropriate type for members of the set.
"""
function projection_gradient_on_set end


text:
using Base.Multimedia
import Base.display

struct _WebDisplay <: AbstractDisplay
    hist::Vector{Tuple{String, Vector{UInt8}}}
    cond::Condition
end

const web_displayable = map(MIME, [ # in "richness" order
    "text/html", "video/mpeg", "video/mp4", "video/ogg", "video/webm",
    "image/svg+xml", "image/png", "image/gif", "image/webp", "image/jpeg",
    "audio/midi", "audio/acc", "audio/wav", "audio/ogg", "audio/webm",
    "application/pdf", "application/xhtml+xml", "text/plain"
])

function display(d::_WebDisplay, x)
    for mime in web_displayable[1:end-1]
        showable(mime, x) && return display(d, mime, x)
    end

    "WEB_DISPLAY_NOTEXT" in keys(ENV) ? throw(MethodError(display, (d, x))) : display(d, MIME("text/plain"), x)
end

function tobytes(mime::MIME, x)
    buf = IOBuffer()
    show(IOContext(buf, :limit=>true), mime, x)
    take!(buf)
end

function display(d::_WebDisplay, mime::Union{map(typeof, web_displayable)...}, x)
    push!(d.hist, (string(mime), tobytes(mime, x)))
    notify(d.cond)
    isinteractive() && println(stderr, "[shown as $mime on WebDisplay #$(length(d.hist))]")
end

const _display = _WebDisplay([], Condition())


text:
# performance benchmark

using SparseVectors

macro benchfun2(bfun, tfun, descr, xs, ys, nrtimes)
    esc(quote
        function $(bfun)(x, y, nr::Int)
            println(string("Benchmark on ", $(string(descr)), " ..."))
            xmat = convert(SparseMatrixCSC, x)
            ymat = convert(SparseMatrixCSC, y)

            gc();
            gc_enable(false)

            # warming
            $(tfun)(x, y)
            $(tfun)(xmat, ymat)

            # main profile
            et1 = @elapsed for i = 1:nr
                $(tfun)(x, y)
            end
            et2 = @elapsed for i = 1:nr
                $(tfun)(xmat, ymat)
            end

            gc_enable(true)

            # show result
            @printf("  sparse vector: %9.4fms (gain = %.4fx)\n", et1 * 1e3, et2 / et1)
            @printf("  sparse matrix: %9.4fms\n", et2 * 1e3)
        end
        $(bfun)($xs, $ys, $nrtimes)
    end)
end

# data

n = 1_000_000
x = sprand(n, 0.25)
y = sprand(n, 0.25)

@benchfun2(bench_vadd, +, "sparse vector addition", x, y, 20)
@benchfun2(bench_vmul, .*, "sparse vector multiplication", x, y, 20)

A = sprand(1000, 1000, 0.1)
x = sprand(1000, 0.2)

@benchfun2(bench_Ax, *, "sparse matrix-vector product (A * x)", A, x, 100)
@benchfun2(bench_Atx, At_mul_B, "sparse matrix-vector product (A'x)", A, x, 100)


text:
function make_taskgraph()
    name = "test_taskgraph"
    nodes = make_nodes()
    edges = make_edges()
    return Taskgraph(name, nodes, edges)
end

function make_fanout_taskgraph()
    name = "test_taskgraph"
    nodes = make_nodes()
    edges = make_fanout_edges()
    return Taskgraph(name, nodes, edges)
end

const input_node_names = ("input1", "input2")
const output_node_names = ("output1", "output2")
# Just have 6 general task nodes so the 8 general primites are underutilized.
const general_node_names = Tuple("task$i" for i in 1:6)

"""
    make_nodes()

Make a basic collection of input, output, and general nodes.
"""
function make_nodes()
    # input nodes.
    input_metadata = Dict("task" => "input")
    input_nodes = [TaskgraphNode(n; metadata = input_metadata) for n in input_node_names]
    # output nodes
    output_metadata = Dict("task" => "output")
    output_nodes = [TaskgraphNode(n; metadata = output_metadata) for n in output_node_names]
    # general nodes
    general_metadata = Dict("task" => "general")
    general_nodes = [
        TaskgraphNode(n; metadata = general_metadata) for n in general_node_names
    ]
    return vcat(input_nodes, output_nodes, general_nodes)
end

function make_edges()
    # The following tuple is a collection: (source_task, sink_task, class)
    # Class can be one of: {A,B,all}
    edges = [
        ("input1", "task1", "A"),
        ("input2", "task1", "B"),
        ("task1", "task2", "B"),
        ("task2", "task3", "B"),
        ("task3", "task4", "B"),
        ("task4", "task5", "B"),
        ("task5", "task6", "B"),
        ("task1", "task6", "A"),
        ("task2", "output1", "A"),
        ("task6", "output2", "B"),
    ]

    return [TaskgraphEdge(a[1], a[2]; metadata = Dict("class" => a[3])) for a in edges]
end

function make_fanout_edges()
    # The following tuple is a collection: (source_task, sink_task, class)
    # Class can be one of: {A,B,all}
    edges = [
        ("input1", "task1", "A"),
        ("input2", "task1", "B"),
        ("task1", "task2", "B"),
        ("task2", "task3", "B"),
        ("task3", ["task4", "task5"], "B"),
        ("task4", "task5", "B"),
        ("task5", "task6", "B"),
        ("task1", "task6", "A"),
        ("task2", "output1", "A"),
        ("task6", "output2", "B"),
    ]

    return [TaskgraphEdge(a[1], a[2]; metadata = Dict("class" => a[3])) for a in edges]
end


text:
# Practical Review: Numeric Optimization (Ch. 12)

##
# Let's start with a simple problem, where we already know the
# answers. We will apply numeric optimization methods and we
# will be able to verify that they give use the correct results.
# To start, let's define some data, and do the basic OLS
# computations
using Econometrics
n = 5
x = [ones(n) 1:n]
β = [10., -1.]
ϵ = randn(n)
y = x*β + ϵ
ols(y,x)

##
# Let's see how to get these results using numeric minimization
# and extremum estimation theory...
using Econometrics, Statistics
objᵢ = β -> (y-x*β).^2.  	# iᵗʰ obs contrib to sum of squares
obj = β -> mean(objᵢ(β))	# average objective
fminunc(obj, zeros(2))

##
# fminunc is just a frontend to the Optim.jl package's LBFGS unconstrained
# minimizer routine. To call that directly, do
using Optim
tol = 1e-08
results = Optim.optimize(obj, zeros(2), LBFGS(),
                            Optim.Options(
                            g_tol = tol,
                            x_tol=tol,
                            f_tol=tol); autodiff=:forward)

##
# The output has the function value and convergence information. To see the
# value of the minimizer, do
βhat = results.minimizer

##
# Let's check that the Hessian is p.d.
using ForwardDiff
H = ForwardDiff.hessian(obj, βhat)
##
using LinearAlgebra
eigen(H)

##
# The eigenvalues are all positive, so the Hessian is p.d. at
# the solution. For the OLS case, the objective function is
# known to be globally convex, so multiple local optima are not
# a problem. Let's look at another problem, which has multiple
# minima, and see how to find the global minimizer
# Here's another objective function
f(x,y) = -(3*(1-x)^2 * exp(-(x^2) - (y+1)^2)
    - 6*(x/5 - x^3 - y^5) * exp(-x^2 - y^2)
    - 1/3 * exp(-(x+1)^2 - y^2))

##
# let's explore it:
using Plots
plotly() # this backend makes nice 3d plots
x = range(-4, step=0.1, stop=4)
y = x
surface(x, y, (x,y)->f(x,y),c=:viridis)
xlabel!("x")
ylabel!("y")
##
contour(x,y,(x,y)->f(x,y),c=:viridis)

##
# This function has 3 local min, and 2 local max.
# The global minimizer is near (0,1.6), with a function
# value of -4.86. We will need some care to find the global
# minimizer. The domain is (-4,4)×(-4,4), which may help us.
# First, let's try gradient-based minimization, starting at
# a random point in the domain.

##
# Before we do that, the form of the function defined above
# does not take a single vector argument. For optimization, we
# need all parameters in a single vector. Julia's multiple
# dispatch allow us to do this easily, by defining another
# method for the function f:
function f(θ)
   x,y = θ
   f(x,y) # pretty neat, eh?
end

##
#=
Another thing to check before doing optimization! Remember
that gradient based methods will work better when the data
are scaled to put the elements of the gradient one a common
order of magnitude. You can check this by examining the
gradient at some points. Run this block a few times to check.
=#
using ForwardDiff
lower = [-4., -4.]
upper = -lower
θstart = 8.0 .* rand(2) .-4.0
ForwardDiff.gradient(f, θstart)
# in this case, things seem to be ok.

##
# Now we can try optimization. Running this block repeatedly (Alt-enter)
# will show that each of the 3 minimizers are found. Thus, if one defined
# LBFGS with enough start values, the global minimizer would be found.
# If you run the code enough times, you will see that the algorithm
# occasionally goes off far away from the 3 local minimizers. In that
# region, the gradients are zero, as we see in the plots, and the algorithm
# can't find better points.
using Econometrics, Plots, Optim
gr() # using the GR backend
x = range(-4, step=0.1, stop=4)
y = x
contour(x,y,f,c=:viridis)
θstart = 8.0 .* rand(2) .-4.0
tol = 1e-08
results = Optim.optimize(f, θstart, LBFGS(),
                            Optim.Options(
                            g_tol = tol,
                            x_tol=tol,
                            f_tol=tol); autodiff=:forward)

θhat = results.minimizer
scatter!([θhat[1]],[θhat[2]],legend=false, markersize=10, c = :viridis)

##
# A more robust algorithm is to use the known domain to define
# box constraints. This will still bounce between the 3 local
# min, but it will not shoot off to far away points.
using Econometrics, Plots, Optim
gr() # using the GR backend
x = range(-4, step=0.1, stop=4)
y = x
contour(x,y,f, c=:viridis)
lower = [-4., -4.]
upper = -lower
θstart = 8.0 .* rand(2) .-4.0
tol = 1e-08
results = Optim.optimize(f, lower, upper, θstart, Fminbox(LBFGS()),
                            Optim.Options(
                            g_tol = tol,
                            x_tol=tol,
                            f_tol=tol); autodiff=:forward)
θhat = results.minimizer
scatter!([θhat[1]],[θhat[2]],legend=false, markersize=10)

##
#
# Global optimization
#
# Another option is to use a global optimizer. An example is the
# simulated annealing algorithm. This one should find the global
# min every time, provided the cooling schedule is slow enough
using Econometrics
# try setting rt=0.05, it will fail sometimes, because the
# search region is shrunk too quickly
# rt=0.9 has worked every time I've tried it
rt = 0.75
lower = [-4., -4.]
upper = -lower
θstart = 8.0 .* rand(2) .-4.0
samin(f, θstart, lower, upper, rt=rt);
println("for reference, the global minimizer is (-0.00879, 1.58163)")
println("with the function value -4.8611920055")

#=
To summarize, a gradient based minimizer should be reliable
when the objective function is globally convex. When this is
not the case, one can use multiple start values for a gradient
based method, or one might prefer to use a global minimizer.
=#

max_stars_repo_name: mcreel/EconometricsNotes

max_issues_repo_name: mcreel/EconometricsNotes

max_forks_repo_name: mcreel/EconometricsNotes