问:
How to pass down constructor parameters transparently or how to use bind in class expressions?

Problem:

Given these classes:

class A {
    public constructor(private n: number) {
        //
    }
}

class B extends A {
    public static readonly X = new class B$X extends B {
    }("abc");

    public static readonly Y = new class B$X extends B {
    }("def");

    public constructor(private s: string) {
        super(1);
    }
}
```
<p>with B having some static fields that are created from class expressions, how can I specify individual values for A's constructor, without modifying B's constructor?</p>
<p>That value <code>1</code> in B's ctor should not be hardcoded by somehow set from the class expressions, without adding that number to the constructor parameter list.</p>
<h2>Background:</h2>
<p>This is an attempt to convert a Java enum to a Typescript class. The Java compiler internally generates some code, which I have to model explicitly. Imaging something like:</p>
<pre class="lang-java prettyprint-override"><code>enum B {
    X("abc"),
    Y("def");

    private String s;

    B(String s) {
        this.s = s;
    }
}
</code>```

An enum is implicitly derived from java.lang.Enum which has a constructor to take the enum constant's name and its ordinal and I have to model that manually. I can generate the code for the class expressions, but I don't know how to pass through the values for constant name and ordinal.

I was thinking of binding the constructor of the class expression, but cannot imagine how that syntax has to look like.

Body:
Problem:

Given these classes:

class A {
    public constructor(private n: number) {
        //
    }
}

class B extends A {
    public static readonly X = new class B$X extends B {
    }("abc");

    public static readonly Y = new class B$X extends B {
    }("def");

    public constructor(private s: string) {
        super(1);
    }
}

with B having some static fields that are created from class expressions, how can I specify individual values for A's constructor, without modifying B's constructor?

That value 1 in B's ctor should not be hardcoded by somehow set from the class expressions, without adding that number to the constructor parameter list.

Background:

This is an attempt to convert a Java enum to a Typescript class. The Java compiler internally generates some code, which I have to model explicitly. Imaging something like:

enum B {
    X("abc"),
    Y("def");

    private String s;

    B(String s) {
        this.s = s;
    }
}

An enum is implicitly derived from java.lang.Enum which has a constructor to take the enum constant's name and its ordinal and I have to model that manually. I can generate the code for the class expressions, but I don't know how to pass through the values for constant name and ordinal.

I was thinking of binding the constructor of the class expression, but cannot imagine how that syntax has to look like.


来源: stackexchange

问:
add $request parameter to wordpress api callback like laravel
As you know you can create a new Request in laravel and pass it to controller methods, like so:

```<code>public function create(CreateNewBookRequest $request){
    //todo method logic
}
</code>```

now I want to implement such a thing in wordpress REST API. As you know when we are registring a new route for wordpress REST API, we do this:

```<code>register_rest_route($this->namespace, $this->baseRoute . '/register', array(
    'methods'  => [WP_REST_Server::CREATABLE],
    'callback' => [$this, 'registerRouteCallback'],
));
</code>```

and in registerRouteCallback method we have:

```<code>public function registerRouteCallback(WP_REST_Request $request)
{
    //todo method logic
}
</code>```

Now how can I implement something like laravel $request in wordpress(specifaclly for validations). I want to use this approach in multiple places not just in REST API callback.

generally I'm looking for a way to have access to a class object inside a function without passing the object as a parameter, I want function to automatically create an object if it was not passed to it.

When I try to do this:

```<code>public function registerRouteCallback(RegisterRequest $request)
{
    //todo method logic
}
</code>```

I'll get a fetal error:

```<code>Argument #1 ($request) must be of type RegisterRequest, WP_REST_Request given.
</code>```

ContentLicense: CC BY-SA 4.0

Body:
As you know you can create a new Request in laravel and pass it to controller methods, like so:

public function create(CreateNewBookRequest $request){
    //todo method logic
}

now I want to implement such a thing in wordpress REST API. As you know when we are registring a new route for wordpress REST API, we do this:

register_rest_route($this->namespace, $this->baseRoute . '/register', array(
    'methods'  => [WP_REST_Server::CREATABLE],
    'callback' => [$this, 'registerRouteCallback'],
));

and in registerRouteCallback method we have:

public function registerRouteCallback(WP_REST_Request $request)
{
    //todo method logic
}

Now how can I implement something like laravel $request in wordpress(specifaclly for validations). I want to use this approach in multiple places not just in REST API callback.

generally I'm looking for a way to have access to a class object inside a function without passing the object as a parameter, I want function to automatically create an object if it was not passed to it.

When I try to do this:

public function registerRouteCallback(RegisterRequest $request)
{
    //todo method logic
}

I'll get a fetal error:

Argument #1 ($request) must be of type RegisterRequest, WP_REST_Request given.


问:
C++ Observer pattern using templates
I'm designing an observer for a logger class. I started migrating my code to a compile-time approach, and have been struggling with a portion of it that uses the observer design pattern

Here is the original implementation of my subject (registry)

```<code>class Registry {
public:

    void SubscribeSink(std::shared_ptr<Sink> param_sink) {
        m_sinks.push_back(param_sink);
    }

    void UnsubscribeSink(std::shared_ptr<Sink> param_sink) {
        auto iterator = std::find(m_sinks.begin(), m_sinks.end(), param_sink);

        if (iterator != m_sinks.end()) {
            m_sinks.erase(iterator);
        }
    }

    void NotifySink() {
        for (auto sink_iterator : m_sinks) {
            sink_iterator->ProcessRegistry(m_registry_buffer, param_level);
            m_registry_buffer.pop_back();
        }
    }

    void SinkIt(std::string& param_message) {
        m_registry_buffer = param_message;
        this->NotifySink(param_level);
    }

private:
    std::vector<std::shared_ptr<Sink>> m_sinks;

    std::string m_registry_buffer;
};
</code>```

The Sink is my observer. Now, since I've changed the sink to be declared as a type such as:

Sink<Wrapper1, Wrapper2, Wrapper3, ...>

```<code>template <typename... Formats>
class ConsoleSink : public Sink<Formats... > {
public:
    template </*sink level*/>
    inline void ProcessRegistry(/*message*/, /*message level*/) {

        ((Formats::template Format</*sink level*/>(/*message*/)), ...);

        if (/*message level*/ == /*sink level*/) {
            std::clog << /*message*/ << std::endl;
        } else {
            return;
        }
    }
};

template <typename... Formats>
struct ConsoleSinkBuilder {
    template <typename Format>
    inline auto AddConfig() {
        return ConsoleSinkBuilder<Formats..., Format>{};
    }
    inline auto Dispatch() {
        return ConsoleSink<Formats...>{};
    }
};
</code>```

And I call an instance like this:

```<code>    console_sink.ProcessRegistry</*sink level*/>(/*message*/, /*message level*/);
</code>```

I have tried to implement my Registry using templates, but I'm not sure if I'm going in the right direction

```<code>template <typename... Formats>
class Registry {
public:

    template <typename... Formats>
    void SubscribeSink(std::shared_ptr<Sink<Formats...>> param_sink) {
        m_sinks.push_back(param_sink);
    }

    void UnsubscribeSink(std::shared_ptr<Sink<Formats...>> param_sink) {
        auto iterator = std::find(m_sinks.begin(), m_sinks.end(), param_sink);

        if (iterator != m_sinks.end()) {
            m_sinks.erase(iterator);
        }
    }

    template <typename SinkLevel>
    void NotifySink() {
        for (auto sink_iterator : m_sinks) {
            sink_iterator->ProcessRegistry(m_registry_buffer, param_level);
            m_registry_buffer.pop_back();
        }
    }

    template <typename SinkLevel>
    void SinkIt(std::string& param_message) {
        m_registry_buffer = param_message;
        this->NotifySink(param_level);
    }

private:
    template <typename... Formats>
    std::vector<std::shared_ptr<Sink<Formats...>>> m_sinks;

    std::string m_registry_buffer;
};
</code>```

I'm also trying to make this work in C++11, but a C++14 solution would be good too.

Title: C++ Observer pattern using templates

Body:
I'm designing an observer for a logger class. I started migrating my code to a compile-time approach, and have been struggling with a portion of it that uses the observer design pattern

Here is the original implementation of my subject (registry)

class Registry {
public:

    void SubscribeSink(std::shared_ptr<Sink> param_sink) {
        m_sinks.push_back(param_sink);
    }

    void UnsubscribeSink(std::shared_ptr<Sink> param_sink) {
        auto iterator = std::find(m_sinks.begin(), m_sinks.end(), param_sink);

        if (iterator != m_sinks.end()) {
            m_sinks.erase(iterator);
        }
    }

    void NotifySink() {
        for (auto sink_iterator : m_sinks) {
            sink_iterator->ProcessRegistry(m_registry_buffer, param_level);
            m_registry_buffer.pop_back();
        }
    }

    void SinkIt(std::string& param_message) {
        m_registry_buffer = param_message;
        this->NotifySink(param_level);
    }

private:
    std::vector<std::shared_ptr<Sink>> m_sinks;

    std::string m_registry_buffer;
};

The Sink is my observer. Now, since I've changed the sink to be declared as a type such as:

Sink<Wrapper1, Wrapper2, Wrapper3, ...>

template <typename... Formats>
class ConsoleSink : public Sink<Formats... > {
public:
    template </*sink level*/>
    inline void ProcessRegistry(/*message*/, /*message level*/) {

        ((Formats::template Format</*sink level*/>(/*message*/)), ...);

        if (/*message level*/ == /*sink level*/) {
            std::clog << /*message*/ << std::endl;
        } else {
            return;
        }
    }
};

template <typename... Formats>
struct ConsoleSinkBuilder {
    template <typename Format>
    inline auto AddConfig() {
        return ConsoleSinkBuilder<Formats..., Format>{};
    }
    inline auto Dispatch() {
        return ConsoleSink<Formats...>{};
    }
};

And I call an instance like this:

    console_sink.ProcessRegistry</*sink level*/>(/*message*/, /*message level*/);

I have tried to implement my Registry using templates, but I'm not sure if I'm going in the right direction

template <typename... Formats>
class Registry {
public:

    template <typename... Formats>
    void SubscribeSink(std::shared_ptr<Sink<Formats...>> param_sink) {
        m_sinks.push_back(param_sink);
    }

    void UnsubscribeSink(std::shared_ptr<Sink<Formats...>> param_sink) {
        auto iterator = std::find(m_sinks.begin(), m_sinks.end(), param_sink);

        if (iterator != m_sinks.end()) {
            m_sinks.erase(iterator);
        }
    }

    template <typename SinkLevel>
    void NotifySink() {
        for (auto sink_iterator : m_sinks) {
            sink_iterator->ProcessRegistry(m_registry_buffer, param_level);
            m_registry_buffer.pop_back();
        }
    }

    template <typename SinkLevel>
    void SinkIt(std::string& param_message) {
        m_registry_buffer = param_message;
        this->NotifySink(param_level);
    }

private:
    template <typename... Formats>
    std::vector<std::shared_ptr<Sink<Formats...>>> m_sinks;

    std::string m_registry_buffer;
};

I'm also trying to make this work in C++11, but a C++14 solution would be good too.


问:
How can I update Android Compose's UI Layer to be constantly updated with data from API Calls?
I'm still trying my best to wrap my head about how Android Compose works so I don't think I am describing the problem I'm facing well but I'll try.

Aim: I am trying to build a Bus Android App that allows users to query about when the next bus will be arriving.

This can be achieved by making API Calls to a locally public transport API (the link is below). Of the APIs available, I am interested in Bus Arrival, Bus Routes, and Bus Stops.

Bus Arrival API allows me to get the timestamp of the next bus, and has 2 query parameters, which is the Bus Stop Code and the Bus Service Number we are interested in. Using this, I implemented the feature that allows Users to check all the incoming buses at a bus stop if they provide the Bus Stop Code.

Bus Stops API allows me to get the details of the Bus Stops, such as the name and road of the bus stops. However, it only has 1 query parameter ($skip), which means that the API call returns all the bus stops found in the country. Each call is also limited to 500 records, so I have to use $skip to get to the next 500 records.

Bus Services API allows me to get the route of a particular bus, that is all the bus stops a bus service will travel to. Similar to Number 2, it returns the routes of all the bus services in the country and can only be traversed using $skip.

(https://datamall.lta.gov.sg/content/dam/datamall/datasets/LTA_DataMall_API_User_Guide.pdf)

Feature Implemented: Currently, I wish to implement a feature where Users can search any Bus Service Number, and the app will return the route for that bus. This means that they can click on any of the bus stops in the Route to get the bus timings for all the buses at that bus stop.

To implement this, I used ViewModelScope.launch { } to call the Data Repository, allowing me to call the functions I implemented to make the API Calls. I have nested this code within onKeyboardSearch so that the 2 functions to get the Bus Timings and Bus Stop Details are called when the User searches for the Bus Stop.

Issue: However, I realised that I have to click the "Search" Button twice for a User to search using the Service Number as the UI is not updated with the data from the API call I think.

Also, I am currently using a nested for loop (so n^2 time complexity) to filter the Bus Stops and Bus Services APIs to get the data I want. I have attached my code below and I am terribly sorry if my explanation is bad, I will try to provide more information if there are any doubts. Thank you for reading my post.

AppViewModel.kt

```<code>package com.example.busexpress.ui.screens

import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.busexpress.BusExpressApplication
import com.example.busexpress.data.SingaporeBusRepository
import com.example.busexpress.determineBusServiceorStop
import com.example.busexpress.network.BusRoutes
import com.example.busexpress.network.BusStopInRoute
import com.example.busexpress.network.BusStopValue
import com.example.busexpress.network.SingaporeBus
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException

/**
 * [AppViewModel] holds information about a cupcake order in terms of quantity, flavor, and
 * pickup date. It also knows how to calculate the total price based on these order details.
 */
class AppViewModel(private val singaporeBusRepository: SingaporeBusRepository): ViewModel() {
    /**
     *  StateFlows to store the Data of API Calls
     */
    private val _busServiceUiState = MutableStateFlow(SingaporeBus())
    val busServiceUiState: StateFlow<SingaporeBus> = _busServiceUiState.asStateFlow()

    private val _busStopNameUiState = MutableStateFlow(BusStopValue())
    val busStopNameUiState: StateFlow<BusStopValue> = _busStopNameUiState.asStateFlow()

    private val _busRouteUiState = MutableStateFlow(BusRoutes())
    val busRouteUiState: StateFlow<BusRoutes> = _busRouteUiState.asStateFlow()

    /** The mutable State that stores the status of the most recent request */
    var busUiState: BusUiState by mutableStateOf(BusUiState.Loading)     // Loading as Default Value
        // Setter is private to protect writes to the busUiState
        private set

    var busNameUiState: BusStopNameUiState by mutableStateOf(BusStopNameUiState.Loading)
        private set

    var busRoutingUiState: BusRouteUiState by mutableStateOf(BusRouteUiState.Loading)
        private set

    // Boolean to determine if we should show Bus Stops or Routes
    var busServiceBoolUiState: Boolean by mutableStateOf(false)
        private set

    /**
     * Call init so we can display status immediately.
     */
    init {
        getBusTimings(null)
        getBusStopNames(0)
    }

    fun getBusRoutes(targetBusService: String?) {
        busServiceBoolUiState = true
        viewModelScope.launch {
            busRoutingUiState = BusRouteUiState.Loading
            busRoutingUiState = try {
                // Goal: To get the Route, i.e. all the Bus Stop Codes for a SINGLE Bus Service
                var skipIndex = 0
                var targetServiceRoute = mutableListOf<BusStopInRoute>()
                var targetRouteFound = false

                do {
                    // Variables to hold Conditions
                    var iteratorIndex = 0
                    var completedRoute = false

                    // API Call
                    val listResult = singaporeBusRepository.getBusRoutes(skipIndex)
                    val busStopRoute = listResult.busRouteArray

                    // 500 since according to LTA Record each API Call is confined to 500 Records
                    for (i in 1..500) {
//                        Log.d("debugTag", "This is output ${busStopRoute[iteratorIndex].serviceNo}")
                        // Must compare string since Bus Services like 901M exist
                        if (busStopRoute[iteratorIndex].serviceNo == targetBusService) {
                            // Found a Bus Stop of Route, append to Result Array
                            targetServiceRoute.add(busStopRoute[i])
                            if (busStopRoute[iteratorIndex].stopSequence != 1) {
                                targetRouteFound = true
                            }
                        }
                        // Condition to Check if Route is Complete
                        else if (targetRouteFound && (busStopRoute[iteratorIndex].stopSequence == 1)) {
                            // Passed the Target Route alr
                            completedRoute = true
                            break
                        }
                        iteratorIndex += 1
                    }

                    // Stopping Condition
                    if (completedRoute) {
                        _busRouteUiState.value = BusRoutes(
                            metaData = listResult.metaData,
                            busRouteArray = targetServiceRoute
                        )
                        // For Loop to get all the Arrival Timings for all Bus Stops in the Route
                        break
                    }
                    else {
                        skipIndex += 500
                    }
                } while(true)

                BusRouteUiState.Success(targetServiceRoute)
            }
            catch (e: IOException) {
                BusRouteUiState.Error
            }
            catch (e: HttpException) {
                BusRouteUiState.Error
            }

        }
    }

    // TODO Make it async and await()
    fun getBusStopNames(targetBusStopCode: Int) {
            busServiceBoolUiState = false
            viewModelScope.launch {
            busNameUiState = BusStopNameUiState.Loading
            busNameUiState = try {
                var targetBusStop = BusStopValue()
                var targetBusStopFound = false
                var skipIndex = 0

                // Retrieve the Desired Bus Stop Object
                do {
                    val listResult = singaporeBusRepository.getBusDetails(numRecordsToSkip = skipIndex)
                    val busStopDetails = listResult.value
                    val forLoopSize = busStopDetails.size
                    var indexBSD = 0

                    // Loop through the 500 Records of this Call to see if the Bus Stop we want is inside
                    for(i in 1..forLoopSize) {
                        if (busStopDetails[indexBSD].busStopCode.toInt() == targetBusStopCode) {
                            targetBusStopFound = true
                            break
                        }
                        // Update to check every Record of API Call
                        indexBSD += 1
                    }

                    // Check if the Bus Stop we want is in this API Call
                    if (targetBusStopFound) {
                        targetBusStop = busStopDetails[indexBSD]
                    }
                    else {
                        // Call the Next 500/ or whatever size pulled Records
                        skipIndex += forLoopSize
                    }
                } while(!targetBusStopFound)

                // After finding the Correct Bus Stop
                if (targetBusStop.busStopCode != "Bus Stop Not Found") {
                    _busStopNameUiState.value = BusStopValue(
                                                    busStopCode = targetBusStop.busStopCode,
                                                    busStopRoadName = targetBusStop.busStopRoadName,
                                                    busStopDescription = targetBusStop.busStopDescription,
                                                    latitude = targetBusStop.latitude,
                                                    longitude = targetBusStop.longitude
                                                )

                }

                BusStopNameUiState.Success(targetBusStop.busStopRoadName)
            }
            catch (e: IOException) {
                BusStopNameUiState.Error
            }
            catch (e: HttpException) {
                BusStopNameUiState.Error
            }
        }
    }

    fun getBusTimings(userInput: String?) {
        // Determine if UserInput is a BusStopCode
        val userInputResult = determineBusServiceorStop(userInput = userInput)
        val busStopCode = userInputResult.busStopCode
        val busServiceNumber = userInputResult.busServiceNo

        //var listResult: SingaporeBus = SingaporeBus(metaData = "Initialised", busStopCode = "Initialised")
        // Launch the Coroutine using a ViewModelScope
        viewModelScope.launch {
            busUiState = BusUiState.Loading
            // Might have Connectivity Issues
            busUiState = try {
                // Within this Scope, use the Repository, not the Object to access the Data, abstracting the data within the Data Layer
                val listResult = singaporeBusRepository.getBusTimings(
                    busServiceNumber = busServiceNumber,
                    busStopCode = busStopCode
                )

                _busServiceUiState.value = SingaporeBus(
                                                metaData = listResult.metaData,
                                                busStopCode = listResult.busStopCode,
                                                services = listResult.services
                                            )
                // Assign results from backend server to busUiState {A mutable state object that represents the status of the most recent web request}
                BusUiState.Success(busTimings = listResult)
            }
            catch (e: IOException) {
                BusUiState.Error
            }
            catch (e: HttpException) {
                BusUiState.Error
            }
        }
    }

    // Factory Object to retrieve the singaporeBusRepository and pass it to the ViewModel
    companion object {
        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                val application = (this[APPLICATION_KEY] as BusExpressApplication)
                val singaporeBusRepository = application.container.singaporeBusRepository
                AppViewModel(singaporeBusRepository = singaporeBusRepository)
            }
        }
    }

}

// Simply saving the UiState as a Mutable State prevents us from saving the different status
// like Loading, Error, and Success
sealed interface BusUiState {
    data class Success(val busTimings: SingaporeBus) : BusUiState
    // The 2 States below need not set new data and create new objects, which is why an object is sufficient for the web response
    object Error: BusUiState
    object Loading: BusUiState
    // Sealed Interface used instead of Interface to remove Else Branch
}

sealed interface BusStopNameUiState {
    data class Success(val busStopName: String): BusStopNameUiState
    object Error: BusStopNameUiState
    object Loading: BusStopNameUiState
}

sealed interface BusRouteUiState {
    data class Success(val busRoutes: MutableList<BusStopInRoute>): BusRouteUiState
    object Error: BusRouteUiState
    object Loading: BusRouteUiState
}
</code>```

CommonComposable.kt
https://pastebin.com/hnXhjDFE

Default Screen.kt
https://pastebin.com/9VzUgChM

Body:
I'm still trying my best to wrap my head about how Android Compose works so I don't think I am describing the problem I'm facing well but I'll try.

Aim: I am trying to build a Bus Android App that allows users to query about when the next bus will be arriving.

This can be achieved by making API Calls to a locally public transport API (the link is below). Of the APIs available, I am interested in Bus Arrival, Bus Routes, and Bus Stops.

Bus Arrival API allows me to get the timestamp of the next bus, and has 2 query parameters, which is the Bus Stop Code and the Bus Service Number we are interested in. Using this, I implemented the feature that allows Users to check all the incoming buses at a bus stop if they provide the Bus Stop Code.

Bus Stops API allows me to get the details of the Bus Stops, such as the name and road of the bus stops. However, it only has 1 query parameter ($skip), which means that the API call returns all the bus stops found in the country. Each call is also limited to 500 records, so I have to use $skip to get to the next 500 records.

Bus Services API allows me to get the route of a particular bus, that is all the bus stops a bus service will travel to. Similar to Number 2, it returns the routes of all the bus services in the country and can only be traversed using $skip.

(https://datamall.lta.gov.sg/content/dam/datamall/datasets/LTA_DataMall_API_User_Guide.pdf)

Feature Implemented: Currently, I wish to implement a feature where Users can search any Bus Service Number, and the app will return the route for that bus. This means that they can click on any of the bus stops in the Route to get the bus timings for all the buses at that bus stop.

To implement this, I used ViewModelScope.launch { } to call the Data Repository, allowing me to call the functions I implemented to make the API Calls. I have nested this code within onKeyboardSearch so that the 2 functions to get the Bus Timings and Bus Stop Details are called when the User searches for the Bus Stop.

Issue: However, I realised that I have to click the "Search" Button twice for a User to search using the Service Number as the UI is not updated with the data from the API call I think.

Also, I am currently using a nested for loop (so n^2 time complexity) to filter the Bus Stops and Bus Services APIs to get the data I want. I have attached my code below and I am terribly sorry if my explanation is bad, I will try to provide more information if there are any doubts. Thank you for reading my post.

AppViewModel.kt

package com.example.busexpress.ui.screens

import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.busexpress.BusExpressApplication
import com.example.busexpress.data.SingaporeBusRepository
import com.example.busexpress.determineBusServiceorStop
import com.example.busexpress.network.BusRoutes
import com.example.busexpress.network.BusStopInRoute
import com.example.busexpress.network.BusStopValue
import com.example.busexpress.network.SingaporeBus
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException

/**
 * [AppViewModel] holds information about a cupcake order in terms of quantity, flavor, and
 * pickup date. It also knows how to calculate the total price based on these order details.
 */
class AppViewModel(private val singaporeBusRepository: SingaporeBusRepository): ViewModel() {
    /**
     *  StateFlows to store the Data of API Calls
     */
    private val _busServiceUiState = MutableStateFlow(SingaporeBus())
    val busServiceUiState: StateFlow<SingaporeBus> = _busServiceUiState.asStateFlow()

    private val _busStopNameUiState = MutableStateFlow(BusStopValue())
    val busStopNameUiState: StateFlow<BusStopValue> = _busStopNameUiState.asStateFlow()

    private val _busRouteUiState = MutableStateFlow(BusRoutes())
    val busRouteUiState: StateFlow<BusRoutes> = _busRouteUiState.asStateFlow()

    /** The mutable State that stores the status of the most recent request */
    var busUiState: BusUiState by mutableStateOf(BusUiState.Loading)     // Loading as Default Value
        // Setter is private to protect writes to the busUiState
        private set

    var busNameUiState: BusStopNameUiState by mutableStateOf(BusStopNameUiState.Loading)
        private set

    var busRoutingUiState: BusRouteUiState by mutableStateOf(BusRouteUiState.Loading)
        private set

    // Boolean to determine if we should show Bus Stops or Routes
    var busServiceBoolUiState: Boolean by mutableStateOf(false)
        private set

    /**
     * Call init so we can display status immediately.
     */
    init {
        getBusTimings(null)
        getBusStopNames(0)
    }

    fun getBusRoutes(targetBusService: String?) {
        busServiceBoolUiState = true
        viewModelScope.launch {
            busRoutingUiState = BusRouteUiState.Loading
            busRoutingUiState = try {
                // Goal: To get the Route, i.e. all the Bus Stop Codes for a SINGLE Bus Service
                var skipIndex = 0
                var targetServiceRoute = mutableListOf<BusStopInRoute>()
                var targetRouteFound = false

                do {
                    // Variables to hold Conditions
                    var iteratorIndex = 0
                    var completedRoute = false

                    // API Call
                    val listResult = singaporeBusRepository.getBusRoutes(skipIndex)
                    val busStopRoute = listResult.busRouteArray

                    // 500 since according to LTA Record each API Call is confined to 500 Records
                    for (i in 1..500) {
//                        Log.d("debugTag", "This is output ${busStopRoute[iteratorIndex].serviceNo}")
                        // Must compare string since Bus Services like 901M exist
                        if (busStopRoute[iteratorIndex].serviceNo == targetBusService) {
                            // Found a Bus Stop of Route, append to Result Array
                            targetServiceRoute.add(busStopRoute[i])
                            if (busStopRoute[iteratorIndex].stopSequence != 1) {
                                targetRouteFound = true
                            }
                        }
                        // Condition to Check if Route is Complete
                        else if (targetRouteFound && (busStopRoute[iteratorIndex].stopSequence == 1)) {
                            // Passed the Target Route alr
                            completedRoute = true
                            break
                        }
                        iteratorIndex += 1
                    }

                    // Stopping Condition
                    if (completedRoute) {
                        _busRouteUiState.value = BusRoutes(
                            metaData = listResult.metaData,
                            busRouteArray = targetServiceRoute
                        )
                        // For Loop to get all the Arrival Timings for all Bus Stops in the Route
                        break
                    }
                    else {
                        skipIndex += 500
                    }
                } while(true)

                BusRouteUiState.Success(targetServiceRoute)
            }
            catch (e: IOException) {
                BusRouteUiState.Error
            }
            catch (e: HttpException) {
                BusRouteUiState.Error
            }

        }
    }

    // TODO Make it async and await()
    fun getBusStopNames(targetBusStopCode: Int) {
            busServiceBoolUiState = false
            viewModelScope.launch {
            busNameUiState = BusStopNameUiState.Loading
            busNameUiState = try {
                var targetBusStop = BusStopValue()
                var targetBusStopFound = false
                var skipIndex = 0

                // Retrieve the Desired Bus Stop Object
                do {
                    val listResult = singaporeBusRepository.getBusDetails(numRecordsToSkip = skipIndex)
                    val busStopDetails = listResult.value
                    val forLoopSize = busStopDetails.size
                    var indexBSD = 0

                    // Loop through the 500 Records of this Call to see if the Bus Stop we want is inside
                    for(i in 1..forLoopSize) {
                        if (busStopDetails[indexBSD].busStopCode.toInt() == targetBusStopCode) {
                            targetBusStopFound = true
                            break
                        }
                        // Update to check every Record of API Call
                        indexBSD += 1
                    }

                    // Check if the Bus Stop we want is in this API Call
                    if (targetBusStopFound) {
                        targetBusStop = busStopDetails[indexBSD]
                    }
                    else {
                        // Call the Next 500/ or whatever size pulled Records
                        skipIndex += forLoopSize
                    }
                } while(!targetBusStopFound)

                // After finding the Correct Bus Stop
                if (targetBusStop.busStopCode != "Bus Stop Not Found") {
                    _busStopNameUiState.value = BusStopValue(
                                                    busStopCode = targetBusStop.busStopCode,
                                                    busStopRoadName = targetBusStop.busStopRoadName,
                                                    busStopDescription = targetBusStop.busStopDescription,
                                                    latitude = targetBusStop.latitude,
                                                    longitude = targetBusStop.longitude
                                                )

                }

                BusStopNameUiState.Success(targetBusStop.busStopRoadName)
            }
            catch (e: IOException) {
                BusStopNameUiState.Error
            }
            catch (e: HttpException) {
                BusStopNameUiState.Error
            }
        }
    }

    fun getBusTimings(userInput: String?) {
        // Determine if UserInput is a BusStopCode
        val userInputResult = determineBusServiceorStop(userInput = userInput)
        val busStopCode = userInputResult.busStopCode
        val busServiceNumber = userInputResult.busServiceNo

        //var listResult: SingaporeBus = SingaporeBus(metaData = "Initialised", busStopCode = "Initialised")
        // Launch the Coroutine using a ViewModelScope
        viewModelScope.launch {
            busUiState = BusUiState.Loading
            // Might have Connectivity Issues
            busUiState = try {
                // Within this Scope, use the Repository, not the Object to access the Data, abstracting the data within the Data Layer
                val listResult = singaporeBusRepository.getBusTimings(
                    busServiceNumber = busServiceNumber,
                    busStopCode = busStopCode
                )

                _busServiceUiState.value = SingaporeBus(
                                                metaData = listResult.metaData,
                                                busStopCode = listResult.busStopCode,
                                                services = listResult.services
                                            )
                // Assign results from backend server to busUiState {A mutable state object that represents the status of the most recent web request}
                BusUiState.Success(busTimings = listResult)
            }
            catch (e: IOException) {
                BusUiState.Error
            }
            catch (e: HttpException) {
                BusUiState.Error
            }
        }
    }

    // Factory Object to retrieve the singaporeBusRepository and pass it to the ViewModel
    companion object {
        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                val application = (this[APPLICATION_KEY] as BusExpressApplication)
                val singaporeBusRepository = application.container.singaporeBusRepository
                AppViewModel(singaporeBusRepository = singaporeBusRepository)
            }
        }
    }

}

// Simply saving the UiState as a Mutable State prevents us from saving the different status
// like Loading, Error, and Success
sealed interface BusUiState {
    data class Success(val busTimings: SingaporeBus) : BusUiState
    // The 2 States below need not set new data and create new objects, which is why an object is sufficient for the web response
    object Error: BusUiState
    object Loading: BusUiState
    // Sealed Interface used instead of Interface to remove Else Branch
}

sealed interface BusStopNameUiState {
    data class Success(val busStopName: String): BusStopNameUiState
    object Error: BusStopNameUiState
    object Loading: BusStopNameUiState
}

sealed interface BusRouteUiState {
    data class Success(val busRoutes: MutableList<BusStopInRoute>): BusRouteUiState
    object Error: BusRouteUiState
    object Loading: BusRouteUiState
}

CommonComposable.kt
https://pastebin.com/hnXhjDFE

Default Screen.kt
https://pastebin.com/9VzUgChM


问:
OAuth2AuthorizedClientService implementations cache tokens per client principal
When configuring WebClient with a ServletOAuth2AuthorizedClientExchangeFilterFunction, we've found that both implementations provided for OAuth2AuthorizedClientService cache tokens in a way that make them only able to be used by the current client.

I have an Rest API setup and configured with OAuth2 authentication that can have a variety of clients.  This API makes a downstream call to another API using its own client credentials.  What we found was that the tokens cached in the OAuth2AuthorizedClientService are only usable if the same client calls my API.  This means that if 2 different clients call my API, a new token will be requested for the second call, even if a perfectly valid token is already saved. This presents an issue since the downstream resource server is rate limited and my API is generally called by a number of different clients.

Looking for a way to configure things so that the tokens in this case are cached globally for all clients to use.  I was able to solve this by writing my own OAuth2AuthorizedClientService, but my preference would be to use OTB Spring to do this if at all possible.

I've tried configuring WebClient and the ServletOAuth2AuthorizedClientExchangeFilterFunction a number of ways, but looking at the internals of the implementations of OAuth2AuthorizedClientService, I'm not sure there is anything out of the box that will satisfy my requirement.

Originally I had WebClient configured like this:

@Bean
protected WebClient webClient(WebClient.Builder builder, ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) {
    AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
    OAuth2AuthorizationFailureHandler oAuth2AuthorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler((clientRegistrationId, principal, attributes) -> authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName()));
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2AuthorizedClientExchangeFilterFunction = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);

    oauth2AuthorizedClientExchangeFilterFunction.setDefaultOAuth2AuthorizedClient(true);
    oauth2AuthorizedClientExchangeFilterFunction.setDefaultClientRegistrationId("oauth2");
    oauth2AuthorizedClientExchangeFilterFunction.setAuthorizationFailureHandler(oAuth2AuthorizationFailureHandler);

    return builder.apply(oauth2AuthorizedClientExchangeFilterFunction.oauth2Configuration())
            .build();
}
```
<p>After looking closer at Spring's provided implementations, my only solution was to write my own OAuth2AuthorizedClientService:</p>
<pre class="lang-java prettyprint-override"><code>public final class IgnorePrincialOAuth2AuthorizedClientService implements OAuth2AuthorizedClientService {

    private static final Authentication ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken("anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));

    private final OAuth2AuthorizedClientService delegate;

    public IgnorePrincialOAuth2AuthorizedClientService(OAuth2AuthorizedClientService delegate) {
        Assert.notNull(delegate, "delegate cannot be null");
        this.delegate = delegate;
    }

    @Override
    public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(String clientRegistrationId, String principalName) {
        return delegate.loadAuthorizedClient(clientRegistrationId, ANONYMOUS_AUTHENTICATION.getName());
    }

    @Override
    public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal) {
        delegate.saveAuthorizedClient(toAnonymousPrincipal(authorizedClient), ANONYMOUS_AUTHENTICATION);
    }

    @Override
    public void removeAuthorizedClient(String clientRegistrationId, String principalName) {
        delegate.removeAuthorizedClient(clientRegistrationId, ANONYMOUS_AUTHENTICATION.getName());
    }

    private OAuth2AuthorizedClient toAnonymousPrincipal(OAuth2AuthorizedClient authorizedClient) {
        return new OAuth2AuthorizedClient(authorizedClient.getClientRegistration(), ANONYMOUS_AUTHENTICATION.getName(), authorizedClient.getAccessToken(), authorizedClient.getRefreshToken());
    }

}
</code>```

Body:
When configuring WebClient with a ServletOAuth2AuthorizedClientExchangeFilterFunction, we've found that both implementations provided for OAuth2AuthorizedClientService cache tokens in a way that make them only able to be used by the current client.

I have an Rest API setup and configured with OAuth2 authentication that can have a variety of clients.  This API makes a downstream call to another API using its own client credentials.  What we found was that the tokens cached in the OAuth2AuthorizedClientService are only usable if the same client calls my API.  This means that if 2 different clients call my API, a new token will be requested for the second call, even if a perfectly valid token is already saved. This presents an issue since the downstream resource server is rate limited and my API is generally called by a number of different clients.

Looking for a way to configure things so that the tokens in this case are cached globally for all clients to use.  I was able to solve this by writing my own OAuth2AuthorizedClientService, but my preference would be to use OTB Spring to do this if at all possible.

I've tried configuring WebClient and the ServletOAuth2AuthorizedClientExchangeFilterFunction a number of ways, but looking at the internals of the implementations of OAuth2AuthorizedClientService, I'm not sure there is anything out of the box that will satisfy my requirement.

Originally I had WebClient configured like this:

@Bean
protected WebClient webClient(WebClient.Builder builder, ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) {
    AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
    OAuth2AuthorizationFailureHandler oAuth2AuthorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler((clientRegistrationId, principal, attributes) -> authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName()));
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2AuthorizedClientExchangeFilterFunction = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);

    oauth2AuthorizedClientExchangeFilterFunction.setDefaultOAuth2AuthorizedClient(true);
    oauth2AuthorizedClientExchangeFilterFunction.setDefaultClientRegistrationId("oauth2");
    oauth2AuthorizedClientExchangeFilterFunction.setAuthorizationFailureHandler(oAuth2AuthorizationFailureHandler);

    return builder.apply(oauth2AuthorizedClientExchangeFilterFunction.oauth2Configuration())
            .build();
}

After looking closer at Spring's provided implementations, my only solution was to write my own OAuth2AuthorizedClientService:

public final class IgnorePrincialOAuth2AuthorizedClientService implements OAuth2AuthorizedClientService {

    private static final Authentication ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken("anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));

    private final OAuth2AuthorizedClientService delegate;

    public IgnorePrincialOAuth2AuthorizedClientService(OAuth2AuthorizedClientService delegate) {
        Assert.notNull(delegate, "delegate cannot be null");
        this.delegate = delegate;
    }

    @Override
    public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(String clientRegistrationId, String principalName) {
        return delegate.loadAuthorizedClient(clientRegistrationId, ANONYMOUS_AUTHENTICATION.getName());
    }

    @Override
    public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal) {
        delegate.saveAuthorizedClient(toAnonymousPrincipal(authorizedClient), ANONYMOUS_AUTHENTICATION);
    }

    @Override
    public void removeAuthorizedClient(String clientRegistrationId, String principalName) {
        delegate.removeAuthorizedClient(clientRegistrationId, ANONYMOUS_AUTHENTICATION.getName());
    }

    private OAuth2AuthorizedClient toAnonymousPrincipal(OAuth2AuthorizedClient authorizedClient) {
        return new OAuth2AuthorizedClient(authorizedClient.getClientRegistration(), ANONYMOUS_AUTHENTICATION.getName(), authorizedClient.getAccessToken(), authorizedClient.getRefreshToken());
    }

}


问:
gitlab-runner cannot POST to gitlab while using docker-compose?
I'm using docker-compose to mount a gitlab container and I want to use pipeline, so I also mount a container to use a gitlab-runner. But when I try to register the runner in my project, I've got an error.

Here is my docker-compose file:

version: "3.3"
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com'
    ports:
      - '80:80'
      - '443:443'
      - '22:22'
    volumes:
      - '${PWD}/config:/etc/gitlab'
      - '${PWD}/logs:/var/log/gitlab'
      - '${PWD}/data:/var/opt/gitlab'
    networks:
      - gitlab
  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    depends_on:
      - gitlab
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
      - '${PWD}/config-runner:/etc/gitlab-runner'
    ports:
      - '8093:8093'
    restart: unless-stopped
    networks:
      - gitlab
networks:
  gitlab:
```
<p>Now if we look at the network with <code>docker network inspect gitlab_gitlab</code> we found the two containers:</p>
<pre class="lang-json prettyprint-override"><code>[
    {
        "Name": "gitlab_gitlab",
        "Id": "f923b00bc70d1fce136094b8de604c296ad9f9a62d30e7e6188dfd6c51299ea8",
        "Created": "2022-12-28T14:54:12.840563956+01:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1a8c04bf4ca810184ef09032d393b84f0864f92406cf98081521b306ecb0e9c3": {
                "Name": "gitlab_gitlab_1",
                "EndpointID": "551b1a625afbc0c3e8770a7e2b2375fc81ce9e85f75fbde0612ff879a651995f",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            },
            "e5e114d027357b56304e83f41e759b5018abcf2f3f81a28def96e8c551c0d844": {
                "Name": "gitlab_gitlab-runner_1",
                "EndpointID": "cfbb83d54604f132e7b207b0ea2b146a697dd6b12b2ad1a3324b9d23e066ac45",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "gitlab",
            "com.docker.compose.project": "gitlab",
            "com.docker.compose.version": "1.29.2"
        }
    }
]

</code>```

And yet, when I try to register the runner with this command:

sudo docker run gitlab/gitlab-runner:latest register \
  --non-interactive \
  --url "http://172.20.0.2/" \
  --registration-token "GR1348941HqsxXDy2T_TRyqAvqJKy" \
  --executor "shell" \
  --docker-image alpine:latest \
  --description "shell-runner" \
  --maintenance-note "nothing to declare" \
  --tag-list "shell,golang" \
  --run-untagged="true" \
  --locked="false" \
  --access-level="not_protected"
```
<p>I've got this error :</p>
<pre class="lang-bash prettyprint-override"><code>v@dev:~/docker/gitlab$ bash register.sh
Runtime platform                                    arch=amd64 os=linux pid=7 revision=6d480948 version=15.7.1
Running in system-mode.

WARNING: Support for registration tokens and runner parameters in the 'register' command has been deprecated in GitLab Runner 15.6 and will be replaced with support for authentication tokens. For more information, see https://gitlab.com/gitlab-org/gitlab/-/issues/380872

ERROR: Registering runner... failed                 runner=GR1348941HqsxXDy2 status=couldn't execute POST against http://172.20.0.2/api/v4/runners: Post "http://172.20.0.2/api/v4/runners": dial tcp 172.20.0.2:80: i/o timeout
PANIC: Failed to register the runner.
</code>```

Yet, when I connect to the 172.20.0.2 or http://gitlab.example.com I've got my gitlab instance, any idea how I can solve this problem ?

EDIT:

I just try by installing gitlab-runner on my computer, and it works. So the problem comes from the docker network if I understand well, but I still have no idea of what happens.

Body:
I'm using docker-compose to mount a gitlab container and I want to use pipeline, so I also mount a container to use a gitlab-runner. But when I try to register the runner in my project, I've got an error.

Here is my docker-compose file:

version: "3.3"
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com'
    ports:
      - '80:80'
      - '443:443'
      - '22:22'
    volumes:
      - '${PWD}/config:/etc/gitlab'
      - '${PWD}/logs:/var/log/gitlab'
      - '${PWD}/data:/var/opt/gitlab'
    networks:
      - gitlab
  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    depends_on:
      - gitlab
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
      - '${PWD}/config-runner:/etc/gitlab-runner'
    ports:
      - '8093:8093'
    restart: unless-stopped
    networks:
      - gitlab
networks:
  gitlab:

Now if we look at the network with docker network inspect gitlab_gitlab we found the two containers:

[
    {
        "Name": "gitlab_gitlab",
        "Id": "f923b00bc70d1fce136094b8de604c296ad9f9a62d30e7e6188dfd6c51299ea8",
        "Created": "2022-12-28T14:54:12.840563956+01:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1a8c04bf4ca810184ef09032d393b84f0864f92406cf98081521b306ecb0e9c3": {
                "Name": "gitlab_gitlab_1",
                "EndpointID": "551b1a625afbc0c3e8770a7e2b2375fc81ce9e85f75fbde0612ff879a651995f",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            },
            "e5e114d027357b56304e83f41e759b5018abcf2f3f81a28def96e8c551c0d844": {
                "Name": "gitlab_gitlab-runner_1",
                "EndpointID": "cfbb83d54604f132e7b207b0ea2b146a697dd6b12b2ad1a3324b9d23e066ac45",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "gitlab",
            "com.docker.compose.project": "gitlab",
            "com.docker.compose.version": "1.29.2"
        }
    }
]

And yet, when I try to register the runner with this command:

sudo docker run gitlab/gitlab-runner:latest register \
  --non-interactive \
  --url "http://172.20.0.2/" \
  --registration-token "GR1348941HqsxXDy2T_TRyqAvqJKy" \
  --executor "shell" \
  --docker-image alpine:latest \
  --description "shell-runner" \
  --maintenance-note "nothing to declare" \
  --tag-list "shell,golang" \
  --run-untagged="true" \
  --locked="false" \
  --access-level="not_protected"

I've got this error :

v@dev:~/docker/gitlab$ bash register.sh
Runtime platform                                    arch=amd64 os=linux pid=7 revision=6d480948 version=15.7.1
Running in system-mode.

WARNING: Support for registration tokens and runner parameters in the 'register' command has been deprecated in GitLab Runner 15.6 and will be replaced with support for authentication tokens. For more information, see https://gitlab.com/gitlab-org/gitlab/-/issues/380872

ERROR: Registering runner... failed                 runner=GR1348941HqsxXDy2 status=couldn't execute POST against http://172.20.0.2/api/v4/runners: Post "http://172.20.0.2/api/v4/runners": dial tcp 172.20.0.2:80: i/o timeout
PANIC: Failed to register the runner.

Yet, when I connect to the 172.20.0.2 or http://gitlab.example.com I've got my gitlab instance, any idea how I can solve this problem ?

EDIT:

I just try by installing gitlab-runner on my computer, and it works. So the problem comes from the docker network if I understand well, but I still have no idea of what happens.


问:
Complete integration of Open Street Map for Android in a Fragment using Kotlin
As I said in the title, I have many problems about the fully integration in my Android Kotlin of Open Street Map (osmdroid).
I have already created an Activity version that works correctly but, when I try to migrate the code into a Fragment version it doesn't work. The dependencies were correctly added and the permissions have been declared.

```<code>class MainActivity : AppCompatActivity() {
    private val REQUEST_PERMISSIONS_REQUEST_CODE = 1
    private lateinit var map : MapView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this))
        setContentView(R.layout.activity_main)

        map = findViewById<MapView>(R.id.mapid)
        map.setTileSource(TileSourceFactory.MAPNIK)

        val mapController = map.controller
        mapController.setZoom(9.5)
        val startPoint = GeoPoint(48.8583, 2.2944)
        mapController.setCenter(startPoint)
    }

    override fun onResume() {
        super.onResume()
        map.onResume()
    }

    override fun onPause() {
        super.onPause()
        map.onPause()
    }
}
</code>```

I hope that someone will help me because I honestly do not know where to look at. Thank you

In The Activity version, in the end I obtain a map with the coordinates inserted in the center of the screen while, in the Fragment version, I get multiple world maps in the same screen.

Body:
As I said in the title, I have many problems about the fully integration in my Android Kotlin of Open Street Map (osmdroid).
I have already created an Activity version that works correctly but, when I try to migrate the code into a Fragment version it doesn't work. The dependencies were correctly added and the permissions have been declared.

class MainActivity : AppCompatActivity() {
    private val REQUEST_PERMISSIONS_REQUEST_CODE = 1
    private lateinit var map : MapView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this))
        setContentView(R.layout.activity_main)

        map = findViewById<MapView>(R.id.mapid)
        map.setTileSource(TileSourceFactory.MAPNIK)

        val mapController = map.controller
        mapController.setZoom(9.5)
        val startPoint = GeoPoint(48.8583, 2.2944)
        mapController.setCenter(startPoint)
    }

    override fun onResume() {
        super.onResume()
        map.onResume()
    }

    override fun onPause() {
        super.onPause()
        map.onPause()
    }
}

I hope that someone will help me because I honestly do not know where to look at. Thank you

In The Activity version, in the end I obtain a map with the coordinates inserted in the center of the screen while, in the Fragment version, I get multiple world maps in the same screen.


问:
Write dining philosopher problem without deadlock Possibility
There are three states of the philosopher: THINKING, HUNGRY, and EATING. Here there are two semaphores: Mutex and a semaphore array for the philosophers. Mutex is used such that no two philosophers may access the pickup or putdown at the same time. The array is used to control the behavior of each philosopher. But, semaphores can result in deadlock due to programming errors.
Here is my code:

```<code>    #include <pthread.h>
    #include <semaphore.h>
    #include <stdio.h>

    #define N 5
    #define THINKING 2
    #define HUNGRY 1
    #define EATING 0
    #define LEFT (phnum + 4) % N
    #define RIGHT (phnum + 1) % N

    int state[N];
    int phil[N] = { 0, 1, 2, 3, 4 };

    sem_t mutex;
    sem_t S[N];

    void test(int phnum)
    {
        if (state[phnum] == HUNGRY
                && state[LEFT] != EATING
            && state[RIGHT] != EATING) {
            // state that eating
            state[phnum] = EATING;

            sleep(2);

            printf("Philosopher %d takes fork %d and %d\n",
                        phnum + 1, LEFT + 1, phnum + 1);

            printf("Philosopher %d is Eating\n", phnum + 1);

            // sem_post(&S[phnum]) has no effect
            // during takefork
            // used to wake up hungry philosophers
           // during putfork
            sem_post(&S[phnum]);
        }
    }

    // take up chopsticks
    void take_fork(int phnum)
     {

        sem_wait(&mutex);

        // state that hungry
        state[phnum] = HUNGRY;

        printf("Philosopher %d is Hungry\n", phnum + 1);

        // eat if neighbours are not eating
        test(phnum);

        sem_post(&mutex);

        // if unable to eat wait to be signalled
        sem_wait(&S[phnum]);

        sleep(1);
    }

    // put down chopsticks
    void put_fork(int phnum)
    {

        sem_wait(&mutex);

        // state that thinking
        state[phnum] = THINKING;

        printf("Philosopher %d putting fork %d and %d down\n",
            phnum + 1, LEFT + 1, phnum + 1);
        printf("Philosopher %d is thinking\n", phnum + 1);

        test(LEFT);
        test(RIGHT);

        sem_post(&mutex);
    }

    void* philosopher(void* num)
    {

        while (1) {

            int* i = num;

            sleep(1);

            take_fork(*i);

            sleep(0);

            put_fork(*i);
        }
    }

    int main()
    {

        int i;
        pthread_t thread_id[N];

        // initialize the semaphores
        sem_init(&mutex, 0, 1);

        for (i = 0; i < N; i++)

            sem_init(&S[i], 0, 0);

        for (i = 0; i < N; i++) {

            // create philosopher processes
             pthread_create(&thread_id[i], NULL,
                        philosopher, &phil[i]);

            printf("Philosopher %d is thinking\n", i + 1);
        }

        for (i = 0; i < N; i++)

            pthread_join(thread_id[i], NULL);
    }

</code>```

But I want to write it without Possibility of deadlock.How canI write it?

Body:
There are three states of the philosopher: THINKING, HUNGRY, and EATING. Here there are two semaphores: Mutex and a semaphore array for the philosophers. Mutex is used such that no two philosophers may access the pickup or putdown at the same time. The array is used to control the behavior of each philosopher. But, semaphores can result in deadlock due to programming errors.
Here is my code:

    #include <pthread.h>
    #include <semaphore.h>
    #include <stdio.h>

    #define N 5
    #define THINKING 2
    #define HUNGRY 1
    #define EATING 0
    #define LEFT (phnum + 4) % N
    #define RIGHT (phnum + 1) % N

    int state[N];
    int phil[N] = { 0, 1, 2, 3, 4 };

    sem_t mutex;
    sem_t S[N];

    void test(int phnum)
    {
        if (state[phnum] == HUNGRY
                && state[LEFT] != EATING
            && state[RIGHT] != EATING) {
            // state that eating
            state[phnum] = EATING;

            sleep(2);

            printf("Philosopher %d takes fork %d and %d\n",
                        phnum + 1, LEFT + 1, phnum + 1);

            printf("Philosopher %d is Eating\n", phnum + 1);

            // sem_post(&S[phnum]) has no effect
            // during takefork
            // used to wake up hungry philosophers
           // during putfork
            sem_post(&S[phnum]);
        }
    }

    // take up chopsticks
    void take_fork(int phnum)
     {

        sem_wait(&mutex);

        // state that hungry
        state[phnum] = HUNGRY;

        printf("Philosopher %d is Hungry\n", phnum + 1);

        // eat if neighbours are not eating
        test(phnum);

        sem_post(&mutex);

        // if unable to eat wait to be signalled
        sem_wait(&S[phnum]);

        sleep(1);
    }

    // put down chopsticks
    void put_fork(int phnum)
    {

        sem_wait(&mutex);

        // state that thinking
        state[phnum] = THINKING;

        printf("Philosopher %d putting fork %d and %d down\n",
            phnum + 1, LEFT + 1, phnum + 1);
        printf("Philosopher %d is thinking\n", phnum + 1);

        test(LEFT);
        test(RIGHT);

        sem_post(&mutex);
    }

    void* philosopher(void* num)
    {

        while (1) {

            int* i = num;

            sleep(1);

            take_fork(*i);

            sleep(0);

            put_fork(*i);
        }
    }

    int main()
    {

        int i;
        pthread_t thread_id[N];

        // initialize the semaphores
        sem_init(&mutex, 0, 1);

        for (i = 0; i < N; i++)

            sem_init(&S[i], 0, 0);

        for (i = 0; i < N; i++) {

            // create philosopher processes
             pthread_create(&thread_id[i], NULL,
                        philosopher, &phil[i]);

            printf("Philosopher %d is thinking\n", i + 1);
        }

        for (i = 0; i < N; i++)

            pthread_join(thread_id[i], NULL);
    }

But I want to write it without Possibility of deadlock.How canI write it?


问:
Why my QR code generated in C# for an UWP application can`t be read only on ARM applications?
I have C# code that generates a QR code on UWP, using ZXing library. The QR code works well, but specifically on ARM computers, it is not readable. The image is generated but can't be read by the camera (any link open, the QR Code seems to be not completely formed). I tried to use QRCoder library too, and same thing occurred. Someone know some way to fix it?
Note: in debug mode, qr code works good in ARM, only in release it is not readable.
I tested it with 2 different ARM computers with different screen types, tried to generate different QR codes too.
Images attached.

My code for generate qr code:

```<code>        options.Hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        BarcodeWriter writer = new BarcodeWriter();
        writer.Format = BarcodeFormat.QR_CODE;
        writer.Options = options;

        BitMatrix input = writer.Encode(text);

        SoftwareBitmap bitmap = GetQRCodeBitmap(QrCodeSize, QrCodeSize, input);
        SoftwareBitmapSource imageSource = new SoftwareBitmapSource();
        await imageSource.SetBitmapAsync(bitmap);
        QRCodeImage = imageSource;
</code>```

QR Code readable image

QR Code not readable

Body:
I have C# code that generates a QR code on UWP, using ZXing library. The QR code works well, but specifically on ARM computers, it is not readable. The image is generated but can't be read by the camera (any link open, the QR Code seems to be not completely formed). I tried to use QRCoder library too, and same thing occurred. Someone know some way to fix it?
Note: in debug mode, qr code works good in ARM, only in release it is not readable.
I tested it with 2 different ARM computers with different screen types, tried to generate different QR codes too.
Images attached.

My code for generate qr code:

        options.Hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        BarcodeWriter writer = new BarcodeWriter();
        writer.Format = BarcodeFormat.QR_CODE;
        writer.Options = options;

        BitMatrix input = writer.Encode(text);

        SoftwareBitmap bitmap = GetQRCodeBitmap(QrCodeSize, QrCodeSize, input);
        SoftwareBitmapSource imageSource = new SoftwareBitmapSource();
        await imageSource.SetBitmapAsync(bitmap);
        QRCodeImage = imageSource;

QR Code readable image

QR Code not readable


问:
'Sequential' object has no attribute 'model'
I was trying to run Integrated Gradients as implemented here but unfortunately I get 'Sequential' object has no attribute 'model'.

My model is:

```<code>def nn_model():
    learning_rate = 0.001
    model = Sequential()
    model.add(Input(shape=(X1.shape[1],)))
    model.add(Dense(units=100,activation='LeakyReLU'))
    model.add(Dropout(0.01))
    model.add(Dense(units=50,activation='LeakyReLU'))
    model.add(Dropout(0.01))
    model.add(Dense(units=25,activation='LeakyReLU'))
    model.add(Dropout(0.01))
    model.add(Dense(units=1,activation='LeakyReLU'))
    # compile model
    model.compile(loss='mae', optimizer=optimizers.Adam(learning_rate=learning_rate), metrics=['mae'])
    return model

final_nn_model = nn_model()

# fit network
history = final_nn_model.fit(X1, y1, batch_size=10, epochs=500, shuffle=True, verbose=1)
</code>```

The line that raises the error is:

```<code>if isinstance(model, Sequential):
---> 35     self.model = model.model
     36 elif isinstance(model, Model):
     37     self.model = model
</code>```

If .model is deprecated, what should I use instead?

Body:
I was trying to run Integrated Gradients as implemented here but unfortunately I get 'Sequential' object has no attribute 'model'.

My model is:

def nn_model():
    learning_rate = 0.001
    model = Sequential()
    model.add(Input(shape=(X1.shape[1],)))
    model.add(Dense(units=100,activation='LeakyReLU'))
    model.add(Dropout(0.01))
    model.add(Dense(units=50,activation='LeakyReLU'))
    model.add(Dropout(0.01))
    model.add(Dense(units=25,activation='LeakyReLU'))
    model.add(Dropout(0.01))
    model.add(Dense(units=1,activation='LeakyReLU'))
    # compile model
    model.compile(loss='mae', optimizer=optimizers.Adam(learning_rate=learning_rate), metrics=['mae'])
    return model

final_nn_model = nn_model()

# fit network
history = final_nn_model.fit(X1, y1, batch_size=10, epochs=500, shuffle=True, verbose=1)

The line that raises the error is:

if isinstance(model, Sequential):
---> 35     self.model = model.model
     36 elif isinstance(model, Model):
     37     self.model = model

If .model is deprecated, what should I use instead?


问:
Python script for changing math delimiters in markdown documents not working as intended
I am writing a script that takes a markdown document containing inline and block equations delimited by $...$ and $$...$$ respectively, and since the dollars are deprecated as math delimiters, I am trying to change them to \(...\) and \[...\] respectively. This is my script:

```<code>import os
import re

# Set the path to the folder containing the markdown documents
folder_path = os.path.join(os.path.dirname(__file__), path_to_folder)

with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "r", encoding="utf-8") as f:
    text = f.read()

# Find all equations regex
all_equations_regex = "\$(.+?)\$+"

# Find multiline equations regex
multiline_equations_regex = "\${2}(.+?)\$+"

equations = re.findall(all_equations_regex, text)
multiline_equations = re.findall(multiline_equations_regex, text)
inline_equations = list(set(equations)-set(["$"+equation for equation in multiline_equations]))
print(inline_equations)
print(multiline_equations)
print(equations)

# Replace the inline equations with \(...\)
for equation in inline_equations:
    text = re.sub(r"\$" + re.escape(equation) + r"\$", r"\\(" + re.escape(equation) + r"\\)", text)

# Replace the multiline equations with \[...\]
for equation in multiline_equations:
    text = re.sub(r"\$\$" + re.escape(equation) + r"\$\$", r"\\[" + re.escape(equation) + r"\\]", text)

# Write the modified text to the same file
with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "w", encoding="utf-8") as f:
    f.write(text)
</code>```

What I am essentially doing is taking the raw text from the markdown document and using regular expressions to find inline and block equations and separate them into two lists. That way I can use re.sub() to change the delimiters. The script works without any errors but the final changes made to the markdown document mess up the equations. The markdown text I am using as a test is:

```<code># $V_1$ y $V_2$ en función de $\Gamma_j$

Podemos expresar las matrices $V_1$ y $V_2$ en función de las [matrices Gamma generales](matrices_gamma_generales.md). Para ello, tomamos las [matrices $V_1$ y $V_2$ en términos de matrices de pauli en bloque](V1_V2_en_funcion_de_Pauli.md) y sustituimos por matrices gamma. Así tenemos $$V_1=(2\sinh2J)^{N/2}\prod_{j=1}^N\exp(-i\theta\Gamma_j\Gamma_{j+N})$$ $$V_2=\prod_{j=1}^N\exp(-iJ\Gamma_{j+N}\Gamma_{j+1})$$
</code>```

I only care about the equations. The change happens without a problem for the inline equations, but as you can see, the block equations are quite more elaborate and their content gets messed up. If I run the script, the text changes in the following manner:

```<code># \(V_1\) y \(V_2\) en función de \(\Gamma_j\)

Podemos expresar las matrices \(V_1\) y \(V_2\) en función de las [matrices Gamma generales](matrices_gamma_generales.md). Para ello, tomamos las [matrices \(V_1\) y \(V_2\) en términos de matrices de pauli en bloque](V1_V2_en_funcion_de_Pauli.md) y sustituimos por matrices gamma. Así tenemos \[V_1=\(2\sinh2J\)\^\{N/2\}\prod_\{j=1\}\^N\exp\(\-i\theta\Gamma_j\Gamma_\{j\+N\}\)\] \[V_2=\prod_\{j=1\}\^N\exp\(\-iJ\Gamma_\{j\+N\}\Gamma_\{j\+1\}\)\]
</code>```

A backslash \ appears in front of a bunch of characters

I am aware that using re.escape() inside the strings of re.sub() is kind of a no go. If I then change the code so I don't have the re.escape() inside the re.sub():

```<code>import os
import re

# Set the path to the folder containing the markdown documents
folder_path = os.path.join(os.path.dirname(__file__), r"C:\Users\Juan\Documents\GitHub\PKB\docs")

with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "r", encoding="utf-8") as f:
    text = f.read()

# Find all equations regex
all_equations_regex = "\$(.+?)\$+"

# Find multiline equations regex
multiline_equations_regex = "\${2}(.+?)\$+"

equations = re.findall(all_equations_regex, text)
multiline_equations = re.findall(multiline_equations_regex, text)
inline_equations = list(set(equations)-set(["$"+equation for equation in multiline_equations]))
print(inline_equations)
print(multiline_equations)
print(equations)

# Replace the inline equations with \(...\)
for equation in inline_equations:
    text = re.sub(r"\$" + equation + r"\$", r"\\(" + equation + r"\\)", text)

# Replace the multiline equations with \[...\]
for equation in multiline_equations:
    text = re.sub(r"\$\$" + equation + r"\$\$", r"\\[" + equation + r"\\]", text)

# Write the modified text to the same file
with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "w", encoding="utf-8") as f:
    f.write(text)
</code>```

I get an error which reads:

```<code>Traceback (most recent call last):
  File "c:/Users/Juan/Documents/GitHub/PKB/PKM/Python/scripts/test.py", line 25, in <module>
    text = re.sub(r"\$" + equation + r"\$", r"\\(" + equation + r"\\)", text)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\re.py", line 210, in sub
    return _compile(pattern, flags).sub(repl, string, count)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\re.py", line 304, in _compile
    p = sre_compile.compile(pattern, flags)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_compile.py", line 764, in compile
    p = sre_parse.parse(p, flags)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 948, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 443, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 525, in _parse
    code = _escape(source, this, state)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 426, in _escape
    raise source.error("bad escape %s" % escape, len(escape))
re.error: bad escape \G at position 2
</code>```

Which I guess it means that my original equations contain protected characters for the regular expressions module. That is the reason I am escaping the equation in the re.sub() method, but that method has the problem shown before this one. Is there any quick way to fix this? or should I try to change the whole script so I don't need to use the re.sub() method, so I can pass the equation string without raising a bad escape error? Also any advice on how to write a script that works as intended is welcome. The content of the equations should remain unchanged, but the delimiters should change

Body:
I am writing a script that takes a markdown document containing inline and block equations delimited by $...$ and $$...$$ respectively, and since the dollars are deprecated as math delimiters, I am trying to change them to \(...\) and \[...\] respectively. This is my script:

import os
import re

# Set the path to the folder containing the markdown documents
folder_path = os.path.join(os.path.dirname(__file__), path_to_folder)

with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "r", encoding="utf-8") as f:
    text = f.read()

# Find all equations regex
all_equations_regex = "\$(.+?)\$+"

# Find multiline equations regex
multiline_equations_regex = "\${2}(.+?)\$+"

equations = re.findall(all_equations_regex, text)
multiline_equations = re.findall(multiline_equations_regex, text)
inline_equations = list(set(equations)-set(["$"+equation for equation in multiline_equations]))
print(inline_equations)
print(multiline_equations)
print(equations)

# Replace the inline equations with \(...\)
for equation in inline_equations:
    text = re.sub(r"\$" + re.escape(equation) + r"\$", r"\\(" + re.escape(equation) + r"\\)", text)

# Replace the multiline equations with \[...\]
for equation in multiline_equations:
    text = re.sub(r"\$\$" + re.escape(equation) + r"\$\$", r"\\[" + re.escape(equation) + r"\\]", text)

# Write the modified text to the same file
with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "w", encoding="utf-8") as f:
    f.write(text)

What I am essentially doing is taking the raw text from the markdown document and using regular expressions to find inline and block equations and separate them into two lists. That way I can use re.sub() to change the delimiters. The script works without any errors but the final changes made to the markdown document mess up the equations. The markdown text I am using as a test is:

# $V_1$ y $V_2$ en función de $\Gamma_j$

Podemos expresar las matrices $V_1$ y $V_2$ en función de las [matrices Gamma generales](matrices_gamma_generales.md). Para ello, tomamos las [matrices $V_1$ y $V_2$ en términos de matrices de pauli en bloque](V1_V2_en_funcion_de_Pauli.md) y sustituimos por matrices gamma. Así tenemos $$V_1=(2\sinh2J)^{N/2}\prod_{j=1}^N\exp(-i\theta\Gamma_j\Gamma_{j+N})$$ $$V_2=\prod_{j=1}^N\exp(-iJ\Gamma_{j+N}\Gamma_{j+1})$$

I only care about the equations. The change happens without a problem for the inline equations, but as you can see, the block equations are quite more elaborate and their content gets messed up. If I run the script, the text changes in the following manner:

# \(V_1\) y \(V_2\) en función de \(\Gamma_j\)

Podemos expresar las matrices \(V_1\) y \(V_2\) en función de las [matrices Gamma generales](matrices_gamma_generales.md). Para ello, tomamos las [matrices \(V_1\) y \(V_2\) en términos de matrices de pauli en bloque](V1_V2_en_funcion_de_Pauli.md) y sustituimos por matrices gamma. Así tenemos \[V_1=\(2\sinh2J\)\^\{N/2\}\prod_\{j=1\}\^N\exp\(\-i\theta\Gamma_j\Gamma_\{j\+N\}\)\] \[V_2=\prod_\{j=1\}\^N\exp\(\-iJ\Gamma_\{j\+N\}\Gamma_\{j\+1\}\)\]

A backslash \ appears in front of a bunch of characters

I am aware that using re.escape() inside the strings of re.sub() is kind of a no go. If I then change the code so I don't have the re.escape() inside the re.sub():

import os
import re

# Set the path to the folder containing the markdown documents
folder_path = os.path.join(os.path.dirname(__file__), r"C:\Users\Juan\Documents\GitHub\PKB\docs")

with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "r", encoding="utf-8") as f:
    text = f.read()

# Find all equations regex
all_equations_regex = "\$(.+?)\$+"

# Find multiline equations regex
multiline_equations_regex = "\${2}(.+?)\$+"

equations = re.findall(all_equations_regex, text)
multiline_equations = re.findall(multiline_equations_regex, text)
inline_equations = list(set(equations)-set(["$"+equation for equation in multiline_equations]))
print(inline_equations)
print(multiline_equations)
print(equations)

# Replace the inline equations with \(...\)
for equation in inline_equations:
    text = re.sub(r"\$" + equation + r"\$", r"\\(" + equation + r"\\)", text)

# Replace the multiline equations with \[...\]
for equation in multiline_equations:
    text = re.sub(r"\$\$" + equation + r"\$\$", r"\\[" + equation + r"\\]", text)

# Write the modified text to the same file
with open(os.path.join(folder_path, "V1_V2_Gamma.md"), "w", encoding="utf-8") as f:
    f.write(text)

I get an error which reads:

Traceback (most recent call last):
  File "c:/Users/Juan/Documents/GitHub/PKB/PKM/Python/scripts/test.py", line 25, in <module>
    text = re.sub(r"\$" + equation + r"\$", r"\\(" + equation + r"\\)", text)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\re.py", line 210, in sub
    return _compile(pattern, flags).sub(repl, string, count)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\re.py", line 304, in _compile
    p = sre_compile.compile(pattern, flags)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_compile.py", line 764, in compile
    p = sre_parse.parse(p, flags)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 948, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 443, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 525, in _parse
    code = _escape(source, this, state)
  File "C:\Users\Juan\AppData\Local\Programs\Python\Python38\lib\sre_parse.py", line 426, in _escape
    raise source.error("bad escape %s" % escape, len(escape))
re.error: bad escape \G at position 2

Which I guess it means that my original equations contain protected characters for the regular expressions module. That is the reason I am escaping the equation in the re.sub() method, but that method has the problem shown before this one. Is there any quick way to fix this? or should I try to change the whole script so I don't need to use the re.sub() method, so I can pass the equation string without raising a bad escape error? Also any advice on how to write a script that works as intended is welcome. The content of the equations should remain unchanged, but the delimiters should change


问:
Why are my dates disappearing when converting them to a date.time object and not merging correctly?
This is one problem of two that I am having. My merge method works fine when I prepare the files by hand, but not when I import it from my client_formatter function. What is also stumping me is relating to my title -- why am I losing the DateOfBirth & HireDate values when I set it to datetime? Date time remains intact for ef_in, but not ul_in. The reason I am converting it in the first place is because my ef_in comes in as a DateTime [NS] objects. I have attached the code here for my merger function:

```<code>def client_merge(ef_in, ul_in):
    pd.set_option('mode.chained_assignment', None)

    ef_in['UniqueID'] = ef_in['UniqueID'].astype(object)
    ef_in['ZipCode'] = ef_in['ZipCode'].astype(object)
    ul_in['UniqueID'] = ul_in['UniqueID'].astype(object)
    ul_in['Action'] = ul_in['Action'].astype(object)
    ul_in['ZipCode'] = ul_in['ZipCode'].astype(object)
    ul_in['HireDate'] = pd.to_datetime(ul_in['HireDate'], errors='coerce', format='%m%d%Y')
    ul_in['DateOfBirth'] = pd.to_datetime(ul_in['DateOfBirth'], errors='coerce', format='%m%d%Y')
    ef_in['HireDate'] = pd.to_datetime(ef_in['HireDate'], errors='coerce', format='%m%d%Y')
    ef_in['DateOfBirth'] = pd.to_datetime(ef_in['DateOfBirth'], errors='coerce', format='%m%d%Y')

    df = pd.concat(([ef_in, ul_in]), axis=0, ignore_index=True, sort=False)
    df.drop_duplicates(subset=['UniqueID'], keep=False, inplace=True)

    new_users = df.merge(ef_in)
    disable_users = df.merge(ul_in)

    disable_users['Action'].fillna('Disable', inplace=True)
    ready_to_print_file = pd.concat([new_users, disable_users], ignore_index=False)

    rtpf1 = ready_to_print_file[ready_to_print_file["FirstName"].str.contains("redactedinfo") == False]
    rtpf2 = rtpf1[rtpf1["FirstName"].str.contains("Clarks") == False]
    rtpf3 = rtpf2[rtpf2["FirstName"].str.contains("Test") == False]

    rtpf3.to_csv(path, header=True, index=False)
</code>```

I have attached the root code that the ul_in is coming from as well here:

```<code>
def rotate_date(strg, n):
    return strg[n:] + strg[:n]

def client_formatter_noprint(input_file):
    pd.set_option('mode.chained_assignment', None)
    input_file = pd.read_csv(input_file, sep=',',
                             dtype={'HIREDATE': str, 'DATE OF BIRTH': str})

    df = input_file[['LAST NAME', 'FIRST AND MIDDLE', 'DATE OF BIRTH', 'GENDER', 'RELATIONSHIP',
                     'HIREDATE', 'ZIP', 'ALT ID', 'EMAIL ADDRESS']]

    df = df.drop(df[df['RELATIONSHIP'] != 'E'].index)

    df = df.drop(['RELATIONSHIP'], axis=1)

    p = -1
    hdf = []
    for _ in (df['HIREDATE']):
        p = (p + len(df['HIREDATE']) - (len(df['HIREDATE']) - 1))
        hd = df['HIREDATE'].iloc[p]
        f = rotate_date(hd, -4)
        hdf.append(f)

    q = -1
    ddf = []
    for _ in (df['DATE OF BIRTH']):
        q = (q + len(df['DATE OF BIRTH']) - (len(df['DATE OF BIRTH']) - 1))
        dob = df['DATE OF BIRTH'].iloc[q]
        f = rotate_date(dob, -4)
        ddf.append(f)

    df['HIREDATE'] = hdf

    df['DATE OF BIRTH'] = ddf

    df['DATE OF BIRTH'] = pd.to_datetime(df['DATE OF BIRTH'], errors='coerce', format='%m%d%Y')

    df['HIREDATE'] = pd.to_datetime(df['HIREDATE'], errors='coerce', format='%m%d%Y')

    df.rename(columns={'HIREDATE': 'HireDate', 'LAST NAME': 'LastName', 'FIRST AND MIDDLE': 'FirstName',
                       'DATE OF BIRTH': 'DateOfBirth', 'ALT ID': 'UniqueID', 'GENDER': 'Gender',
                       'ZIP': 'ZipCode', 'EMAIL ADDRESS': 'Email'}, inplace=True)

    df['Region'] = pd.Series(dtype=str)
    df['Role'] = pd.Series(dtype=str)
    df['Company'] = pd.Series(dtype=str)
    df['Action'] = pd.Series(dtype=str)

    df = df.reindex(columns=['FirstName', 'LastName', 'Region', 'UniqueID', 'DateOfBirth', 'Gender', 'ZipCode', 'Email',
                             'Role', 'HireDate', 'Company', 'Action'])

    df['Company'].fillna('privateinfo', inplace=True)
    df['Role'].fillna('Employee On Plan', inplace=True)

    return df
</code>```

I am trying to merge these files so that new users from the ef_in are singled out, and old users from the ul_in are singled out, and then put together for a monthly user upload I do for my health data job. I apologize for the ugliness, I built the Client formatter a long time ago when I was even more new than I already am.

Body:
This is one problem of two that I am having. My merge method works fine when I prepare the files by hand, but not when I import it from my client_formatter function. What is also stumping me is relating to my title -- why am I losing the DateOfBirth & HireDate values when I set it to datetime? Date time remains intact for ef_in, but not ul_in. The reason I am converting it in the first place is because my ef_in comes in as a DateTime [NS] objects. I have attached the code here for my merger function:

def client_merge(ef_in, ul_in):
    pd.set_option('mode.chained_assignment', None)

    ef_in['UniqueID'] = ef_in['UniqueID'].astype(object)
    ef_in['ZipCode'] = ef_in['ZipCode'].astype(object)
    ul_in['UniqueID'] = ul_in['UniqueID'].astype(object)
    ul_in['Action'] = ul_in['Action'].astype(object)
    ul_in['ZipCode'] = ul_in['ZipCode'].astype(object)
    ul_in['HireDate'] = pd.to_datetime(ul_in['HireDate'], errors='coerce', format='%m%d%Y')
    ul_in['DateOfBirth'] = pd.to_datetime(ul_in['DateOfBirth'], errors='coerce', format='%m%d%Y')
    ef_in['HireDate'] = pd.to_datetime(ef_in['HireDate'], errors='coerce', format='%m%d%Y')
    ef_in['DateOfBirth'] = pd.to_datetime(ef_in['DateOfBirth'], errors='coerce', format='%m%d%Y')

    df = pd.concat(([ef_in, ul_in]), axis=0, ignore_index=True, sort=False)
    df.drop_duplicates(subset=['UniqueID'], keep=False, inplace=True)

    new_users = df.merge(ef_in)
    disable_users = df.merge(ul_in)

    disable_users['Action'].fillna('Disable', inplace=True)
    ready_to_print_file = pd.concat([new_users, disable_users], ignore_index=False)

    rtpf1 = ready_to_print_file[ready_to_print_file["FirstName"].str.contains("redactedinfo") == False]
    rtpf2 = rtpf1[rtpf1["FirstName"].str.contains("Clarks") == False]
    rtpf3 = rtpf2[rtpf2["FirstName"].str.contains("Test") == False]

    rtpf3.to_csv(path, header=True, index=False)

I have attached the root code that the ul_in is coming from as well here:

def rotate_date(strg, n):
    return strg[n:] + strg[:n]

def client_formatter_noprint(input_file):
    pd.set_option('mode.chained_assignment', None)
    input_file = pd.read_csv(input_file, sep=',',
                             dtype={'HIREDATE': str, 'DATE OF BIRTH': str})

    df = input_file[['LAST NAME', 'FIRST AND MIDDLE', 'DATE OF BIRTH', 'GENDER', 'RELATIONSHIP',
                     'HIREDATE', 'ZIP', 'ALT ID', 'EMAIL ADDRESS']]

    df = df.drop(df[df['RELATIONSHIP'] != 'E'].index)

    df = df.drop(['RELATIONSHIP'], axis=1)

    p = -1
    hdf = []
    for _ in (df['HIREDATE']):
        p = (p + len(df['HIREDATE']) - (len(df['HIREDATE']) - 1))
        hd = df['HIREDATE'].iloc[p]
        f = rotate_date(hd, -4)
        hdf.append(f)

    q = -1
    ddf = []
    for _ in (df['DATE OF BIRTH']):
        q = (q + len(df['DATE OF BIRTH']) - (len(df['DATE OF BIRTH']) - 1))
        dob = df['DATE OF BIRTH'].iloc[q]
        f = rotate_date(dob, -4)
        ddf.append(f)

    df['HIREDATE'] = hdf

    df['DATE OF BIRTH'] = ddf

    df['DATE OF BIRTH'] = pd.to_datetime(df['DATE OF BIRTH'], errors='coerce', format='%m%d%Y')

    df['HIREDATE'] = pd.to_datetime(df['HIREDATE'], errors='coerce', format='%m%d%Y')

    df.rename(columns={'HIREDATE': 'HireDate', 'LAST NAME': 'LastName', 'FIRST AND MIDDLE': 'FirstName',
                       'DATE OF BIRTH': 'DateOfBirth', 'ALT ID': 'UniqueID', 'GENDER': 'Gender',
                       'ZIP': 'ZipCode', 'EMAIL ADDRESS': 'Email'}, inplace=True)

    df['Region'] = pd.Series(dtype=str)
    df['Role'] = pd.Series(dtype=str)
    df['Company'] = pd.Series(dtype=str)
    df['Action'] = pd.Series(dtype=str)

    df = df.reindex(columns=['FirstName', 'LastName', 'Region', 'UniqueID', 'DateOfBirth', 'Gender', 'ZipCode', 'Email',
                             'Role', 'HireDate', 'Company', 'Action'])

    df['Company'].fillna('privateinfo', inplace=True)
    df['Role'].fillna('Employee On Plan', inplace=True)

    return df

I am trying to merge these files so that new users from the ef_in are singled out, and old users from the ul_in are singled out, and then put together for a monthly user upload I do for my health data job. I apologize for the ugliness, I built the Client formatter a long time ago when I was even more new than I already am.


问:
How to convert a comma separated string into json array using MySQL and Go
I have a table named Product with a JSON column called data. Inside data there is a property called formerIds, which is a comma separated list stored as string.

{
    "formerIds": "12345,54321,09876"
}
```
<p>The ids are previous ids of a product. I want to be able to search for any of those ids quickly. My idea is to convert the comma separated list of ids into a json array and create a multi-valued index in MySQL. So as an example, look at the following</p>
<pre class="lang-sql prettyprint-override"><code>CREATE TABLE Product (
    productId VARCHAR(200) NOT NULL PRIMARY KEY,
    data NOT NULL JSON,
    ...
    formerIds JSON GENERATED ALWAYS AS (JSON_OBJECT('ids', CAST(CONCAT('["', REPLACE(data->>'$.formerIds', ',', '","'), '"]') AS JSON))),
    INDEX product_formerIds_idx (CAST(formerIds->'$.ids' AS CHAR(255) ARRAY))
);
</code>```

This is working fine. The only problem is, that I want to use Golang and GORM to implement it. Here's what I've done so far.

type Product struct {
    ProductId string         `gorm:"column:productId;index;primaryKey"`
    Data      datatypes.JSON `gorm:"column:data"`
    FormerIds JSON           `gorm:"column:formerIds;index:,expression:CAST(formerIds->'$.ids' AS CHAR(255) ARRAY);type:JSON GENERATED ALWAYS AS (JSON_OBJECT('ids', CAST(CONCAT('["', REPLACE(data->>'$.formerIds', ',', '","'), '"]') AS JSON)))"`
}
```

The problem lies in the structure tags of Product, because I want to use double quotes inside the tag value itself to convert the comma separated list into a json array using CONCAT and REPLACE. I've already tried to escape those quotes, but I can't get it run.

In my opinion, I could solve it by...

... don't use GORM and it's migration mechanism, but my own predefined statements to create and maintain the tables,

... somehow escaping the quotes in the structure tags,

... using other SQL statements for the string conversion to prevent using double quotes in structure tags.

Do you have any other ideas or solutions? I've already tried to use SUBSTRING_INDEX and JSON_ARRAYAGG instead of CONCAT and REPLACE for the virtual column, but row aggregation is not working there.

Body:
I have a table named Product with a JSON column called data. Inside data there is a property called formerIds, which is a comma separated list stored as string.

{
    "formerIds": "12345,54321,09876"
}

The ids are previous ids of a product. I want to be able to search for any of those ids quickly. My idea is to convert the comma separated list of ids into a json array and create a multi-valued index in MySQL. So as an example, look at the following

CREATE TABLE Product (
    productId VARCHAR(200) NOT NULL PRIMARY KEY,
    data NOT NULL JSON,
    ...
    formerIds JSON GENERATED ALWAYS AS (JSON_OBJECT('ids', CAST(CONCAT('["', REPLACE(data->>'$.formerIds', ',', '","'), '"]') AS JSON))),
    INDEX product_formerIds_idx (CAST(formerIds->'$.ids' AS CHAR(255) ARRAY))
);

This is working fine. The only problem is, that I want to use Golang and GORM to implement it. Here's what I've done so far.

type Product struct {
    ProductId string         `gorm:"column:productId;index;primaryKey"`
    Data      datatypes.JSON `gorm:"column:data"`
    FormerIds JSON           `gorm:"column:formerIds;index:,expression:CAST(formerIds->'$.ids' AS CHAR(255) ARRAY);type:JSON GENERATED ALWAYS AS (JSON_OBJECT('ids', CAST(CONCAT('["', REPLACE(data->>'$.formerIds', ',', '","'), '"]') AS JSON)))"`
}

The problem lies in the structure tags of Product, because I want to use double quotes inside the tag value itself to convert the comma separated list into a json array using CONCAT and REPLACE. I've already tried to escape those quotes, but I can't get it run.

In my opinion, I could solve it by...

... don't use GORM and it's migration mechanism, but my own predefined statements to create and maintain the tables,

... somehow escaping the quotes in the structure tags,

... using other SQL statements for the string conversion to prevent using double quotes in structure tags.

Do you have any other ideas or solutions? I've already tried to use SUBSTRING_INDEX and JSON_ARRAYAGG instead of CONCAT and REPLACE for the virtual column, but row aggregation is not working there.