mjakeman / extension-manager Goto Github PK
View Code? Open in Web Editor NEWA utility for browsing and installing GNOME Shell Extensions.
Home Page: https://mattjakeman.com/apps/extension-manager
License: GNU General Public License v3.0
A utility for browsing and installing GNOME Shell Extensions.
Home Page: https://mattjakeman.com/apps/extension-manager
License: GNU General Public License v3.0
In a rather unfortunate turn of events, extensions.gnome.org is down at the moment.
This is a good opportunity to improve error reporting within the program. We should notify the user if:
It would be good to use libadwaita's new in-app notification widgets to display this.
Preparing...
Cloning extension-manager build files...
Generating extension-manager information...
Checking extension-manager dependencies...
Resolving dependencies...
Checking inter-conflicts...
Building extension-manager...
==> Making package: extension-manager 0.1.0-1 (Пн 10 янв 2022 17:22:56)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
-> Found v0.1.0.tar.gz
==> Validating source files with b2sums...
v0.1.0.tar.gz ... Passed
==> Removing existing $srcdir/ directory...
==> Extracting sources...
-> Extracting v0.1.0.tar.gz with bsdtar
==> Removing existing $pkgdir/ directory...
==> Starting build()...
+ exec meson setup --prefix /usr --libexecdir lib --sbindir bin --buildtype plain --auto-features enabled --wrap-mode nodownload -D b_lto=true -D b_pie=true extension-manager-0.1.0 build
The Meson build system
Version: 0.60.3
Source dir: /var/tmp/pamac-build-alphas/extension-manager/src/extension-manager-0.1.0
Build dir: /var/tmp/pamac-build-alphas/extension-manager/src/build
Build type: native build
Project name: extension-manager
Project version: 0.1.0
C compiler for the host machine: cc (gcc 11.1.0 "cc (GCC) 11.1.0")
C linker for the host machine: cc ld.bfd 2.36.1
Host machine cpu family: x86_64
Host machine cpu: x86_64
Configuring exm-config.h using configuration
Program desktop-file-validate found: YES (/usr/bin/desktop-file-validate)
Program appstream-util found: YES (/usr/bin/appstream-util)
Program glib-compile-schemas found: YES (/usr/bin/glib-compile-schemas)
Found pkg-config: /usr/bin/pkg-config (1.8.0)
Run-time dependency gtk4 found: YES 4.4.1
Run-time dependency libadwaita-1 found: YES 1.0.0.alpha.4
Run-time dependency json-glib-1.0 found: YES 1.6.6
Run-time dependency libsoup-3.0 found: YES 3.0.3
Program blueprint-compiler found: YES (/usr/bin/blueprint-compiler)
Found pkg-config: /usr/bin/pkg-config (1.8.0)
Program glib-compile-resources found: YES (/usr/bin/glib-compile-resources)
Program build-aux/meson/postinstall.py found: YES (/var/tmp/pamac-build-alphas/extension-manager/src/extension-manager-0.1.0/build-aux/meson/postinstall.py)
Build targets in project: 9
extension-manager 0.1.0
User defined options
auto_features: enabled
buildtype : plain
libexecdir : lib
prefix : /usr
sbindir : bin
wrap_mode : nodownload
b_lto : true
b_pie : true
Found ninja-1.10.2 at /usr/bin/ninja
ninja: Entering directory `/var/tmp/pamac-build-alphas/extension-manager/src/build'
[1/15] Generating data/com.mattjakeman.ExtensionManager.desktop_data_merge with a custom command
[2/15] Generating data/com.mattjakeman.ExtensionManager.appdata.xml_data_merge with a custom command
[3/15] Generating src/blueprints with a custom command
[4/15] Generating src/exm-resources_h with a custom command
[5/15] Generating src/exm-resources_c with a custom command
[6/15] Compiling C object src/extension-manager.p/model_exm-extension.c.o
../extension-manager-0.1.0/src/model/exm-extension.c: In function ‘exm_extension_finalize’:
../extension-manager-0.1.0/src/model/exm-extension.c:54:19: warning: unused variable ‘self’ [-Wunused-variable]
54 | ExmExtension *self = (ExmExtension *)object;
| ^~~~
../extension-manager-0.1.0/src/model/exm-extension.c: In function ‘exm_extension_init’:
../extension-manager-0.1.0/src/model/exm-extension.c:193:35: warning: unused parameter ‘self’ [-Wunused-parameter]
193 | exm_extension_init (ExmExtension *self)
| ~~~~~~~~~~~~~~^~~~
[7/15] Compiling C object src/extension-manager.p/meson-generated_.._exm-resources.c.o
[8/15] Compiling C object src/extension-manager.p/model_exm-manager.c.o
../extension-manager-0.1.0/src/model/exm-manager.c: In function ‘exm_manager_finalize’:
../extension-manager-0.1.0/src/model/exm-manager.c:32:17: warning: unused variable ‘self’ [-Wunused-variable]
32 | ExmManager *self = (ExmManager *)object;
| ^~~~
../extension-manager-0.1.0/src/model/exm-manager.c: In function ‘exm_manager_set_property’:
../extension-manager-0.1.0/src/model/exm-manager.c:61:17: warning: unused variable ‘self’ [-Wunused-variable]
61 | ExmManager *self = EXM_MANAGER (object);
| ^~~~
../extension-manager-0.1.0/src/model/exm-manager.c:58:41: warning: unused parameter ‘value’ [-Wunused-parameter]
58 | const GValue *value,
| ~~~~~~~~~~~~~~^~~~~
../extension-manager-0.1.0/src/model/exm-manager.c: In function ‘on_signal’:
../extension-manager-0.1.0/src/model/exm-manager.c:385:24: warning: unused parameter ‘proxy’ [-Wunused-parameter]
385 | on_signal (GDBusProxy *proxy,
| ~~~~~~~~~~~~^~~~~
../extension-manager-0.1.0/src/model/exm-manager.c:386:24: warning: unused parameter ‘sender_name’ [-Wunused-parameter]
386 | gchar *sender_name,
| ~~~~~~~~~~~~^~~~~~~~~~~
../extension-manager-0.1.0/src/model/exm-manager.c:388:24: warning: unused parameter ‘parameters’ [-Wunused-parameter]
388 | GVariant *parameters,
| ~~~~~~~~~~~~^~~~~~~~~~
[9/15] Compiling C object src/extension-manager.p/web_exm-search-result.c.o
../extension-manager-0.1.0/src/web/exm-search-result.c: In function ‘exm_search_result_finalize’:
../extension-manager-0.1.0/src/web/exm-search-result.c:47:22: warning: unused variable ‘self’ [-Wunused-variable]
47 | ExmSearchResult *self = (ExmSearchResult *)object;
| ^~~~
../extension-manager-0.1.0/src/web/exm-search-result.c: In function ‘exm_search_result_init’:
../extension-manager-0.1.0/src/web/exm-search-result.c:186:42: warning: unused parameter ‘self’ [-Wunused-parameter]
186 | exm_search_result_init (ExmSearchResult *self)
| ~~~~~~~~~~~~~~~~~^~~~
../extension-manager-0.1.0/src/web/exm-search-result.c: In function ‘json_serializable_iface_init’:
../extension-manager-0.1.0/src/web/exm-search-result.c:191:54: warning: unused parameter ‘iface’ [-Wunused-parameter]
191 | json_serializable_iface_init (JsonSerializableIface *iface)
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~
[10/15] Compiling C object src/extension-manager.p/web_exm-search-provider.c.o
../extension-manager-0.1.0/src/web/exm-search-provider.c:23:20: warning: ‘properties’ defined but not used [-Wunused-variable]
23 | static GParamSpec *properties [N_PROPS];
| ^~~~~~~~~~
[11/15] Compiling C object src/extension-manager.p/web_exm-image-resolver.c.o
../extension-manager-0.1.0/src/web/exm-image-resolver.c: In function ‘image_loaded_callback’:
../extension-manager-0.1.0/src/web/exm-image-resolver.c:57:19: warning: implicit declaration of function ‘gdk_texture_new_from_bytes’; did you mean ‘gdk_texture_new_from_file’? [-Wimplicit-function-declaration]
57 | texture = gdk_texture_new_from_bytes (bytes, &error);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
| gdk_texture_new_from_file
../extension-manager-0.1.0/src/web/exm-image-resolver.c:57:17: warning: assignment to ‘GdkTexture *’ {aka ‘struct _GdkTexture *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
57 | texture = gdk_texture_new_from_bytes (bytes, &error);
| ^
At top level:
../extension-manager-0.1.0/src/web/exm-image-resolver.c:20:20: warning: ‘properties’ defined but not used [-Wunused-variable]
20 | static GParamSpec *properties [N_PROPS];
| ^~~~~~~~~~
[12/15] Compiling C object src/extension-manager.p/main.c.o
[13/15] Compiling C object src/extension-manager.p/exm-application.c.o
../extension-manager-0.1.0/src/exm-application.c: In function ‘exm_application_finalize’:
../extension-manager-0.1.0/src/exm-application.c:42:21: warning: unused variable ‘self’ [-Wunused-variable]
42 | ExmApplication *self = (ExmApplication *)object;
| ^~~~
../extension-manager-0.1.0/src/exm-application.c: In function ‘exm_application_show_about’:
../extension-manager-0.1.0/src/exm-application.c:94:44: warning: unused parameter ‘action’ [-Wunused-parameter]
94 | exm_application_show_about (GSimpleAction *action,
| ~~~~~~~~~~~~~~~^~~~~~
../extension-manager-0.1.0/src/exm-application.c:95:44: warning: unused parameter ‘parameter’ [-Wunused-parameter]
95 | GVariant *parameter,
| ~~~~~~~~~~~~~~~^~~~~~~~~
[14/15] Compiling C object src/extension-manager.p/exm-window.c.o
../extension-manager-0.1.0/src/exm-window.c: In function ‘on_install_done’:
../extension-manager-0.1.0/src/exm-window.c:199:32: warning: unused parameter ‘self’ [-Wunused-parameter]
199 | ExmWindow *self)
| ~~~~~~~~~~~~~~^~~~
../extension-manager-0.1.0/src/exm-window.c: In function ‘create_thumbnail’:
../extension-manager-0.1.0/src/exm-window.c:240:37: warning: unused parameter ‘resolver’ [-Wunused-parameter]
240 | create_thumbnail (ExmImageResolver *resolver,
| ~~~~~~~~~~~~~~~~~~^~~~~~~~
../extension-manager-0.1.0/src/exm-window.c:241:37: warning: unused parameter ‘icon_uri’ [-Wunused-parameter]
241 | const gchar *icon_uri)
| ~~~~~~~~~~~~~~~~~~^~~~~~~~
../extension-manager-0.1.0/src/exm-window.c: In function ‘search_widget_factory’:
../extension-manager-0.1.0/src/exm-window.c:275:16: warning: unused variable ‘screenshot’ [-Wunused-variable]
275 | GtkWidget *screenshot;
| ^~~~~~~~~~
../extension-manager-0.1.0/src/exm-window.c: In function ‘update_extensions_list’:
../extension-manager-0.1.0/src/exm-window.c:380:30: warning: cast between incompatible function types from ‘GtkWidget * (*)(ExmExtension *)’ {aka ‘struct _GtkWidget * (*)(struct _ExmExtension *)’} to ‘GtkWidget * (*)(void *, void *)’ {aka ‘struct _GtkWidget * (*)(void *, void *)’} [-Wcast-function-type]
380 | (GtkListBoxCreateWidgetFunc) widget_factory,
| ^
At top level:
../extension-manager-0.1.0/src/exm-window.c:222:1: warning: ‘on_image_loaded’ defined but not used [-Wunused-function]
222 | on_image_loaded (GObject *source,
| ^~~~~~~~~~~~~~~
[15/15] Linking target src/extension-manager
FAILED: src/extension-manager
cc -o src/extension-manager src/extension-manager.p/meson-generated_.._exm-resources.c.o src/extension-manager.p/main.c.o src/extension-manager.p/exm-window.c.o src/extension-manager.p/exm-application.c.o src/extension-manager.p/model_exm-manager.c.o src/extension-manager.p/model_exm-extension.c.o src/extension-manager.p/web_exm-search-provider.c.o src/extension-manager.p/web_exm-search-result.c.o src/extension-manager.p/web_exm-image-resolver.c.o -flto -Wl,--as-needed -Wl,--no-undefined -pie -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -Wl,--start-group /usr/lib/libgtk-4.so /usr/lib/libpangocairo-1.0.so /usr/lib/libpango-1.0.so /usr/lib/libharfbuzz.so /usr/lib/libgdk_pixbuf-2.0.so /usr/lib/libcairo-gobject.so /usr/lib/libcairo.so /usr/lib/libgraphene-1.0.so /usr/lib/libgio-2.0.so /usr/lib/libgobject-2.0.so /usr/lib/libglib-2.0.so /usr/lib/libadwaita-1.so /usr/lib/libjson-glib-1.0.so /usr/lib/libsoup-3.0.so -Wl,--export-dynamic /usr/lib/libgmodule-2.0.so -Wl,--end-group -pthread
/usr/bin/ld: /tmp/cc2Tzjok.ltrans0.ltrans.o: in function `image_loaded_callback':
<artificial>:(.text+0x12ed): undefined reference to `gdk_texture_new_from_bytes'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
==> ERROR: A failure occurred in build().
Aborting...
when VPN with proxy is activated, it does not find any extensions:
debug_extension.txt
Version: 0.2.2
Ubuntu 20.04.3 LTS
Gnome: 3.36.8
Flatpak 1.6.5
Font (not changed): Ubuntu Regular
Hi. I have a problem with the application. I've installed it as 'system'. It runs well until I try to install any extension since nothing happens after pushing the install button.
Starting the application from a terminal, an error is listed which is:
"** (extension-manager:2): CRITICAL **: 01:00:47.977: GDBus.Error:org.gtk.GDBus.UnmappedGError.Quark._g_2dio_2derror_2dquark.Code36: GDBus.Error:org.gnome.Shell.DownloadInfoError: 6"
My system is Ubuntu 20.04.3 LTS with Gnome 3.36.8 under X11
Any ideas?
Thanks a lot and congratulations for this amazing application.
This would allow people to share their extension setups and migrate between different PCs easier.
Hi,
would you mind giving a tutorial how to setup and install
this please, learning linux so it would greatly help me?
going to use fedora
Thankyou
Some times I might not remember the name of the extension I want to change some settings of. So I have to scroll trough my list and look at the names. Then it would be very useful if I could sort the list such that all turned on extensions show first, instead of there being a mix of on and off extensions.
Hope that makes sense. Thanks for this fantastic application!
In the header bar, though, it's referring to a plural name ("installed [extensions]") while in the button it's a singular ("[the extension is] installed"), so in languages like Italian where you conjugate also adjectives in one of the two circumstances the string is wrong. I don't know how to make localization, but would it maybe be possible to make a plural and singular form of the string for use in the header bar and in the button respectively?
That's a good question, I'm not too familiar with gettext either. Taking a look at the GLib documentation, we should be able to use the C_()
macro to provide context to the string. So the header bar might be C_("Navigation", "Installed")
and the button would be C_("State", "Installed")
or something like that. I'll give it a try soon, it might need some changes to our gettext setup.
Originally posted by @mjakeman in #27 (comment)
I installed development version of Ubuntu 22.04. I installedExtention-manager 0.2.2 from Flathub flatpak package.
This is feature request. Please move all of the Unsupported extensions at bottom of the list or say it differently first group by installation type:
We've been getting a lot of translations lately, which is fantastic.
It would be good to:
If you would like to translate extension-manager into your language, contributions are very welcome.
on openSUSE MicroOS (Desktop), if installed with SELinux enabled, the app does not start, and the following error is shown on the console:
cannot enable executable stack as shared object requires: Permission denied
Which seemed SELinux related. in /var/log/audit/audit.log
I see:
type=AVC msg=audit(1643361322.448:108): avc: denied { execstack } for pid=2080 comm="extension-manag" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=process permissive=0
I'm no SELinux expert, but I have a test system and can provide more information, if necessary, or run tests
Is it possible to make the application compatible with the official ubuntu themes?
will there be any support for snap for ubuntu in future?
Hiding unsupported extension would make installing extension quicker and make the UI cleaner especially when your search query resulted in almost all unsupported extension.
The normal extension app can do this. It's super helpful to debug extension issues.
Might be a uncommon bug, but if you have your extensions disabled via GNOME Extensions, Extension Manager will still mark extensions as being turned on. Allowing extensions in GNOME Extensions restores functionality to the application.
Perhaps there could be an indicator if a user has both application installed that extensions have been disabled?
Hi,
compiling extension-manager on Fedora 35 fails with this error messages:
`+ cd extension-manager-0.2.3
Found ninja-1.10.2 at /usr/bin/ninja
ninja: build stopped: subcommand failed.
`
When I want to install an extension and I go to the browse tab, the application crashes.
I tried to create a traceback and saw the following:
/usr/include/c++/11.2.0/string_view:233: constexpr const value_type& std::basic_string_view<_CharT, _Traits>::operator[](std::basic_string_view<_CharT, _Traits>::size_type) const [with _CharT = char; _Traits = std::char_traits<char>; std::basic_string_view<_CharT, _Traits>::const_reference = const char&; std::basic_string_view<_CharT, _Traits>::size_type = long unsigned int]: Assertion '__pos < this->_M_len' failed.
Aborted (core dumped)
I hope this helps somehow.
I want translate this application in to Russian Language
It would be nice if the extensions would be ordered in some way. Alphabetically by their name would make the most sense I guess...
The appstream data (which determines what is displayed on GNOME Software and Flathub) is very barebones at the moment.
For the next update, fill out more fields:
See: https://www.freedesktop.org/software/appstream/docs/chap-Quickstart.html
Fun fact: Extension Manager now has nearly 4500 unique installs. This is a great milestone, but it also means 4000+ people are using the logo I created in less than 5 minutes :)
GNOME provides some excellent resources on creating compelling app icons. While the current icon is perfectly serviceable, I think the program has outgrown it. It would be nice to have a modern "GNOME-Style" icon which properly fits in with the rest of the desktop. Some goals to keep in mind:
Help wanted - If you are good with design and would like to contribute, please get in touch!
The default extensions app has manually installed and system installed lists and inside the 2 lists the extensions are sorted by name.
IMHO there is no need for 2 lists. But the info if its systemwide installed could be shown in the list and also the list could be sorted alphabetically.
Currently the placeholder green extension icon is used for everything. We should dynamically load the correct icons from the internet and save them to some form of offline cache which persists between restarts (as to show them for installed extensions).
Investigate GTK's support for Assistive Technologies: https://docs.gtk.org/gtk4/section-accessibility.html
Can we make Extension Manager friendly to screen readers (e.g. Orca)?
Extension Manager respects the system dark preference. As that's not going to be widely available until GNOME 42, let's add an in-app toggle as well. As an added benefit, it will let the user override the system preference if they wish.
There's a very good implementation of this in the new Text Editor app. Maybe we can reuse some of it? See: https://gitlab.gnome.org/GNOME/gnome-text-editor
Currently, trying to download a shell extension that does not support your version of GNOME Shell will fail silently in the background. We should grey-out (or even filter-out) search results which are not installable.
Follow this issue for notifications of a new release or string freeze.
Translators: Starting from version 0.3, there will be a "string freeze" where no changes to strings will occur. This will be a period of five days or so, giving time for translators to update their language(s).
Packagers: Releases will also be announced here, in case you wish to package extension-manager for a format other than flatpak.
Release Checklist:
Release Test Plan:
First of all: great app, thanks a lot - and congrats for the new release!
I'm a Mutter developer and thus run a development version of Mutter/Gnome-Shell most of the cycle as my daily driver - essentially dogfooding myself all the new features to help ensuring stability. As extensions usually only declare versions supported once a stable version was released, I have to run with /org/gnome/shell/disable-extension-version-validation
enabled.
I'd love to use your app to try extensions from time to time, thus I'd like to humbly request to allow that if the setting above is set - maybe with some kind of visual warning.
Currently adding/updating translations has a non-trivial barrier to entry. We can make this far more straightforward through a hosted PO editor.
Weblate offers free hosting for FOSS projects provided they meet the criteria:
Unfortunately, the project has only existed for two months. In mid-April, we should be eligible for free hosting.
The gschema file is currently in our POTFILES for translation.
According to https://wiki.gnome.org/HowDoI/GSettings, this is wrong:
⚠️ There are several examples in the wild of projects that use .gschema.xml.in files. This is almost always wrong. You should absolutely never use intltool or itstool-based XML "translation merging" functionality with schema files. It is also typically unnecessary to use expansions such as @GETTEXT_PACKAGE@, as these things are not configurable by the user (and shouldn't be).
Application (version 0.2.2) doesn't remember it's size after reopening.
A catch-all issue for some improvements to the search page:
Detect if there is an update available (via DBus) and prompt the user to update to the latest version.
First of all, I'm not related to the Gnome project in any way (except using Gnome as my daily driver).
Recently, I leaned about Gnome Circle -> https://circle.gnome.org/
And as I found that your software is super useful and adds a lot to the functionality of Gnome, I think it deserves the attention that the initiative could give it.
I'm not sure if you were already aware of this but I just wanted to make sure you wont miss it.
Allow "popping out" screenshots so the user can zoom in and see them in a larger size.
The user should be able to view comments and extension ratings as part of the search results.
Displaying the comments will be quite tricky. We need a way to either render HTML or (ideally) convert it to Pango markup.
Investigate whether there is a way to display simple HTML markup without using webkit.
Display a pop-up when loading a new version, showing the user release notes.
In the official extensions app (since version 40 I think?) you can search through installed extensions. Would be awesome if you could make something similar!
I know that most of the people here hate snaps, but at least in my eyes, snaps are better. Because they can be installed in any device including servers, Iots etc. So I would request you to create a snap version of this also. There is also a documentation of snaps by canonical, if u need. Thanks in advance.
The program should be able to poll for updates when the user logs in. The current behaviour as of #119 is to check for updates when the program is launched. To match the official extensions app, this will likely be enabled by default, with an option to turn it off.
To make GNOME extensions more decentralised, maybe creating a way to self host your own GNOME extensions repository and be able to add it into the extension manager.
Just like the normal app. Helps to quickly see which extensions can be uninstalled from the app.
We should display images when browsing through the available extensions.
This involves:
There is already a naive implementation of asynchronous image resolution in src/web/exm-image-resolver.c
. This works for the most part, but seems to have issues with deadlocking.
Make the application available on flathub for ease of download. It has many other benefits like automatic updates, and should appear in GNOME Software for most users.
A few changes will need to be made for this:
Are there any other specific requirements for being distributable on flathub?
Hi,
Since you are using libadwaita it makes sense to follow GNOME's design language more closely. Don't know how far ahead you thought about the design but here are my 2¢ about it. (I did see you posting on GNOME Shell's extension issue. So if you got contacted by a GNOME dev, just ignore me since they'll probably have their own design plans 😉)
My idea can be summarised as "Because your app is basically an extension store, you can just copy GNOME Software (instead of GNOME's extensions app)".
I think you can unify the rows of the Installed
and Browse
page. Currently, the row of the Installed
page expands to reveal the description, a 'See Details' and a remove button. The description isn't useful for extensions you already have installed because you likely know what you installed. So essientially you have a revealer for 2 buttons, which IMO isn't worth it. Also, that means the Details page is 2 clicks away. My suggestion: instead of an expander make the row always go to the details subpage.
I think unifying the Installed
and Browse
page in general make sense. I. e. having a global search like a normal app store etc...
Spacing between items is sometimes off. GNOME (unofficially) uses a multiples of 12, sometimes 6.
Here is a mockup I created to illustrate my ideas more clearly. I am not a designer so sometimes I was inconsistent when it comes to spacing, shadows and what not...
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.