Git Product home page Git Product logo

riker's People

Contributors

anacrolix avatar ancwrd1 avatar casonadams avatar dreamersdw avatar elenaf9 avatar ghtyrant avatar hardliner66 avatar igalic avatar jpopesculian avatar kitsuneninetails avatar leenozara avatar mkj avatar mrjoe7 avatar nothingismagick avatar olanod avatar olexiyb avatar riemass avatar sergey-melnychuk avatar teymour-aldridge avatar xacrimon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

riker's Issues

terminate actor with no more messages guarantee

Currently, there is no way to terminate the actor from recv callback in a way, that no messages will arrive (recv will not be called) after termination. Clearly ctx.stop(ctx.myself()); does not satisfy this criteria.

Here is the typical use case:

impl Actor for MyActor {
    type Msg = MyEvent;

    fn post_start(&mut self, ctx: &Context<Self::Msg>) {
        // do request wait for MyEvent::Response
        issue_request_to_someont(ctx.myself());

        // or MyEvent::Timeout 
        ctx.schedule_once(ctx.myself(), Duration::from_sec(1), MyEvent::Timeout)
    }
    
    fn recv(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, _sender: Sender) {
        match msg {
            MyEvent::Response(_) => {
                // handle response
            },

            MyEvent::Timeout => {
                // handle timeout
            }
        }
        
        // missing :(
        ctx.terminate();
   }
}

In Erlang, I would simply stop receiving messages and leave the process function. Since here we are based on callback, I believe that such a function is really important.

[Discussion] Add a way wait/block the main thread on `ActorSystem`

Currently there is no clear way how to wait for the actor system to complete as the main thread would exit, since creation of the actor system dose not block.

After discussing this issue with @leenozara and @riemass and others we got these proposals:

1 - one way to add a method to the ActorSystem like .wait() that returns a rx from a oneshot channel (acts like a future) and then using block_on(sys.wait()) to wait until this future resolves, and it will only resolve on system shutdown event.

2 - similar to the previous proposal but @leenozara introduced the when_terminated() instead like in the akka's when_terminated and it would return the Terminated (type alias for Receiver<()> for now), and I started to build on this idea by adding another feature that would also enable to get notified in another places on the application when the system is terminated, the idea also is inspired by akka ActorSystem, adding a sys.register_on_termination(fn)
by register a callback to run after system is terminated, and the termination event/message has been issued and all actors in this actor system have been stopped. that also would be possible to add multiply callbacks by calling this method multiple times. Note that ActorSystem will not terminate until all the registered callbacks are finished. (which would be a good place to add a tx to send you a notification when the system is terminated).

3- added by @leenozara and @riemass too, We have channels that are PubSub and we have ask that is a tmp actor bridging the actor space and main thread space as a future. One idea could be to combine those two, for example using .when_terminated() creates an ask that subscribes to some SystemTerminatedChannel. When shutdown happens all the subscribed temporaty ask actors fulfill their futures.

Any other Ideas/proposals ?

Change rustfmt newline_style to "Auto"

I'm currently using auto-crlf in git. With newline_style "Unix" I always have "changed" files in git because the newlines don't match. Setting it to "Native" would solve that for me, but everyone who uses auto-crlf false will than have the same problem.

I think it would be better to leave the newlines as is while formatting because git already handles that conversion.

clippy module inception: module has the same name as its containing module

I feel like these warnings are point towards a structural or architectural issue:

    Checking riker v0.4.0 (/home/meena/src/ap/riker)
warning: module has the same name as its containing module
 --> src/actor/mod.rs:1:1
  |
1 | pub mod actor;
  | ^^^^^^^^^^^^^^
  |
  = note: `#[warn(clippy::module_inception)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

warning: module has the same name as its containing module
 --> src/kernel/mod.rs:1:1
  |
1 | pub(crate) mod kernel;
  | ^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

warning: module has the same name as its containing module
 --> src/system/mod.rs:2:1
  |
2 | pub(crate) mod system;
  | ^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

warning: module has the same name as its containing module
 --> src/actor/mod.rs:1:1
  |
1 | pub mod actor;
  | ^^^^^^^^^^^^^^
  |
  = note: `#[warn(clippy::module_inception)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

warning: module has the same name as its containing module
 --> src/kernel/mod.rs:1:1
  |
1 | pub(crate) mod kernel;
  | ^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

warning: module has the same name as its containing module
 --> src/system/mod.rs:2:1
  |
2 | pub(crate) mod system;
  | ^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

[Discussion] notify Subscribe/Unsubscribe subscriber when subscription is actually added

Maybe it makes sense to inform channel subscriber, that subscription has been added to the subscription list?

Such notification can be useful in the case when subscriber has to be sure that it will be notified on something, it immediately initiated. This will help to avoid race conditions similar to what currently happens in ActorSystem::shutdown. I believe that this is quite a common pattern.

default config, don't try to unwrap if the toml not found

I'm getting this if i haven't setup the config toml:

thread 'tests::can_instantiate' panicked at 'called `Result::unwrap()` on an `Err` value: configuration file "config/riker.toml" not found', libcore/result.rs:945:5

it seems to me that default fallback config could work better than an unwrap

what would be an appropriate way to integrate this with a web framework

I am new to Rust as well as the Actor Pattern on a whole, so I am trying to understand How do i integrate it with an existing web framework.

Should I include the code below within an actor (will it cause any performance issues?)
Should I include the code below within another thread. If so, how do I refer to all the actors.

Basically I am trying to forward all HTTP messages to existing actors that are running.
I did have a look at actix, but it doesn't support named actors(which is big for me) and docs aren't great.

#[macro_use] extern crate nickel;

use nickel::{Nickel, HttpRouter};
fn main() {
    let mut server = Nickel::new();

    server.get("/bar", middleware!("This is the /bar handler"));
    server.get("/user/:userid", middleware! { |request|
        format!("This is user: {:?}", request.param("userid"))
    });
    server.get("/a/*/d", middleware!("matches /a/b/d but not /a/b/c/d"));
    server.get("/a/**/d", middleware!("This matches /a/b/d and also /a/b/c/d"));

    server.listen("127.0.0.1:6767");
}

why only one system per application?

i saw this in the docs but wasn't sure why

it seems like it would be advantageous to have an actor system in a module with its own protocol

what are the consequences of having more than one system running?

assoc_unix_epoch feature no longer needed

The #![feature(assoc_unix_epoch)] is no longer required as it's now stabilized. Also incidentally: riker 0.1.8 compiles for stable rust just fine with that line removed.

Typos in tutorial

Hi.
Thank you for making Riker!

In the "Message Types" section of the tutorial the code for implementing Receiver and Receiver both have _msg: Add ...

The example ran correctly after changing _msg: to Sub and Print, respectively.

I didn't try running it as is...

Thanks.

P.S. I am going to try to use Seed (a WASM web-framework) with Riker, just to experiment and learn. Is there anything you think I should know about using Riker with WASM?

Noob to webdev, Rust, actors, distributed computing, etc. (pretty much a noob to all this tech with Rust being my first language for anything more than dabbling (dabbled with Haskell and Python each for a bit...)).
email is [email protected]

How do I get a message response?

Hi, this is more of a question than an issue.

I am new to Actor model and trying to figure out how it works while reading some papers on it. So please bear with me.

Here I am trying to get response for the messages I sent.

extern crate riker;
extern crate riker_default;
#[macro_use]
extern crate log;

use riker::actors::*;
use riker_default::DefaultModel;
use std::time::Duration;

struct Counter {
    count: i32,
}

impl Counter {
    fn get_count(&mut self) -> i32 {
        self.count
    }

    fn new() -> BoxActor<Opr> {
        Box::new(Counter{ count: 0 })
    }
}


#[derive(Debug, Clone)]
enum Opr {
    Add(i32),
    Sub(i32)
}

impl Into<ActorMsg<Opr>> for Opr {
    fn into(self) -> ActorMsg<Opr> {
        ActorMsg::User(self)
    }
}

impl Actor for Counter {
    type Msg = Opr;

    fn receive(
        &mut self,
        _ctx: &Context<Self::Msg>,
        msg: Self::Msg,
        _sender: Option<ActorRef<Self::Msg>>,
    ) {
        match msg {
            Opr::Add(n) => {
                self.count += n;
            }
            Opr::Sub(n) => {
                self.count -= n;
            }
        }
    }
}

fn main() {
    let model: DefaultModel<Opr> = DefaultModel::new();
    let sys = ActorSystem::new(&model).unwrap();

    let props = Props::new(Box::new(Counter::new));
    let my_actor = sys.actor_of(props, "my-actor").unwrap();

    my_actor.tell(Opr::Add(10), None);
    my_actor.tell(Opr::Sub(3), None);

    std::thread::sleep(Duration::from_millis(500));
}

From looking at the Actor trait's receive method, currently that should not be possible, right?

pub trait Actor : Send {
    type Msg: Message;

    // ...

    fn receive(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, sender: Option<ActorRef<Self::Msg>>);

    // ...
}

Hewitt writes,

Messages in the Actor Model are decoupled from the sender and are delivered by the system on a best efforts basis.

If an Actor is sent a request, then the continuation must be one of the following two mutually exclusive possibilities:

  1. to process the response resulting from the recipient receiving the request
  2. to throw a Messaging exception

Just sitting there forever after a request has been sent is a silent failure, which is unacceptable. So, in due course, the infrastructure must throw a Messaging exception as governed by the policies in place if a response (return value or exception) to the request has not been received.

Ideally, if the continuation of sending a request is to throw a Messaging exception, then the sender of a response to the request also receives a Messaging exception saying that the response could not be processed.

If desired, things can be arranged so that Messaging exceptions are distinguished from all other exceptions.

Runtime failures are always a possibility in Actor systems and are dealt with by runtime infrastructures. Message acknowledgement, reception, and response cannot be guaranteed although best efforts are made.

So, does current implementation fit into this description? How can I get a response for the message I sent?

Also, let's say I like to have two different messages rather than an enum, so that each has its own impl blocks:

struct Add(i32);

impl Add {
   // ...
}

struct Sub(i32);

impl Sub {
   // ...
}

So, to handle them, still I have to use pattern matching in receive function, right? Wouldn't it be better to have a separate handler for each message?

Background on this project

Hey! I've been monitoring this project for a little while, and I'm super excited to see how far it's come. Thanks for all your work so far.

I'm hoping to maybe even start using this at work (although Rust is still a hard sell, yet). I was wondering if you could give a little background on who the maintainers of this project are, what your plans for the project are, how development is sustained, and that kind of context. I'm asking a little ways ahead of when I might need to pitch at work because I'm gonna have to jump through some compliance hoops, and having good stories to tell about each of the libraries I'd recommend would be super helpful.

That said, I understand I'm asking for info which might be considered personal, this is completely optional, and I have no expectations here. I'm asking from a place of preparation and hope 😄

Thanks!

Possibility of no_std alloc subset?

I'm probably asking for something whose difficulty far outweighs its worth, but I'm personally attempting to create an OS kernel built on an actor system, which naturally doesn't support std. I figure, instead of reimplementing everything manually, it would be nice to be able to reuse some of the abstractions from this crate. Namely some of the key traits for the most part. From a cursory glance at the code, the most that the critical parts depend on seems to be Arc, which would be available with just alloc.

Feel free to close as Won't fix if this would be too much trouble for too little gain. I mostly just like seeing such a wide range of libraries that can be used in a freestanding environment.

No object-capabilities?

The selectors directly break object capabilities. Although actors may be used without capabilities, I don't see why you wouldn't unless you're not aware of capabilities?

I don't see any references to asynchronous messaging (where an actor can do other work while it waits to send a message), nor anything that would prevent this due to the flexibility in futures-rs. If you're using unbounded channels, then the system may consume all resources due to the lack of back-pressure. If they are bounded, you may run into deadlocks.

If you support asynchronous messaging and other optimizations such as promise pipelines, you'll need to be careful to enforce E-order such that messages are delivered in a valid partial order.

I'm working on my own actor system in Rust, not yet published, featuring ocaps with bounded buffers and actors may continue to do other work while they wait to send messages.

I'd be surprised if you haven't already found this, but just in case you haven't, I strongly recommend this thesis. 'Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control' - Mark Samuel Miller

About Remote actors

The readme talks about remote actors, which looks super interesting! Are there more details on how that would work?

One usage example would be to build distributed apps with one side being a server others wasm compiled Riker code in web browsers.

Format code with new rustfmt

New rustfmt.toml file is ready.
Please review and comment on the settings. These are mostly sane defaults.
For feature merge requests it would be obligatory to follow the format, sparing time on manual formatting, having an consistent code and preventing situations where someone accidentally pushes someone else's code that was just reformatted.

Because most of the code is authored by @leenozara , it would be the best for if he could run cargo fmt on the entire project and immediately push the formatted code.

Please note that for rustfmt versions before "1.3.3" fail to format kernel_ref.rs. The required version is available in today's nightly release, or can be downloaded from the rustfmt project repository.

Double-kill of an actor will panic the kernel

If an actor is killed twice (either in a row or from consecutive messages), the kernel will panic and take the entire system with it. As killing an actor which is already dead is a meaningless action, maybe it would be better just to warn! and let the second kill fall through.

Here is example code to reproduce:

use riker::actors::*;
use riker_default::DefaultModel;

pub struct TestActor {
}

impl TestActor {
    pub fn actor() -> BoxActor<u32> {
        Box::new(TestActor { })
    }

    pub fn props() -> BoxActorProd<u32> {
        Props::new(Box::new(TestActor::actor))
    }
}

impl Actor for TestActor {
    type Msg = u32;

    fn receive(&mut self,
               ctx: &Context<u32>,
               _: u32,
               _sender: Option<ActorRef<u32>>) {
        ctx.stop(&ctx.myself());
    }
}

pub fn main() {
    let asys = ActorSystem::new(&DefaultModel::<u32>::new()).unwrap();
    let a = asys.actor_of(TestActor::props(), "test-actor").unwrap();

    a.tell(0, None);
    a.tell(0, None);

    asys.shutdown();

}

Here is the output:

Starting actor system: System[riker]
2018-09-12 06:54:14+00:00 DEBUG [riker::system::system] Actor system [fcd7cdc2-3639-4a2f-9d6a-b58f703862b9] [riker] started
thread '<unnamed>' panicked at 'ACTOR DOCK NONE ON TERMINATE. THIS SHOULD NEVER HAPPEN', /home/micucci/.cargo/registry/src/github.com-1ecc6299db9ec823/riker-0.1.7/src/kernel/kernel.rs:229:17

cargo build error

error[E0554]: #![feature] may not be used on the stable release channel
--> src\lib.rs:2:1
|
2 | #![feature(async_await)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try rustc --explain E0554.
error: Could not compile riker.

slack channel?

could be cool to have a channel to discuss riker

is it possible to create a new channel under the main rust slack?

[Discussion] Moving Riker development forward

Dear all,

I would like us to begin to discuss how we can move forward with Riker development, both from a code perspective but maybe also a wider project concept.

I created Riker a couple of years ago, which itself was a reiteration of a previous closed source project from the early days of Rust. Riker has come a long way and I’m pretty proud of the result. I must say that the best updates to the project have come from others discussing and making PRs, rather than myself. Thank you to everyone that has given their time to improving Riker!

For Riker to now evolve, for it to see its potential, we must change the way the project is developed. It’s simply not enough to have one person setting the direction, without communication, and then relying on others to pick through code to see where changes might be useful. Collaboration needs to start at the design and roadmap phases. We need thoughtful discussion, a sense of collective ownership as well as specialist ownership of specific systems.

To be clear, I am committed to Riker. This isn’t me offloading the project to any group of people that want to take it. My skills as a Rust developer however aren’t nearly as good as many of you and my value is more on actor system design and concepts. I’m also in a position to fund server/hosting/build costs that save time, etc. If we continue to evolve I imagine other costs will emerge.

We’ve always tried to maintain a few core principles:

  • Riker isn’t reproducing or competing with Rust’s concurrency, i.e. Riker actors are not a unit of concurrency like they are in Erlang.
  • Riker isn’t a complete stack including HTTP servers, e.g. like Akka is for Scala.
  • Riker makes it easy to work with state concurrently, including changes in state and behavior.
  • Riker makes it easy to build complex systems by using actors to represent parts of the system and providing guarantees.
  • Provide excellent documentation (or at least try to).

I had originally planned to create a roadmap, contribution guide, GitHub labels, etc and communicating this to everyone earlier last month. However, it became clear that even these must be done collaboratively.

So with a bit of the background laid out, what I would like to do is invite you all to share your thoughts and ideas here. The immediate main two questions I have are:

  1. Is there interest in forming a collective development of Riker from you?
  2. If so, what does that look like? (What are the best practices? How do we organize?)

Let’s keep in mind that it might take some contributors a few days to see this issue. I’d like to give enough time to hear from new and old members of the community, as well as any one who would like to join but hasn’t yet.

Finally, this is certainly a discussion. Not limited to sharing ideas specifically with me, but to actually discussing between us all.

Thank you all and I hope everyone is starting safe. Looking forward!

Spawning a future inside Actor::receive

Hello there, I'm trying to spawn futures inside my actor but I'm not sure how to get access to the inner ThreadPool. This is as far as I got:

#![feature(async_await, await_macro, futures_api, rustc_private)]
extern crate riker;
#[macro_use]
extern crate log;

use futures::executor::block_on;
use riker::actors::*;
use riker_default::*;
use riker_patterns::ask::ask;

struct MyActor;

impl Actor for MyActor {
    type Msg = String;

    fn receive(
        &mut self,
        ctx: &Context<Self::Msg>,
        msg: Self::Msg,
        sender: Option<ActorRef<Self::Msg>>,
    ) {
        let myself = ctx.myself();
        let sender = sender.unwrap();

        ctx.execute(async move {
          debug!("Got message {:?}", msg);
          sender.tell("This is your answer", Some(myself));
        });
    }
}

impl MyActor {
    fn actor() -> BoxActor<String> {
        Box::new(MyActor)
    }

    fn props() -> BoxActorProd<String> {
        Props::new(Box::new(MyActor::actor))
    }
}

// start the system and create an actor
fn main() {
    let model: DefaultModel<String> = DefaultModel::new();
    let sys = ActorSystem::new(&model).unwrap();

    let props = MyActor::props();
    let actor = sys.actor_of(props, "my-actor").unwrap();

    let res = ask(&sys, &actor, "Hello world");
    debug!("Got response {:?}", block_on(res));
}

I understand that Context::execute returns a RemoteHandle but I'm not sure where I should spawn it.

Is there a way to send a message back to sender after persisting?

I understand how I would return messages to a non actor with the ask pattern, but is it possible to do that after persisting?

  fn receive(&mut self,
                ctx: &Context<Self::Msg>,
                msg: Self::Msg,
                sender: Option<ActorRef<Self::Msg>>) {
        ctx.persist_event(msg);
    }

    fn apply_event(&mut self, _ctx: &Context<Self::Msg>, evt: Self::Msg) {
       // how could I access `sender` here?
    }

Filter logger

It would be nice to have a filter on the main logger, as sometimes the logging gets pretty verbose when many actors are present using many other libraries which all have logs flowing through. Since the Riker logger is an actor itself, this should be fairly easy to set up.

I was thinking just a simple array of terms which will be filtered out which will then do a simple check on each log. Since this array should hopefully be fairly small, and the logging strings not too large, I was thinking this would be simple but still not too much of a hit performance-wise.

Note: I have a basic implementation of a filter logger with this set up already written. I will post a PR so it can be reviewed.

Thanks!

Use Instant instead of SystemTime

Instant is intended to be used for timers. SystemTime can go backwards, e.g. if the system clock is adjusted. If the clock goes backwards, then everything relying on a timer would stop working until time catches up again (e.g. hours/days later). See the docs in the std lib.

cant Build with cargo

error: aborting due to 6 previous errors

For more information about this error, try rustc --explain E0554.
error: Could not compile runtime-fmt.

How to use a (diesel) database thru riker?

in transforming a project to async, we've hit a bit of a wall: Plume-org/Plume#777
that wall is the database, or the way we currently (have to) use it.
i was looking into using riker as the actor framework of choice, instead of creating an ad-hoc solution by ourselves

based on some unsuccessful experiments however, I'm not sure riker alone will do.

especially considering this comment:
#98 (comment)
if my Context is a Connection, that can't be read only!
but it also doesn't make sense for the Actor holding a Connection Context, to recv a Connection Msg

the correct message would be either String or Statement

i feel like the tools are there in riker to do this, buti don't have the understanding of how to put them together yet

(and if they aren't in riker alone, they should be in https://github.com/riker-rs/riker-cqrs
(but that library's documentation is even more incomprehensible to me))

Async `recv` Functions?

I'm curious, would it make sense to have Actor::recv an async fn? That way you could use futures inside of them with .await and avoid having to ctx.run() and block_on.

The problem I would see with it would be that you wouldn't want to do blocking operations in a recv implementation because it would stall the executor. Tokio handles those situations with a spawn_blocking(|| do_blocking_stuff()) pattern. That might be something to consider.

Anyway, I just wanted to open up the discussion and see what thoughts were on it. I'm really liking the look of Riker so far.

Add configuration files location overriding to docs

It's possible to override the location using an env variable:

  • RIKER_CONF to override the full path to riker.toml
  • APP_CONF to override the full path to app.toml

Example:

export RIKER_CONF=/var/conf/riker/riker.toml.

This feature is already there but not documented. I'll add an issue to add this to the documentation.

Benchmarking

When changes to kernel and system modules are made, as well as changes to dependencies, we should run a series of standard benchmarks. These would include both rust/cargo benchmarks and common actor system benchmarks (such as Ring Token and Skynet).

These tests would provide a benchmark between riker versions to ensure changes made don’t impact performance.

Additionally, benchmarks could be made between different actor systems both rust based and Scala, Erlang, C++, etc. This is less of a priority however at this point.

See:
https://arxiv.org/pdf/1505.07368.pdf
https://github.com/actor-framework/benchmarks

`ActorId` needs to be truly unique

Currently ActorId, which is type ActorId = u32, is simply generated using a random u32.

There is an unacceptable probability of the same u32 being generated in the same application. An alternative such as Uuid needs to be considered.

Update to stable dependencies

The current version still has alpha dependencies in the manifest file.
Would be great to update them to the released ones.

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.