text:
function process_raw_csv_api_data(api_call_raw_data::String)::PSResult

    # check: do we have an empty string?
    # check: legit string?

    # need to check to see if legit data is coming back from the service -
    if (is_valid_json(api_call_raw_data) == true)
        api_data_dictionary = JSON.parse(api_call_raw_data)
        if (haskey(api_data_dictionary,"Error Message") == true)

            # grab the error mesage -
            error_message = api_data_dictionary["Error Message"]

            # throw -
            return PSResult{PSError}(PSError(error_message))
        else

            # formulate an error message -
            error_message = "Error: CSV type returns JSON without error message"

            # throw -
            return PSResult{PSError}(PSError(error_message))
        end
    end

    # create a data table from the CSV data -
    tmp_data_table = CSV.read(IOBuffer(api_call_raw_data), DataFrame)

    # sort the table according to the timestamps -
    idx_sort = sortperm(tmp_data_table[:,1])

    # create a sorted data table -
    sorted_data_table = tmp_data_table[idx_sort,:]

    # return the sorted table -
    return PSResult{DataFrame}(sorted_data_table)
end

function process_raw_json_api_data_sts(api_call_raw_data::String, data_series_key::String)::(Union{PSResult{T}, Nothing} where T<:Any)

    # is the data coming back well formed, and does it contain valid data?
    check_result = check_json_api_return_data(api_call_raw_data)
    if check_result != nothing
        return check_result
    end

    # TODO - check for missing data series key -
    # ...

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing the Time series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end

    # array of keys -
    data_key_label_array = ["1. open", "2. high", "3. low", "4. close", "5. volume"]
    number_of_fields = length(data_key_label_array)

    # initialize storage for the fields -
    timestamp_array = Dates.Date[]
    open_price_array = Float64[]
    high_price_array = Float64[]
    low_price_array = Float64[]
    close_price_array = Float64[]
    volume_array = Int64[]

    # ok, we have the time series key, go through the data and load into the table -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # cache -
        push!(timestamp_array, Dates.Date(timestamp_value,"yyyy-mm-dd"))

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            # populate the array's -
            if (key_index == 1)
                push!(open_price_array, parse(Float64, value))
            elseif (key_index == 2)
                push!(high_price_array, parse(Float64, value))
            elseif (key_index == 3)
                push!(low_price_array, parse(Float64, value))
            elseif (key_index == 4)
                push!(close_price_array, parse(Float64, value))
            else
                push!(volume_array, parse(Int64, value))
            end
        end
    end

    # we need to sort the timestamps, to make them in reverse order -
    idx_sort = sortperm(timestamp_array)

    # build the data frame -
    data_frame = DataFrame(timestamp=timestamp_array[idx_sort], open=open_price_array[idx_sort], high=high_price_array[idx_sort], low=low_price_array[idx_sort], close=close_price_array[idx_sort], volume=volume_array[idx_sort])

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

function process_raw_json_api_data_sts_adjusted(api_call_raw_data::String, data_series_key::String)::(Union{PSResult{T}, Nothing} where T<:Any)

    # is the data coming back well formed, and does it contain valid data?
    check_result = check_json_api_return_data(api_call_raw_data)
    if check_result !== nothing
        return check_result
    end

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing the Time series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end
    #all repeated up to here possibly look to make the above a function for just checking data
    # array of keys -- this is changed per function
    data_key_label_array = ["1. open", "2. high", "3. low", "4. close", "5. adjusted close", "6. volume", "7. dividend amount"]
    number_of_fields = length(data_key_label_array)

    #initialize arrays to hold these fields for all dates
    timestamp_array = Dates.Date[]
    open_price_array = Float64[]
    high_price_array = Float64[]
    low_price_array = Float64[]
    close_price_array = Float64[]
    adjusted_close_array = Float64[]
    volume_array = Int64[]
    dividend_amount_array = Float64[]

    # ok, we have the time series key, go through the data and load into the table -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # cache -
        push!(timestamp_array, Dates.Date(timestamp_value,"yyyy-mm-dd"))

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            # populate the array's -
            if (key_index == 1)
                push!(open_price_array, parse(Float64, value))
            elseif (key_index == 2)
                push!(high_price_array, parse(Float64, value))
            elseif (key_index == 3)
                push!(low_price_array, parse(Float64, value))
            elseif (key_index == 4)
                push!(close_price_array, parse(Float64, value))
            elseif (key_index == 5)
                push!(adjusted_close_array, parse(Float64, value))
            elseif (key_index == 6)
                push!(volume_array, parse(Int64, value))
            else
                push!(dividend_amount_array, parse(Float64, value))
            end
        end
    end
    # we need to sort the timestamps, to make them in reverse order -
    idx_sort = sortperm(timestamp_array)

    # build the data frame -
    data_frame = DataFrame(timestamp=timestamp_array[idx_sort], open=open_price_array[idx_sort], high=high_price_array[idx_sort], low=low_price_array[idx_sort], close=close_price_array[idx_sort], adjusted_close = adjusted_close_array[idx_sort], volume=volume_array[idx_sort], dividend_amount = dividend_amount_array[idx_sort])

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

function process_raw_json_sts_intraday_data(api_call_raw_data::String)::PSResult

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)
    overall_intraday_data_dictionary = Dict{String,Any}()

    # grab the Meta Data block -
    keys_metadata_block = [
        "1. Information",
        "2. Symbol",
        "3. Last Refreshed",
        "4. Interval",
        "5. Output Size",
        "6. Time Zone"
    ]
    metadata_block_dictionary = api_data_dictionary["Meta Data"]
    interval_value = metadata_block_dictionary["4. Interval"]

    # process the intraday data dictionary -
    intraday_data_keys = [
        "1. open", "2. high", "3. low", "4. close", "5. volume"
    ]

    # setup date formatter -
    F = DateFormat("yyyy-mm-dd HH:MM:SS")

    # setup the data frame -
    intraday_dataframe = DataFrame(timestamp=Dates.DateTime[],open=Union{Missing,Float64}[],close=Union{Missing,Float64}[],
        high=close=Union{Missing,Float64}[],low=close=Union{Missing,Float64}[],volume=close=Union{Missing,Int64}[])

    data_array_key_string = "Time Series ($(interval_value))"
    list_of_intraday_dictionaries = api_data_dictionary[data_array_key_string]
    list_of_timestamp_keys = keys(list_of_intraday_dictionaries)
    for intraday_timestamp_key in list_of_timestamp_keys

        # create an empty row -
        data_row = Array{Union{DateTime,Float64},1}()

        # format the timestamp -
        timestamp_value = DateTime(intraday_timestamp_key, F)
        push!(data_row, timestamp_value)

        # from the intraday timestamp => get the data dictionary -
        intraday_dictionary = list_of_intraday_dictionaries[intraday_timestamp_key]
        for intraday_data_key in intraday_data_keys
            data_value = intraday_dictionary[intraday_data_key]
            push!(data_row, parse(Float64,data_value))
        end

        # push into the data frame -
        push!(intraday_dataframe, tuple(data_row...))
    end

    # lets sort by timestamp -
    timestamp_array = intraday_dataframe[:,:timestamp]
    idx_sort = sortperm(timestamp_array)
    sorted_intraday_dataframe = intraday_dataframe[idx_sort,:]

    # package -
    overall_intraday_data_dictionary["Meta Data"] = metadata_block_dictionary
    overall_intraday_data_dictionary[data_array_key_string] = sorted_intraday_dataframe

    # return -
    return PSResult(overall_intraday_data_dictionary)
end

function process_raw_json_api_data_sts_daily_adjusted(api_call_raw_data::String, data_series_key::String)::(Union{PSResult{T}, Nothing} where T<:Any)

    # is the data coming back well formed, and does it contain valid data?
    check_result = check_json_api_return_data(api_call_raw_data)
    if check_result !== nothing
        return check_result
    end

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing the Time series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end
    #all repeated up to here possibly look to make the above a function for just checking data
    # array of keys -- this is changed per function
    data_key_label_array = ["1. open", "2. high", "3. low", "4. close", "5. adjusted close", "6. volume", "7. dividend amount", "8. split coefficient"]
    number_of_fields = length(data_key_label_array)

    #initialize arrays to hold these fields for all dates
    timestamp_array = Dates.Date[]
    open_price_array = Float64[]
    high_price_array = Float64[]
    low_price_array = Float64[]
    close_price_array = Float64[]
    adjusted_close_array = Float64[]
    volume_array = Int64[]
    dividend_amount_array = Float64[]
    split_coefficient = Float64[]

    # ok, we have the time series key, go through the data and load into the table -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # cache -
        push!(timestamp_array, Dates.Date(timestamp_value,"yyyy-mm-dd"))

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            # populate the array's -
            if (key_index == 1)
                push!(open_price_array, parse(Float64, value))
            elseif (key_index == 2)
                push!(high_price_array, parse(Float64, value))
            elseif (key_index == 3)
                push!(low_price_array, parse(Float64, value))
            elseif (key_index == 4)
                push!(close_price_array, parse(Float64, value))
            elseif (key_index == 5)
                push!(adjusted_close_array, parse(Float64, value))
            elseif (key_index == 6)
                push!(volume_array, parse(Int64, value))
            elseif (key_index == 7)
                push!(dividend_amount_array, parse(Float64, value))
            else
                push!(split_coefficient, parse(Float64, value))
            end
        end
    end
    # we need to sort the timestamps, to make them in reverse order -
    idx_sort = sortperm(timestamp_array)

    # build the data frame -
    data_frame = DataFrame(timestamp=timestamp_array[idx_sort], open=open_price_array[idx_sort], high=high_price_array[idx_sort], low=low_price_array[idx_sort], close=close_price_array[idx_sort], adjusted_close = adjusted_close_array[idx_sort], volume=volume_array[idx_sort], dividend_amount = dividend_amount_array[idx_sort])

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

function process_raw_json_data_sts_global_quote(api_call_raw_data::String, data_series_key::String)::(Union{PSResult{T}, Nothing} where T<:Any)

     # is the data coming back well formed, and does it contain valid data?
     check_result = check_json_api_return_data(api_call_raw_data)
     if check_result !== nothing
         return check_result
     end

     # if we get here, we have valid JSON. Build dictionary -
     api_data_dictionary = JSON.parse(api_call_raw_data)

     # grab the time series data -
     time_series_key = data_series_key
     if (haskey(api_data_dictionary, time_series_key) == false)

         # throw an error -
         error_message = "Error: Missing the Time series key = $(time_series_key)"

         # throw -
         return PSError(error_message)
     end

     #all repeated up to here possibly look to make the above a function for just checking data
     # array of keys -- this is changed per function
     data_key_label_array = ["01. symbol", "02. open", "03. high", "04. low", "05. price", "06. volume", "07. latest trading day", "08. previous close", "09. change", "10. change percent"]
     number_of_fields = length(data_key_label_array)

     #initialize arrays to hold these fields for all dates
     symbol_array = String[]
     open_price_array = Float64[]
     high_price_array = Float64[]
     low_price_array = Float64[]
     price_array = Float64[]
     volume_array = Int64[]
     latest_trading_day = Dates.Date[]
     previous_close_array = Float64[]
     change_array = Float64[]
     change_percentage_array = String[]

     # ok, we have the time series key, go through the data and load into the table -
     data_dictionary = api_data_dictionary[time_series_key]
     for key_index = 1:number_of_fields

        # grab key -
        local_key = data_key_label_array[key_index]
        value = data_dictionary[local_key]

        # populate the array's -
        if (key_index == 1)
            push!(symbol_array, value)
        elseif (key_index == 2)
            push!(open_price_array, parse(Float64, value))
        elseif (key_index == 3)
            push!(high_price_array, parse(Float64, value))
        elseif (key_index == 4)
            push!(low_price_array, parse(Float64, value))
        elseif (key_index == 5)
            push!(price_array, parse(Float64, value))
        elseif (key_index == 6)
            push!(volume_array, parse(Int64, value))
        elseif (key_index == 7)
            push!(latest_trading_day, Dates.Date(value,"yyyy-mm-dd"))
       elseif (key_index == 8)
           push!(previous_close_array, parse(Float64, value))
       elseif (key_index == 9)
           push!(change_array, parse(Float64, value))
       else
            push!(change_percentage_array, value)
        end
    end

    # build the data frame -
    data_frame = DataFrame(symbol=symbol_array, open=open_price_array, high=high_price_array, low=low_price_array, price=price_array,
        volume=volume_array, timestamp=latest_trading_day, previous_close = previous_close_array, change=change_array, change_percentage = change_percentage_array)

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

function process_raw_json_data_sts_search_data(api_call_raw_data::String, data_series_key::String)::(Union{PSResult{T}, Nothing} where T<:Any)

    # is the data coming back well formed, and does it contain valid data?
    check_result = check_json_api_return_data(api_call_raw_data)
    if check_result !== nothing
        return check_result
    end

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing data series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end
    #all repeated up to here possibly look to make the above a function for just checking data
    # array of keys -- this is changed per function
    data_key_label_array = ["1. symbol", "2. name", "3. type", "4. region", "5. marketOpen", "6. marketClose", "7. timezone", "8. currency", "9. matchScore"]
    number_of_fields = length(data_key_label_array)

    #initialize arrays to hold these fields for all dates
    symbol_array = String[]
    name_array = String[]
    type_array = String[]
    region_array = String[]
    market_open_array = String[]
    market_close_array = String[]
    timezone_array = String[]
    currency_array = String[]
    match_score_array = Float64[]

    # ok, we have the time series key, go through the data and load into the table -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            # populate the array's -
            if (key_index == 1)
                push!(symbol_array, value)
            elseif (key_index == 2)
                push!(name_array, value)
            elseif (key_index == 3)
                push!(type_array, value)
            elseif (key_index == 4)
                push!(region_array, value)
            elseif (key_index == 5)
                push!(market_open_array, value)
            elseif (key_index == 6)
                push!(market_close_array, value)
            elseif (key_index == 7)
                push!(timezone_array, value)
            elseif (key_index == 8)
                push!(currency_array, value)
            elseif (key_index == 9)
                push!(match_score_array, parse(Float64,value))
            end
        end
    end

    # build the data frame -
    data_frame = DataFrame(symbol=symbol_array, name=name_array, type=type_array, region=region_array, marketOpen=market_open_array, marketClose = market_close_array,
        timezone=timezone_array, currency = currency_array, match = match_score_array)

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

# Technical indicators --
function process_raw_json_data_ti_sma_data(api_call_raw_data::String, data_series_key::String)::PSResult

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing the series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end

    # initialize -
    data_key_label_array = ["SMA"]
    number_of_fields = length(data_key_label_array)
    timestamp_array = Dates.Date[]
    sma_value_array = Float64[]

    # ok, get the data for each time point -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # cache -
        push!(timestamp_array, Dates.Date(timestamp_value,"yyyy-mm-dd"))

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            if (key_index == 1)
                push!(sma_value_array, parse(Float64,value))
            end
        end
    end

    # we need to sort the timestamps, to make them in reverse order -
    idx_sort = sortperm(timestamp_array)

    # build the data frame -
    data_frame = DataFrame(timestamp=timestamp_array[idx_sort], sma=sma_value_array[idx_sort])

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

function process_raw_json_data_ti_ema_data(api_call_raw_data::String, data_series_key::String)::PSResult

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing the series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end

    # initialize -
    data_key_label_array = ["EMA"]
    number_of_fields = length(data_key_label_array)
    timestamp_array = Dates.Date[]
    ema_value_array = Float64[]

    # ok, get the data for each time point -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # cache -
        push!(timestamp_array, Dates.Date(timestamp_value,"yyyy-mm-dd"))

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            if (key_index == 1)
                push!(ema_value_array, parse(Float64,value))
            end
        end
    end

    # we need to sort the timestamps, to make them in reverse order -
    idx_sort = sortperm(timestamp_array)

    # build the data frame -
    data_frame = DataFrame(timestamp=timestamp_array[idx_sort], ema=ema_value_array[idx_sort])

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

function process_raw_json_data_ti_rsi_data(api_call_raw_data::String,
    data_series_key_array::String)::PSResult

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)

    # grab the time series data -
    time_series_key = data_series_key
    if (haskey(api_data_dictionary, time_series_key) == false)

        # throw an error -
        error_message = "Error: Missing the series key = $(time_series_key)"

        # throw -
        return PSError(error_message)
    end

    # initialize -
    data_key_label_array = ["RSI"]
    number_of_fields = length(data_key_label_array)
    timestamp_array = Dates.Date[]
    rsi_value_array = Float64[]

    # ok, get the data for each time point -
    time_series_dictionary = api_data_dictionary[time_series_key]
    time_series_key_array = collect(keys(time_series_dictionary))
    for timestamp_value in time_series_key_array

        # get the local_dictionary -
        local_dictionary = time_series_dictionary[timestamp_value]

        # cache -
        push!(timestamp_array, Dates.Date(timestamp_value,"yyyy-mm-dd"))

        # add the price data -
        for key_index = 1:number_of_fields

            # grab key -
            local_key = data_key_label_array[key_index]
            value = local_dictionary[local_key]

            if (key_index == 1)
                push!(rsi_value_array, parse(Float64,value))
            end
        end
    end

    # we need to sort the timestamps, to make them in reverse order -
    idx_sort = sortperm(timestamp_array)

    # build the data frame -
    data_frame = DataFrame(timestamp=timestamp_array[idx_sort], rsi=rsi_value_array[idx_sort])

    # return the data back to the caller -
    return PSResult{DataFrame}(data_frame)
end

# Fundamentals -
function process_raw_json_fundamentals_earnings_data(api_call_raw_data::String)::PSResult

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)
    earnings_data_dictionary = Dict{String,Any}()

    # ok, so there is a symbol key that comes back -
    earnings_data_dictionary["symbol"] = api_data_dictionary["symbol"]

    # grab: annualEarnings -
    list_of_annual_earnings_dictionaries =  api_data_dictionary["annualEarnings"]
    earnings_dataframe = DataFrame(fiscalDateEnding=Dates.Date[],reportedEPS=Union{Float64,Missing}[])
    for earnings_dictionary in list_of_annual_earnings_dictionaries

        # grab -
        timestamp_value = earnings_dictionary["fiscalDateEnding"]
        eps_value = earnings_dictionary["reportedEPS"]

        # convert -
        converted_timestamp_value = Dates.Date(timestamp_value,"yyyy-mm-dd")
        converted_eps_value = parse(Float64, eps_value)

        # package into the df -
        push!(earnings_dataframe, (converted_timestamp_value, converted_eps_value))
    end

    # grab: quarterlyEarnings -
    list_of_quaterly_earnings_dictionaries = api_data_dictionary["quarterlyEarnings"]
    quarterly_dataframe = DataFrame(fiscalDateEnding=Dates.Date[],
        reportedDate=Dates.Date[],
        reportedEPS=Union{Float64,Missing}[],
        estimatedEPS=Union{Float64,Missing}[],
        surprise=Union{Float64,Missing}[],
        surprisePercentage=Union{Float64,Missing}[])

    for earnings_dictionary in list_of_quaterly_earnings_dictionaries

        # grab data from dictionary -
        fiscalDateEnding = Dates.Date(earnings_dictionary["fiscalDateEnding"], "yyyy-mm-dd")
        reportedDate = Dates.Date(earnings_dictionary["reportedDate"], "yyyy-mm-dd")

        # check reported EPS -
        reportedEPS_value = earnings_dictionary["reportedEPS"]
        reportedEPS = missing
        if (reportedEPS_value != "None")
            reportedEPS = parse(Float64, reportedEPS_value)
        end

        # check estimated EPS -
        estimatedEPS_value = earnings_dictionary["estimatedEPS"]
        estimatedEPS = missing
        if (estimatedEPS_value != "None")
            estimatedEPS = parse(Float64, estimatedEPS_value)
        end

        # check suprise -
        surprise_value = earnings_dictionary["surprise"]
        surprise = missing
        if (surprise_value != "None")
            surprise = parse(Float64, surprise_value)
        end

        # check surprisePercentage -
        surprisePercentage_value = earnings_dictionary["surprisePercentage"]
        surprisePercentage = missing
        if (surprisePercentage_value != "None")
            surprisePercentage = parse(Float64, surprisePercentage_value)
        end

        # package -
        push!(quarterly_dataframe,(fiscalDateEnding, reportedDate, reportedEPS, estimatedEPS, surprise, surprisePercentage))
    end

    # package -
    earnings_data_dictionary["annualEarnings"] = earnings_dataframe
    earnings_data_dictionary["quarterlyEarnings"] = quarterly_dataframe

    # return -
    return PSResult(earnings_data_dictionary)
end

function process_raw_json_fundamentals_income_statement_data(api_call_raw_data::String)::PSResult

    # if we get here, we have valid JSON. Build dictionary -
    api_data_dictionary = JSON.parse(api_call_raw_data)
    income_statement_data_dictionary = Dict{String,Any}()

    # ok, so there is a symbol key that comes back -
    income_statement_data_dictionary["symbol"] = api_data_dictionary["symbol"]

    # process the annualReports -
    # what keys are we looking for in the annual report dictionary -
    annual_report_key_array = [
        "fiscalDateEnding"                  ;
        "reportedCurrency"                  ;
        "grossProfit"                       ;
        "totalRevenue"                      ;
        "costOfRevenue"                     ;
        "costofGoodsAndServicesSold"        ;
        "operatingIncome"                   ;
        "sellingGeneralAndAdministrative"   ;
        "researchAndDevelopment"            ;
        "operatingExpenses"                 ;
        "investmentIncomeNet"               ;
        "netInterestIncome"                 ;
        "interestIncome"                    ;
        "interestExpense"                   ;
        "nonInterestIncome"                 ;
        "otherNonOperatingIncome"           ;
        "depreciation"                      ;
        "depreciationAndAmortization"       ;
        "incomeBeforeTax"                   ;
        "incomeTaxExpense"                  ;
        "interestAndDebtExpense"            ;
        "netIncomeFromContinuingOperations" ;
        "comprehensiveIncomeNetOfTax"       ;
        "ebit"                              ;
        "ebitda"                            ;
        "netIncome"                         ;
    ]

    # get the array of annual report dictionaries -
    list_of_annual_report_dictionaries =  api_data_dictionary["annualReports"]
    annual_reports_dataframe = DataFrame(fiscalDateEnding=Dates.Date[],reportedCurrency=String[],grossProfit=Union{Float64,Missing}[],
        totalRevenue=Union{Float64,Missing}[],costOfRevenue=Union{Float64,Missing}[],costofGoodsAndServicesSold=Union{Float64,Missing}[],operatingIncome=Union{Float64,Missing}[],
        sellingGeneralAndAdministrative=Union{Float64,Missing}[],researchAndDevelopment=Union{Float64,Missing}[],operatingExpenses=Union{Float64,Missing}[],investmentIncomeNet=Union{Float64,Missing}[],
        netInterestIncome=Union{Float64,Missing}[],interestIncome=Union{Float64,Missing}[],interestExpense=Union{Float64,Missing}[],nonInterestIncome=Union{Float64,Missing}[],otherNonOperatingIncome=Union{Float64,Missing}[],
        depreciation=Union{Float64,Missing}[],depreciationAndAmortization=Union{Float64,Missing}[],incomeBeforeTax=Union{Float64,Missing}[],incomeTaxExpense=Union{Float64,Missing}[],interestAndDebtExpense=Union{Float64,Missing}[],
        netIncomeFromContinuingOperations=Union{Float64,Missing}[],comprehensiveIncomeNetOfTax=Union{Float64,Missing}[],ebit=Union{Float64,Missing}[],ebitda=Union{Float64,Missing}[],netIncome=Union{Float64,Missing}[])

    # loop throw, and pakage the annual report values into the dataframe -
    for annual_report in list_of_annual_report_dictionaries

        # init the row of data -
        data_row = Array{Any,1}()

        # go throw all the keys -
        for annual_report_key in annual_report_key_array

            # ok, so if we have fiscalDateEnding or reportedCurrency we have a non-numeric value
            clean_value = 0.0
            if annual_report_key == "fiscalDateEnding"
                clean_value = Dates.Date(annual_report["fiscalDateEnding"], "yyyy-mm-dd")
            elseif annual_report_key == "reportedCurrency"
                clean_value = annual_report["reportedCurrency"]
            else

                # grab the value, check if none -
                value = annual_report[annual_report_key]
                clean_value = check_for_numerical_none_value(value)
            end

            # cache -
            push!(data_row, clean_value)
        end

        # push the data row into the data frame -
        push!(annual_reports_dataframe, tuple(data_row...))
    end
    income_statement_data_dictionary["annualReports"] = annual_reports_dataframe

    # process the quarterly reports -
    list_of_quaterly_report_dictionaries =  api_data_dictionary["quarterlyReports"]
    quaterly_reports_dataframe = DataFrame(fiscalDateEnding=Dates.Date[],reportedCurrency=String[],grossProfit=Union{Float64,Missing}[],
        totalRevenue=Union{Float64,Missing}[],costOfRevenue=Union{Float64,Missing}[],costofGoodsAndServicesSold=Union{Float64,Missing}[],operatingIncome=Union{Float64,Missing}[],
        sellingGeneralAndAdministrative=Union{Float64,Missing}[],researchAndDevelopment=Union{Float64,Missing}[],operatingExpenses=Union{Float64,Missing}[],investmentIncomeNet=Union{Float64,Missing}[],
        netInterestIncome=Union{Float64,Missing}[],interestIncome=Union{Float64,Missing}[],interestExpense=Union{Float64,Missing}[],nonInterestIncome=Union{Float64,Missing}[],otherNonOperatingIncome=Union{Float64,Missing}[],
        depreciation=Union{Float64,Missing}[],depreciationAndAmortization=Union{Float64,Missing}[],incomeBeforeTax=Union{Float64,Missing}[],incomeTaxExpense=Union{Float64,Missing}[],interestAndDebtExpense=Union{Float64,Missing}[],
        netIncomeFromContinuingOperations=Union{Float64,Missing}[],comprehensiveIncomeNetOfTax=Union{Float64,Missing}[],ebit=Union{Float64,Missing}[],ebitda=Union{Float64,Missing}[],netIncome=Union{Float64,Missing}[])

    # loop throw, and pakage the annual report values into the dataframe -> same keys as annualReport
    for quaterly_report in list_of_quaterly_report_dictionaries

        # init the row of data -
        data_row = Array{Any,1}()

        # go throw all the keys -
        for annual_report_key in annual_report_key_array

            # ok, so if we have fiscalDateEnding or reportedCurrency we have a non-numeric value
            clean_value = 0.0
            if annual_report_key == "fiscalDateEnding"
                clean_value = Dates.Date(quaterly_report["fiscalDateEnding"], "yyyy-mm-dd")
            elseif annual_report_key == "reportedCurrency"
                clean_value = quaterly_report["reportedCurrency"]
            else

                # grab the value, check if none -
                value = quaterly_report[annual_report_key]
                clean_value = check_for_numerical_none_value(value)
            end

            # cache -
            push!(data_row, clean_value)
        end

        # push the data row into the data frame -
        push!(quaterly_reports_dataframe, tuple(data_row...))
    end
    income_statement_data_dictionary["quarterlyReports"] = quaterly_reports_dataframe

    # return -
    return PSResult(income_statement_data_dictionary)
end

ext: jl


text:
using Comonicon
using Markdown
using Comonicon.Types
using Comonicon.Parse
using Comonicon.BuildTools: install
using Test

Comonicon.disable_cache()

module Dummy
using Comonicon
using Test

"""
foo foo

# Arguments

- `x`: an argument

# Options

- `--foo <foo>`: foo foo
- `--dash-dash <dash>`: dash dash.
"""
@cast function foo(
    x::Int,
    y;
    foo::Int = 1,
    hulu::Float64 = 2.0,
    flag::Bool = false,
    dash_dash::String = "dash",
) where {T}
    @test x == 1
    @test y == "2.0"
    @test foo == 2
    @test hulu == 3.0
    @test flag == true
    @test dash_dash == "underscore"
end

"""
goo goog gooasd dasdas

goo asdas dasd assadas

# Arguments

- `ala`: ala ahjsd asd wvxzj
- `gaga`: djknawd sddasd kw

# Options

- `-g,--giao <name>`: huhuhuhuhuuhu

# Flags

- `-f,--flag`: dadsa fasf gas
"""
@cast function goo(ala::Int, gaga; giao = "Bob", flag::Bool = false)
    @test ala == 1
    @test gaga == "2.0"
    @test giao == "Sam"
    @test flag == true
end

"""
tick tick.

# Arguments

- `xx`: xxxxxxxxxxxx
- `yy`: yyyyyyyyyyyy
"""
@cast function tick(xx::Int, yy::Float64 = 1.0)
    @test xx == 1
    @test yy in [1.0, 2.0]
end

"""
dummy command. dasdas dsadasdnaskdas dsadasdnaskdas
sdasdasdasdasdasd adsdasdas dsadasdas dasdasd dasda
"""
@main
end

@test Dummy.command_main(String[
    "foo",
    "1.0",
    "2.0",
    "--foo",
    "2",
    "--hulu=3.0",
    "--flag",
    "--dash-dash=underscore",
]) == 0
@test Dummy.command_main(String[
    "foo",
    "1.0",
    "2.0",
    "--foo",
    "2",
    "--hulu=3.0",
    "-f",
    "--dash-dash",
    "underscore",
]) == 0
@test Dummy.command_main(String["goo", "1.0", "2.0", "-gSam", "-f"]) == 0
@test_throws ErrorException LeafCommand(
    identity;
    name = "foo",
    options = [Option("huhu"; short = true)],
)
@test Dummy.command_main(String["tick", "1.0", "2.0"]) == 0
@test Dummy.command_main(String["tick", "1.0"]) == 0

empty!(ARGS)
append!(ARGS, ["2", "--opt1", "3"])

"""
ArgParse example implemented in Comonicon.

# Arguments

- `x`: an argument

# Options

- `--opt1 <arg>`: an option
- `-o, --opt2 <arg>`: another option

# Flags

- `-f, --flag`: a flag
"""
@main function main(x; opt1 = 1, opt2::Int = 2, flag = false)
    @test flag == false
    @test x == "2"
    @test opt1 == "3"
    @test opt2 == 2
end

empty!(ARGS)
Comonicon.install(
    Dummy;
    path = Comonicon.PATH.project("test"),
    completion = false,
    quiet = false,
)

@test isfile(Comonicon.PATH.project("test", "bin", "dummy"))
@test isfile(Comonicon.PATH.project("test", "bin", "dummy.jl"))

@testset "default_name" begin
    @test Comonicon.PATH.default_name("Foo.jl") == "foo"
    @test Comonicon.PATH.default_name(sin) == "sin"
end

cmd = @cast(f_issue_47(xs::Int...) = xs)

@testset "issue/#47" begin
    @test cmd.args[1].type == Int
    @test cmd.args[1].vararg == true
end

@testset "markdown parsing" begin
    doc = md"""
    ArgParse example implemented in `Comonicon`.

    # Arguments

    - `x`: an argument, `args`
    """

    intro, args, flags, optionsa = Parse.read_doc(doc)
    @test intro == "  ArgParse example implemented in \e[36mComonicon\e[39m."
    @test haskey(args, "x")
    @test args["x"] == "an argument, \e[36margs\e[39m"

    doc = md"""
    ArgParse example implemented in Comonicon.

    # Args
    - `x`: an argument

    # Options

    - `--option1=<value>`: option with assign
    - `--option2=<value>`: option with space
    """

    intro, args, flags, options = Parse.read_doc(doc)
    @test intro == "  ArgParse example implemented in Comonicon."
    @test haskey(args, "x")
    @test args["x"] == "an argument"
    @test haskey(options, "option1")
    @test haskey(options, "option2")
    @test options["option1"] == ("value", "option with assign", false)
    @test options["option2"] == ("value", "option with space", false)

    doc = md"""
    ArgParse example implemented in Comonicon.

    # Args
    - `x`: an argument

    # Arguments
    - `x`: an argument
    """

    @test_throws ErrorException Parse.read_doc(doc)
end


text:
# Sine Dictionary based example
using PyPlot
using Statistics
using Random

include("../src/LocallyCompetitive.jl")
Random.seed!(0xcafebeef)

# First we create 'dim' basis functions, each consisting of 'n_elm' samples.
# Using the dictionary 'D' a set of output samples can be created.
# We will create a 'k' sparse signal 'y' and attempt to reconstruct it.
# For a basis function we will use a set of sine functions with the norm of each
# function set to 1.
# The sparse signal 'y' will have 'k' randomly chosen signals.
#
# LCA can effectively reconstruct 'y' original representation even with changes
# to the dictionary used to create it and if LCA attempts to reconstruct
# 'y'+noise it will attempt to impose sparsity on the solution

dim     = 64   #number of basis functions
n_elms  = 1024 #samples per function
D       = zeros(n_elems,dim);
k       = 3    #Sparsity factor
s       = zeros(dim)

for i=1:dim,
    j=1:n_elems
    D[j,i] = sin(2pi*j*i/n_elems)
end
LCA.unitary_columns!(D)

# The original sparse representation
s = rand(dim)*4
s[sortperm(randn(dim))[k+1:end]] .= 0

# The signal that is observed
y = D*s

noise   = randn(n_elems)

sparse_clean  = LCA.lca(y+0.0*noise, D, T_soft=0.20)
sparse_noise  = LCA.lca(y+0.2*noise, D, T_soft=0.25)

figure(1);PyPlot.clf()
subplot(3,1,1)
title("The original sparse elements")
ylabel("Magnitude")
stem(s)
subplot(3,1,2)
title("The reconstructed sparse elements")
ylabel("Magnitude")
stem(sparse_clean)
subplot(3,1,3)
title("The reconstructed elements under noisy observation")
xlabel("Dictionary Element")
ylabel("Magnitude")
stem(sparse_noise)

figure(2);PyPlot.clf()
title("The original sparse elements")
ylabel("Magnitude")
plot(D*s)
plot(D*sparse_clean)
figure(43);PyPlot.clf()
subplot(1,3,1)
plot(y+0.2*noise)
axis([0,n_elms, -0.6, 0.6])
subplot(1,3,2)
plot(y)
axis([0,n_elms, -0.6, 0.6])
subplot(1,3,3)
plot(D*sparse_noise)
axis([0,n_elms, -0.6, 0.6])

println("If LCA is working as expected, then the sparsity of the original")
println("signal input should be identical. For processing the signal with noise")
println("the sparsity should be similar though higher (sparsity will go down")
println("with higher soft_threshold values)")

println()

println("Sparsity of original signal = ", sum(s.!=0))
println("Sparsity of LCA on the clean observation = ", sum(sparse_clean.!=0))
println("Sparsity of LCA on the dirty observation = ", sum(sparse_noise.!=0))

println()
println("Although the sparsity of LCA on the dirty observation is higher,")
println("let's see what happens to the reconstruction error")
println()
println("Original     = ", norm(D*s-y), " (Defined to be zero)")
println("LCA clean    = ", norm(D*sparse_clean-y), " (Should be small)")
println("noisy signal = ", norm(y+noise-y),
        " (Defined to be the norm of the noise")
println("LCA dirty    = ", norm(D*sparse_noise-y),
        " (Much lower than the noisy observation)")


text:
# jump_utils
using GraphPlot, LightGraphs,MetaGraphs,DataFrames,DataFramesMeta,JuMP
using MetaGraphs,Colors

function vertexCover(g::Graph)
	m= Model(GLPK.Optimizer)
	@variable(m, 0<=x[i=vertices(g)]<=1,Bin)
	@constraint(m,meh[e = edges(g)], x[e.src]+x[e.dst]>=1)
	@objective(m,Min,sum(x))
	m
end

function edgeCover(g::Graph)
	m=Model(GLPK.Optimizer)
	@variable(m,ed[e = edges(g)],Bin)
	@constraint(m,NodeCovered[v = vertices(g)],
	  sum([ed[e] for e in edges(g) if v in [e.src,e.dst]])>=1
	)
	@objective(m,Min, sum(ed))
	m
end

# function create
function facilityLocationSimpleModel(;m,n,Xc,Yc,Xf,Yf,f,c,facilityCapacities,customerDemands)
	mod= Model(GLPK.Optimizer)
	@variable(mod,openFacilities[i=1:n],Bin)
	@variable(mod,0<=serviceFromFacilities[i = 1:n , j = 1:m]<=1.0)
	#constraint- everything is covered
	@constraint(mod,coverDemands[j=1:m],sum(serviceFromFacilities[:,j])==1)
	@constraint(mod,facilityCapacities[i=1:n],
        sum(customerDemands[j]*serviceFromFacilities[i,j] for j in 1:m)<=facilityCapacities[i]*openFacilities[i])

	@objective(mod,Min,sum([f[i]*openFacilities[i] for i in 1:n])+0.2*sum([c[j,i]*serviceFromFacilities[i,j] for i=1:n,j=1:m]))
	mod
end

function CreateFacilityLocationGraph(m,n,model,Xc,Yc,Xf,Yf)
	gr = MetaGraphs.MetaGraph()
	i = 1
	for v in 1:m
		add_vertex!(gr)
		set_props!(gr,i,Dict(:type=>"client",:number=>v,:X=>Xc[v],:Y=>Yc[v]))
		i+=1
	end

	for v in 1:n
		add_vertex!(gr)
		set_props!(gr,i,Dict(:type=>"facility",:number=>v,:present=>value(
            variable_by_name(model,"openFacilities[$v]")
        ),:X=>Xf[v],:Y=>Yf[v]))
		i+=1
	end

	for i = 1:n,j=1:m
		add_edge!(gr,m+i,j)
        # println(
        #     value(variable_by_name(model,"serviceFromFacilities[$i,$j]"))
        # )
        set_props!(gr,m+i,j,Dict(:prop=>value(variable_by_name(model,"serviceFromFacilities[$i,$j]"))))
	end
    # color clients as red
    for v in filter_vertices(gr,(gr,x)->(has_prop(gr,x,:type)&&get_prop(gr,x,:type)=="client"))
        set_props!(gr,v,Dict(:color=>colorant"red"))
    end
    # color open facilities as green
    for v in filter_vertices(gr,(gr,x)->(has_prop(gr,x,:type)&&
              get_prop(gr,x,:type)=="facility"&&
              get_prop(gr,x,:present)>=1 ))
        set_prop!(gr,v,:color,colorant"green")
    end

    # color edges with flow with red
    for e in filter_edges(gr,(gr,e)->(has_prop(gr,e,:prop)&&(get_prop(gr,e,:prop)>0.0)))
        set_prop!(gr,e,:color,colorant"blue")
    end

	gr
end

function plotFacLocGraph(gr)
gplot(SimpleGraph(gr),
    [get_prop(gr,v,:X) for v in vertices(gr)],
    [get_prop(gr,v,:Y) for v in vertices(gr)],
    nodefillc =[has_prop(gr,v,:color) ? get_prop(gr,v,:color) : nothing for v in vertices(gr)],
    edgestrokec=[has_prop(gr,e,:color) ? get_prop(gr,e,:color) : nothing for e in edges(gr)],
    edgelinewidth = [get_prop(gr,e,:prop)>0 ? get_prop(gr,e,:prop) : 0.0  for e in edges(gr)]
    )
end


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "Shaderc"
version = v"2022.1.0"

# Collection of sources required to complete build
sources = [
    GitSource("https://github.com/google/shaderc.git", "e4722b0ad49ee60c143d43baae8390f75ba27d2d")
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/shaderc*/
./utils/git-sync-deps
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=${prefix} \
    -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TARGET_TOOLCHAIN} \
    -DCMAKE_BUILD_TYPE=Release \
    -DSHADERC_SKIP_TESTS=1 \
    -DSHADERC_SKIP_EXAMPLES=1 \
    -DSHADERC_SKIP_COPYRIGHT_CHECK=1 \
    -S .. \
    -B .
make -j${nproc}
make install
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = expand_cxxstring_abis(supported_platforms())

# The products that we will ensure are always built
products = [
    LibraryProduct("libshaderc_shared", :libshaderc_shared),
    LibraryProduct("libSPIRV-Tools-shared", :libSPIRV_Tools_shared),
    ExecutableProduct("spirv-dis", :spirv_dis),
    ExecutableProduct("spirv-lint", :spirv_lint),
    ExecutableProduct("spirv-opt", :spirv_opt),
    ExecutableProduct("glslangValidator", :glslangValidator),
    ExecutableProduct("spirv-cfg", :spirv_cfg),
    ExecutableProduct("spirv-link", :spirv_link),
    ExecutableProduct("glslc", :glslc),
    ExecutableProduct("spirv-remap", :spirv_remap),
    ExecutableProduct("spirv-val", :spirv_val),
    ExecutableProduct("spirv-reduce", :spirv_reduce),
    ExecutableProduct("spirv-as", :spirv_as)
]

# Dependencies that must be installed before this package can be built
dependencies = Dependency[
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; julia_compat="1.6")

max_stars_repo_name: cmhamel/Yggdrasil

max_issues_repo_name: cmhamel/Yggdrasil

max_forks_repo_name: cmhamel/Yggdrasil


text:
type Pixel1{T}
x::Int64
y::Int64
color::T
end

max_stars_repo_path: Module 2/Chapter03/tyoepixe.jl

max_issues_repo_path: Module 2/Chapter03/tyoepixe.jl

max_forks_repo_path: Module 2/Chapter03/tyoepixe.jl


text:
using NumberIntervals, Turmeric, StaticArrays, ForwardDiff
using Test

all_unique(rts) = length(rts[2]) == 0

function test_newtonlike(f, X, method, nsol)
    rts = roots(f, X, method)
    @test length(rts[1]) == nsol
    @test all_unique(rts)
end

newtonlike_methods = (Newton(), Krawczyk())

@testset "1D roots" begin
    # Default
    rts = roots(sin, NumberInterval(-5, 5))
    @test length(rts[1]) == 3
    @test all_unique(rts)

    # Bisection()
    rts = roots(sin, NumberInterval(-5, 6), Bisection(), 1e-3)
    @test length(rts[2]) == 3

    for method in newtonlike_methods
        test_newtonlike(sin, NumberInterval(-5, 5), method, 3)
    end

    # Infinite interval
    rts = roots(x -> x^2 - 2, NumberInterval(-Inf, Inf), Newton())
    @test length(rts[1]) == 2
end

@testset "2D roots" begin
    f(x, y) = SVector(x^2 + y^2 - 1, y - 2x)
    f(X) = f(X...)
    X = SVector(
        NumberInterval(-6, 6),
        NumberInterval(-6, 6)
    )

    # Bisection()
    rts = roots(f, X, Bisection(), 1e-3)
    @test_broken length(rts[2]) == 2

    for method in newtonlike_methods
        test_newtonlike(f, X, method, 2)
    end

    # Infinite interval
    X = SVector(NumberInterval(-Inf, Inf), NumberInterval(-Inf, Inf))
    rts = roots(f, X, Newton())
    @test length(rts[1]) == 2
end

# From R docs:
# https://www.rdocumentation.org/packages/pracma/versions/1.9.9/topics/broyden

@testset "3D roots" begin
    function g(x)
        (x1, x2, x3) = x
        SVector(    x1^2 + x2^2 + x3^2 - 1,
                    x1^2 + x3^2 - 0.25,
                    x1^2 + x2^2 - 4x3
                )
    end

    X = NumberInterval(-5, 5)
    XX = SVector(X, X, X)

    for method in newtonlike_methods
        rts = roots(g, XX, method)
        @test length(rts[1]) == 4
        @test all_unique(rts)
    end
end

@testset "Out of domain" begin
    for method in newtonlike_methods
        @test_skip length(roots(log, NumberInterval(-100, 2), method)[1]) == 1
        @test length(roots(log, NumberInterval(-100, -1), method)[1]) == 0
    end
end

@testset "Infinite domain" begin
    for method in newtonlike_methods
        rts = roots(x -> x^2 - 2, NumberInterval(-Inf, Inf), method)
        @test length(rts[1]) == 2
        @test all_unique(rts)
    end
end

@testset "NaN return value" begin
    f(xx) = ( (x, y) = xx; SVector(log(y/x) + 3x, y - 2x) )
    X = SVector(NumberInterval(-100.0, 0.0), NumberInterval(-100.0, 0.0))
    for method in newtonlike_methods
        rts = roots(f, X, method)
        @test length(rts[1]) == 1
        @test_broken length(rts[2]) == 0 # failure due to singularity
    end
end

@testset "Stationary points" begin
    f(xx) = ( (x, y) = xx; sin(x) * sin(y) )
    gradf(x) = ForwardDiff.gradient(f, x)
    XX = SVector(NumberInterval(-5, 6), NumberInterval(-5, 6))
    tol = 1e-5

    for method in newtonlike_methods
        test_newtonlike(gradf, XX, method, 25)
    end
end

@testset "Full contraction of roots" begin
    region = NumberInterval(-5, 5)
    tol = 1e-7
    for method in newtonlike_methods
        rts = roots(sin, region, method, tol)
        contractor = GradientContractor(sin, method, region)
        contracted_regions = tfullcontract(contractor, rts[1], tol)
        for _region in contracted_regions
            @test diam(_region) < tol
        end
    end
end


text:
using DoubletFinder
using Test

@testset "DoubletFinder" begin
test_array=[2.1,3.0,0.8,0.7,0.5,0.4,0.2,1.01,1.33,3.88,0.99,0.96,0.98,1.23,4.55]
@testset "Testing linear algebra results" begin
   @test 1 == 1
end;

@testset "findV" begin
    @test findV(3.12,3.12) == 0.0
    @test findV(3.0,3.12) ≈ 8858.92604 atol=1e-4
end;

@testset "findZAbs" begin
    @test findZAbs(0.0, 3.12) == 3.12
    @test findZAbs(1.0, 3.12) ≈ 3.119986 atol=1e-4
end;

@testset "getblocks1" begin
    @test getblocks1(test_array)[1] == (3, 7)
    @test getblocks1(test_array)[2] == (11, 13)
end;
@testset "iscontained" begin
    @test iscontained(test_array,66.0) == false
    @test iscontained(test_array,3.25) == true
end;

    end; #DoubletFinder


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

#############################################################################

# lattice visualizations are drawn with Luxor because it is easier to do 2D drawings with Luxor than with Makie.

function draw(tilebasis::AbstractBasis, tilesize, i, j, color, name)
    vertices = Repeat.tilevertices(tilebasis)
    tile = tilesize * [Luxor.Point(vertices[:,i]...) for i in 1:size(vertices)[2]]
    pt = tilesize * tilebasis[i,j]
    offset = Luxor.Point(pt[1], -pt[2]) # flip y so indices show up correctly

    Luxor.translate(offset)

    Luxor.sethue(color)

    Luxor.poly(tile, :fill, close=true)
    Luxor.sethue("lightgrey")
    Luxor.poly(tile, :stroke, close=true)
    Luxor.sethue("black")

    # scale and offset text so coordinates are readable
    Luxor.fontsize(tilesize / 3)
    Luxor.text("$i, $j", Luxor.Point(-tilesize / 3, tilesize / 2.5))
    if name !== nothing
        Luxor.text(name, Luxor.Point(-tilesize / 4, -tilesize / 4))
    end

    Luxor.translate(-offset)
end

function drawcells(clstr::Repeat.ClusterWithProperties,scale,points)
    _,npts = size(points)
    repeats = npts ÷ clustersize(clstr)
    props = repeat(Repeat.properties(clstr), repeats)
    drawcells(elementbasis(clstr), scale, points, color=props[:,:Color], name=props[:,:Name])
end

drawcells(clstr::Repeat.LatticeCluster,scale,points) = drawcells(elementbasis(clstr),scale,points)

"""Draws a list of hexagonal cells, represented by their lattice coordinates, which are represented as a 2D matrix, with each column being one lattice coordinate."""
function drawcells(tilebasis::AbstractBasis, tilesize, cells::AbstractMatrix; color::Union{AbstractArray,Nothing}=nothing, name::Union{AbstractArray{String},Nothing}=nothing, format=:png, resolution=(1000, 1000))

    numcells = size(cells)[2]
    Luxor.Drawing(resolution[1], resolution[2], format)
    Luxor.origin()
    Luxor.background(Colors.RGBA(1, 1, 1, 0.0))
    if color === nothing
        color = Colors.distinguishable_colors(numcells, lchoices=30:250) # type unstable but not performance critical code
    end

    for i in 1:numcells
        cell = cells[:,i]
        cellname = name === nothing ? nothing : name[i]
        draw(tilebasis, tilesize, cell[1], cell[2], color[i], cellname)
    end

    Luxor.finish()
    if (format == :svg)
        res = Luxor.svgstring()
        return res
    end
    if (format == :png)
        Luxor.preview()
    end
end

""" draw the ClusterWithProperties at coordinates specified by lattice_coordinate_offset """
function draw(clstr::Repeat.AbstractLatticeCluster, cluster_coordinate_offset::AbstractMatrix{T} = [0;0;;] , scale=50.0) where{T}
    dims = size(cluster_coordinate_offset)
    clstrsize = clustersize(clstr)
    points = Matrix{Int64}(undef, dims[1], dims[2] * clstrsize)
    for i in 1:dims[2]
        points[:,(i - 1) * clstrsize + 1:i * clstrsize] = clustercoordinates(clstr, cluster_coordinate_offset[:,i]...)
    end

    drawcells(clstr,scale,points)
end


text:
using Parameters, Distributions, StatsBase, Random, Match, DataFrames

# health status
@enum HEALTH SUS LAT PRE ASYMP INF REC DED UNDEF

# define an agent and all agent properties
Base.@kwdef mutable struct Student
    idx::Int64 = 0                              # id
    health::HEALTH = SUS                        # health status
    swap::HEALTH = UNDEF
    sickfrom::HEALTH = UNDEF                    # sick from who?
    nextday_meetcnt::Int16 = 0                  # number of contacts per day
    grade::Int16 = 0                            # school grade 9 - 12
    association::Int16 = 0                      # student association, 1 => general body, 2 => athletics
    mask::Bool = true                           # wearing a mask?
    tis::Int16   = 0                            # time in state
    exp::Int16   = 0                            # max statetime
    dur::NTuple{4, Int8} = (0, 0, 0, 0)         # Order: (latents, asymps, pres, infs) TURN TO NAMED TUPS LATER
    doi::Int16   = 999                          # day of infection.
    iso::Bool = false                           # isolated (dosn't enter school)
end
Base.show(io::IO, ::MIME"text/plain", z::Student) = dump(z)

## default system parameters
@with_kw mutable struct ModelParameters @deftype Float64    ## use @with_kw from Parameters
    β = 0.0
    frelasymp::Float64 = 0.11                   # relative transmission of asymptomatic
    popsize::Int64 = 1000                       # total population size
    calibration::Bool = false                   # calibration mode
    modeltime::Int64 = 14                       # time period
    asymp_props::Float64 = 0.25                 # proportion of 0 - 19 years old that are asymptomatic
end

## load empty constants  (will be loaded for each process if using pmap, monitor for memory issues)
const humans = Array{Student}(undef, 0)
const p = ModelParameters()  ## setup default parameters

function runsequential()
    # run n simulations sequentially and average the results.
    N = 50
    mp = ModelParameters()
    allresults = map(1:N) do x
        runsim(x, mp)
    end
    sum(allresults) ./ N
end

function runsim(simnum, ip::ModelParameters)
    # runs a single simulation and creates a dataframe
    Random.seed!(simnum*726)
    results = main(ip)

    # get incidence/prevalnce data
    all = _collectdf(results)
    #insertcols!(all, 1, :sim => simnum)
    return all
end

function main(ip::ModelParameters)
    # reset the parameters for the simulation scenario
    reset_params(ip)
    initialize() # initialize population

    hmatrix = zeros(Int16, p.popsize, p.modeltime)

    # insert initial infected agents into the model
    if p.calibration
        error("calibration code not implemented")
    end
    # split population in agegroups
    grps = map(x -> findall(y -> y.grade == x, humans), 1:4)

    # start the time loop
    for st = 1:p.modeltime
        @info "time: $st"
        _get_model_state(st, hmatrix) ## this datacollection needs to be at the start of the for loop
        time_update()
        dyntrans(grps)
        daily_inf()
        # end of day
    end
    return hmatrix ## return the model state as well as the age groups.
end

## Initialization Functions
reset_params() = reset_params(ModelParameters())
function reset_params(ip::ModelParameters)
    # the p is a global const
    # the ip is an incoming different instance of parameters, copy the values from ip to p.
    for x in propertynames(p)
        setfield!(p, x, getfield(ip, x))
    end
end
export reset_params

function initialize()
    # error checks
    p.popsize == 0 && error("no population size given")
    println("popultion size $(p.popsize)")
    resize!(humans, p.popsize) # resize the human array to change population size
    for i = 1:p.popsize
        humans[i] = Student()              ## create an empty human
        x = humans[i]
        x.idx = i
        x.grade = rand(1:4)
        x.exp = 999  ## susceptible (by default) people don't expire.
        x.dur = sample_epi_durations() # sample epi periods
        # initialize the next day counts (this is important in initialization since dyntrans runs first)
        get_nextday_counts(x)
    end
end

## Data Collection/ Model State functions
function _get_model_state(t, hmatrix)
    # collects the model state at time t
    for i=1:length(humans)
        hmatrix[i, t] = Int(humans[i].health)
    end
end

function _collectdf(hmatrix)
    ## takes the output of the humans x time matrix and processes it into a dataframe
    #_names_inci = Symbol.(["lat_inc", "mild_inc", "miso_inc", "inf_inc", "iiso_inc", "hos_inc", "icu_inc", "rec_inc", "ded_inc"])
    #_names_prev = Symbol.(["sus", "lat", "mild", "miso", "inf", "iiso", "hos", "icu", "rec", "ded"])
    mdf_inc, mdf_prev = _get_incidence_and_prev(hmatrix)
    #mdf = hcat(mdf_inc, mdf_prev)
    #_names_inc = Symbol.(string.((Symbol.(instances(HEALTH)[1:end - 1])), "_INC"))
    #_names_prev = Symbol.(string.((Symbol.(instances(HEALTH)[1:end - 1])), "_PREV"))
    #_names = vcat(_names_inc..., _names_prev...)
    #datf = DataFrame(mdf, _names)
    #insertcols!(datf, 1, :time => 1:p.modeltime) ## add a time column to the resulting dataframe
    return mdf_inc
end

function _get_incidence_and_prev(hmatrix)
    cols = instances(HEALTH)[1:end - 1] ## don't care about the UNDEF health status
    inc = zeros(Int64, p.modeltime, length(cols))
    pre = zeros(Int64, p.modeltime, length(cols))
    for i = 1:length(cols)
        inc[:, i] = _get_column_incidence(hmatrix, cols[i])
        pre[:, i] = _get_column_prevalence(hmatrix, cols[i])
    end
    return inc, pre
end

function _get_column_incidence(hmatrix, hcol)
    inth = Int(hcol)
    timevec = zeros(Int64, p.modeltime)
    for r in eachrow(hmatrix)
        idx = findfirst(x -> x == inth, r)
        if idx !== nothing
            timevec[idx] += 1
        end
    end
    return timevec
end

function _get_column_prevalence(hmatrix, hcol)
    inth = Int(hcol)
    timevec = zeros(Int64, p.modeltime)
    for (i, c) in enumerate(eachcol(hmatrix))
        idx = findall(x -> x == inth, c)
        if idx !== nothing
            ps = length(c[idx])
            timevec[i] = ps
        end
    end
    return timevec
end

function _count_infectors()
    pre_ctr = asymp_ctr = mild_ctr = inf_ctr = 0
    for x in humans
        if x.health != SUS ## meaning they got sick at some point
            if x.sickfrom == PRE
                pre_ctr += 1
            elseif x.sickfrom == ASYMP
                asymp_ctr += 1
            elseif x.sickfrom == MILD
                mild_ctr += 1
            elseif x.sickfrom == INF
                inf_ctr += 1
            else
                error("sickfrom not set right: $(x.sickfrom)")
            end
        end
    end
    return (pre_ctr, asymp_ctr, mild_ctr, inf_ctr)
end

## Disease Functions
function daily_inf()
    # everywhere there is a probability that one of the susceptible individuals will come in as asymptomatic
    dailyprob = 0.005 # move to ModelParameters
    allsus = findall(x -> x.health == SUS, humans)
    for x in allsus
        if rand() < dailyprob
            @info ("debug: human $x will be infected next day")
            move_to_latent(humans[x])
            humans[x].tis = humans[x].exp # force the switch to asymp/pre
        end
    end
end

function sample_epi_durations()
    # when a person is sick, samples the
    lat_dist = truncated(LogNormal(log(5.2), 0.1), 4, 7) # truncated between 4 and 7
    pre_dist = truncated(Gamma(1.058, 5/2.3), 0.8, 3)#truncated between 0.8 and 3
    asy_dist = Gamma(5, 1)
    inf_dist = Gamma((3.2)^2/3.7, 3.7/3.2)

    latents = Int.(round.(rand(lat_dist)))
    pres = Int.(round.(rand(pre_dist)))
    latents = latents - pres # ofcourse substract from latents, the presymp periods
    asymps = Int.(ceil.(rand(asy_dist)))
    infs = Int.(ceil.(rand(inf_dist)))
    return (latents, asymps, pres, infs)
end

# Main Time Step of the Model
function time_update()
    # counters to calculate incidence at each time step
    lat=0; pre=0; asymp=0; inf=0; rec=0; ded=0;
    for x in humans
        x.tis += 1
        x.doi += 1 # increase day of infection. variable is garbage until person is latent
        if x.tis >= x.exp
            @match Symbol(x.swap) begin
                :LAT  => begin move_to_latent(x); lat += 1; end
                :PRE  => begin move_to_pre(x); pre += 1; end
                :ASYMP => begin move_to_asymp(x); asymp += 1; end
                :INF  => begin move_to_inf(x); inf +=1; end
                :REC  => begin move_to_recovered(x); rec += 1; end
                :DED  => begin move_to_dead(x); ded += 1; end
                _    => error("swap expired, but no swap set.")
            end
        end
        # get the meet counts for the next day
        get_nextday_counts(x)
    end
    return (lat, asymp, inf, rec, ded)
end

function move_to_latent(x::Student)
    ## transfers human h to the incubation period and samples the duration
    x.health = LAT
    x.doi = 0 ## day of infection is reset when person becomes latent
    x.tis = 0   # reset time in state
    x.exp = x.dur[1] # get the latent period
    x.swap = rand() <  p.asymp_props ? ASYMP : PRE
    ## in calibration mode, latent people never become infectious.
    if p.calibration
        x.swap = LAT
        x.exp = 999
    end
end

function move_to_asymp(x::Student)
    ## transfers human h to the asymptomatic stage
    x.health = ASYMP
    x.tis = 0
    x.exp = x.dur[2] # get the presymptomatic period
    x.swap = REC
end

function move_to_pre(x::Student)
    x.health = PRE
    x.tis = 0   # reset time in state
    x.exp = x.dur[3] # get the presymptomatic period
    x.swap = INF
end

function move_to_inf(x::Student)
    ## transfers human h to the severe infection stage for γ days
    ## simplified function for calibration/general purposes
    x.health = INF
    x.tis = 0
    x.exp = x.dur[4]
    x.iso = true
    x.swap = REC
end

function move_to_dead(h::Student)
    # no level of alchemy will bring someone back to life.
    h.health = DED
    h.swap = UNDEF
    h.tis = 0
    h.exp = 999 ## stay recovered indefinitely
    h.iso = true # a dead person is isolated
    # isolation property has no effect in contact dynamics anyways (unless x == SUS)
end

function move_to_recovered(h::Student)
    h.health = REC
    h.swap = UNDEF
    h.tis = 0
    h.exp = 999 ## stay recovered indefinitely
end

## Transmission Dynamics
@inline function _get_betavalue(xhealth)
    # values coming from FRASER Figure 2... relative tranmissibilities of different stages.
    bf = p.β
    if xhealth == ASYMP
        bf = bf * p.frelasymp
    elseif xhealth == INF
        bf = bf * 0.89
    end
    return bf
end

@inline function get_nextday_counts(x::Student)
    # gets the number of agents x will meet (or recieve contacts from)
    # we can sample this at the start of the simulation to avoid everyday but its type stable and fast
    cnt = 0
    ag = x.grade
    x.health != DED && (cnt = rand(nbs[ag]))  # expensive operation, try to optimize
    x.nextday_meetcnt = cnt
    return cnt
end

@inline function beta_mask_adjust(beta, inf_mask, sus_mask)
    # https://msphere.asm.org/content/5/5/e00637-20
    nb = beta
    if inf_mask && !sus_mask
        nb = beta * rand(27:42) / 100   # 58 to 73% reduction if infected person wearing mask
    elseif !inf_mask && sus_mask
        nb = beta * rand(63:83) / 100   # 20 - 40% reduction if susceptible person wearing mask
    elseif inf_mask && sus_mask
        nb = beta * rand(24:29) / 100   # if both of them are wearing mask, figure 2E of the refernece
    end
    return nb
end

@inline function beta_vax_adjust()
    error("not implemented")
end

function dyntrans(grps)
    totalmet = 0 # count the total number of contacts (total for day, for all INF contacts)
    totalinf = 0 # count number of new infected

    ## find all the people infectious in school.
    infs = findall(x -> x.health in (PRE, ASYMP), humans)

    # go through every infectious person
    for xid in infs
        x = humans[xid]
        xhealth = x.health
        beta = _get_betavalue(xhealth)
        cnts = x.nextday_meetcnt        ## how many contacts to give
        cnts == 0 && continue
        gpw = Int.(round.(cm[x.grade]*cnts)) # split the counts over students in other grades
        for (i, g) in enumerate(gpw)
            # sample the people from each group
            meet = rand(grps[i], g)
            # go through each person
            for j in meet
                y = humans[j]
                ycnt = y.nextday_meetcnt
                ycnt == 0 && continue
                y.nextday_meetcnt = y.nextday_meetcnt - 1 # remove a contact
                totalmet += 1

                # tranmission dynamics
                if  y.health == SUS && y.swap == UNDEF
                    beta = beta_mask_adjust(beta, x.mask, y.mask)
                    if rand() < beta
                        totalinf += 1
                        y.swap = LAT
                        y.exp = y.tis   ## force the move to latent in the next time step.
                        y.sickfrom = xhealth ## stores the infector's status to the infectee's sickfrom
                    end
                end
            end
        end
    end
    @info("number of infecteds: $(length(infs)), total met $(totalmet), new infections $totalinf")
    return totalmet, totalinf
end
export dyntrans

## Contact Matrix Functions
function contact_matrix()
    # regular contacts, just with 5 age groups.
    #  0-4, 5-19, 20-49, 50-64, 65+
    CM = Array{Array{Float64, 1}, 1}(undef, 5)
    CM[1] = [0.2287, 0.1839, 0.4219, 0.1116+0.0539]
    CM[2] = [0.0276, 0.5964, 0.2878, 0.0591+0.0291]
    CM[3] = [0.0376, 0.1454, 0.6253, 0.1423+0.0494]
    CM[4] = [0.0242, 0.1094, 0.4867, 0.2723+0.1074]
    CM[5] = [0.0207, 0.1083, 0.4071, 0.2193+0.2446]
    return CM
end

function negative_binomials()
    ## the means/sd here are calculated using _calc_avgag
    means = [10.21, 16.793, 13.7950, 11.2669]
    sd = [7.65, 11.7201, 10.5045, 9.5935]
    totalbraks = length(means)
    nbinoms = Vector{NegativeBinomial{Float64}}(undef, totalbraks)
    for i = 1:totalbraks
        p = 1 - (sd[i]^2-means[i])/(sd[i]^2)
        r = means[i]^2/(sd[i]^2-means[i])
        nbinoms[i] =  NegativeBinomial(r, p)
    end
    return nbinoms
end
const nbs = negative_binomials()
const cm = contact_matrix()

## internal functions to do intermediate calculations
function _calc_avgag(lb, hb)
    ## internal function to calculate the mean/sd of the negative binomials
    ## returns a vector of sampled number of contacts between age group lb to age group hb
    dists = _negative_binomials_15ag()[lb:hb]
    totalcon = Vector{Int64}(undef, 0)
    for d in dists
        append!(totalcon, rand(d, 10000))
    end
    return totalcon
end


text:
function igyp02(m)
#
#  generalization of Igarash and Ypma
#
   p = poly([10*(1+im)*ones(m); -1*ones(10-m)])
   z = [10.0*(1+im) m; -1 10-m];
   p, PolyZeros(z)
end


text:
@generated _fieldnames(::Type{T}) where {T} = fieldnames(T)
_fieldcount(::Type{T}) where {T} = length(_fieldnames(T))

"""
    StructAxis{T}

An axis that uses a structure `T` to form its keys.
"""
struct StructAxis{T,Inds} <: AbstractAxis{Int,Inds}
    parent::Inds

    function StructAxis{T,Inds}(inds::Inds) where {T,Inds}
        if typeof(T) <: DataType
            new{T,Inds}(inds)
        else
            throw(ArgumentError("Type must be have all field fully paramterized, got $T"))
        end
    end

    function StructAxis{T}(inds::AbstractAxis) where {T}
        fc = _fieldcount(T)
        if known_length(inds) === fc
            return StructAxis{T,typeof(inds)}(inds)
        else
            if known_first(inds) === nothing
                throw(ArgumentError("StructAxis cannot have a parent type whose first index and last index are not known at compile time."))
            else
                f = static_first(inds)
                l = f + StaticInt(fc) - One()
                return StructAxis{T}(unsafe_reconstruct(inds, f:l))
            end
        end
    end
    StructAxis{T}(inds) where {T} = StructAxis{T}(compose_axis(inds))
    function StructAxis{T}() where {T}
        inds = SimpleAxis(One():StaticInt{_fieldcount(T)}())
        return new{T,typeof(inds)}(inds)
    end
end

Base.parent(axis::StructAxis) = getfield(axis, :parent)

@inline Base.propertynames(axis::StructAxis{T}) where {T} = (_fieldnames(T), propertynames(parent(axis))...)
@inline function Base.getproperty(axis::StructAxis{T}, k::Symbol) where {T}
    i = _to_field_index(T, k)
    if i === 0
        return getproperty(parent(axis), k)
    else
        return @inbounds(parent(axis)[i + (One() - static_first(axis))])
    end
end

function Base.keys(axis::StructAxis{T}) where {T}
    axs = (SimpleAxis(One():static_length(axis)),)
    return AxisArray{Symbol,1,Vector{Symbol},typeof(axs)}(
        Symbol[fieldnames(T)...], axs; checks=NoChecks
    )
end

# TODO ArrayInterface.unsafe_reconstruct(axis::StructAxis
@inline function ArrayInterface.unsafe_reconstruct(axis::StructAxis{T}, inds) where {T}
    if known_length(inds) === known_length(axis)
        return StructAxis{T,typeof(inds)}(inds)
    else
        indexΔ = One() - static_first(axis)
        return _unsafe_reconstruct_struct_axis(axis, inds, static_first(inds) + indexΔ, static_last(inds) + indexΔ)
    end
end
@inline function _unsafe_reconstruct_struct_axis(axis::StructAxis{T}, inds, start, stop) where {T}
    return Axis([fieldname(T, i) for i in start:stop], inds; checks=NoChecks)
end

@inline function _unsafe_reconstruct_struct_axis(axis::StructAxis{T}, inds, start::StaticInt, stop::StaticInt) where {T}
    return StructAxis{NamedTuple{__names(T, start, stop), __types(T, start, stop)}}(inds)
end

@generated function __names(::Type{T}, ::StaticInt{F}, ::StaticInt{L}) where {T,F,L}
    e = Expr(:tuple)
    for i in F:L
        push!(e.args, QuoteNode(fieldname(T, i)))
    end
    return e
end

@generated function __types(::Type{T}, ::StaticInt{F}, ::StaticInt{L}) where {T,F,L}
    return Tuple{[fieldtype(T, i) for i in F:L]...}
end

# TODO figure out how to place type inference of each field into indexing
@inline function structdim(A::AxisArray{<:Any,<:Any,<:Any,Axs}) where {Axs}
    d = _structdim(Axs)
    if d === 0
        throw(MethodError(structdim, A))
    else
        return StaticInt(d)
    end
end
Base.@pure function _structdim(::Type{T}) where {T<:Tuple}
    for i in OneTo(length(T.parameters))
        T.parameters[i] <: StructAxis && return i
    end
    return 0
end

to_index_type(axis::StructAxis{T}, arg) where {T} = fieldtype(T, to_index(axis, arg))

"""
    struct_view(A)

Creates a `MappedArray` whose element type is derived from the first `StructAxis` found as
an axis of `A`.
"""
@inline function struct_view(A)
    dim = structdim(A)
    axis = axes(A, dim)
    axs = _not_axes(axes(A), dim)
    data = _tuple_of_views(parent(A), static_first(axis), static_last(axis), dim)
    return _struct_view(_struct_view_type(axis), data, axs)
end

_struct_view_type(::StructAxis{T}) where {T} = T
_struct_view_function(::Type{T}) where {T<:NamedTuple} = (args...) -> T(args)
_struct_view_function(::Type{T}) where {T} = T

@generated function _tuple_of_views(A::AbstractArray{<:Any,N}, ::StaticInt{F}, ::StaticInt{L}, dim::StaticInt{D}) where {N,F,L,D}
    e = Expr(:tuple)

    slice_before = [:(:) for i in 1:(D - 1)]
    slice_after = [:(:) for i in 1:(N - D)]

    for i in F:L
        view_i = :(view(A))
        append!(view_i.args, slice_before)
        push!(view_i.args, i)
        append!(view_i.args, slice_after)
        push!(e.args, view_i)
    end
    return Expr(:block, Expr(:meta, :inline), e)
end
@generated function _not_axes(axs::Tuple{Vararg{<:Any,N}}, ::StaticInt{I}) where {N,I}
    e = Expr(:tuple)
    for i in OneTo(N)
        if i !== I
            push!(e.args, :(getfield(axs, $i)))
        end
    end
    return Expr(:block, Expr(:meta, :inline), e)
end
function _struct_view(::Type{T}, data, axs) where {T}
    f = _struct_view_function(T)
    aview = __struct_view(T, f, data)
    return AxisArray{T,length(axs),typeof(aview),typeof(axs)}(aview, axs; checks=NoChecks)
end
@inline function __struct_view(::Type{T}, f, data) where {T}
    return ReadonlyMultiMappedArray{T,ndims(first(data)),typeof(data),typeof(f)}(f, data)
end
@inline function __struct_view(::Type{T}, ::Type{T}, data) where {T}
    return ReadonlyMultiMappedArray{T,ndims(first(data)),typeof(data),Type{T}}(T, data)
end

function print_axis(io, axis::StructAxis{T}) where {T}
    print(io, "StructAxis($(T) => $(parent(axis)))")
end


text:
using Genie.Router
using MyLib

route("/") do
  serve_static_file("/welcome.html")
end

route("/hello") do
  "Welcome to Genie!"
end

route("/getdata") do
  MyLib.GetData()
end

route("/traintest") do
  MyLib.TrainTest()
end


text:
function lock(c::Channel)
    take!(c)
end
function unlock(c::Channel)
    # We don't deal with recurrent locking; we go only one level deep
    if !isready(c)
        put!(c, UInt8(1))
    end
end

btask_status = Dict{AbstractString,Tuple{Float64,Function}}()
function btask_draw()
    global prompt_state, last_enter, last_draw_enter, last_draw_lines, btask_status, running_mutex

    # If we haven't supplanted the backend yet, then wait it out
    if prompt_state === nothing
        return nothing
    end

    # Useful constant
    term_width = LineEdit.width(TTYTerminal("",STDIN,STDOUT,STDERR))

    # Read in any new reports from the outside world
    while isready(btask_report)
        name, callback = take!(btask_report)
        btask_status[name] = (time(), callback)
    end

    status_timestamps = Tuple{Float64,AbstractString}[]
    for name in keys(btask_status)
        status = btask_status[name][2](term_width)
        if status === nothing
            delete!(btask_status, name)
        else
            push!(status_timestamps, (btask_status[name][1], status))
        end
    end

    statuses = AbstractString[status for (timestamp, status) in sort(status_timestamps)]

    # Ensure we're the only one messing with the screen at the moment
    lock(running_mutex)

    # Calculate widths of status lines
    all_widths = Int[strwidth(status) for status in statuses]
    num_lines = sum(Int[div(max(0,w-1),term_width)+1 for w in all_widths])

    # Have we hit enter since the last time we drew?
    if last_enter != last_draw_enter
        # If so, then update last_draw_enter and reset last_draw_lines
        last_draw_enter = last_enter
        last_draw_lines = 0
    end

    num_lines = max(num_lines, last_draw_lines)

    # Calculate how many lines we need to move up due to the user typing stuff
    skip_lines = max(cursor_position(prompt_state)[1], 0)

    # Now draw the lines
    if num_lines > 0
        # Move up to just above julia> prompt, plus last_draw_lines
        write(STDOUT,"$(CSI)$(skip_lines + last_draw_lines)A$(CSI)1G")

        # Clear all lines in case some are shorter, or we dropped some
        for idx in 1:num_lines
            write(STDOUT,"$(CSI)1G$(CSI)0K$(CSI)1B")
        end

        # Jump back up the number of lines we have to spit out
        if length(statuses) > 0
            write(STDOUT,"$(CSI)$(length(statuses))A")
        end
        for status in statuses
            write(STDOUT, status)
            write(STDOUT, " n$(num_lines),s$(skip_lines),len$(length(statuses)),l$(last_draw_lines)")
            write(STDOUT,"\n")
        end

        #if length(statuses) - last_draw_lines > 0
        #    write(STDOUT,"$(CSI)$(length(statuses) - last_draw_lines)B")
        #end

        # Jump back down however many lines we need to in order to satisfy skip_lines
        if skip_lines > 0
            write(STDOUT,"$(CSI)$(skip_lines)B")
        end

        # Refresh the line, save how many lines we just wrote
        LineEdit.refresh_line(prompt_state)
        last_draw_lines = max(last_draw_lines, num_lines)
    end
    flush(STDOUT)
    unlock(running_mutex)
    return nothing
end


text:
@testset "bfs" begin
    A = load_matrix_network("bfs_example")
    A_ref = [1 0 1 1; 0 1 1 1; 1 1 0 1; 1 1 1 0]
    d_ref = [0,2,1,1]
    dt_ref = [0,3,1,2]
    pred_ref = [1,3,1,1]

    @testset "MatrixNetwork" begin
        bfs(MatrixNetwork(A), 1)

        (d,dt,pred) = bfs(MatrixNetwork(sparse(A_ref)), 1)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred

        bfs(MatrixNetwork(A), 1, 0)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred
    end
    @testset "SparseMatrixCSC" begin
        bfs(A,1)

        (d,dt,pred) = bfs(sparse(A_ref), 1)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred

        bfs(A,1,0)
        (d,dt,pred) = bfs(sparse(A_ref ),1,0)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred
    end
    @testset "triplet" begin
        bfs(findnz(A)[1], findnz(A)[2], 1)

        (d,dt,pred) = bfs(findnz(sparse(A_ref))[1], findnz(sparse(A_ref))[2],1)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred

        bfs(findnz(A)[1], findnz(A)[2], 1, 0)

        (d,dt,pred) = bfs(findnz(sparse(A_ref))[1], findnz(sparse(A_ref))[2], 1, 0)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred
    end
    @testset "CSR" begin
        A_csr = sparse_to_csr(A)
        bfs(A_csr..., 1)

        (d,dt,pred) = bfs(sparse_to_csr(sparse(A_ref))..., 1)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred

        bfs(A_csr..., 1, 0)

        (d,dt,pred) = bfs(sparse_to_csr(sparse(A_ref))..., 1, 0)
        @test d == d_ref
        @test dt_ref == dt
        @test pred_ref == pred
    end
end


text:
########################################################################
# Codes for the paper:
# An Anthropocene Map of Genetic Diversity
#
# Andreia Miraldo, Sen Li, Michael K. Borregaard, Alexander Floréz-Rodriguéz, Shyam Gopalakrishnan, Mirneza Risvanovic, Zhiheng Wang, Carsten Rahbek, Katharine A. Marske & David Nogués-Bravo
#
# Submitted to Science, 2016
# Code in this file by Michael K. Borregaard
#########################################################################

#Load the necessary library
using DataFrames
include("GD_summary_functions.jl")

for typ in ["gridcells", "anthromes", "biomes", "latbands", "equalarea"]
    # Read in the matrices for mammals and amphibians and concatenate them
    am = ready_data("pairwise_$(typ)_amphibians_cytb.csv")
    ma = ready_data("pairwise_$(typ)_mammals_cytb.csv")
    macoi = ready_data("pairwise_$(typ)_mammals_coi.csv")
    dats = vcat(am, ma)
    # restrict to pairs with at least 0.5 overlap value

    amphibs, amphibsfull = calc_cellvalues(am)
    mamms, mammalfull  = calc_cellvalues(ma)
    total, full = calc_cellvalues(dats)
    macois, fullmacois = calc_cellvalues(macoi)

    fig_data = join(total, mamms, on = :site, kind = :left)
    fig_data = join(fig_data, amphibs, on = :site, kind = :left)
    fig_data = join(fig_data, macois, on = :site, kind = :left)

    names!(fig_data, [:site, :totalGDval, :totalrichness, :totalbasepairs, :mammalsGDval, :mammalsrichness, :mammalsbasepairs, :amphibiansGDval, :amphibiansrichness, :amphibiansbasepairs, :macoiGDval, :macoirichness, :macoibasepairs])
    writetable("$(typ)_numbers.csv", fig_data)
    writetable("$(typ)_full_numbers.csv", full)
    writetable("$(typ)_amphibsfull_numbers.csv", amphibsfull)
    writetable("$(typ)_mammalfull_numbers.csv", mammalfull)
    writetable("$(typ)_macoifull_numbers.csv", fullmacois)
end

ma = readtable("pairwise_equalarea_mammals_coi.csv")
ma = ma[!isna(ma[:seq1]), :]
ma = ma[ma[:overlap] .> 0.5, :]
# restrict to pairs with at least 0.5 overlap value

mamms, mammalfull  = calc_cellvalues(ma)

names!(mamms, [:site, :mammalsGDval, :mammalsrichness, :mammalsbasepairs])
writetable("equalarea_coi_numbers.csv", mamms)
writetable("equalarea_coi_full_numbers.csv", mammalfull)

max_stars_repo_path: Miraldo et al. 2016/Calculate_Values_for_Figures_1_and_3_and_S2_to_S4.jl

max_stars_repo_name: mkborregaard/codes-for-published-papers

max_issues_repo_name: DalavanCloud/codes-for-published-papers

max_forks_repo_name: DalavanCloud/codes-for-published-papers


text:
using Pkg
Pkg.add("Cxx")

using Cxx

cxx""" #include<iostream> """

# Declare the function
cxx"""
   void mycppfunction() {
      int z = 0;
      int y = 5;
      int x = 10;
      z = x*y + 2;
      std::cout << "The number is " << z << std::endl;
   }
"""
# Convert C++ to Julia function
julia_function() = @cxx mycppfunction()

# Run the function
julia_function()

#%% MathLink
using Pkg
Pkg.add("MathLink")
using MathLink

W"Sin"

sin1 = W"Sin"(1.0)

sinx = W"Sin"(W"x")

weval(sin1)
weval(sinx)
weval(W"Integrate"(sinx, (W"x", 0, 1)))

max_stars_repo_name: JeffreySarnoff/techytok-examples

max_issues_repo_name: JeffreySarnoff/techytok-examples

max_forks_repo_name: JeffreySarnoff/techytok-examples


text:
@testset "with Zygote" begin
    k = 1

    function foo_(a, b, c, d, e, f)
        @tensoropt !C x[A, B] :=
            k * conj(a[A, C]) * (-sin.(b)[C, D] * c.d[D, B] - c.d[C, B])
        @tensor x[A, B] -= d * conj(e[1])[A, (B')', B', B', (B')', B]
        x = x + f * k
        @tensor x[A, B] += (@tensor _[A, C] := a[A, B] * a[B, C])[A, C] * (a * a)[C, B]
        return x
    end

    @∇ function foo(a, b, c, d, e, f)
        @tensoropt !C x[a, b] :=
            k * conj(a[a, c]) * (-sin.(b)[c, d] * c.d[d, b] - c.d[c, b])
        @tensor x[A, B] -= d * conj(e[1])[A, (B')', B', B', (B')', B]
        x = x + f * k
        @tensor x[A, B] += (@tensor _[A, C] := a[A, B] * a[B, C])[A, C] * (a * a)[C, B]
        return x
    end

    T = ComplexF64
    a = randn(T, 3, 3)
    b = randn(T, 3, 3)
    c = (d=randn(T, 3, 3),)
    d = randn(T)
    e = [randn(T, 3, 2, 1, 1, 2, 3) for i in 1:2]
    f = randn(T, 3, 3)

    @test foo(a, b, c, d, e, f) ≈ foo_(a, b, c, d, e, f)

    for F in [angle ∘ first, angle ∘ sum, real ∘ sum]
        ad = gradient((a, b, c, d, e, f) -> F(foo(a, b, c, d, e, f)), (a, b, c, d, e, f)...)
        fd = grad(
            central_fdm(5, 1),
            (a, b, c, d, e, f) -> F(foo(a, b, c, d, e, f)),
            (a, b, c, d, e, f)...,
        )

        @test ad[1] ≈ fd[1] atol = cbrt(eps())
        @test ad[2] ≈ fd[2] atol = cbrt(eps())
        @test ad[3].d ≈ fd[3].d atol = cbrt(eps())
        @test ad[4] ≈ fd[4] atol = cbrt(eps())
        @test ad[5][1] ≈ fd[5][1] atol = cbrt(eps())
        @test ad[6] ≈ fd[6] atol = cbrt(eps())
    end
end


text:
using Documenter, DataEnvelopmentAnalysis

makedocs(sitename = "DataEnvelopment\nAnalysis.jl",
        authors = "Javier Barbero and José Luis Zofío.",
        pages = [
        "Home" => "index.md",
        "Technical Efficiency Models" => Any[
                "Radial Models" => "technical/radial.md",
                "Directional Distance Function Models" => "technical/directional.md",
                "Additive Models" => "technical/additive.md",
                "Generalized Distance Function Models" => "technical/generalizeddf.md"
                ],
        "Economic Efficiency Models" => Any[
                "Cost Models" => "economic/cost.md",
                "Revenue Models" => "economic/revenue.md",
                "Profit Models" => "economic/profit.md",
                "Profitability Models" => "economic/profitability.md"
                ],
        "Productivity Change Models" => Any[
                "Malmquist Index" => "productivity/malmquist.md"
                ],
        "Bibliography" => "bibliography.md"
        ],
        format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true")
)

deploydocs(
    repo = "github.com/javierbarbero/DataEnvelopmentAnalysis.jl.git",
)


text:
module JuliaWebAPIPlugins

using JuliaWebAPI
using AMQPClient
using Logging

import JuliaWebAPI: sendrecv, sendresp, recvreq, close
import JuliaWebAPI: wireformat, juliaformat, cmd, args, data, httpresponse, fnresponse

import Base: run
export AMQPTransport
export APIClient, srvrcall, hasclient, purgeclients, closeclient
export APIServer, run, configure

include("amqp_transport.jl")
include("amqp_client_server.jl")

end # module

max_stars_repo_name: tanmaykm/JuliaWebAPIPlugins

max_issues_repo_name: tanmaykm/JuliaWebAPIPlugins

max_forks_repo_name: tanmaykm/JuliaWebAPIPlugins


text:
################################################################################
### SUPPORTING FUNCTIONS - NOT FOR CALLING BY USER

function GreatCircle(ref_lon, ref_lat, dest_lon, dest_lat)
    """
    Calculates the great circle distance between a reference location (ref)
    and a destination (dest) and returns the great circle distances in km
    """
    # mean Earth radius used for Great Circle distance calculation
    R = 6335.439

    # haversine formula for Great Circle distance calculation
    dist = 2*R*asin(sqrt(((sind((dest_lat - ref_lat)/2))^2) +
        cosd(dest_lat)*cosd(ref_lat)*((sind((dest_lon - ref_lon)/2))^2)))
    return(dist)
end

function TextListFromCSV(IDs,DataCol)
    """
    This function recovers comma-separated lists of text labels stored as
    single entries in a csv file (separated by a non-comma separator) and
    returns them as a dictionary indexed by the given IDs
    i.e., |P01,P02,P03| -> ["P01","P02","P03"]
    Inputs:
        IDs - a list of labels to be used as dictionary keys
        DataCol - The column of data with rows corresponding to the labels in
            IDS, with each containing one or more text labels separated by commas
    Outputs:
        Out - a dictionary mapping the keys in IDs to the values in DataCol

    Note: This function replaces code of the form:
    for s = 1:length(asset_id) # AssetData[s,4] is a comma-separated list
        asset_inputs[asset_id[s]] = [String(i) for i in split(AssetData[s,4],",")]
    end
    """
    Out = Dict()
    for i = 1:length(IDs)
        Out[IDs[i]] = [String(i) for i in split(DataCol[i],",")]
    end
    return Out
end

function NumericListFromCSV(IDs,ID2s,DataCol)
    """
    For data that may be stored as a list of numeric values within CSV data
    i.e., |0.1,0.2,0.3,0.4| in a "|"-separated data file. This function parses
    these data as Float64 values and assigns them to a dictionary using given
    keys; the dictionary is returned.
    Inputs:
        IDs - a list of IDs corresponding to the rows of the data in DataCol; also used as dict keys
        ID2s - a list of secondary IDs for use as keys in the dict; a list of lists
        DataCol - a column of data from a .csv file

    Note: This function replaces code like this:
    for s = 1:length(asset_id) # AssetData[s,7] is a comma-separated list
        check = typeof(AssetData[s, 7])
        if check != Float64 && check != Int64 # then it's a string of numbers
            temp = split(asset_data[s, 7],",")
            values = [parse(Float64,temp[i]) for i = 1:length(temp)] # Float64 array
        else # in the case it was a Float64 or an Int64
            values = asset_data[s, 7]
        end
        key1 = asset_id[s]
        key2s = asset_inputs[key1]
        for i = 1:length(key2s)
            asset_input_stoich[key1,key2s[i]] = values[i]
        end
    end
    """
    Out = Dict()
    L = length(IDs)
    for l = 1:L
        check = typeof(DataCol[l])
        if check != Float64 && check != Int64 # then it's a string of numbers
            temp = split(DataCol[l],",") # separate by commas into temporary list
            values = [parse(Float64,temp[i]) for i = 1:length(temp)] # parse as Float64 array
        else # in the case it was already a Float64 or an Int64
            values = DataCol[l]
        end
        key1 = IDs[l]
        key2s = ID2s[key1]
        for i = 1:length(key2s)
            Out[key1,key2s[i]] = values[i]
        end
    end
    return Out
end

function DictInit(OrderedMeyList,InitValue)
    """
    Initializes a dictionary with the keys in OrderedMeyList and assigns each
    key the value in InitValue
    Inputs:
        OrderedMeyList - a list of lists (i.e., list of lists of keys)
        InitValue - probably either 0 or false
    Outputs:
        Out - a dictionary
    Note: replaces the initialization loop for dictionaries that require full
    population; i.e., in the case of set intersections
    """
    Out = Dict()
    if length(OrderedMeyList) == 1
        for key in OrderedMeyList[1]
            Out[key] = InitValue
        end
    else
        SplatMeys = collect(Iterators.product(OrderedMeyList...))
        for key in SplatMeys
            Out[key] = InitValue
        end
    end
    return Out
end

function PrettyPrint(Data, OrderedIndexList, TruthTable=nothing; Header="*"^50, DataName="", VarName="")
    """
    Prints Data values indexed by OrderedIndexList based on whether or not
    the corresponding index value of TruthTable is true; Data and TruthTable
    share the same index pattern.
    Inputs:
        Data - an indexed data structure; a dictionary or JuMP variable
        OrderedIndexList - a list of the indices corresponding to Data and TruthTable
        TruthTable - a dictionary indexed on OrderedindexList which outputs Boolean values (true/false)
        Header - A string to print above any data
        DataName - A string to be printed as a header for the data
        VarName - A string to be printed before each line
    """
    # check truthtable; if not, default to true
    if TruthTable == nothing
        TruthTable = DictInit(OrderedIndexList, true)
    end
    # Start printing headers
    println(Header)
    println(DataName)
    # Check index index list length for proper index handling
    if length(OrderedIndexList) == 1
        SplatIndex = OrderedIndexList[1]
        for index in SplatIndex
            if TruthTable[index]
                println(VarName*"(\""*string(index)*"\"): "*string(Data[index]))
            end
        end
    else
        SplatIndex = collect(Iterators.product(OrderedIndexList...))
        for index in SplatIndex
            if TruthTable[index...]
                println(VarName*string(index)*": "*string(Data[index...]))
            end
        end
    end
end

function Nonzeros(Data, OrderedIndexList; Threshold=1E-9)
    """
    Given a dictionary of data indexed by the labels in OrderedIndexList
    returns a Boolean dictionary pointing to nonzero indices in Data, where
    nonzero is subject to a threshold value Threshold, defaulting to 1E-9.
    """
    OutDict = Dict()
    if length(OrderedIndexList) == 1
        SplatIndex = OrderedIndexList[1]
        for index in SplatIndex
            if abs(Data[index]) > Threshold
                OutDict[index] = true
            else
                OutDict[index] = false
            end
        end
    else
        SplatIndex = collect(Iterators.product(OrderedIndexList...))
        for index in SplatIndex
            if abs(Data[[i for i in index]...]) > Threshold
                OutDict[[i for i in index]...] = true
            else
                OutDict[[i for i in index]...] = false
            end
        end
    end
    return(OutDict)
end

function FilePrint(Variable,OrderedIndexList,filename;Header="*"^50,DataName="",VarName="")
    """
    Generates a list of strings and prints them to file with nice formatting;
    reduces required script code clutter.
    > Variable: the result of a JuMP getvalue() call; a Dict().
    > OrderedIndexList: a list of indices in the same order as the indices of
      the data in Variale; each element is a list of index elements. As an
      example: [A,B,C] where A = [a1,a2,...,aN], B = ....
    > filename: the file name for printing
    > Header: a string to be used as a header above the printed data
    > DataName: a header to appear above the printed data
    > VarName: the desired output name of the variable on screen; a string
    """
    # Header and DataName:
    print(filename,"\n"*Header*"\n"*DataName)

    # Collect indices via splatting to create all permutations; print each permuted index and value to file
    if length(OrderedIndexList) == 1
        SplatIndex = OrderedIndexList[1]
        for index in SplatIndex
            print(filename,"\n"*VarName*"(\""*string(index)*"\") = "*string(Variable[index]))
        end
    else
        SplatIndex = collect(Iterators.product(OrderedIndexList...))
        for index in SplatIndex
            print(filename,"\n"*VarName*string(index)*" = "*string(Variable[[i for i in index]...]))
        end
    end
end

#=
function RawDataPrint(data,filename;Header="*"^50,DataName="")
    """
    Prints raw data to file for record-keeping purposes;
    reduces required script code clutter.
    > data: an array of data read from a .csv file.
    > filename: the file name for printing
    > Header: a string to be used as a header above the printed data
    > DataName: a header to appear above the printed data
    """
    # Header and DataName:
    print(filename,"\n"*Header*"\n"*DataName)

    # number of rows
    n = size(data)[1]

    # print rows of data array to file
    for i = 1:n
        print(filename,"\n")
        print(filename,data[i,:])
    end
end
=#


text:
#=

1. which is faster ?

=#
using BenchmarkTools
Base.@propagate_inbounds function bLookup!(a = 1, b = 4; h = 1)  #optimal #rapid: median 71.5 ns #Approved

    α = 1
    β = 1 #Whatever _b could be picked-up, inside loop it 'll get overwritten
    q = [] #DataStructures.Deque{Tuple{Int64,Int64}}()
    n = 1

    while α != b && β <= b # adding inbounds slightly fastens the total process
        #   2 + (2) = 4 = _b
        β = α + (n * h)  # = 3
        push!(q, (α, β)) #1 (1,2) #infer: sub-range [1,2]  #Deque (b=4 !isa b[1]=2  (now a[2] = b[1]=2 for next op ) a starts at 2
        α = β # Swap a = 2
        n += 1 # 2
    end

    return q
end
vec = bLookup!()
typeof(vec)
length(vec)  # length ; size
l = length(vec)
flag = nothing

isMod(vec) = length(vec) % 2 == 0 ? flag = true : flag = false; #use of global

#benchmark isMod(vec)
#=using globals freely : flag = true global , l =

v =r = [1, 2, 3, 4]

=#
v = [1, 2, 3, 4]
typeof(v)
s(v) = last(v)
last(v) # last equal size (length)
isMod(last(v) / 2)
first(v)
@time begin
    flag = isMod(vec)
    if flag == true
        l = length(vec) / 2
    elseif flag == false
        l = (length(vec) + 1) / 2
    else
        print("something's wrong")
    end

end

# 0.000019 seconds (1 allocation: 16 bytes) #correct!
#=
what is the max of list ?
=#

#---

r = [1, 2, 3, 4]
last(r)
maxr = last(r)
number = Int(last(r) / 2)

isMod(r)#we can divide

for i in r
    print(i)
end

for i in r
    if number
        if number < r[4]
            1:r
        end
    end
end

#is divisible
#= if it has a multiple f that factor! - easier said than done i.e. m = ak (m divisible by a & k )  =#

#=
1. isMod() [true, false]
2.
=#

#---
#fl = nothing
isMod(a, b; fl = nothing) = (max(a, b) - abs(min(a, b))) % 2 == 0 ? fl = true : fl = false;

isMod(vec; fl = nothing) = length(vec) % 2 == 0 ? fl = true : fl = false;
isMod(vec::Vector; fl = nothing) = last(vec) % 2 == 0 ? fl = true : fl = false; #
len(vec::Vector; fl = nothing) = last(vec) + 1

function isMod(a::Int64, b::Int64) #any two numbers
    dif = (max(a, b) - abs(min(a, b))) #% 2 == 0 #? fl = true : fl = false;

    if rem(dif, 2) == 0
        return true
    elseif rem(dif, 2) != 0
        return false
    else
        return nothing
    end
end

isMod(1, 3)

#
"""elementat() mind procrastinates by asking another interesting question (don't answer it ) #Done!
odd  = odd +1 = last() + Findfirst.indexOf() # findfirst() #easier than last()+first() can also (to prevent misconseptions)-what if one made 0-vector? (wrecks whole thing) so do this correct

possibilities
findprev
"""
findprev

#
    #=
if(isa odd(last(v))#i.e. 3

        #assumes a sorted array  # divisible
lenDiv2(vec::Vector;fl=nothing) = last(vec)/2   #assumes divisible
#benchmark isMod(vec)
#using globals freely
isExits(v,i) = try  v[i], true catch println("Does not exist") ;nothing, false;
prev(v,i) = if isExits(v,i) v[i-1]
succeed(v, i) = isExits(v,i) v[i+1];
transfer(v, m, n) = v[m], v[n] = v[n], v[m]
#v[m] -> v[n]
insertat!(v, m, i) = v[i] = m;
jump(v, ; m, n) = v[n] -> tmp, v[m] -> v[n], tmp->v[m];

v[n] -> tmp

a = zeros(2);

b = ones(2);

c = (a, b)
# ([0.0, 0.0], [1.0, 1.0])

 @swap!(a, b);

# c  # unchanged, because all the `@swap!` macro did was change the bindings "a" and "b"
#([0.0, 0.0], [1.0, 1.0])

#; && v[m] -> v[n] && tmp -> v[m]

#@time begin flag = isMod(vec)
    #=
if fl == true
    l = length(vec) / 2
elseif flag == false
    l = (length(vec) + 1) / 2 # not correct # skipping 1
end
=#=#

function len(v::Vector)
    return length(v)
end

len(v)

max_stars_repo_name: adamwillisMastery/DeepLearner

max_issues_repo_name: adamwillisMastery/DeepLearner

max_forks_repo_name: adamwillisXanax/DeepLearner