Giter VIP home page Giter VIP logo

Comments (22)

brummer10 avatar brummer10 commented on June 2, 2024

Unfortunately the debugging version of the nightly build didn't work with the debugger on debian/sid.
All I could see now is that it is a std::exeption, If I know which, I could catch it.
I'm going to setup a virtual machine with ubuntu 20.4 now to run the debugger and find out what goes wrong on session load. I've used a Ardour debugging version from the 7.x series before, and that one works correct with guitarix.vst

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

So I had run a debugging session under Ubuntu 22.04 and get a backtrace, unfortunately I've no idea what the root issue is here:
https://pastebin.com/LuxQCUm3

maybe @x42 have a idea?

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

Unfortunately the debugging version of the nightly build didn't work with the debugger on debian/sid.

What is the actual issue? I have just tested and it works fine on debian/sid (updated just now).

gdb: symbol lookup error: /lib64/libbabeltrace.so.1: undefined symbol: g_string_free_and_steal -- If so try a recent version of Ardour (8.2-144 or later)

If it is a different issue, please let us know.

unfortunately I've no idea what the root issue is here

me neither. That exception is caught by Ardour (and should not happen in the first place), so my best guess so far is memory corruption.

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

@axel-rank How do you produce this crash?

I just installed Ardour8.3 (current nightly build) then got Guitarix.vst3.zip from here, unzipped it to ~/.vst3/

Then:

  • start Ardour8 (and scanned VST3s)
  • create a new session
  • add a new track
  • load Guitarix on that track
  • Save/Quit.

Reloading the session works just fine. no Crash.

--
PS. I realize the plugin is dynamically linked. So that may cause issues.

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

AddressSanitizer delivers.. sendMovedResizedMessages causing issues was fixed in JUCE a while ago.

=19531==ERROR: AddressSanitizer: SEGV on unknown address 0x14f7287b1d97 (pc 0x7fb7583ba388 bp 0x7ffed4be0900 sp 0x7ffed4be08d0 T0)                                                             
==19531==The signal is caused by a READ memory access.
    #0 0x7fb7583ba388 in Gtk::Widget::on_configure_event(_GdkEventConfigure*) ../libs/tk/ytkmm/widget.cc:7618
    #1 0x7fb723ba0057 in juce::Component::sendMovedResizedMessages(bool, bool) (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x5a0057) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #2 0x7fb723e5e5f5 in PluginSelector::PluginSelector(MachineEditor*, bool, char const*, char const*) (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x85e5f5) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #3 0x7fb723e024a0 in MachineEditor::createPluginEditors() (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x8024a0) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #4 0x7fb723e074e4 in MachineEditor::MachineEditor(GuitarixProcessor&, bool, MachineEditor::MonoT) (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x8074e4) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #5 0x7fb723e0781e in GuitarixEditor::GuitarixEditor(GuitarixProcessor&) (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x80781e) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #6 0x7fb723c80dc5 in GuitarixProcessor::createEditor() (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x680dc5) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #7 0x7fb72396e4c3 in juce::AudioProcessor::createEditorIfNeeded() (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x36e4c3) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #8 0x7fb723937d22  (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x337d22) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #9 0x7fb72393858f  (/home/rgareus/.vst3/Guitarix.vst3/Contents/x86_64-linux/Guitarix.so+0x33858f) (BuildId: b49ca45ee2ff513baf2974982fee05a5a8e9f30c)
    #10 0x7fb75c69b47e in Steinberg::VST3PI::try_create_view() const ../libs/ardour/vst3_plugin.cc:3150
    #11 0x7fb75c69ba02 in Steinberg::VST3PI::has_editor() const ../libs/ardour/vst3_plugin.cc:3192
    #12 0x7fb75c6662d9 in ARDOUR::VST3Plugin::has_editor() const ../libs/ardour/vst3_plugin.cc:351
    #13 0x55e54205aa5f in ProcessorEntry::setup_tooltip() ../gtk2_ardour/processor_box.cc:554
    #14 0x55e542056094 in ProcessorEntry::ProcessorEntry(ProcessorBox*, std::shared_ptr<ARDOUR::Processor>, Width) ../gtk2_ardour/processor_box.cc:271
    #15 0x55e54206a1fb in PluginInsertProcessorEntry::PluginInsertProcessorEntry(ProcessorBox*, std::shared_ptr<ARDOUR::PluginInsert>, Width) ../gtk2_ardour/processor_box.cc:1256
    #16 0x55e54208c4e1 in ProcessorBox::add_processor_to_display(std::weak_ptr<ARDOUR::Processor>) ../gtk2_ardour/processor_box.cc:3146
    #17 0x55e5420e6cfa in sigc::bound_mem_functor1<void, ProcessorBox, std::weak_ptr<ARDOUR::Processor> >::operator()(std::weak_ptr<ARDOUR::Processor> const&) const /usr/include/sigc++-2.0/sigc++/functors/mem_fun.h:2066
    #18 0x55e5420dc361 in boost::detail::function::void_function_obj_invoker1<sigc::bound_mem_functor1<void, ProcessorBox, std::weak_ptr<ARDOUR::Processor> >, void, std::weak_ptr<ARDOUR::Processor> >::invoke(boost::detail::function::function_buffer&, std::weak_ptr<ARDOUR::Processor>) /usr/include/boost/function/function_template.hpp:158
    #19 0x55e541b51661 in boost::function1<void, std::weak_ptr<ARDOUR::Processor> >::operator()(std::weak_ptr<ARDOUR::Processor>) const /usr/include/boost/function/function_template.hpp:771
    #20 0x55e541b50232 in ARDOUR::Route::foreach_processor(boost::function<void (std::weak_ptr<ARDOUR::Processor>)>) const ../libs/ardour/ardour/route.h:230
    #21 0x55e54208aa7d in ProcessorBox::redisplay_processors() ../gtk2_ardour/processor_box.cc:3040
    #22 0x55e54207a6fd in ProcessorBox::set_route(std::shared_ptr<ARDOUR::Route>) ../gtk2_ardour/processor_box.cc:2032
    #23 0x55e541b31f6b in MixerStrip::set_route(std::shared_ptr<ARDOUR::Route>) ../gtk2_ardour/mixer_strip.cc:574
    #24 0x55e5411715cf in Editor::set_selected_mixer_strip(TimeAxisView&) ../gtk2_ardour/editor_mixer.cc:247
    #25 0x55e5412dcd86 in Editor::presentation_info_changed(PBD::PropertyChange const&) ../gtk2_ardour/editor_selection.cc:1148
    #26 0x55e540e567c8 in Editor::set_session(ARDOUR::Session*) ../gtk2_ardour/editor.cc:1407
    #27 0x55e540b08c8b in ARDOUR_UI::connect_dependents_to_session(ARDOUR::Session*) ../gtk2_ardour/ardour_ui_dependents.cc:130
    #28 0x55e540b19194 in ARDOUR_UI::set_session(ARDOUR::Session*) ../gtk2_ardour/ardour_ui_dialogs.cc:225
    #29 0x55e540bafe9b in ARDOUR_UI::load_session_stage_two(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) ../gtk2_ardour/ardour_ui_session.cc:576
    #30 0x55e540bae269 in ARDOUR_UI::load_session(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) ../gtk2_ardour/ardour_ui_session.cc:365
    #31 0x55e540bd9ec0 in ARDOUR_UI::load_session_from_startup_fsm() ../gtk2_ardour/ardour_ui_startup.cc:698

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

Possibly juce-framework/JUCE#867
Then again it could also be a different issue, like calling setSize before creating the component.

But the odd part is that sendMovedResizedMessages directly manages to call Gtk::Widget::on_configure_event.

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

@x42 Thanks for checking that out!
It's using juce 7.0.3 so this fix should be in.
Somehow it must be a X11 event forcing the Gtk::Widget::on_configure_event call, as juce didn't is linked with gtk.
I'll walk to the juce source now to find any call to sendMovedResizedMessages and disable that to look if it helps.
AdressSanitizer seems to be a nice tool, didn't know it before.

Odd is that there are no issues with the Ardour version from debian/sid.

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

Odd is that there are no issues with the Ardour version from debian/sid.

That is still 8.2 which uses system-wide GTK2 (which is due to removed from debian next week).

Somehow it must be a X11 event forcing the Gtk::Widget::on_configure_event call

If so, that would show up in the callgraph.

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

I'm switch of the call from juce::Component::sendMovedResizedMessages in the source, but that didn't change the error.

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

I added some printouts to the guitarix startup sequence, this is what it prints when I add guitarix to a session:

GuitarixProcessor::getStateInformation called 
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::getStateInformation done 
GuitarixProcessor::createEditor
GuitarixEditor try start
GuitarixEditor
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR called
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR done
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::createEditor
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR called
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR done
GuitarixEditor try start
GuitarixEditor
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed done

guitarix loads successful.

this is when I try to reload this session:

GuitarixProcessor::getStateInformation called 
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::getStateInformation done 
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed done
GuitarixProcessor::loadState called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::on_param_value_changed called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR called
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR done
GuitarixProcessor::setStateInformation
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR called
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR done
GuitarixProcessor::getStateInformation called 
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::getStateInformation done 
Setting time domain
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR called
GuitarixProcessor::saveState called
GuitarixProcessor::saveState done
GuitarixProcessor::loadState called
GuitarixProcessor::loadState done
GuitarixProcessor::cloneSettingsToMachineR done
locate to 0 took 6805 usecs for 4 tracks = 1701 per track
MAE: Draw Velocity/draw-velocity-auto

(ardour-8.4.0:54726): glibmm-ERROR **: 05:11:55.354: 
unhandled exception (type std::exception) in signal handler:
what: missing action: Draw Velocity/draw-velocity-auto

Trace/Breakpoint ausgelöst

It seems that Ardour crash exactly when the call to createEditor() should happen.
The startup sequence on Ardour 8.2 from debian/sid looks similar then the one from 8.4, just that it starts the editor instead crashing.

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

Where can I get a plugin with those prints?

It is weird. Since other JUCE based plugins work, this is worrying. Right now I cannot tell if the issue in in Ardour or the plugin, or both.

I am testing on debian/sid (really trixie), Ardour/git configured with ./waf configure --strict --backtrace --libjack=weak --address-sanitizer

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

There was no change to VST3 hosting or VST3 GUI 8.2 .. 8.3/8.4

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

I've done it local here, but, if you are interested I'll implement that for debugging and push it to the repository.

My impression so far is that it don't have to do with the vst hosting code in Ardour, but with the patched GTK2 version ardour use. It may absolutely be that I do things wrong, as this is my first vst3 plug and my first use of Juce, but currently only Ardour have issues with it, and, that only on session reload. And, only, when Ardour use it's own patched GTK2 version.
Maybe guitarix takes to long to init itself (it preload all plugs it use, regardless if they been in use or not), maybe that leads to a race condition. Maybe I do some things wrong at all and Ardours GTK2 implementation is completely right.
However, if you would help to identify the root cause that will be more then welcome.

I'll push tomorrow the version with debugging output like posted above to the repository.

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

I've done a very simple patch...

diff --git a/JuceModules/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp b/JuceModules/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
index 5e2c974..5f5e9a7 100644
--- a/JuceModules/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
+++ b/JuceModules/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
@@ -2154,6 +2154,8 @@ private:
 
             void resized() override
             {
+                printf ("VST3 RESIZED()\n");^M
+                return;^M
                 if (pluginEditor != nullptr)
                 {
                     if (! resizingParent)
diff --git a/JuceModules/modules/juce_gui_basics/components/juce_Component.cpp b/JuceModules/modules/juce_gui_basics/components/juce_Component.cpp
index 3ed50b8..83ef2b8 100644
--- a/JuceModules/modules/juce_gui_basics/components/juce_Component.cpp
+++ b/JuceModules/modules/juce_gui_basics/components/juce_Component.cpp
@@ -1224,7 +1224,9 @@ void Component::sendMovedResizedMessages (bool wasMoved, bool wasResized)
 
     if (wasResized)
     {
+        printf ("CALL RESIZED..\n");^M
         resized();
+        printf ("CALLED RESIZED..\n");^M
 
         if (checker.shouldBailOut())
             return;

And when reloading the session,.. I see

JUCE v7.0.3
***PREPARE buffersize:1024 delay:0 quantum:256 olen:1280
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
CALL RESIZED..
AddressSanitizer:DEADLYSIGNAL
=================================================================
==40126==ERROR: AddressSanitizer: SEGV on unknown address 0x14fda0fdbe17 (pc 0x7f1bab1ba388 bp 0x7ffe2d4729e0 sp 0x7ffe2d4729b0 T0)
==40126==The signal is caused by a READ memory access.
    #0 0x7f1bab1ba388 in Gtk::Widget::on_configure_event(_GdkEventConfigure*) ../libs/tk/ytkmm/widget.cc:7618
    #1 0x7f1b75dc28fa in juce::Component::sendMovedResizedMessages(bool, bool) ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1228
    #2 0x7f1b75dc2817 in juce::Component::sendMovedResizedMessagesIfPending() ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1209
    #3 0x7f1b75dc2795 in juce::Component::setBounds(int, int, int, int) ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1195
    #4 0x7f1b76286e4e in PluginSelector::PluginSelector(MachineEditor*, bool, char const*, char const*) ../../Source/PluginEditor.cpp:802
    #5 0x7f1b7620e2b3 in MachineEditor::createPluginEditors() ../../Source/GuitarixEditor.cpp:901
    #6 0x7f1b7620d107 in MachineEditor::MachineEditor(GuitarixProcessor&, bool, MachineEditor::MonoT) ../../Source/GuitarixEditor.cpp:722
    #7 0x7f1b76207378 in GuitarixEditor::GuitarixEditor(GuitarixProcessor&) ../../Source/GuitarixEditor.cpp:38
    #8 0x7f1b75fcaa4c in GuitarixProcessor::createEditor() ../../Source/GuitarixProcessor.cpp:1247

So

  • resized() never returns
  • the overridden implementation in VST3 is never called (!)
  • somehow sendMovedResizedMessages calls resized() multiple times.. and yet resized never returns.

Time to call valgrind...

If I had to guess... there is a missing return value somewhere, which corrupts the stack

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

valgrind didn't help (but found various uninitialized variables notably "flags" in

gx_engine::Plugin::register_vars(gx_engine::ParamMap&, gx_engine::EngineControl&) (gx_pluginloader.cpp:339
gx_engine::Plugin::register_vars(gx_engine::ParamMap&, gx_engine::EngineControl&) (gx_pluginloader.cpp:350)

Another test. when simply returning early in Component::sendMovedResizedMessages Ardour crashes like this this

#0  0x00007ffff4ff01da in Gtk::Widget::on_grab_notify(bool) (this=0x55555e6b4f20, was_grabbed=200) at ../libs/tk/ytkmm/widget.cc:7435
#1  0x00007fff7e9c4136 in juce::Component::internalChildrenChanged() (this=0x55555e6b4f20) at ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1698
#2  0x00007fff7e9c3b16 in juce::Component::addChildComponent(juce::Component&, int) (this=0x55555e6b4f20, child=..., zOrder=0)
    at ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1538
#3  0x00007fff7e9c3b5f in juce::Component::addAndMakeVisible(juce::Component&, int) (this=0x55555e6b4f20, child=..., zOrder=-1)
    at ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1545

Weird.

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

I just built Adour against system-wide gtk2 (./waf configure --no-ytk ...) and the error persists. Except now it's

==71954==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x7f418270c043 bp 0x51d00036cf50 sp 0x7ffe91f100e0 T0)
==71954==The signal is caused by a READ memory access.
==71954==Hint: this fault was caused by a dereference of a high value address (see register values below).  Disassemble the provided pc to learn which register was used.
    #0 0x7f418270c043 in Gtk::Widget::on_configure_event(_GdkEventConfigure*) (/lib/x86_64-linux-gnu/libgtkmm-2.4.so.1+0x30c043) (BuildId: d868d89d032e97fd12324b722cd52cf9be5e26ad)
    #1 0x7f414d9c2a0b in juce::Component::sendMovedResizedMessages(bool, bool) ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1227
    #2 0x7f414d9c2937 in juce::Component::sendMovedResizedMessagesIfPending() ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1209
    #3 0x7f414d9c28b5 in juce::Component::setBounds(int, int, int, int) ../../JuceModules/modules/juce_gui_basics/components/juce_Component.cpp:1195

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

Very wired. I tried your patch but here it didn't even reach the stage that a component gets created.
It didn't reach the stage that the Editor was inited so no call to any GUI stuff happen here.

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

@x42
It seems I found the issue.
guitarix.vst sets
std::locale::global(std::locale("C"))
in it's startup sequence

https://github.com/brummer10/guitarix.vst/blob/main/Source/GuitarixProcessor.cpp#L39

to avoid issues when load/save preset files.
Removing this solved this issue,

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

This issue should be fixed with the last commit.
Ready to test binary is available on the project page. Please let me know if it works for you now as well.

regards
hermann

from guitarix.vst.

axel-rank avatar axel-rank commented on June 2, 2024

Yes, working now. Great!
Tested with Ardour 8.4.11

from guitarix.vst.

x42 avatar x42 commented on June 2, 2024

That is surprising. How did you even find that?! Well done.

While messing with the global stdlibc locale can cause various issues, I am surprised that it caused this issue.

from guitarix.vst.

brummer10 avatar brummer10 commented on June 2, 2024

I'm going to switch off every function from button to top, then I end up at this one.

I'm now set the std::locale::classic() directly and only on the i/ostream ( imbue()) for read and write internal presets so that it didn't interference with the host.

from guitarix.vst.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.