Git Product home page Git Product logo

kino's Introduction

Hello there 👋

Kotlin TypeScript RxJS Android Angular

🧠 Currently learning vim motions.

📖 Libraries

  • comparing · Easily create descriptive comparators
  • ts-code-contracts · Design by contract with TypeScript
  • angular/components · Component infrastructure and Material Design components for Angular
  • Navi · Android library to reduce boilerplate code for official Compose navigation (experimental)
  • ngxs-labs/entity-state · Entity adapter for NGXS (inactive)

✨ Apps

  • Navi · In-browser code generator for Compose navigation boilerplate code.
  • flextangler · Create flextangles with your own images
  • BackUpper · Simple and portable backup tool, that creates backups by simply copying
  • ssl-at-home · Create and host your own self-signed certificates, intended for your home network
  • the doomsday method · Demonstrate and practice the doomsday method
  • permutations · Generate all permutations without repetitions

💡 Miscellaneous

... and some others.

kino's People

Contributors

dependabot[bot] avatar janmalch avatar kollb avatar marekhohmann avatar snyk-bot avatar

Stargazers

 avatar

Watchers

 avatar

kino's Issues

Frontend guards

Guard the following routes

  • reservation (3ac44f2)
    • CUSTOMER & not owner -> 404
    • MODERATOR -> redirect to /admin
  • account, if not logged in (7154e94)

UseCases: Customer

  • Logout
  • Bisherige Eigene Reservierungen anzeigen / ändern / löschen
  • Reservierung aufgeben
    • Nach Persistierung auf doppelte Reservierung prüfen
    • Validierung ob Sitzplatz verfügbar ist
  • Eigenen Account anzeigen / ändern / löschen

Empty Path Annotation

WARNING: The (sub)resource method getAllPriceCategories in io.github.janmalch.kino.api.boundary.PriceCategoryResource contains empty path annotation.
WARNING: The (sub)resource method createPriceCategory in io.github.janmalch.kino.api.boundary.PriceCategoryResource contains empty path annotation.
WARNING: The (sub)resource method getAllAccounts in io.github.janmalch.kino.api.boundary.AccountResource contains empty path annotation.

Util methods for common problems

Wäre utility Methoden für häufige Probleme praktisch? Z.B. einfacher null-check mit Problems.requireNonNull:

public SignUpControl(SignUpDto data) {
  this.data = Problems.requireNonNull(data, "No sign-up data provided");
  // ungefähr das gleiche wie
  if (data != null) {
   // hier fehlt problem usw.
   throw new NullPointerException();
  } 
  this.data = data;
}

Dadurch würde im null-Fall eine Exception geworfen werden, die dann vom globalen APIExceptionMapper gefangen wird. Die enthält automatisch ein 400-Problem mit geeignetem Text à la "Failed to provide required data" & "No sign-up data provided".
Eigentlich muss man nicht erwarten, dass SignUpDto null ist. Wenn es der Fall ist ohne dieses requireNonNull gibts halt irgendwann anders eine NullPointerException, bei der es dann am Ende ein generisches 500er-Problem gibt, ohne genauen Infos.

Fix dummy data SQL Scripts

Linux is case sensitive while parsing sql-scripts, lowercase tablenames in drop-and-create would fit the insert statements in dummy-movies.sql and users.sql

UseCases: Moderator

  • Accounts anzeigen
  • Reservierungen ändern / löschen
  • Saal hinzufügen / ändern / löschen
  • Sitze hinzufügen / ändern / löschen
  • Vorstellungen hinzufügen / ändern / löschen
  • Filme hinzufügen / ändern / löschen
  • Preiskategorie hinzufügen / ändern / löschen

Diskussion: Optional oder Exception für Validierung

Bitte diskutieren ob intern in den Controls mit Optional<Problem> oder Exceptions (ThrowableProblem) gearbeitet werden soll.

Ich würde einfach das nehmen, was ihr besser findet. Kann mich mit beidem anfreunden, da das Thema nur klassen-intern sein dürfte. Eigentlich wollen wir ja Exceptions vermeiden, aber haben ja nicht gesagt wie weit wir das treiben. Drum herum kommen wir eh nicht weil es Exceptions gibt die wir halt catchen müssen. Und die Kommunikation von Control zu Endpoint würde ich definitiv ohne Exceptions machen.

Hier geht es um kleinere Scopes (klassenintern), da Java ja keine multiple-return-values kann und Wrapper-Objekte teilweise auch umständlich sein können.
In diesem Issue geht es um die Schneide bei Methoden, die in Vanilla-Java entweder ohne return value durchlaufen oder eine Exception schmeißen würden. Diese Methoden könnte man auch mit Optional statt void & Exception umschreiben.


Folgende Problematik (beim birthday):

public static class SignUpMapper implements Mapper<User, SignUpDto> {
    public static final SimpleDateFormat BIRTHDAY_FORMAT = new SimpleDateFormat("YYYY-MM-DD");
    @Override
    public User mapToEntity(SignUpDto signUpDto) {
        User user = new User();
        user.setEmail(signUpDto.getEmail());
        user.setFirstName(signUpDto.getFirstName());
        user.setLastName(signUpDto.getLastName());
        try {
            user.setBirthday(BIRTHDAY_FORMAT.parse(signUpDto.getBirthday()));
        } catch (ParseException e) {
            Problem problem = SignUpProblem.INVALID_BIRTHDAY.generateProblem(
                    Map.of("birthday", signUpDto.getBirthday()),
                    signUpDto.getBirthday()
            );
            throw new ThrowableProblem(problem, e);
        }
        return user;
    }
}

Bei einer solchen Klasse würde ich mit einer Exception arbeiten, da man sonst alle Mapper mit irgendwelchen Quittungsobjekten wrappen müsste.. Daher catche ich die ParseException (was ich muss) und rethrowe sie als ThrowableProblem extends RuntimeException (da ich die Methoden-Signatur nicht ändern kann).

Damit kann ich das in meiner aufrufenden Methode ganz entspannt fangen:

User user;
try {
    user = new SignUpMapper().mapToEntity(data);
} catch (ThrowableProblem e) {
    // failure branch: invalid birthday format
    // this shouldn't happen if API is used correctly -> log.warn
    log.warn("Invalid birthday format in sign-up: " + data.getBirthday(), e.getCause());
    return result.failure(e.getProblem());
}
repository.add(user);

Jetzt hatten wir ja aber gesagt, dass wir Exceptions möglichst vermeiden wollen. Jetzt gibt es eine Validierungsmethode, die man entweder mit void & Exception oder Optional<Problem> implementieren könnte.

Optional<Problem>

➕ keine Exceptions
➖ nicht einheitlich

Optional<Problem> checkIfEmailTaken() {
    Specification<User> presentCheck = new UserByEmailSpec(data.getEmail());
    Optional<User> referredUser = repository.queryFirst(presentCheck);
    if (referredUser.isPresent()) {
        // failure branch: user already exists
        Problem problem = SignUpProblem.EMAIL_EXISTS.generateProblem(
                Map.of("email", data.getEmail()),
                data.getEmail()
        );
        return Optional.of(problem);
    } else {
        // success
        return Optional.empty();
    }
}

@Override
public <T> T execute(ResultBuilder<T, Object> result) {
    Optional<Problem> emailTakenProblem = checkIfEmailTaken();
    if (emailTakenProblem.isPresent()) {
        return result.failure(emailTakenProblem.get());
    }
    // ...
}
void & Exception

➕ einheitlich mit Exceptions
➖ Exception wollten wir möglichst vermeiden

void doCheckIfEmailTaken() throws ThrowableProblem {
    Specification<User> presentCheck = new UserByEmailSpec(data.getEmail());
    Optional<User> referredUser = repository.queryFirst(presentCheck);
    if (referredUser.isPresent()) {
        // failure branch: user already exists
        Problem problem = SignUpProblem.EMAIL_EXISTS.generateProblem(
                Map.of("email", data.getEmail()),
                data.getEmail()
        );
        throw new ThrowableProblem(problem);
    } 
}

@Override
public <T> T execute(ResultBuilder<T, Object> result) {
    try {
        doCheckIfEmailTaken();
    } catch (ThrowableProblem e) {
        return result.failure(e.getProblem());
    }
    // ...
} 

Presentation overview

Filter presentations from the past in overview.


In der Hauptübersicht: die Filme werden halt anhand ihres Start- und Endedatums angezeigt. Ist verwirrend wenn der bis Juni läuft aber wir nur Vorstellungen bis Mitte Mai drin haben und der Film in jeder Woche angezeigt wird. Eventuell die Daten auf dem Movie rausnehmen und nur über die existierenden Vorstellungen anzeigen?


"Aufführungen" -> "Vorführungen"

Hashing and Salting

Hashing and Salting für Passwörter implementieren.

Dedicated Hash/Salting-Class im package io.github.janmalch.kino.security:

public interface HashedPassword {
    String getHash();
    String getSalt();
}

public interface PasswordManager {
    HashedPassword hashPassword(String clearPassword);
    boolean isSamePassword(String clearPassword, HashedPassword hashedPassword);
    // boolean isSamePassword(String clearPassword, String hash, String salt);
}

(Konkrete Namen könnte man noch ändern ...)
Dann könnte ich im SignUp-to-Account-Mapper einfach folgendes machen:

@Override
public Account mapToEntity(SignUpDto signUpDto) {
  Account account = new Account();
  account.setEmail(signUpDto.getEmail());
  // ...
  var hasher = new PasswordHasher();
  var securePassword = hasher.hashPassword(signUpDto.getPassword());
  account.setPassword(securePassword.getHash());
  account.setSalt(securePassword.getSalt());
  return account;
}

Still "Too many connections"

Caused by: java.sql.SQLNonTransientConnectionException: Data source rejected establishment of connection,  message from server: "Too many connections"

less frequent now. maybe just one or two calls where closing is missing. Maybe auth filter

Improve Endpoints and DTOs

  • Reservierung (ReservationInfoDto)
    • mit Account (mind. für Mitarbeiter-Übersicht. Den normalen User würde es aber auch nicht stören) (91d14e7)
    • mit Presentation statt ID, um in der eigenen Übersicht Datum der Vorstellung anzuzeigen
  • getMyAccount mit AccountDto (#69)
  • Moderator
    • CinemaHall
    • Movie: readAll (88599bc), create (fix: ohne PriceCategory Instanz) (78a7123)
    • Presentation: create, delete, update (0af77a9)

Upgrade to OpenAPI

<dependency>
 <groupId>io.swagger.core.v3</groupId>
 <artifactId>swagger-jaxrs2</artifactId>
 <version>2.0.0</version>
</dependency>
<dependency>
  <groupId>io.swagger.core.v3</groupId>
  <artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
  <version>2.0.0</version>
</dependency>

http://localhost:8080/kino/api/openapi.json

enable CDI

  • rewrite controls
  • rewrite resources
  • tests with custom repository implementation and constructor parameter injection

ForbiddenException: User not authorized

ForbiddenException: User not authorized bei meine Reservierungen. Grund unklar.


Ich hab folgendes gemacht:

  • Passwort "erfolgreich" geändert für customer (Siehe auch #71 )
  • umloggen auf customer1 (erfolgreich, kriege auch meinen Namen angezeigt, etc.)
  • Forbidden Fehler beim Aufruf meiner Reservierungen

Common success response

Develop common success response template, just like we have a common failure response template with Problem.

Proposal:

public interface Success<T> {
  @Nullable
  default String getMessage() {
    return null;
  }

  @Nullable
  default Response.StatusType getStatus() {
    return Response.Status.OK;
  }

  @Nullable
  default T getData() {
    return null;
  }
}

Controls should always return a Success object (or Problem for failure).

Fix date parsing

Improve either backend or frontend

Differentiate between date and date with time


See #96

Delete orphans in OneToMany relationships

Muss für jeden Use-Case individuell entschieden werden.
z.B. wenn eine Movie Entity gelöscht wird, sollten auch alle verknüpften Presentations gelöscht werden.


https://stackoverflow.com/a/5642615

If professions are only part of this relationship, then you can guarantee that when a profession is removed from the User's set it will also be removed from the database by turning on orphanRemoval on the OneToMany side of the relationship.

@OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Profession> professions;

Fix mvn install

[INFO] --- maven-install-plugin:2.4:install (default-install) @ kino ---
[WARNING] Error injecting: org.apache.maven.artifact.installer.DefaultArtifactInstaller
com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Error injecting: private org.eclipse.aether.spi.log.Logger org.apache.maven.repository.internal.DefaultVersionRangeResolver.logger
  while locating org.apache.maven.repository.internal.DefaultVersionRangeResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.VersionRangeResolver
    for parameter 2 at org.eclipse.aether.internal.impl.DefaultDependencyCollector.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultDependencyCollector
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.DependencyCollector
    for parameter 5 at org.eclipse.aether.internal.impl.DefaultRepositorySystem.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultRepositorySystem
  while locating java.lang.Object annotated with *
  while locating org.apache.maven.artifact.installer.DefaultArtifactInstaller
Caused by: java.lang.IllegalArgumentException: Can not set org.eclipse.aether.spi.log.Logger field org.apache.maven.repository.internal.DefaultVersionRangeResolver.logger to org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
	at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
	at java.base/java.lang.reflect.Field.set(Field.java:780)
	at org.eclipse.sisu.bean.BeanPropertyField.set(BeanPropertyField.java:72)
	at org.eclipse.sisu.plexus.ProvidedPropertyBinding.injectProperty(ProvidedPropertyBinding.java:48)
	at org.eclipse.sisu.bean.BeanInjector.injectMembers(BeanInjector.java:52)
	at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:140)
	...

2) Error injecting: private org.eclipse.aether.spi.log.Logger org.apache.maven.repository.internal.DefaultVersionResolver.logger
  while locating org.apache.maven.repository.internal.DefaultVersionResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.VersionResolver
    for parameter 2 at org.eclipse.aether.internal.impl.DefaultArtifactResolver.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultArtifactResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.ArtifactResolver
    for parameter 2 at org.eclipse.aether.internal.impl.DefaultRepositorySystem.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultRepositorySystem
  while locating java.lang.Object annotated with *
  while locating org.apache.maven.artifact.installer.DefaultArtifactInstaller
Caused by: java.lang.IllegalArgumentException: Can not set org.eclipse.aether.spi.log.Logger field org.apache.maven.repository.internal.DefaultVersionResolver.logger to org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
	at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
	at java.base/java.lang.reflect.Field.set(Field.java:780)
	at org.eclipse.sisu.bean.BeanPropertyField.set(BeanPropertyField.java:72)
	at org.eclipse.sisu.plexus.ProvidedPropertyBinding.injectProperty(ProvidedPropertyBinding.java:48)
	at org.eclipse.sisu.bean.BeanInjector.injectMembers(BeanInjector.java:52)
	at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:140)
	...

3) Error injecting: private org.eclipse.aether.spi.log.Logger org.apache.maven.repository.internal.DefaultVersionResolver.logger
  while locating org.apache.maven.repository.internal.DefaultVersionResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.VersionResolver
    for parameter 1 at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.<init>(Unknown Source)
  while locating org.apache.maven.repository.internal.DefaultArtifactDescriptorReader
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.ArtifactDescriptorReader
    for parameter 1 at org.eclipse.aether.internal.impl.DefaultDependencyCollector.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultDependencyCollector
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.DependencyCollector
    for parameter 5 at org.eclipse.aether.internal.impl.DefaultRepositorySystem.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultRepositorySystem
  while locating java.lang.Object annotated with *
  while locating org.apache.maven.artifact.installer.DefaultArtifactInstaller
Caused by: java.lang.IllegalArgumentException: Can not set org.eclipse.aether.spi.log.Logger field org.apache.maven.repository.internal.DefaultVersionResolver.logger to org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
	at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
	at java.base/java.lang.reflect.Field.set(Field.java:780)
	at org.eclipse.sisu.bean.BeanPropertyField.set(BeanPropertyField.java:72)
	at org.eclipse.sisu.plexus.ProvidedPropertyBinding.injectProperty(ProvidedPropertyBinding.java:48)
	at org.eclipse.sisu.bean.BeanInjector.injectMembers(BeanInjector.java:52)
	at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:140)
	...

4) Error injecting: private org.eclipse.aether.spi.log.Logger org.apache.maven.repository.internal.DefaultVersionResolver.logger
  while locating org.apache.maven.repository.internal.DefaultVersionResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.VersionResolver
    for parameter 2 at org.eclipse.aether.internal.impl.DefaultArtifactResolver.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultArtifactResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.ArtifactResolver
    for parameter 2 at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.<init>(Unknown Source)
  while locating org.apache.maven.repository.internal.DefaultArtifactDescriptorReader
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.ArtifactDescriptorReader
    for parameter 1 at org.eclipse.aether.internal.impl.DefaultDependencyCollector.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultDependencyCollector
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.DependencyCollector
    for parameter 5 at org.eclipse.aether.internal.impl.DefaultRepositorySystem.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultRepositorySystem
  while locating java.lang.Object annotated with *
  while locating org.apache.maven.artifact.installer.DefaultArtifactInstaller
Caused by: java.lang.IllegalArgumentException: Can not set org.eclipse.aether.spi.log.Logger field org.apache.maven.repository.internal.DefaultVersionResolver.logger to org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
	at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
	at java.base/java.lang.reflect.Field.set(Field.java:780)
	at org.eclipse.sisu.bean.BeanPropertyField.set(BeanPropertyField.java:72)
	at org.eclipse.sisu.plexus.ProvidedPropertyBinding.injectProperty(ProvidedPropertyBinding.java:48)
	at org.eclipse.sisu.bean.BeanInjector.injectMembers(BeanInjector.java:52)
	at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:140)
	...

UseCases: Guest

  • Kino Programm, aktuelle Filme (e8373e8)
  • Vorstellungszeiten des gewählten Films (6ee2f8a)
    • Nur zukünftige
  • Platzauswahl für die gewählte Vorstellung (´Angular´)
    • Unterscheidung, ob Platz verfügbar oder nicht (4c7d8a6)
  • Preise anzeigen (In MovieDTO) (9515ed2)
    • Preiskategorie in MovieDTO nur via ID referenzieren. Frontend kann Kategorien cachen
  • Registrierung
  • Login

Fix JPA for tests

Make sure that JPA works in tests without the prod MySQL connection (e.g. for Travis CI)

Clean up reservation controls

Reduce the number of controls, by passing the current role into certain controls, to check if the logged in user is allowed to view the queried reservation (by id)

Close DB connection

Datenbankverbindungen werden aktuell nicht geschlossen. Man kann auf EntityManager close aufrufen. Allerdings kann man das nicht nach jeder Transaktion machen, weil dieselbe Instanz häufiger verwendet wird. Wenn die nicht geschlossen werden, stürzt der Server irgendwann ab.


Man könnte die Repositories um das Closeable interface ergänzen und in den Controls alle verwendeten Repositories registrieren und beim Verlassen auf allen close aufrufen. Entweder macht man das manuell oder wir führen eine abstrakte BaseControl-Klasse ein, die Methoden zum Registrieren und schließen anbietet. Dabei müsste man dann allerdings alle execute Aufrufe durch eine andere Methode ersetzen (nur den Namen).

How to handle dates in requests

Implement a uniform way to handle dates in POST-request payloads.

Either:

  • use String and map manually in either
    • the control
    • the boundary
  • implement deserializer with JAX-RS
  • use custom class that accepts String in constructor

Problem is that some payloads only require a day (YYYY-MM-DD) and some require a full timestamp with HH:mm:SS.

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.