Giter VIP home page Giter VIP logo

restate's Introduction

RESTATE


restate

A fractal state management library.

Build status Greenkeeper

Restate connects to the Redux State AND to the local component state, producing a new state, you can use with, or without Redux.

Restate, re-store, redux-focus, redux-lenses, re-dux, redux-tree... Oh, it was not easy to name The base layer for a redux composition.

The goal of Restate is to provide hierarchical, decoupled, isolated synthetic stores, and make your application faster and simpler. Restate just creates a new branch, from a original store, allowing you to control it, and use composition on redux-level. And it does not need Redux for it. You can use Restate without Redux, connecting your components to the syntetic derived state.

import reduxRestate from 'redux-restate'; // to low-level redux manupulations
import reactReduxRestate from 'react-redux-restate'; // to work with multiple stores
import reactReduxFocus from 'react-redux-focus'; // to focus a lens on a single store
import reactReduxLoop from 'react-redux-loop'; // to call React from Redux
import reactSemaphore from 'react-redux-semaphore'; // to create *suspense* 

The problem

As long React spreads component architecture and highly composable patterns, the major part of it - Redux - do not follow this way.

In the world of redux Store is a singlentone. You can create a connection to that store, and fetch the data you need. But how?

Redux is the same for any connection, created from any point of Render Tree.

You have to use React props, to pass the ids you need deeply into react Tree to use them to get the data out of the store.

Redux is not composable. Redux is not component friendly.

Medium articles about: Restate , Fractal state .

The borders

Redux's connect method produces PureComponent. No update from the top will pass PureComponent. All updates will start from PureComponent.

Connect is the end for all updates, and the beginning.

Then you will change the store, all connected component will be triggered to update. They will mapStateToProps and maybe do nothing more, in case the result object is shallowEqual to the older one.

Unless you will specify areStatesEqual for each connect, which is not quite possible, to say the truth.

The idea

This is rework of ideas from Yandex Map API Option Manager. Option Manager was build to handle 2 cases:

  • GeoJSON. Where a lot of similar objects can be nested inside each other (features and collections).
  • The single configuration file.

It is easier to explain via example:

  1. You are setTimeone. You need your durition, and you are reading from store values named -> duration
  2. Actually you are an animation. You prepend your request by your name -> animationDuration
  3. Animation is internal component of Zoom Control. And it add to all data-requests passed from nested components it's name -> zoomControlAnimationDuration. As result - final component could use simple names - color, duration, value,- but store could contains much more complex names.

OptionManager (OptionMapper to be clear) work as lenses scoping the store.

The solution

Redux-restate get:

  • one or more stores as input,
  • combine function to create a new store
  • dispatch function, to handle dispatch

And produces the new store.

Thus makes redux composable, and enabled the component way.

Restate is the end for any update, and the beginning. But not for all. Only the ones you need.

The implementation

  • redux-restate for redux level.
  • react-redux-retate for react multy-state case.
  • react-redux-focus for single store case.
  • recct-redux-semaphore to control update propagation.

Usage

redux-restate

import restate from 'redux-restate';
const newStore = restate({ store: baseStore }, composeState, routeDispatch, options);
  • composeState(states):NewState get one one more states as input, produce the output
  • routeDispatch(dispatchers, event) get one one more dispatch as input, then call the disired one with even, also provided.

react-redux-restate

import reactReduxRestate from 'react-redux-restate';
const RestatedComponent = reactReduxRestate(
  { otherStore: otherStore /*store or store key*/ }, // default store will be injected automagically
  (stores, props) => composeState,
  (dispatchers, event, props) => routeDispatch,
  options,
)(WrappedComponent);

The same as redux-restate, but in form of React HOC. The default store, accessible with storeKey, is available as .default for next functions.

  • composeState(states, event, props) get one one more states as input, plus props, produce the output

  • routeDispatch(dispatchers, event, props) dispatch as input, plus props, then call the disired one with even, also provided.

Note: if composeState will return undefined the state will not change.

reproviding a state

Sometimes it is worth to keep the old store. Just save it using a different name.

import { reprovide } from 'react-redux-restate';
const Reprovider = reprovide('new-store-name', 'old-store-name');
const DefaultReprovider = reprovide('new-store-name'); // old will be `store`

Fork/Unfork

There is a "standard way" to reprovide a state

import { ForkReduxStore, UnforkReduxStore } from 'react-redux-restate';

const App = () => (
  <Provider state={state}>
    <ForkReduxState>
      // state "forked" into "global" state
      <FocusOrRestateTheStore>
        // state is "altered" here // you can always refer to "global" as a state key
        <UnforkReduxState>// state is reverted to the original</UnforkReduxState>
      </FocusOrRestateTheStore>
    </ForkReduxState>
  </Provider>
);

react-redux-focus

import reactReduxFocus from 'react-redux-focus';
const FocusedComponent = reactReduxFocus(
  (state, props) => state.todos[props.id],
  (dispatch, event, props) => dispatch({ ...event, id: props.id }),
)(WrappedComponent);

Or you can use Component approach

import { ReduxFocus } from 'react-redux-focus';

<ReduxFocus
  focus={(state, props) => state.todos[props.id]}
  onDispatch={(dispatch, event, props) => dispatch({ ...event, id: props.id })}
>
  <WrappedComponent />
</ReduxFocus>;

The same as react-redux-restate, but for a single store.

  • composeState(state, props): newState - focus will work only with one state
  • routeDispatch(dispatch, props)

react-redux-semaphore

HOC approach.

import reduxSemaphore from 'react-redux-semaphore';

const WillUseOldStateUnlessConditionAreMet = reduxSemaphore((state, props) => isValid(store.importantData))(
  TargetComponent,
);

Component approach

import { ReduxSemaphore } from 'react-redux-semaphore';
<ReduxSemaphore condition={(state, props) => isValid(store.importantData)}>
  <TargetComponent />
</ReduxSemaphore>;

Optimization

Restate will perform shallowEqual compare for the old and the new states. Please use reselect or another memoization library to keep branches unchanged. Otherwise - specify areStatesEqual option.

Multiple store case

It is absolutely common, that some parts of application can be absolutely independent. But, in the same time, they are united. The simplest examples

  • routing
  • notifications
  • user data
  • analytics

Using the composeState you can control how your data passes down.
Using the routeDispatch you can control how dispatches bubbles up.

  • You can extend dispatched event by some data.
  • You can choose which dispatch to call - the original one, from a nearest (default) store, or the parent one (the Application level)

Examples

Deepdive with Restart instantly

Connect all restate to the original store, just for original store lensing and optimization.

 import {createProvider} from 'react-redux'
 import reactReduxRestate from 'react-redux-restate';

 const Provider = createProvider('non-default-name');
 const Remap = reactReduxRestate(...., {
   storeKey:'non-default-name'
   // restoreKey: 'store' // will defaults to store
 })

Isolate middle of application

Provide store, reprovide store, restore original store...

import reactReduxRestate, { reprovider } from 'react-redux-restate';
const Reprovider = reprovider('realStore');
const RestoreStore = reprovider('store', 'realStore');

const RestateStore = reactReduxRestate(
  {}, // no extra stores
  states => focusOnSomeBranchIn(states.default),
  (dispatch, event, props) => dispatch.default({ ...event, id: props.id }),
);

const RestateWithOriginalStore = reactReduxRestate(
  { realStore: 'realStore' }, // connect the real store back
  states => mixStates(states.default, states.realStore),
  (dispatch, event, props) => dispatch.realStore({ ...event, id: props.id }),
);

const RestateForOriginalStore = reactReduxRestate(
  {}, // no extra stores
  states => focusOnSomeBranchIn(states.default),
  (dispatch, event, props) => dispatch.default({ ...event, id: props.id }),
  {
    storeKey: 'realStore', // use `realStore` as default
  },
);

const Application = () => (
  // put redux store inside
  <Provider store={myReduxStore}>
    // re-export current store as `realStore
    <Reprovider>
      // switch to syntetic redux
      <RestateStore>
        <SomePartOfAnApplication>
          // restore original store
          <RestoreStore>
            <WorkWithOriginalStore />
          </RestoreStore>
          // or use restate with 2 stores connected
          <RestateWithOriginalStore />
          // or connect restate to the real store
          <RestateForOriginalStore />
        </SomePartOfAnApplication>
      </RestateStore>
    </Reprovider>
  </Provider>
);

Also Check out example-todo in packages.

Before all the things - map Todos

const mapStateToProps = state => ({
  todos: getVisibleTodos(state.todos, state.visibilityFilter),
});

const mapDispatchToProps = {
  onTodoClick: toggleTodo,
};

export const VisibleTodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList);

Next - render Todo...

The original Redux-todo-list

const TodoListRedux = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo => (
      // Here redux "ends". You have to map onClick in magic way
      <Todo key={todo.id} {...todo} onClick={() => onTodoClick(todo.id)} />
    ))}
  </ul>
);

The remap variant

// direct mapping. Here is nothing more that Todo need
const mapStateToProps = state => state;
const mapDispatchToProps = {
  onClick: toggleTodo,
};
const ConnectedTodo = connect(mapStateToProps, mapDispatchToProps)(Todo);

// Focusing on Todo-only
const TodoMapped = reduxFocus(
  (state, props) => state.todos[props.id],
  // Todo should just dispatch an event. All logic is here.
  (dispatch, event, props) => dispatch({ ...event, id: props.id }),
)(ConnectedTodo);

const TodoList = ({ todos, onTodoClick }) => <ul>{todos.map(todo => <TodoMapped key={todo.id} id={todo.id} />)}</ul>;

The variant with Remap is twice longer, but it will run faster out of the box. No Todo will be re-rendered if any other gonna to change Todo will become isolated from rest of application.

[Animation]

As result you can re-connect any existing "connected" component.

Licence

MIT

restate's People

Contributors

greenkeeper[bot] avatar thekashey 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

Watchers

 avatar  avatar  avatar  avatar

restate's Issues

An in-range update of enzyme is breaking the build 🚨

There have been updates to the enzyme monorepo:

    • The dependency enzyme was updated from 3.6.0 to 3.7.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the enzyme group definition.

enzyme is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of enzyme is breaking the build 🚨

There have been updates to the enzyme monorepo:

    • The dependency enzyme was updated from 3.6.0 to 3.7.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the enzyme group definition.

enzyme is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of storybook is breaking the build 🚨

There have been updates to the storybook monorepoundefined

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the storybook group definition.

storybook is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Release Notes for v3.4.11

3.4.11

2018-September-17

Dependencies

  • Allow v1 or v2 in airbnb-js-shims #4190
FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of hoist-react-statics is breaking the build 🚨

The dependency hoist-react-statics was updated from 1.0.1 to 1.0.2.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

hoist-react-statics is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Commits

The new version differs by 2 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of react is breaking the build 🚨

There have been updates to the react monorepo:

    • The dependency react was updated from 16.5.2 to 16.6.0.
  • The dependency react-dom was updated from 16.5.2 to 16.6.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the react group definition.

react is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of prop-types is breaking the build 🚨

The dependency prop-types was updated from 15.6.2 to 15.7.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

prop-types is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of eslint-plugin-react is breaking the build 🚨

The devDependency eslint-plugin-react was updated from 7.11.1 to 7.12.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

eslint-plugin-react is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Release Notes for v7.12.0

Added

Fixed

Changed

Commits

The new version differs by 127 commits.

  • a83d65c Update CHANGELOG and bump version
  • 0c6160e [Dev Deps] update coveralls, babel-eslint, typescript
  • cd6c8e6 [Deps] update resolve
  • d2b5b73 Merge pull request #1828 from alexzherdev/1721-no-typos-create-class
  • e747459 [Tests] remove node 5/7/9, add node 11
  • b33ae84 Merge pull request #1098 from arian/createElement-display-test
  • 84be80a Merge pull request #1824 from alexzherdev/1762-jsx-max-depth-false-positive
  • a442067 Merge pull request #2029 from sstern6/issue1422
  • 7d07c37 Merge pull request #2032 from alexzherdev/jsx-fragments-message
  • 8c6a8e2 Merge pull request #2089 from jomasti/feature/support-react-forwardref-memo
  • 14451d4 Merge pull request #2085 from himynameisdave/issues/2083
  • 8be52c7 πŸ“ Addresses CR comments
  • f7e3121 Merge branch 'master' of https://github.com/yannickcr/eslint-plugin-react into issues/2083
  • 77e3fd0 Merge pull request #2090 from JBallin/no-method-set-state-docs-url
  • 7da9e0d Fix noMethodSetState docsUrl's

There are 127 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of enzyme is breaking the build 🚨

There have been updates to the enzyme monorepo:

    • The dependency enzyme was updated from 3.6.0 to 3.7.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the enzyme group definition.

enzyme is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of eslint-plugin-jsx-a11y is breaking the build 🚨

The devDependency eslint-plugin-jsx-a11y was updated from 6.1.1 to 6.1.2.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

eslint-plugin-jsx-a11y is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Release Notes for Minor fixes and documentation updates

6.1.2 / 2018-10-05
[fix] Add link-type styling recommendation to anchor-is-valid #486
[fix] label-has-for: textareas are inputs too #470

Commits

The new version differs by 12 commits.

  • c538d35 6.1.2
  • ea964b1 Update changelog
  • 43d1d94 Add link-type styling recommendation to anchor-is-valid
  • 71819a0 [Docs] accessible-emoji: plural of emoji is emoji
  • 4a0608b [Docs] label-has-associated-control: update label id
  • 9957219 [Tests] temporarily allow node 4 + eslint 4 to fail
  • 969ce6d [Dev Deps] add missing dev dep
  • 1be1744 [Tests] use nvm install-latest-npm
  • 9103c7a [Tests] add additional test case for #474
  • bbad58a Merge pull request #471 from ljharb/textarea
  • 47633fb [Fix] label-has-for: textareas are inputs too
  • c1bf3c1 Update aria-props.md to link to the correct doc

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of react-redux is breaking the build 🚨

The dependency react-redux was updated from 5.0.7 to 5.1.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

react-redux is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Release Notes for v5.1.0

The biggest fix is for connect() being used with React's newer forwardRef, memo, and lazy APIs.

We also have begun a complete rewrite of our docs for React Redux. Check them out! Many thanks to those who contributed: @markerikson, @sveinpg, @wgao19, @BTMPL, @pyliaorachel, @dagstuan, @Kerumen, and @carloluis (sorry if I forgot someone!). Docs are a great way to get started contributing to open source, so open a PR today! Check #1001 to see what else needs to be done.

We're also looking at overhauling Redux's documentation. Check out reduxjs/redux#2590 for the latest there.

Changes

Commits

The new version differs by 56 commits.

  • b245f83 5.1.0
  • 307f463 Rebuild lock files with npm 6.4.1
  • 1b43eaa (feat): support react 16.6 (#1062)
  • 2093fbb Upgrade to babel@7 (#1043)
  • bc7b6a9 docs: enable search for docusaurus site (#1060)
  • 1e93536 Add nodejs version 10 for ci (#1058)
  • 1ab1596 fix log message hint for ownProps on map function (#1056)
  • 0d9325e Docs/refactor getting started (#1054)
  • ba6b010 Update docs link
  • dde1a0a Clean-Ups after mapState (#1042)
  • 294c42c [Docs] Fix duplicated words in mapState (#1037)
  • 05f943d Fixed broked links in footer (#1041)
  • cde9c04 Fix a very small typo in mapStateToProps docs (#1040)
  • 1db16a4 Fix link to getting started doc (#1039)
  • f930a76 Docs/extracting data with mapstate (#1036)

There are 56 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of lint-staged is breaking the build 🚨

The devDependency lint-staged was updated from 7.2.2 to 7.3.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

lint-staged is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Release Notes for v7.3.0

7.3.0 (2018-09-20)

Features

  • Allow linting files outside of project folder (#495) (d386c80)
Commits

The new version differs by 1 commits.

  • d386c80 feat: Allow linting files outside of project folder (#495)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of prettier is breaking the build 🚨

The devDependency prettier was updated from 1.14.2 to 1.14.3.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

prettier is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Release Notes for 1.14.3

πŸ”— Changelog

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of enzyme is breaking the build 🚨

There have been updates to the enzyme monorepo:

    • The dependency enzyme was updated from 3.6.0 to 3.7.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the enzyme group definition.

enzyme is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of enzyme is breaking the build 🚨

There have been updates to the enzyme monorepo:

    • The dependency enzyme was updated from 3.7.0 to 3.8.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the enzyme group definition.

enzyme is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

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.