blippy / neoleo Goto Github PK
View Code? Open in Web Editor NEWLightweight curses spreadsheet based on GNU oleo
License: GNU General Public License v2.0
Lightweight curses spreadsheet based on GNU oleo
License: GNU General Public License v2.0
Using gcc the compilation fails. With clang it works fine.
==> Making package: neoleo-git 12.0-1 (Tue Jul 12 12:25:20 2022)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
-> Updating neoleo git repo...
==> Validating source files with sha256sums...
neoleo ... Skipped
==> Extracting sources...
-> Creating working copy of neoleo git repo...
Reset branch 'makepkg'
==> Starting pkgver()...
==> Removing existing $pkgdir/ directory...
==> Starting build()...
autoreconf: export WARNINGS=
autoreconf: Entering directory '.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: configure.ac: not using Intltool
autoreconf: configure.ac: not using Gtkdoc
autoreconf: running: /usr/bin/autoconf
autoreconf: running: /usr/bin/autoheader
autoreconf: running: automake --add-missing --copy --no-force
autoreconf: Leaving directory '.'
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
configure: checking if debugging required ... no
configure: checking if gprof profiling required ... no
checking for g++... g++
checking whether the C++ compiler works... yes
checking for C++ compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C++... yes
checking whether g++ accepts -g... yes
checking for g++ option to enable C++11 features... none needed
checking whether make supports the include directive... yes (GNU style)
checking dependency style of g++... gcc3
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating examples/Makefile
config.status: creating src/Makefile
config.status: creating tests/Makefile
config.status: creating tests/out/Makefile
config.status: creating tests/verified/Makefile
config.status: executing depfiles commands
cd . && /bin/sh ./config.status config.h
config.status: creating config.h
config.status: config.h is unchanged
make all-recursive
make[1]: Entering directory '/home/haawda/paketierung/meine_Pakete/neoleo-git/src/neoleo'
Making all in examples
make[2]: Entering directory '/home/haawda/paketierung/meine_Pakete/neoleo-git/src/neoleo/examples'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/home/haawda/paketierung/meine_Pakete/neoleo-git/src/neoleo/examples'
Making all in src
make[2]: Entering directory '/home/haawda/paketierung/meine_Pakete/neoleo-git/src/neoleo/src'
g++ -DHAVE_CONFIG_H -I. -I.. -Werror -std=c++17 -DDATADIR="\"/usr/share\"" -Wall -Wfatal-errors -Wno-psabi -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -D_GLIBCXX_ASSERTIONS -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2,-Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -Wp,-D_GLIBCXX_ASSERTIONS -MT oleofile.o -MD -MP -MF .deps/oleofile.Tpo -c -o oleofile.o oleofile.cc
In file included from /usr/include/c++/12.1.0/string:53,
from /usr/include/c++/12.1.0/bits/locale_classes.h:40,
from /usr/include/c++/12.1.0/bits/ios_base.h:41,
from /usr/include/c++/12.1.0/ios:42,
from /usr/include/c++/12.1.0/ostream:38,
from /usr/include/c++/12.1.0/iostream:39,
from oleofile.cc:25:
In constructor 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with <template-parameter-2-1> = std::allocator<char>; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]',
inlined from 'char* read_new_value(CELLREF, CELLREF, char*, char*)' at oleofile.cc:54:16:
/usr/include/c++/12.1.0/bits/basic_string.h:641:23: error: 'text' may be used uninitialized [-Werror=maybe-uninitialized]
641 | const _CharT* __end = __s + traits_type::length(__s);
| ^~~~~
compilation terminated due to -Wfatal-errors.
cc1plus: all warnings being treated as errors
make[2]: *** [Makefile:481: oleofile.o] Error 1
make[2]: Leaving directory '/home/haawda/paketierung/meine_Pakete/neoleo-git/src/neoleo/src'
make[1]: *** [Makefile:416: all-recursive] Error 1
make[1]: Leaving directory '/home/haawda/paketierung/meine_Pakete/neoleo-git/src/neoleo'
make: *** [Makefile:336: all] Error 2
==> ERROR: A failure occurred in build().
Aborting...
Process makepkg exited abnormally with code 4
Using set_c_z() is problematical, as I noted in cell.h:
/* mcarter 02-May-2018 issue#37
* This is a potential source of bugs, because set_c_z() does not
* set the type as well. So you might be mixing up types. I encountered
* this when I juiced up class cell to derive from class value, and
* tried the copy-region function. set_c_z() is used in other places,
* so there are likely to be other bugs lurking in the code
*/
Home, and delete keys in edit mode do no work properly. Fix required.
Om io-curses.cc:show_main_menu()
, copied_cell_formula
(grep for TODO HIGH
) is stored as a static within the function. It should be a global variable.
Jude DaShiell wrote:
In a cell once you key in alt-a+f where the f is keyed in after alt-a was hit and released, is it possible to bring up a picker list of known formats? I'm going to be putting currency formats into three adjacent columns and I don't know how far down in the spreadsheet these columns will run.
When you edit cells, the arrow keys work as expected. However, when you do something like
M-x save-spreadsheet
, the arrows keys seem to move cells, which is not good behaviour. It should work the same as something like edit-cell
In Slackware, not everything in the examples directory is installed.
Undoubtedly the same in Arch.
Html documentation could also do with a check to ensure they are installed correctly.
The whole thing basically works, though, so it is only a minor issue.
test.oleo fails in the example directory. It references cells outside the minimum range, creating bad numbers. The parser prior to 2019 did not misbehave like that.
I noticed that on the Arch AUR, there is a build patch for Arch:
diff --git a/io-curses.patch b/io-curses.patch
new file mode 100644
index 00000000000..ffff789ec1e
--- /dev/null
+++ b/io-curses.patch
@@ -0,0 +1,13 @@
+diff --git a/src/io-curses.cc b/src/io-curses.cc
+index e808775..d0ec3a7 100644
+--- a/src/io-curses.cc
++++ b/src/io-curses.cc
+@@ -538,7 +538,7 @@ _io_repaint (void)
+ if (win->lh_wid)
+ {
+ move (win->win_down - 1, win->win_over - win->lh_wid);
+- printw ("#%*d ", win->lh_wid - 2, 1 + win - wins);
++ printw ("#%*ld ", win->lh_wid - 2, 1 + win - wins);
+ if (win->flags & WIN_EDGE_REV)
+ s_display.cdstandout();
+ cc = win->screen.lc;
I have incorporates this patch, so it should now build nicely.
Alas, there always seems to be configuration wonks that vary from distro to distro.
Hi blippy, I would like to use oleo on arch linux, but the aura package https://aur.archlinux.org/packages/oleo/ is broken. Can you be so kind and provide one for noleo?
In the cells, neoleo should display integers using the format for decimals. So if, for example, the user is using fixed.2
, 0
should be displayed at 0.00
.
Under Arch Linux using g++ 10.1.0 and the environment variable LANG=C the compilation fails with an overflow.
Strangely the overflow also appears if I use the german language localization, but the values are different.
In cell.h
, move cell-type
from cell_flags_s
to the class itself.
It parses a cell formula like rc1+1
as r1c11
The user manual should mention C-g as a way of cancelling the current operation.
I have been trying to compile this with the following version of gcc
gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1)
I have been getting the following error when I compile it. I have compiled it on both linux mint and on the raspberry pi running Raspbian. I get the same error. Do you have any ideas.
g++ -Werror -std=c++17 -DDATADIR=""/usr/local/share"" -o neoleo basic.o cell.o cmd.o convert.o errors.o format.o input.o io-2019.o io-headless.o io-curses.o io-edit.o io-term.o io-utils.o logging.o oleofile.o parser-2019.o ref.o regions.o sheet.o spans.o tbl.o utils.o window.o main.o tests.o value.o -lm -lncurses -ltinfo -lpanel -lform
/usr/bin/ld: logging.o: in function Log::Log()': logging.cc:(.text+0x90): undefined reference to
std::filesystem::create_directories(std::filesystem::__cxx11::path const&)'
/usr/bin/ld: logging.o: in function std::filesystem::__cxx11::path::path<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::filesystem::__cxx11::path>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::filesystem::__cxx11::path::format)': logging.cc:(.text._ZNSt10filesystem7__cxx114pathC2INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES1_EERKT_NS1_6formatE[_ZNSt10filesystem7__cxx114pathC5INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES1_EERKT_NS1_6formatE]+0x60): undefined reference to
std::filesystem::__cxx11::path::_M_split_cmpts()'
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:435: neoleo] Error 1
LeakSanitizer detects memory leaks at exit when you
wrt Arch Linux release 4.0.1:
In an email on 12-Feb-2017:
Background:
I'm using archlinux in command line environment since graphical user interface software and screen readers are too unstable for my tastes.
I installed neoleo from the aur repository with all dependencies.
I started the package with neoleo -x.
I tried c-xc-v and got asked for an alternate filename so keyed in spending.oleo that didn't exist and got back an unknown error with a bunch of numbers after it.
Trying neoleo -x spending.oleo as a package start produced the same unknown error.
Why am I still using the spreadsheet? Because I'm a hacker at heart and believe in supporting those that make an effort for improved software.
What did I do about it?
I used a text editor and created spending.csv then used
neoleo -x spending.csv and that worked.
Then I did c-xc-s and when spending.csv came up as the file to be saved, I hit backspace three times and keyed in oleo and hit enter.
When I quit the spreadsheet I tried
neoleo -x spending.oleo and it worked.
two things I don't yet know about.
How to adjust column widths and how to enter valid dates.
I downloaded the original oleo documentation from gnu.org and that's what I've been using to get this far.
Thanks for the good work done so far and please keep on going!
On 13-Feb-2017:
I also found alt-d w asked for an integer or some def. and when I entered an integer it threw an error and failed to work. My work around was to set a default width for cells for the whole spreadsheet and that did work.
No examples of entering a basic date were provided so I'm keeping those stored in strings until further notice.
On 13-Feb-2017:
I'm running archlinux on an x86-64 amd k8 athelon machine built in 1994.
neoleo
should produce something that can be used by groff
.
groff
is a little tricky to get working, so an example is given below.
Suppose foo.tbl
contains:
.TS
tab(;);
l r.
Name of person;Company
.T&
r r.
Marks;Fortune 1000
.TE
Then executing
cat foo.tbl | groff -T ascii -t | head -3
produces the result:
Name of person Company
Marks Fortune 1000
When configuring using
./configure --without-motif
running neoleo
gives:
(warning) Font 8x13 could not be loaded.
neoleo 4.0.1:Default font 8x13 could not be loaded.
Distributions such as debian have policies that require a minimum of documentation included in a package, in the form of at least one man
page. In the worst cases, a package will include a stub of a man
page providing the most basic information and links to where the complete documentation may be found. In the case of this package, it would be expected for the html documentation (already included in the source tarball) to be installed to /usr/share/doc/html
(many packages do this). It's also nice not to have to use the network for basic documentation. Further, documentation tends to include be version-specific information, so someone using a historical version of a package would be at a loss when there is no local documentation and the network provides documentation for a (much?) newer version.
Also, I liked the help interface that exists in version 7.0.0. I don't know what was going on 'under the hood', but from a user interface perspective it was a nice touch.
Remove compiler warning for regions.cc
.
When attempting to build 5.0.0 I encountered a make error on Linux Mint 18 per the attached. I was able to build a previous version through commit 50e2a90.
make-error.txt
Use C-q as a shortcut to quit.
This is likely to be very useful info.
sum() doesn't automatically recalculate when you change a value in a range. This is probably a regression introduced in c8064e1
Graphing functionality was removed from neoleo recently. There's a lot of zered pointers existing, so the following causes a crash:
neoleo examples/plot.oleo
Copying regions fails, as evidenced by the following commands in tests/cpreg-01.scr
:
i
1
;
r1c1 + 1
.
copy-region r1c1:r1c2 r2c1:r2c2
w
q
Running neoleo -H <cpreg-01.scr
causes a hang.
The hang occurs (as of writing) at: ref.cc:copy_cell():655
on commit c9e13456fcd2a6f97c8a3c800b8ceefb73978a86
:
if(len)
bcopy (my_cell->get_cell_formula(), cpf->get_cell_formula(), len);
Hi. I just found your version of neoleo
(v8.0.0), and am beginning to go through the documentation; thanks for the work!
I've downloaded the tarball to a debian environment, and performed make
, but not make install
. By running ./neoleo
from the src
directory, the program loads and can perform a basic calculation of adding two cells; however, when attempting to set alignment using either the C-l
or C-r
keybinding, the program crashes, with an error message free(): invalid pointer
.
BTW: I have other things to report (basic keybindings and commands not functioning), but thought to first post this, and get feedback.
Go to any cell. Type
="foo
NB: there is no matching double-quote.
Save the file.
Quit neoleo.
Restart it again with the file you saved.
Notice that you'll have a parse error in that cell. This is due to an unterminated string.
The "releases" page of the github site offers three files for each release. For each set, there exist two tar.gz
files with identical names but different content!
The source tarball should be named maybe neoleo-x.y.z.src.tar.gz
.
In init.cc
, add the line
set-default-format general.float
When editing a cell, the home and end keys should work.
diff --git a/src/basic.cc b/src/basic.cc
index 29d629a..0542726 100644
--- a/src/basic.cc
+++ b/src/basic.cc
@@ -48,7 +48,7 @@ using std::endl;
/* Indexed by MAGIC + 1 */
-const int boundrymagic[3] = { MIN_ROW, NON_ROW, MAX_ROW };
+// const int boundrymagic[3] = { MIN_ROW, NON_ROW, MAX_ROW };
/* A very basic command. */
diff --git a/src/io-utils.cc b/src/io-utils.cc
index ee0f3ea..d62afb2 100644
--- a/src/io-utils.cc
+++ b/src/io-utils.cc
@@ -109,13 +109,13 @@ const char *date_formats[] = {
NULL
};
-
+#if 0
static RETSIGTYPE
ignore_sig (int sig)
{
(void) signal (SIGFPE, ignore_sig);
}
-
+#endif
/* It's ok of this fails and generates signals. In that case,
* the same signal will occur when evaluating formulas and a
* (less informative) error value substituted. Note that this
diff --git a/src/sheet.h b/src/sheet.h
index 37ae3c5..fdedfb8 100644
--- a/src/sheet.h
+++ b/src/sheet.h
@@ -31,9 +31,9 @@ typedef std::deque<cell_t*> celldeq_t;
void decoord(const CELL* cp, CELLREF& r, CELLREF& c);
std::tuple<CELLREF, CELLREF> decoord(const CELL* cp);
void flush_cols();
-struct cell* find_cell(CELLREF row, CELLREF col);
-struct cell* find_cell(coord_t coord);
-struct cell* find_or_make_cell(CELLREF row, CELLREF col);
+cell* find_cell(CELLREF row, CELLREF col);
+cell* find_cell(coord_t coord);
+cell* find_or_make_cell(CELLREF row, CELLREF col);
cell_t* find_or_make_cell (coord_t coord);
diff --git a/src/tests.cc b/src/tests.cc
index fc2c410..97e5b3b 100644
--- a/src/tests.cc
+++ b/src/tests.cc
@@ -59,10 +59,10 @@ check_fmt(num_t v, const std::string& s)
void
test_formatting()
{
- check_fmt(24.6DD, "24.60");
- check_fmt(16.36DD, "16.36"); // a source of potential rounding oddities
- check_fmt(0.0DD, "0.00"); // issue #10
- check_fmt(1.0DD, "1.00");
+ check_fmt(24.6f, "24.60");
+ check_fmt(16.36f, "16.36"); // a source of potential rounding oddities
+ check_fmt(0.0f, "0.00"); // issue #10
+ check_fmt(1.0f, "1.00");
}
diff --git a/src/utils.cc b/src/utils.cc
index 2550adf..d7357f3 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -46,7 +46,7 @@
// very useful function!
// https://stackoverflow.com/questions/15106102/how-to-use-c-stdostream-with-printf-like-formatting
-std::string format(const std::string& format, ...)
+std::string format(const std::string format, ...)
{
va_list args;
va_start(args, format);
Allow copying of current cell via a command:
copy-this-cell-formula
, and paste it using
paste-this-cell-formula
Jude DaShiell wrote:
Is neoleo capable when handling dates? If so, what entry format is used to make them presentable and so neoleo recognizes them as dates? If I try doing numerology with neoleo some date math would be involved sooner or later.
When inserting cells using i
, blank lines should not be ignored. Currently:
i
1
2
.
view
will print out
1
2
but it should print out
1
2
Using C-s
to save the spreadsheet is easier than typing M-x save-spreadsheet
The fix is to add the following to init.cc
:
bind-key main save-spreadsheet ^s",
The delete key should delete a cell.
Address sanitiser reports memory leaks with formula copy and past.
You can see memory leak report in tests/issue19.log
(assuming you have ASAN compiled in.
If all you do is copy and paste using the menu (C-m c, C- v), then neoleo does not mark the spreadsheet as changed, and in need of a save when it is time to quite.
Make the page up/down work.
FYI:
KEY_NPAGE Next page
KEY_PPAGE Previous page
In 30d7081 I rewrote the code so that spans (i.e. rows and columns) no longer depended on the functionality provided in lists.cc. However, I didn't program the bit that did shift_spans(). I'll need to do that,
[lucas@archlinux neoleo-9.0]$ env CPPFLAGS=-I/user/local/include LDFLAGS=-s ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
configure: checking if debugging required ... no
configure: checking if gprof profiling required ... no
checking for g++... g++
checking whether the C++ compiler works... yes
checking for C++ compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking whether make supports the include directive... yes (GNU style)
checking dependency style of g++... gcc3
checking for bison... bison -y
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating examples/Makefile
config.status: creating src/Makefile
config.status: creating tests/Makefile
config.status: creating tests/out/Makefile
config.status: creating tests/verified/Makefile
config.status: executing depfiles commands
[lucas@archlinux neoleo-9.0]$ sudo make install
[sudo] password for lucas:
Making install in examples
make[1]: Entering directory '/home/lucas/aur/neohleo/neoleo-9.0/examples'
make[2]: Entering directory '/home/lucas/aur/neohleo/neoleo-9.0/examples'
make[2]: Nothing to be done for 'install-exec-am'.
/usr/bin/mkdir -p '/usr/local/share/neoleo/examples'
/usr/bin/install -c -m 644 blank.oleo docs.oleo loop.oleo mysql.oleo nogood.oleo pivot.oleo plot.oleo shit.oleo test.oleo types.oleo xy.oleo q110399.csv formula.sylk oleo.pm6 create_koers.txt data.sql pivot.r '/usr/local/share/neoleo/examples'
make[2]: Leaving directory '/home/lucas/aur/neohleo/neoleo-9.0/examples'
make[1]: Leaving directory '/home/lucas/aur/neohleo/neoleo-9.0/examples'
Making install in src
make[1]: Entering directory '/home/lucas/aur/neohleo/neoleo-9.0/src'
make install-am
make[2]: Entering directory '/home/lucas/aur/neohleo/neoleo-9.0/src'
g++ -DHAVE_CONFIG_H -I. -I.. -I/user/local/include -Werror -std=c++17 -Wno-write-strings -DDATADIR=""/usr/local/share"" -Wfatal-errors -MT args.o -MD -MP -MF .deps/args.Tpo -c -o args.o args.cc
mv -f .deps/args.Tpo .deps/args.Po
g++ -DHAVE_CONFIG_H -I. -I.. -I/user/local/include -Werror -std=c++17 -Wno-write-strings -DDATADIR=""/usr/local/share"" -Wfatal-errors -MT basic.o -MD -MP -MF .deps/basic.Tpo -c -o basic.o basic.cc
mv -f .deps/basic.Tpo .deps/basic.Po
g++ -DHAVE_CONFIG_H -I. -I.. -I/user/local/include -Werror -std=c++17 -Wno-write-strings -DDATADIR=""/usr/local/share"" -Wfatal-errors -MT busi.o -MD -MP -MF .deps/busi.Tpo -c -o busi.o busi.cc
mv -f .deps/busi.Tpo .deps/busi.Po
g++ -DHAVE_CONFIG_H -I. -I.. -I/user/local/include -Werror -std=c++17 -Wno-write-strings -DDATADIR=""/usr/local/share"" -Wfatal-errors -MT byte-compile.o -MD -MP -MF .deps/byte-compile.Tpo -c -o byte-compile.o byte-compile.cc
mv -f .deps/byte-compile.Tpo .deps/byte-compile.Po
g++ -DHAVE_CONFIG_H -I. -I.. -I/user/local/include -Werror -std=c++17 -Wno-write-strings -DDATADIR=""/usr/local/share"" -Wfatal-errors -MT cell.o -MD -MP -MF .deps/cell.Tpo -c -o cell.o cell.cc
cell.cc: In member function ‘void cell::set_error(const ValErr&)’:
cell.cc:74:23: error: cannot convert ‘int’ to ‘value_t’ {aka ‘std::variant<double, std::__cxx11::basic_string<char, std::char_traits, std::allocator >, err_t, rng, bool_t, empty_t>’}
74 | set_value_2019(ve.num());
| ~~~~~~^~
| |
| int
compilation terminated due to -Wfatal-errors.
make[2]: *** [Makefile:529: cell.o] Error 1
make[2]: Leaving directory '/home/lucas/aur/neohleo/neoleo-9.0/src'
make[1]: *** [Makefile:682: install] Error 2
make[1]: Leaving directory '/home/lucas/aur/neohleo/neoleo-9.0/src'
make: *** [Makefile:413: install-recursive] Error 1
The string function find()
in stringo.cc
does not seem to work properly. E.g. find("greetings", "ee", 1)
returns an anomolous number.
It is annoying!
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.