Giter VIP home page Giter VIP logo

transport-eta's Introduction

Icon

Transport ETA

compileSdkVersion 28 Codacy Badge Build Status

An utility app using an SMS based service (or the web) to request a more precise ETA of a publc-transport (Bus, Metro etc.) to a specific station, currently implementing for Lisbon 🇵🇹, but the idea is to scale up to any other cities around the world that provide the same kind of service(s).

Some of the cool stuff I'll be integrating in this project:

  • Multi module Clean architecture
  • Rx
  • Kotlin
  • Android Architecture Components
  • Firebase Suite
  • Tests 🙌

Built from the ground-up on my twitch channel: twitch.tv/joaquimley


Why 🤔

Since I'm always working on some side-projects, I decided to document the progress live on a coding stream, this way I'll force myself into completing, while giving something back to a community that already thought me so much.

Stream PR log

Come and say Hi 👋 and be part of the develpoment live at twitch.tv/joaquimley

About the author

Hi, my name is Joaquim Ley, I'm a Software Engineer (Android).

The easiest way to contact me is through:

You can also follow me on:

Personal website:

Coming from the medium blog?

Important references

It would take substantially more time to setup this project without this reference projects, so a special thanks to:

Contributing

Contributions are always welcome! Follow the "fork-and-pull" Git workflow.

Issues:
Open a new issue. Follow the ISSUE_TEMPLATE.MD

License

Copyright © 2018 Joaquim Ley

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
See the License for the specific language governing permissions and
limitations under the License.

transport-eta's People

Contributors

joaquimley 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

transport-eta's Issues

MVP: Display service-specific SMS on a list

Display SMS-service-specific results to the screen, this way the user gets some actual value from the APP (ease of use)

Tasks ⚙

  • List of SMS data separated by Station code

  • Ability to easily make the same request

BottomNavigationBar behaviour

Makes sense to add a scrolling behavior to the BottomNavigationBar for better visibility

Here's the link to the article: https://android.jlelse.eu/scroll-your-bottom-navigation-view-away-with-10-lines-of-code-346f1ed40e9e?__s=ep727fgnkqv7dsftb1ut

Tasks ⚙

  • Copy The code into project

  • Set the behavior to the HomeActivity's BottomNavigationBar

The code

class BottomNavigationBehavior<V : View>(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<V>(context, attrs) {

	override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
		return axes == ViewCompat.SCROLL_AXIS_VERTICAL
	}

	override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
		super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
		child.translationY = max(0f, min(child.height.toFloat(), child.translationY + dy))
	}

	override fun layoutDependsOn(parent: CoordinatorLayout?, child: V, dependency: View?): Boolean {
		if (dependency is Snackbar.SnackbarLayout) {
			updateSnackbar(child, dependency)
		}
		return super.layoutDependsOn(parent, child, dependency)
	}

	private fun updateSnackbar(child: View, snackbarLayout: Snackbar.SnackbarLayout) {
		if (snackbarLayout.layoutParams is CoordinatorLayout.LayoutParams) {
			val params = snackbarLayout.layoutParams as CoordinatorLayout.LayoutParams

			params.anchorId = child.id
			params.anchorGravity = Gravity.TOP
			params.gravity = Gravity.TOP
			snackbarLayout.layoutParams = params
		}
	}
}

And on the BottomNavigationView XML add this attribute

app:layout_behavior="com.joaquimley.transporteta.<_SOME_PACKAGE_>.BottomNavigationBehavior"

MVP: Write initial test cases

Currently, there is zero coverage.

Why

For the initial setup and basic functionally (mostly on stream), no tests were written, but the goal is to have a fully tested app. This will also enable the full power of having a CI/CD pipeline (#19).

Tasks ⚙️

  • Initial setup (dependencies and example tests running)

  • Instrumentation FavoritesFragment

  • Unit tests for FavoritesViewModel

  • Unit tests for SmsController

  • Unit tests for SmsBroadcastReceiver

  • Integration tests (UI -> ViewModel + ViewModel -> SMSController)

  • Integrate with some codecov like service for overview

    • Be sure to properly configure (ignore unwanted files to provide accurate %)

Resources and references

App shortcuts

From @JoaquimLey on August 10, 2017 9:47

Send SMS request from app shortcut for favorite stations.

Copied from original issue: JoaquimLey/transport-eta-android#5

Data Layer V1.0

Already started building on stream14 and stream15

  • FavoritesRepository Units tests

  • FavoritesRepository implementation

  • TransportRepository Units tests

  • TransportRepository implementation

  • TransportDataStore Unit testes

  • TransportDataStore implementation

    • Should decide which source to pull data from/to
    • Gets the sources via DI
    • Check if data is expired/dirty and needs an update

Sources

  • Shared preferences data source #17
    • Tests

Decide if SMS actions (requestEta/cancelEta) should come from the repository or the SmsController directly

Other refs: #12, #14

Add status dashboard

Some nice status dashboard that can be shown on the stream

Context

  • Viewers on the stream will have both an overview and might be a way to increase engagement (on stream and github too).

  • This might help to get some contributions to this repository

  • The work vs potential makes this an interesting thing to tackle early in the project too hence Priority - Medium

Some resources

Is it working?

I tried to run this project but getting below error.

2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:16.151 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:16.152 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:21.171 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 249, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:21.171 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:21.171 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:21.172 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:26.191 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 257, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:26.191 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:26.191 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:26.192 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:31.211 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 265, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:31.213 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:31.213 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:31.214 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:33.465 3214-3214/? E/cutils-trace: Error opening trace file: Permission denied (13) 08-20 22:40:33.503 3214-3214/? E/memtrack: Couldn't load memtrack module (No such file or directory) 08-20 22:40:33.503 3214-3214/? E/android.os.Debug: failed to load memtrack module: -2 08-20 22:40:33.917 3233-3233/? E/cutils-trace: Error opening trace file: Permission denied (13) 08-20 22:40:33.955 3233-3233/? E/memtrack: Couldn't load memtrack module (No such file or directory) 08-20 22:40:33.955 3233-3233/? E/android.os.Debug: failed to load memtrack module: -2 08-20 22:40:35.530 3245-3245/? E/cutils-trace: Error opening trace file: Permission denied (13) 08-20 22:40:35.539 3248-3248/? E/cutils-trace: Error opening trace file: Permission denied (13) 08-20 22:40:35.580 3248-3248/? E/memtrack: Couldn't load memtrack module (No such file or directory) 08-20 22:40:35.580 3248-3248/? E/android.os.Debug: failed to load memtrack module: -2 08-20 22:40:35.596 3245-3245/? E/memtrack: Couldn't load memtrack module (No such file or directory) 08-20 22:40:35.596 3245-3245/? E/android.os.Debug: failed to load memtrack module: -2 08-20 22:40:36.241 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 273, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:36.242 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:36.242 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:36.242 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:41.263 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 281, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:41.263 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:41.264 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:41.264 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:46.292 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 297, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:46.293 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:46.293 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:46.293 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:51.312 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 305, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:51.313 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:51.313 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:51.314 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:40:56.343 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 313, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:40:56.343 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:40:56.343 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:40:56.344 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:41:01.361 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 321, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:41:01.362 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:41:01.362 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:41:01.363 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:41:06.388 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 329, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:41:06.388 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:41:06.388 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:41:06.389 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:41:17.555 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 337, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:41:17.555 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:41:17.555 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:41:17.555 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:41:22.571 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 345, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:41:22.572 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:41:22.572 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:41:22.572 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:41:27.590 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 353, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:41:27.591 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:41:27.591 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:41:27.591 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded 08-20 22:41:32.612 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord: Could not get audio input for session 361, record source 1999, sample rate 16000, format 0x1, channel mask 0x10, flags 0 08-20 22:41:32.614 2300-2397/com.google.android.googlequicksearchbox:search E/AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22. 08-20 22:41:32.614 2300-2397/com.google.android.googlequicksearchbox:search E/android.media.AudioRecord: Error code -20 when initializing native AudioRecord object. 08-20 22:41:32.615 2300-2397/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded

Automated Screenshots

Add a task for automated screenshots

Context

  • With this task, the PlayStore listing will be localized for each supported language/city

  • This can be a simple step of the CI pipeline #19

References

Test class example:

@RunWith(AndroidJUnit4.class)
public class FirstScreenShootTest {

	@ClassRule
	public static final LocaleTestRule localeTestRule = new LocaleTestRule();

	@Rule
	public ActivityTestRule<SomeActivity> activityRule = new ActivityTestRule<>(SomeActivity.class);

	@BeforeClass
	public static void setupClass() {
		Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());
	}

	@AfterClass
	public static void tearDownClass() throws Exception {
                //		 Code executed after the last test method
	}


	@Before
	public void setup() {

	}

	@After
	public void tearDown() {

	}

	@Test
	public void testTakeScreenshot() {
		Screengrab.screenshot("file_name");

		onView(withId(R.id.fab)).perform(click());

		Screengrab.screenshot("after_click_screen_shot_file_name");
	}
}

Setup CI/CD server

Since the project will have (at least unit) tests. It makes sense to set up a CI server (also good for demo purposes).

Also look into Firebase test lab

Context

This way the builds will automatically run all the tests, build APKs, deploy to test lanes and to play store.
There are some good tools it makes sense to explore


There are some cool articles helping out with this:

Domain layer

Start building the domain layer so we can start integrating remote and local data layers without affecting the rest of the present code.

This way we can start extracting some of this logic out of the ViewModel.

This will greatly improve the way we cand o tests

Add cronjob monitoring

Not for now, just to keep the reference

Context

In the future is more than likely that some cronjobs will run on the backend, this "service" provides a good and easy way to monitor the status of each cronjob.

App crashes if pressing on fab button while refresh is in progress

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Launch the app. Wait until the loading of bus list finished.
  2. Swipe to refresh.
  3. While the loading view is still displaying, press the fab icon at the bottom right corner
  4. App crashes.

Expected behavior
App should not crash

Smartphone (please complete the following information):

  • Device: HTC one
  • OS: Android 6.0

Setup crash reporting

It's paramount that the crashes are correctly displayed.

Options

There are some obvious choices

  • Fabric.io

  • Directly migrate from ☝️ to Firebase

  • Microsoft's AppCenter


No matter the tool the project goes with should be coupled with the same one used on #19, I'm initially inclined to Firebase due to the strong developer tools suite.

Fix FavoritesFragment tests

Due to changes with the introduction of the Domain layer, the FavoritesViewModel dependencies will be simple interfaces (UseCases and the model mapper).

This might make the tests easier

Include Kotlin

Depends on versions.gradle task #10

Top level build.gradle

buildscript {
    ext.kotlin_version = '1.1.4-2'
    apply from: './versions.gradle'
    addRepos(repositories)
    dependencies {
        classpath deps.android_gradle_plugin
        classpath deps.kotlin.plugin
    }
}

allprojects {
    addRepos(repositories)
}

Migrate to Jetpack

With all the new sugary things announced at I/O'18, this is the perfect playground project to test things.

Context

This will provide way cleaner APIs and dependencies, unifying the maven paths, testing the 28-alpha versions etc.

Tasks ⚙️

UI 🎨

Moareee

These will have new separate issues.

Favorites list UI

In order to facilitate the user, we should add the ability to save favorite stations. Depends on #17

  • Make it easy UX-wise to make these same favorite requests (MD2.0).

Tasks ⚙


  • Instrumentation tests

  • Unit tests

Extract Android permissions from HomeActivity

HomeActivity is currently responsible for requesting the necessary Android permissions, this is wrong.

Context

The idea is the HomeActivity should only be responsible for navigation.

Tasks

  • Create a specific activity to request the permissions (since the app is unusable without), keeps the responsibilities simple.

Extract this code from HomeActivity

 /**
     * Runtime permission shenanigans
     */
    private fun hasReadSmsPermission(): Boolean {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED
    }

    private fun requestReadAndSendSmsPermission() {
        ActivityCompat.requestPermissions(this,
                arrayOf(Manifest.permission.SEND_SMS, Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS), SMS_PERMISSION_CODE)
    }

Setup initial project

Why 🤔

  • Since the original project has become quite stale and the idea now is to develop this with the Twitch Stream there is a need to do the initial setup again.

Tasks ⚙️

  • Initial project setup

  • Use versions.gradle configuration

  •  Initial project scaffold

  • Include initial dependencies (AAC/D2/ETC)

Fix FavoritesViewModel implementation

Due to the introduction of the Domain layer, the current implementation makes no sense (directly leaking SmsController)

  • Remove all of the SmsController related code

  • Handle (and execute) UseCases

  • Fix Unit tests

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.