brendonovich / macrograph-rs Goto Github PK
View Code? Open in Web Editor NEWNode-based programming engine written entirely in Rust
Node-based programming engine written entirely in Rust
gonna be a huge task but ultimately worth it
Helpful: https://www.figma.com/blog/how-figmas-multiplayer-technology-works/
Executing node chains by retrieving values from node pins directly works decently well, but presents issues around performance (so many Arc
s) and reliability (async nodes retrieving stale/too recent data).
When an event node is fired, create an ExecutionContext struct that is basically a map of each node in the chain to its output data. Then when a node is executed, it will use the values from that context, rather than from the node's pins directly.
When a chain is modified, whether that be addition/removal of nodes, or modification of properties, serialize the chain to JSON or something, so that knowing the nodes & connections can be done independent of the nodes themselves. This means that requests can hold on to an old chain while a new one is being updated. This has the issue of async nodes locking requests into old chains rather than going on to newer ones.
&mut self
without core requiring mutable accessAccessing engine state in node schemas is nice, but introduces a decent amount of complexity. Instead, engines should act as completely separate tasks and do all their work through message passing, both for lifecycle control and communicating with nodes. This way, state can be localized to a single task and actions can be taken based on immutable events.
pretty important tbh
Using an IO proxy for node schemas made packages unaware of the existence of nodes, which is handy since it allows for the package api to be smaller. This hasn't been done yet though.
Will be especially beneficial once #9 lands
Currently, IO is generated at runtime by a schema's build function. This presents a problem where to know what value types a node can take, we must build a node. In future, it would be nice for the node selector to allow for filtering of schemas by node IO type, but this requires knowing a node's IO in the first place.
If a package's engine wants to spawn a tokio task, whether directly with tokio::spawn
or indirectly in the case of the OBS package, a new tokio runtime must be created specific to that library, since runtimes use Thread Local Storage. This requires the entirety of tokio's core and rt features to be bundled with the package, increasing its size by a couple of megabytes.
Instead, a function on the engine's EngineContext could take an async closure and execute it in the main thread's context, and then return the value. This would require the return value to be Send (and possibly Sync, not quite sure though), but would remove the need for tokio to be bundled with packages.
Gonna be a bitch of a task with #16
Will simplify the experience of developing packages and make binaries smaller, since most of the core can be stripped out.
Current solution works fine, but will need to change in the future anyeay when nodes can have state that influences how they are built. Instead, maybe declare the IO schema on some sort of BuildContext that is provided as an argument to the build function, compare that (externally of the package api) to the existing IO schema and make adjustments as necessary
Add an IO section to ExecutionContext that contains the node's current data and buffers updates to the node's outputs. Core can then update data outputs as necessary
Idea: Separate data storage from pins entirely. Pins can still contained ArcSwapped default values, but the node's actual data can be in a hashmap. Not sure how this would work out but it's worth looking into
Similar to execute function, just set output values on an IO context
Will be super useful with arrays
BigInt and strings maybe?
error[E0026]: variant `obws::events::Event::SceneCreated` does not have a field named `scene_name`
--> packages/obs/src/engine.rs:118:44
|
118 | ... SceneCreated { scene_name, is_group } => {
| ^^^^^^^^^^
| |
| variant `obws::events::Event::SceneCreated` does not have this field
| help: `obws::events::Event::SceneCreated` has a field named `name`
error[E0027]: pattern does not mention field `name`
--> packages/obs/src/engine.rs:118:29
|
118 | ... SceneCreated { scene_name, is_group } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `name`
|
help: include the missing field in the pattern
|
118 | SceneCreated { scene_name, is_group, name } => {
| ~~~~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
118 | SceneCreated { scene_name, is_group, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneRemoved` does not have a field named `scene_name`
--> packages/obs/src/engine.rs:121:44
|
121 | ... SceneRemoved { scene_name, is_group } => {
| ^^^^^^^^^^
| |
| variant `obws::events::Event::SceneRemoved` does not have this field
| help: `obws::events::Event::SceneRemoved` has a field named `name`
error[E0027]: pattern does not mention field `name`
--> packages/obs/src/engine.rs:121:29
|
121 | ... SceneRemoved { scene_name, is_group } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `name`
|
help: include the missing field in the pattern
|
121 | SceneRemoved { scene_name, is_group, name } => {
| ~~~~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
121 | SceneRemoved { scene_name, is_group, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneNameChanged` does not have fields named `old_scene_name`, `scene_name`
--> packages/obs/src/engine.rs:124:48
|
124 | ... SceneNameChanged { old_scene_name, scene_name} => {
| ^^^^^^^^^^^^^^ ^^^^^^^^^^ variant `obws::events::Event::SceneNameChanged` does not have these fields
error[E0027]: pattern does not mention fields `old_name`, `new_name`
--> packages/obs/src/engine.rs:124:29
|
124 | ... SceneNameChanged { old_scene_name, scene_name} => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `old_name`, `new_name`
|
help: include the missing fields in the pattern
|
124 | SceneNameChanged { old_scene_name, scene_name, old_name, new_name } => {
| ~~~~~~~~~~~~~~~~~~~~~~
help: if you don't care about these missing fields, you can explicitly ignore them
|
124 | SceneNameChanged { old_scene_name, scene_name, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::CurrentProgramSceneChanged` does not have a field named `scene_name`
--> packages/obs/src/engine.rs:127:58
|
127 | ... CurrentProgramSceneChanged { scene_name } => {
| ^^^^^^^^^^
| |
| variant `obws::events::Event::CurrentProgramSceneChanged` does not have this field
| help: `obws::events::Event::CurrentProgramSceneChanged` has a field named `name`
error[E0027]: pattern does not mention field `name`
--> packages/obs/src/engine.rs:127:29
|
127 | ... CurrentProgramSceneChanged { scene_name } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `name`
|
help: include the missing field in the pattern
|
127 | CurrentProgramSceneChanged { scene_name, name } => {
| ~~~~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
127 | CurrentProgramSceneChanged { scene_name, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::CurrentPreviewSceneChanged` does not have a field named `scene_name`
--> packages/obs/src/engine.rs:130:58
|
130 | ... CurrentPreviewSceneChanged { scene_name } => {
| ^^^^^^^^^^
| |
| variant `obws::events::Event::CurrentPreviewSceneChanged` does not have this field
| help: `obws::events::Event::CurrentPreviewSceneChanged` has a field named `name`
error[E0027]: pattern does not mention field `name`
--> packages/obs/src/engine.rs:130:29
|
130 | ... CurrentPreviewSceneChanged { scene_name } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `name`
|
help: include the missing field in the pattern
|
130 | CurrentPreviewSceneChanged { scene_name, name } => {
| ~~~~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
130 | CurrentPreviewSceneChanged { scene_name, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneItemCreated` does not have fields named `scene_name`, `source_name`, `scene_item_id`, `scene_item_index`
--> packages/obs/src/engine.rs:133:47
|
133 | ... SceneItemCreated {scene_name, source_name, scene_item_id, scene_item_index} => {
| ^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ variant `obws::events::Event::SceneItemCreated` does not have these fields
error[E0027]: pattern does not mention fields `scene`, `source`, `item_id`, `index`
--> packages/obs/src/engine.rs:133:29
|
133 | ... SceneItemCreated {scene_name, source_name, scene_item_id, scene_item_index} => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `scene`, `source`, `item_id`, `index`
|
help: include the missing fields in the pattern
|
133 | SceneItemCreated {scene_name, source_name, scene_item_id, scene_item_index, scene, source, item_id, index } => {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if you don't care about these missing fields, you can explicitly ignore them
|
133 | SceneItemCreated {scene_name, source_name, scene_item_id, scene_item_index, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneItemRemoved` does not have fields named `scene_name`, `input_name`, `scene_item_id`
--> packages/obs/src/engine.rs:136:47
|
136 | ... SceneItemRemoved {scene_name, input_name, scene_item_id} => {
| ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^ variant `obws::events::Event::SceneItemRemoved` does not have these fields
error[E0027]: pattern does not mention fields `scene`, `source`, `item_id`
--> packages/obs/src/engine.rs:136:29
|
136 | ... SceneItemRemoved {scene_name, input_name, scene_item_id} => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `scene`, `source`, `item_id`
|
help: include the missing fields in the pattern
|
136 | SceneItemRemoved {scene_name, input_name, scene_item_id, scene, source, item_id } => {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if you don't care about these missing fields, you can explicitly ignore them
|
136 | SceneItemRemoved {scene_name, input_name, scene_item_id, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneItemEnableStateChanged` does not have fields named `scene_name`, `scene_item_id`, `scene_item_enabled`
--> packages/obs/src/engine.rs:139:59
|
139 | ... SceneItemEnableStateChanged { scene_name, scene_item_id, scene_item_enabled } => {
| ^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ variant `obws::events::Event::SceneItemEnableStateChanged` does not have these fields
error[E0027]: pattern does not mention fields `scene`, `item_id`, `enabled`
--> packages/obs/src/engine.rs:139:29
|
139 | ... SceneItemEnableStateChanged { scene_name, scene_item_id, scene_item_enabled } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `scene`, `item_id`, `enabled`
|
help: include the missing fields in the pattern
|
139 | SceneItemEnableStateChanged { scene_name, scene_item_id, scene_item_enabled, scene, item_id, enabled } => {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if you don't care about these missing fields, you can explicitly ignore them
|
139 | SceneItemEnableStateChanged { scene_name, scene_item_id, scene_item_enabled, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneItemLockStateChanged` does not have fields named `scene_name`, `scene_item_id`, `scene_item_locked`
--> packages/obs/src/engine.rs:142:57
|
142 | ... SceneItemLockStateChanged { scene_name, scene_item_id, scene_item_locked } => {
| ^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ variant `obws::events::Event::SceneItemLockStateChanged` does not have these fields
error[E0027]: pattern does not mention fields `scene`, `item_id`, `locked`
--> packages/obs/src/engine.rs:142:29
|
142 | ... SceneItemLockStateChanged { scene_name, scene_item_id, scene_item_locked } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `scene`, `item_id`, `locked`
|
help: include the missing fields in the pattern
|
142 | SceneItemLockStateChanged { scene_name, scene_item_id, scene_item_locked, scene, item_id, locked } => {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if you don't care about these missing fields, you can explicitly ignore them
|
142 | SceneItemLockStateChanged { scene_name, scene_item_id, scene_item_locked, .. } => {
| ~~~~~~
error[E0026]: variant `obws::events::Event::SceneItemSelected` does not have fields named `scene_name`, `scene_item_id`
--> packages/obs/src/engine.rs:145:49
|
145 | ... SceneItemSelected { scene_name, scene_item_id } => {
| ^^^^^^^^^^ ^^^^^^^^^^^^^ variant `obws::events::Event::SceneItemSelected` does not have these fields
error[E0027]: pattern does not mention fields `scene`, `item_id`
--> packages/obs/src/engine.rs:145:29
|
145 | ... SceneItemSelected { scene_name, scene_item_id } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `scene`, `item_id`
|
help: include the missing fields in the pattern
|
145 | SceneItemSelected { scene_name, scene_item_id, scene, item_id } => {
| ~~~~~~~~~~~~~~~~~~
help: if you don't care about these missing fields, you can explicitly ignore them
|
145 | SceneItemSelected { scene_name, scene_item_id, .. } => {
| ~~~~~~
error[E0599]: no method named `create_scene` found for struct `obws::client::Scenes` in the current scope
--> packages/obs/src/engine.rs:188:45
|
188 | ... client.scenes().create_scene(&scene_name).await;
| ^^^^^^^^^^^^ help: there is an associated function with a similar name: `create`
error[E0599]: no method named `remove_scene` found for struct `obws::client::Scenes` in the current scope
--> packages/obs/src/engine.rs:191:45
|
191 | ... client.scenes().remove_scene(&scene_name).await;
| ^^^^^^^^^^^^ help: there is an associated function with a similar name: `remove`
error[E0599]: no method named `set_scene_name` found for struct `obws::client::Scenes` in the current scope
--> packages/obs/src/engine.rs:197:45
|
197 | ... client.scenes().set_scene_name(&scene_name, &new_name).await;
| ^^^^^^^^^^^^^^ help: there is an associated function with a similar name: `set_name`
error[E0599]: no method named `create_scene_item` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:206:34
|
206 | ... .create_scene_item(obws::requests::scene_items::CreateSceneItem {
| ^^^^^^^^^^^^^^^^^ method not found in `SceneItems<'_>`
error[E0560]: struct `obws::requests::scene_items::CreateSceneItem<'_>` has no field named `scene_name`
--> packages/obs/src/engine.rs:207:37
|
207 | ... scene_name: &scene_name,
| ^^^^^^^^^^ `obws::requests::scene_items::CreateSceneItem<'_>` does not have this field
|
= note: available fields are: `scene`, `source`, `enabled`
error[E0560]: struct `obws::requests::scene_items::CreateSceneItem<'_>` has no field named `source_name`
--> packages/obs/src/engine.rs:208:37
|
208 | ... source_name: &source_name,
| ^^^^^^^^^^^ `obws::requests::scene_items::CreateSceneItem<'_>` does not have this field
|
= note: available fields are: `scene`, `source`, `enabled`
error[E0560]: struct `obws::requests::scene_items::CreateSceneItem<'_>` has no field named `scene_item_enabled`
--> packages/obs/src/engine.rs:209:37
|
209 | ... scene_item_enabled: Some(enabled),
| ^^^^^^^^^^^^^^^^^^ `obws::requests::scene_items::CreateSceneItem<'_>` does not have this field
|
= note: available fields are: `scene`, `source`, `enabled`
error[E0599]: no method named `remove_scene_item` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:219:34
|
219 | ... .remove_scene_item(&scene_name, item_id)
| ^^^^^^^^^^^^^^^^^ method not found in `SceneItems<'_>`
error[E0599]: no method named `set_scene_item_enabled` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:229:34
|
229 | ... .set_scene_item_enabled(SetSceneItemEnabled {
| ^^^^^^^^^^^^^^^^^^^^^^ help: there is an associated function with a similar name: `set_enabled`
error[E0308]: mismatched types
--> packages/obs/src/engine.rs:230:49
|
230 | ... scene_name: &scene_name,
| ^^^^^^^^^^^ expected struct `std::string::String`, found `&std::string::String`
|
help: consider removing the borrow
|
230 - scene_name: &scene_name,
230 + scene_name: scene_name,
|
error[E0559]: variant `Request::SetSceneItemEnabled` has no field named `scene_item_id`
--> packages/obs/src/engine.rs:231:37
|
231 | ... scene_item_id,
| ^^^^^^^^^^^^^ `Request::SetSceneItemEnabled` does not have this field
|
= note: available fields are: `scene_name`, `item_id`, `enabled`
error[E0559]: variant `Request::SetSceneItemEnabled` has no field named `scene_item_enabled`
--> packages/obs/src/engine.rs:232:37
|
232 | ... scene_item_enabled: enabled,
| ^^^^^^^^^^^^^^^^^^ `Request::SetSceneItemEnabled` does not have this field
|
= note: available fields are: `scene_name`, `item_id`, `enabled`
error[E0599]: no method named `set_scene_item_locked` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:243:34
|
243 | ... .set_scene_item_locked(SetSceneItemLocked {
| ^^^^^^^^^^^^^^^^^^^^^ help: there is an associated function with a similar name: `set_enabled`
error[E0308]: mismatched types
--> packages/obs/src/engine.rs:244:49
|
244 | ... scene_name: &scene_name,
| ^^^^^^^^^^^ expected struct `std::string::String`, found `&std::string::String`
|
help: consider removing the borrow
|
244 - scene_name: &scene_name,
244 + scene_name: scene_name,
|
error[E0559]: variant `Request::SetSceneItemLocked` has no field named `scene_item_id`
--> packages/obs/src/engine.rs:245:37
|
245 | ... scene_item_id,
| ^^^^^^^^^^^^^ `Request::SetSceneItemLocked` does not have this field
|
= note: available fields are: `scene_name`, `item_id`, `locked`
error[E0559]: variant `Request::SetSceneItemLocked` has no field named `scene_item_locked`
--> packages/obs/src/engine.rs:246:37
|
246 | ... scene_item_locked: locked,
| ^^^^^^^^^^^^^^^^^ `Request::SetSceneItemLocked` does not have this field
|
= note: available fields are: `scene_name`, `item_id`, `locked`
error[E0599]: no method named `set_scene_item_index` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:257:34
|
257 | ... .set_scene_item_index(SetSceneItemIndex {
| ^^^^^^^^^^^^^^^^^^^^ method not found in `SceneItems<'_>`
error[E0308]: mismatched types
--> packages/obs/src/engine.rs:258:49
|
258 | ... scene_name: &scene_name,
| ^^^^^^^^^^^ expected struct `std::string::String`, found `&std::string::String`
|
help: consider removing the borrow
|
258 - scene_name: &scene_name,
258 + scene_name: scene_name,
|
error[E0559]: variant `Request::SetSceneItemIndex` has no field named `scene_item_id`
--> packages/obs/src/engine.rs:259:37
|
259 | ... scene_item_id,
| ^^^^^^^^^^^^^ `Request::SetSceneItemIndex` does not have this field
|
= note: available fields are: `scene_name`, `item_id`, `index`
error[E0559]: variant `Request::SetSceneItemIndex` has no field named `scene_item_index`
--> packages/obs/src/engine.rs:260:37
|
260 | ... scene_item_index: index,
| ^^^^^^^^^^^^^^^^ `Request::SetSceneItemIndex` does not have this field
|
= note: available fields are: `scene_name`, `item_id`, `index`
error[E0599]: no method named `start_stream` found for struct `Streaming` in the current scope
--> packages/obs/src/engine.rs:265:48
|
265 | ... client.streaming().start_stream().await;
| ^^^^^^^^^^^^ help: there is an associated function with a similar name: `status`
error[E0599]: no method named `stop_stream` found for struct `Streaming` in the current scope
--> packages/obs/src/engine.rs:268:48
|
268 | ... client.streaming().stop_stream().await;
| ^^^^^^^^^^^ method not found in `Streaming<'_>`
error[E0599]: no method named `get_scene_list` found for struct `obws::client::Scenes` in the current scope
--> packages/obs/src/engine.rs:283:54
|
283 | ... Box::new(client.scenes().get_scene_list().await.ok().map(|s| {
| ^^^^^^^^^^^^^^ method not found in `obws::client::Scenes<'_>`
error[E0599]: no method named `get_scene_item_enabled` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:296:34
|
296 | ... .get_scene_item_enabled(&scene_name, item_id)
| ^^^^^^^^^^^^^^^^^^^^^^ help: there is an associated function with a similar name: `set_enabled`
error[E0599]: no method named `get_scene_item_locked` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:306:34
|
306 | ... .get_scene_item_locked(&scene_name, item_id)
| ^^^^^^^^^^^^^^^^^^^^^ method not found in `SceneItems<'_>`
error[E0599]: no method named `get_scene_item_index` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:316:34
|
316 | ... .get_scene_item_index(&scene_name, item_id)
| ^^^^^^^^^^^^^^^^^^^^ method not found in `SceneItems<'_>`
error[E0599]: no method named `get_scene_item_id` found for struct `SceneItems` in the current scope
--> packages/obs/src/engine.rs:326:34
|
326 | ... .get_scene_item_id(&scene_name, &source_name)
| ^^^^^^^^^^^^^^^^^ method not found in `SceneItems<'_>`
error[E0599]: no method named `toggle_stream` found for struct `Streaming` in the current scope
--> packages/obs/src/engine.rs:331:69
|
331 | ToggleStream => Box::new(client.streaming().toggle_stream().await.ok()),
| ^^^^^^^^^^^^^ method not found in `Streaming<'_>`
error[E0599]: no method named `get_current_program_scene` found for struct `obws::client::Scenes` in the current scope
--> packages/obs/src/engine.rs:333:54
|
333 | ... Box::new(client.scenes().get_current_program_scene().await.ok())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: there is an associated function with a similar name: `current_program_scene`
Some errors have detailed explanations: E0026, E0027, E0308, E0559, E0560, E0599.
For more information about an error, try `rustc --explain E0026`.
Will mean more error handling is required but it'll be a lot safer
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.