forestgeo / fgeo.analyze Goto Github PK
View Code? Open in Web Editor NEW[R-package on CRAN] Analyze fgeo data.
Home Page: https://forestgeo.github.io/fgeo.analyze/
License: GNU General Public License v3.0
[R-package on CRAN] Analyze fgeo data.
Home Page: https://forestgeo.github.io/fgeo.analyze/
License: GNU General Public License v3.0
fgeo.analyze/docs/news/index.html
Lines 134 to 139 in 14e7c83
TODO
comment in 14e7c83 when #77 was merged. cc @maurolepore.See survival package: https://cran.r-project.org/web/packages/survival/index.html
fgeo.analyze/.buildignore/tmp.R
Line 1 in 881c28a
TODO
comment in 881c28a. It's been assigned to @maurolepore because they committed the code.This is not simply picking the main stem, it also involves computing tree-status from the status of each stem.
fgeo.analyze/docs/news/index.html
Lines 134 to 139 in 5e6af2d
TODO
comment in 5e6af2d. It's been assigned to @maurolepore because they committed the code.Lines 11 to 16 in 5e6af2d
TODO
comment in 5e6af2d. It's been assigned to @maurolepore because they committed the code.Prepare for release:
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
rhub::check_for_cran()
revdepcheck::revdep_check(num_workers = 4)
cran-comments.md
Submit to CRAN:
usethis::use_version('patch')
devtools::submit_cran()
Wait for CRAN...
usethis::use_github_release()
usethis::use_dev_version()
library(tidyverse)
#> Warning: package 'purrr' was built under R version 3.5.3
library(fgeo)
#> -- Attaching packages -------------------------------------------- fgeo 1.1.2.9000 --
#> v fgeo.analyze 1.1.4 v fgeo.tool 1.2.2
#> v fgeo.plot 1.1.3.9000 v fgeo.x 1.1.2
#> -- Conflicts ---------------------------------------------------- fgeo_conflicts() --
#> x fgeo.tool::filter() masks dplyr::filter(), stats::filter()
#> x dplyr::intersect() masks base::intersect()
#> x dplyr::lag() masks stats::lag()
#> x dplyr::setdiff() masks base::setdiff()
#> x dplyr::setequal() masks base::setequal()
#> x dplyr::union() masks base::union()
set.seed(1)
# Small dataset from Luquillo
cns_luq <- fgeo.x::tree6_3species
hab_luq <- fgeo.x::habitat
sp_top3_luq <- unique(fgeo.x::tree6_3species$sp)
pdim_luq <- c(320, 500)
gsize_luq <- 20
# Passes
hab <- fgeo_habitat(fgeo.x::elevation, 20, 8)
as_tibble(tt_test(cns_luq, hab))
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.
#> Using `gridsize = 20`. To change this value see `?tt_test()`.
#> # A tibble: 24 x 8
#> habitat sp N.Hab Gr.Hab Ls.Hab Eq.Hab Rep.Agg.Neut Obs.Quantile
#> * <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 CASARB 11 587 1012 1 0 0.367
#> 2 2 CASARB 16 1433 163 4 0 0.896
#> 3 3 CASARB 2 1200 368 32 0 0.75
#> 4 4 CASARB 14 886 710 4 0 0.554
#> 5 5 CASARB 6 223 1365 12 0 0.139
#> 6 6 CASARB 6 418 1177 5 0 0.261
#> 7 7 CASARB 5 932 658 10 0 0.582
#> 8 8 CASARB 6 1423 171 6 0 0.889
#> 9 1 PREMON 49 1223 374 3 0 0.764
#> 10 2 PREMON 37 627 968 5 0 0.392
#> # ... with 14 more rows
autoplot(hab)
# Errs
hab <- fgeo_habitat(fgeo.x::elevation, 20, 16)
as_tibble(tt_test(cns_luq, hab))
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.
#> Using `gridsize = 20`. To change this value see `?tt_test()`.
#> Error in if (spprophab[i] > Torspprophab[i]) {: missing value where TRUE/FALSE needed
autoplot(hab)
Created on 2019-03-22 by the reprex package (v0.2.1)
Prepare for release:
devtools::check_win_devel()
rhub::check_on_macos()
revdepcheck::revdep_check(num_workers = 4)
Perform release:
update.packages()
)?(Walk through devtools::release()
but don't submit)
R CMD check
locally?spell_check()
)?devtools::check_win_devel()
.rhub::check_for_cran()
.NEWS.md
file?DESCRIPTION
(version number, use_tidy_version()
, use_tidy_description()
)?cran-comments.md?
Publish release:
Announce
Templatate at forestgeo/learn#182 (adapted from https://github.com/r-lib/usethis/issues/338
).
@maurolepore
When I use a dataset with a single species, I get an error message related to the issue https://github.com/forestgeo/fgeo.analyze/issues/40. The Error can be reproduced using the example data in the tt_test function:
# Using the same example of tt_test
library(fgeo.tool, warn.conflicts = FALSE)
assert_is_installed("fgeo.x")
tree <- fgeo.x::tree6_3species
elevation <- fgeo.x::elevation
# Pick alive trees, of 10 mm or more
census <- filter(tree, status == "A", dbh >= 10)
# Selecting CASARB species
w <- which(census$sp == "CASARB")
census.CASARB <- census[w,]
# An error occur with any of the following codes when you use a file with a single species
fgeo.analyze::tt_test(census.CASARB, fgeo.x::habitat)
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.Using
#> `gridsize = 20`. To change this value see `?tt_test()`.
#> Error: Every quadrat in the dataset must have at lease one tree.
#> For more information see https://github.com/forestgeo/fgeo.analyze/issues/40.
fgeo.analyze::tt_test(census.CASARB, fgeo.x::habitat, sp = "CASARB")
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.Using
#> `gridsize = 20`. To change this value see `?tt_test()`.
#> Error: Every quadrat in the dataset must have at lease one tree.
#> For more information see https://github.com/forestgeo/fgeo.analyze/issues/40.
# I think it doesn't have to do with the low sample size issue and the error is being incorrectly reported because no error is returned when the species is included along with other species
fgeo.analyze::tt_test(census, fgeo.x::habitat, sp = "CASARB")
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.Using
#> `gridsize = 20`. To change this value see `?tt_test()`.
#> [[1]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> CASARB 29 1242 356 2 0 0.77625
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> CASARB 20 390 1206 4 0 0.24375
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> CASARB 12 778 817 5 0 0.48625
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> CASARB 5 932 658 10 0 0.5825
Sabrina Russo said:
... I guess thereβs a wrapper function in which the user can pick what minimum tree abundance they wish to use and that then subsets the data so that only the species meeting the minimum abundance criterion are run for the TT? If not, then there should be one.
Tue, Dec 4, 2018 at 1:45 PM Lao, Suzanne [email protected]
As was done with the species abundance tables, we need to update the BCI growth and mortality tables on the forestgeo website also. ... The numbers should be very similar to the ones on the website, and you would have 2 more census intervals: https://forestgeo.si.edu/sites/south-america/barro-colorado-island/bci-species-growth-and-mortality
Paper that explains how the tables were calculated and code:
Some items yet unclear to me:
Should I use the data I used for the tables of abundance and basal area?
How are the time-intervals defined? For example, From the website it is not obvious how to resolve this: The interval 1995-2000 includes six years (1995, 1996, 1997, 1998, 1999, 2000), and 2000 overlaps with the interval 2000-2005.
Background:
On Tue, Dec 4, 2018 at 5:05 PM Lao, Suzanne [email protected] wrote:
talk to Stuart and ask him whether we should leave the site as is, or whether we should recalculate the relative growth rates and add 2005-2010 and 2010-2015
What the columns mean and how the rates were calculated:
growth:
rate: observed relative growth rate (mean of log-transformed relative growth rates of individual trees, subsequently back-transformed); fitted: estimated growth rate from Gibbs sampler; lower and upper: 95 pct. confidence limits of the fitted rate, based on the Gibbs sampler (see Methods in Supporting Online Material). All rates are percentages, that is, 100 times the relative growth. _10 indicates data for the 10-99-mm dbh category, and _100 for stems dbh 100 and above.
mortality:
rate: observed mortality rate constant (based only on N, S, time); fitted: estimated mortality rate constant from Gibbs sampler; lower and upper: 95 pct. confidence limits of the fitted rate, based on the Gibbs sampler (see Methods in Supporting Online Material). All rates are percentages, that is, 100 times the rate constant. _10 indicates data for the 10-99-mm dbh category, _100 for stems dbh 100 and above.
.
Prepare for release:
usethis::use_cran_comments()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
rhub::check_for_cran()
cran-comments.md
Submit to CRAN:
usethis::use_version('patch')
devtools::submit_cran()
Wait for CRAN...
usethis::use_github_release()
usethis::use_dev_version()
From forestgeo/forum#19 (comment):
"count woods" sounds weird. Maybe say "count individuals"?
I think vft2[2,3] should be 1.2, isn't it ?
would be good to show how to count abundance of stems and not only individual trees (e.i. a multi-stem tree with 2 stems counts for 2)
Prepare for release:
Copy job results to results object in the global environment:
Also:
Perform release:
update.packages()
)?devtools::release()
Wait for CRAN...
Templatate at forestgeo/learn#182 (adapted from
Lines 11 to 16 in 14e7c83
TODO
comment in 14e7c83 when #77 was merged. cc @maurolepore.Contributed by Gabriel Arellano (via @)
# Mortality rate calculation using different interval lengths
# for the different observations. Based on Kubo et al. 2000.
mortality_rate_Kubo <- function(data)
{
# Approach taken by Kubo et al., using different
# intervals for each observation, and the same
# mortality rate for all the individuals:
# Journal of Tropical Ecology (2000) 16:753-756.
# The mortality rate is the value that makes
# Equation 3 of Kubo et al. 2000 equal to 0.
Eq3 <- function(mortality.rate, data)
{
alive <- which(data$status == "A")
dead <- which(data$status == "D")
Ti <- data[alive, "t"]
Tj <- data[dead, "t"]
x = -sum(Ti) + sum((Tj * exp(-mortality.rate * Tj))/(1 - exp(-mortality.rate * Tj)))
abs(x)
}
# It is a single-parameter optimization problem.
# The upper limit of the instantaneous mortality rate is +Inf in theory,
# but at low mortality rates it should be almost equal to the truly annual
# mortality rate, which is constrained within [0, 1]. In our system the
# mortality rates are typically low, so often an upper limit of 1 is reasonable.
# In some cases (certain species, seedling data with very short intervals, ...)
# this upper limit should be increased to allow mortality rates > 1.
# Definition of the upper limit, as 10 times the "typical" mortality rate:
N = sum(data$status %in% c("A", "D"))
S = sum(data$status == "A")
mean.t = mean(data$t[data$status %in% c("A", "D")])
U = 10 * ((log(N) - log(S))/mean.t)
# (Very loosely) constrained optimization:
mortality.rate <- optimize(f = Eq3, lower = 0, upper = U, data = data)$minimum
return(mortality.rate)
}
if(FALSE) # example -- if FALSE it will not run by doing source
{
# Comparison between methods:
N = 1000
data <- data.frame(id = 1:N,
status = sample(c("A", "D"), size = N, prob = c(0.6, 0.4), replace = TRUE),
t = runif(N, min = 1, max = 8))
# Typical calculation of the mortality rate,
# assuming the average time for all the observations:
N = sum(data$status %in% c("A", "D"))
S = sum(data$status == "A")
mean.t = mean(data$t[data$status %in% c("A", "D")])
(log(N) - log(S))/mean.t
# Alternative calculation
# (should be very similar).
mortality_rate_Kubo(data)
# Using extremely high mortality rates (>1)
data2 <- data
data2$t <- data2$t / 100
N = sum(data2$status %in% c("A", "D"))
S = sum(data2$status == "A")
mean.t = mean(data2$t[data2$status %in% c("A", "D")])
(log(N) - log(S))/mean.t
mortality_rate_Kubo(data2)
}
The example in the help file of tt_test gives an error.
(NOTE: I don't think I'll use that function, but I just wanted to give a heads up about it here)
library(fgeo.tool)
assert_is_installed("fgeo.x")
# Example data
tree <- fgeo.x::tree6_3species
Error: 'tree6_3species' is not an exported object from 'namespace:fgeo.x'
elevation <- fgeo.x::elevation
> sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] fgeo.tool_1.2.2 fgeo.analyze_1.1.4 fgeo.abundance_0.0.0.9006 fgeo_0.0.0.9002
[5] rlang_0.3.1 fgeo.base_0.0.0.9001 stringr_1.3.1 MuMIn_1.42.1
[9] lme4_1.1-21 Matrix_1.2-15 sm_2.2-5.6 jpeg_0.1-8
[13] raster_2.8-4 sp_1.3-1 SDMTools_1.1-221
loaded via a namespace (and not attached):
[1] Rcpp_1.0.0 pillar_1.3.1 compiler_3.5.1 nloptr_1.2.1
[5] fgeo.ctfs_0.0.0.9003 R.methodsS3_1.7.1 R.utils_2.7.0 tools_3.5.1
[9] drat_0.1.5 boot_1.3-20 tibble_2.0.1 nlme_3.1-137
[13] lattice_0.20-35 pkgconfig_2.0.2 fgeo.demography_0.0.0.9103 cli_1.0.1
[17] rstudioapi_0.10 yaml_2.2.0 rgdal_1.3-6 parallel_3.5.1
[21] dplyr_0.8.0.1 stats4_3.5.1 grid_3.5.1 tidyselect_0.2.5
[25] glue_1.3.0 R6_2.3.0 tcltk_3.5.1 minqa_1.2.4
[29] purrr_0.3.2 magrittr_1.5 codetools_0.2-15 MASS_7.3-51.1
[33] splines_3.5.1 assertthat_0.2.0 fgeo.x_1.1.2 stringi_1.2.4
[37] crayon_1.3.4 R.oo_1.22.0
@srusso2 and @DanielZuleta,
Small tree tables used to err because
Torspstcnthab / Tortotstcnthab = NaN
(edited, thanks @srusso2 for noticing the mistake via #40 (comment))
Now they no longer err because I'm now converting NaN
to 0
with a warning. Is this OK?
(I know that users "should only try to determine the habitat association for sufficiently abundant species" but we lack a formal definition of sufficiently abundant that I can use to programatically reject bad inputs.)
The warning is the one right below, and the code that implements this warning is here and here (see details in the example below):
#> Warning: Using zero (`0`) where the relative stem density of focal species
#> per habitat of the focal torus-based map can't be calculated
#> because `Tortotstcnthab` and `Torspstcnthab` are zero:
#> * `Tortotstcnthab` determines total number of stems per habitat of the
#> focal torus-based map.
#> * `Torspstcnthab` determines tot. no. stems for focal sp. per habitat of
#> the focal torus-based map.
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(fgeo))
tree <- fgeo.x::tree6_3species
autoplot(sp(tree))
tt_test(tree, fgeo.x::habitat)
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.
#> Using `gridsize = 20`. To change this value see `?tt_test()`.
#> [[1]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> CASARB 29 1242 356 2 0 0.77625
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> CASARB 20 390 1206 4 0 0.24375
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> CASARB 12 778 817 5 0 0.48625
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> CASARB 5 932 658 10 0 0.5825
#> attr(,"fixed_nan")
#> [1] FALSE
#>
#> [[2]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> PREMON 91 1093 504 3 0 0.683125
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> PREMON 89 1254 344 2 0 0.78375
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> PREMON 40 305 1292 3 0 0.190625
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> PREMON 14 270 1322 8 0 0.16875
#> attr(,"fixed_nan")
#> [1] FALSE
#>
#> [[3]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> SLOBER 18 273 1324 3 0 0.170625
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> SLOBER 24 810 788 2 0 0.50625
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> SLOBER 17 1155 440 5 0 0.721875
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> SLOBER 7 1292 303 5 0 0.8075
#> attr(,"fixed_nan")
#> [1] FALSE
# Used to err because `Tortotstcnthab / Torspstcnthab = NaN`
smaller_tree <- sample_n(tree, 50)
autoplot(sp(smaller_tree))
# Now no longer errs because I'm now converting `NaN` to `0` with a warning.
# Is this OK?
tt_test(smaller_tree, fgeo.x::habitat)
#> Using `plotdim = c(320, 500)`. To change this value see `?tt_test()`.
#> Using `gridsize = 20`. To change this value see `?tt_test()`.
#> Warning: Using zero (`0`) where the relative stem density of focal species
#> per habitat of the focal torus-based map can't be calculated
#> because `Tortotstcnthab` and `Torspstcnthab` are zero:
#> * `Tortotstcnthab` determines total number of stems per habitat of the
#> focal torus-based map.
#> * `Torspstcnthab` determines tot. no. stems for focal sp. per habitat of
#> the focal torus-based map.
#> [[1]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> SLOBER 4 1021 544 35 0 0.638125
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> SLOBER 4 1120 408 72 0 0.7
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> SLOBER 0 0 1054 546 -1 0
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> SLOBER 0 0 676 924 -1 0
#> attr(,"fixed_nan")
#> [1] TRUE
#>
#> [[2]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> PREMON 9 388 1179 33 0 0.2425
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> PREMON 10 487 1072 41 0 0.304375
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> PREMON 6 1318 236 46 0 0.82375
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> PREMON 4 1117 0 483 0 0.698125
#> attr(,"fixed_nan")
#> [1] TRUE
#>
#> [[3]]
#> N.Hab.1 Gr.Hab.1 Ls.Hab.1 Eq.Hab.1 Rep.Agg.Neut.1 Obs.Quantile.1
#> CASARB 3 1154 394 52 0 0.72125
#> N.Hab.2 Gr.Hab.2 Ls.Hab.2 Eq.Hab.2 Rep.Agg.Neut.2 Obs.Quantile.2
#> CASARB 2 654 878 68 0 0.40875
#> N.Hab.3 Gr.Hab.3 Ls.Hab.3 Eq.Hab.3 Rep.Agg.Neut.3 Obs.Quantile.3
#> CASARB 1 861 664 75 0 0.538125
#> N.Hab.4 Gr.Hab.4 Ls.Hab.4 Eq.Hab.4 Rep.Agg.Neut.4 Obs.Quantile.4
#> CASARB 0 0 683 917 -1 0
#> attr(,"fixed_nan")
#> [1] TRUE
Created on 2018-12-31 by the reprex package (v0.2.1)
fgeo.analyze/.buildignore/tmp.R
Line 1 in e119313
TODO
comment in e119313 when #51 was merged. cc @maurolepore.Prepare for release:
devtools::build_readme()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
rhub::check_for_cran()
revdepcheck::revdep_check(num_workers = 4)
cran-comments.md
Submit to CRAN:
usethis::use_version('patch')
devtools::submit_cran()
Wait for CRAN...
usethis::use_github_release()
usethis::use_dev_version()
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.