Coder Social home page Coder Social logo

router's Introduction

Build Status license PullRequest

Router

中文wiki. 方便的话给个star!❤️

screenshot

Getting started

  • Add router gradle plugin to your project-level build.gradle, as shown below.
buildscript {
    repositories {
        google()
        mavenCentral()
        // jcenter() // deprecated
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:+'
        classpath "com.chenenyu.router:gradle-plugin:x.y.z"
    }
}

latest router-gradle-plugin version: maven

  • Apply router plugin in your module-level 'build.gradle'.
apply plugin: 'com.android.application' // apply plugin: 'com.android.library'
apply plugin: 'com.chenenyu.router'

注意: 在rootProject的build.gradle文件中, 可以指定插件引用的library版本.

ext {
    routerVersion = 'x.y.z'
    compilerVersion = 'x.y.z'
    compilerLoggable = true/false // 打开/关闭编译期log
}

latest router version: maven

latest compiler version: maven

基本用法

  • 添加拦截器(可选)
@Interceptor("SampleInterceptor")
public class SampleInterceptor implements RouteInterceptor {
    @Override
    public RouteResponse intercept(Chain chain) {
        // do something
        return chain.process();
    }
}
  • 添加注解
// 给Activity添加注解,指定了路径和拦截器(可选)
@Route(value = "test", interceptors = "SampleInterceptor")
public class TestActivity extends AppCompatActivity {
    @InjectParam(key="foo") // 参数映射
    String foo;
  
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Router.injectParams(this);  // 自动从bundle中获取并注入参数
        ...
    }
}

// 给Fragment添加注解
@Route("test")
public class TestFragment extends Fragment {
    ...
}
  • 跳转
// 简单跳转
Router.build("test").go(this);
// startActivityForResult
Router.build("test").requestCode(0).go(this);
// 携带bundle参数
Router.build("test").with("key", Object).go(this);
// 添加回调
Router.build("test").go(this, new RouteCallback() {
    @Override
    public void callback(RouteStatus status, Uri uri, String message) {
        // do something
    }
});

// 获取路由对应的intent
Router.build("test").getIntent();
// 获取注解的Fragment
Router.build("test").getFragment();

进阶用法

建议浏览 wiki.

讨论

QQ group: 271849001

Donate ❤️

Click here.

License

Apache 2.0

router's People

Contributors

chenenyu avatar chenqizheng avatar jasonhezz avatar leimsnow 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

router's Issues

有个问题

有没有根据注解,自动生成 路由跳转的文档

which version should i use?

i android sdk is 24, gradle is 2.14.1,
which version should i use,

classpath 'com.chenenyu.router:gradle-plugin:0.2.0',
has error.

跳转web url失败

跳转https://m.baidu.com 会使用BrowserMatcher匹配器匹配,AbsImplicitMatcher generate生成intent时,会校验@nullable Class target是否是activity,如果给fragment添加route注解后,可能传进来的是fragment导致跳转失败, for (Map.Entry> entry : entries) {
if (matcher.match(context, mRouteRequest.getUri(), entry.getKey(), mRouteRequest)) {
RLog.i("Caught by " + matcher.getClass().getCanonicalName());
// Ignore implicit intent.
if (!(matcher instanceof AbsImplicitMatcher) &&
intercept(context, entry.getValue())) {
return null;
}
Object intent = matcher.generate(context, mRouteRequest.getUri(), entry.getValue());
if (intent instanceof Intent) {
assembleIntent((Intent) intent);
return (Intent) intent;
}
return null;
}
}
matcher.generate时直接传进了路由表中的class,路由表中的class有可能是fragment

不知道为什么怎么都跳转不了

我建了一个baseModule,然后用app去依赖baseModule包括继承里面的BaseApplication和BaseActivity,依赖添加步骤我都完成过了,可是我在baseModule的application中初始化Router之后,不管是我对一个叫GuideActivity的注入方式@route("guide")还是添加到路由表map中,当我在onclick中要跳转的时候Router.build("guide").go(this);的时候,并没有响应跳转,然而用startActivity试可以跳转的,不知道哪儿出问题了,

想了个办法用来自动生成modules并注册

注册modules的地方从BuildConfig里读取:
Router.registerModules(new HashSet(Arrays.asList(BuildConfig.ALL_MODULES.split(","))));

BuildConfig里的字符串是在build.gradle里生成的
buildConfigField "String", "ALL_MODULES", ""${getRouterModules()}""

def getRouterModules() {
StringBuilder sb = new StringBuilder()
Set subs = project.rootProject.subprojects
subs.findAll {
it.plugins.hasPlugin("com.android.library") &&it.plugins.hasPlugin("com.chenyu.router")
}
.each {
sb.append(validateName(it.name)).append(",") // library
}
// sb.append(validateName(project.name)) // app
return sb
}

找不到activity

为什么我加了 注解 @route("test") 使用router跳转时,callback返回找不到activity。
不是只添加注解就可以了吗?

组件间通信

楼主 您好
请问 在组件化里 modle1 想调用 modle2 里面的方法 如何使用呢。没有页面跳转

router path是否考虑支持自定义schema

目前的router path是否可以支持自定义schema,并且获取到参数?

需求来源 是想在h5中打开app的,在h5中定义schema并且带参数,如myappschema://information/view?id=1234。
目前的处理办法是对于App的InformationViewActivity增加过滤

<intent-filter>
 <action android:name="android.intent.action.VIEW"/>
 <category android:name="android.intent.category.DEFAULT"/>
 <category android:name="android.intent.category.BROWSABLE"/>
 <data android:scheme="myappschema"/>
</intent-filter>

然后在activity初始化的时候获取到id值

Uri uri = getIntent().getData();
String id = uri.getQueryParameter("id");

请教一下是否可以使用router来简化这部分工作?

需要帮助:Interceptor中如何调用异步网络请求

需求:在router打开一个新页面的时候需要用Interceptor做一下判断,比如判断是否已经登录(这个可以通过本地数据判断,可以实现),也有可能需要判断用户身份(可能需要调用网络请求判断)。
请教一下,如何在Interceptor中调用异步的网络请求,然后根据网络返回数据来返回true/false实现跳转拦截与否的逻辑。

Thanks

help wanted: 如何自定义BrowserMatcher处理流程

目前发现当path是url路径(startwith http or https)的时候,会先尝试匹配有没有对于的schema,没有的话,则跳转打开系统默认浏览器。

请教如何自定义无法匹配的path的时候,自己处理跳转逻辑,我希望用我app内置的webview来打开这个页面,而不是使用系统内置浏览器。

谢谢

使用aar 加载 fragment

获取到的fragment对象为空 ,但是直接new fragment 对象可以得到对象

依赖 aar 文件这样是无法获取的,但是直接依赖 moudle 可以获取到

        if(Router.build("IndexFragment").getFragment(this)!=null){
            fragments.add((Fragment) Router.build("IndexFragment").getFragment(this));
       }

拦截器顺序(优先级)问题

请问拦截器有没有顺序(优先级)的。
我现在不管是通过注解加入interceptors = {"Ops","Login"}的,还是add加入的(addInterceptors("Login"))
一直都是先过其中的Ops,再过Login。
注解中也调整过前后顺序,也没有用。

请问如果我想指定拦截器的顺序,应该怎么设置?

[help wanted]在activity中注入的参数是否可以传递到fragment中

目前打开一个新页面,新页面是activity套fragment的方式。
打开新activity通过with传递了三五个参数,而实际使用这些参数的是被嵌套的fragment。
现在我需要现在activity中@InjectParam这些参数,然后依次with到被嵌套的fragment。
最后再在fragment中@InjectParam这些参数。
实际新activity只是一个中间套,无需处理,只需要原样把参数传递就可以。

是否有更加合理的办法处理,直接将activity获取到的参数传递给fragment?

分享一个router的实际使用场景

如图,这是最近完成的一个app的首页。
default

首页提供有许多的功能入口,而且功能(包括图片、文字、跳转页面)都是会变化的。
解决的思路是是包括banner、grid、marquee都是通过接口获取配置文件,同时将配置文件缓存在本地。
启动的时候先加载本地缓存配置文件,然后通过接口对比本地配置文件的版本和线上版本,有更新则替换缓存同时刷新页面。

配置文件属性主要包括title、img、path、loginRequired,分别用于来控制显示的标题、图片、跳转页面以及跳转页面是否必须要先登录。

path

对于Router.build(path)。定义有三种类型

  1. 空 则表示不跳转、功能暂时未实现、点击无对于事件等情况
  2. ADView这样的标记,表示需要在app中实现的功能
  3. http开始的链接
    3.1 app中已实现的功能。比如http://example.com/h5/ad/view?id=123。 可能app中已经实现了一个ADView.activity。则给这个ADViewActivity.java加上了@Route({"ADView", "http://example.com/h5/ad/view"})注解。由于android、ios进度差异、各版本之间差异等情况,有些app中未实现这个ADView的原生功能,这个时候就是直接打开这个ad/view?id=123的h5链接。
    3.2 app中未实现或者不准备实现的功能,直接用浏览器打开这个path地址就可以。至于如何用app自己实现的浏览器来打开可以参见#30

loginRequired

有些功能是需要登录的,有些功能可以不需要,这个时候可以通过loginRequired在跳转之间做判断,也可以在被跳转页面通过注解跳转,比如上面提到的ADViewActivity查看功能,是一个登录用户才可以使用的功能,这个时候就可以在ADViewActivity中加上LoginInterceptor

在未使用router的lib中apply plugin: 'com.chenenyu.router',导致找不到uri

#8 现象与这个issue类似。
我在base library和app application都应用了Router apply plugin: 'com.chenenyu.router'
但是在base中未实际使用router,导致在app中使用的时候报错:Router: Can not find an Activity that matches the given uri: uriname

log信息如下:
I/Router: com.chenenyu.router.BaseRouteTable I/RouteTable: {} I/Router: There is no interceptor table in module: base. I/InterceptorTable: {} I/Router: There are no interceptors in module: base. I/Router: There are no interceptors in module: app. I/Interceptors: {}

解决方法:不使用就不应用Router apply plugin: 'com.chenenyu.router',在base中删除了就正常工作了

无法识别 路由咋回事

  1. 初始化
    Router.initialize(new Configuration.Builder()
    .setDebuggable(BuildConfig.DEBUG)
    .registerModules("app", "easeui")
    .build());
    2.给Acitivity 添加注解
    @route("cartondetail")
    3.在一个工具类里面跳转
    Intent intent = Router.build("cartondetail").getIntent(context);
    intent.putExtra("feed_id", id);
    context.startActivity(intent);
    有什么问题吗? 为什么找不到这个路由呢?

较大概率会报NoClassDefFoundError 约千分之2左右概率

Fatal Exception: java.lang.NoClassDefFoundError
Failed resolution of: Lxxxx/xx/x/PersonalFragmentN;
Raw Text
com.xunmeng.router.AppRouteTable.handle (AppRouteTable.java:108)
com.xunmeng.router.AptHub.init (AptHub.java:76)
com.xunmeng.router.AptHub.initDefault (AptHub.java:58)
com.xunmeng.router.Router.initialize (Router.java:45)
com.xunmeng.router.Router.initialize (Router.java:32)

有没有这种操作

public interface RouterService {

@FullUri("router://com.baronzhang.android.router.FourthActivity")
void startUserActivity(@UriParam("cityName") 
        String cityName, @IntentExtrasParam("user") User user);

}
接下来我们就可以通过如下方式实现 Activity 的跳转传参了:

RouterService routerService = new Router(this).create(RouterService.class);

User user = new User("张三", 17, 165, 88);
routerService.startUserActivity("上海", user);

是否考虑将source version提高到jdk1.8

升级了AS3.1
AS一直提醒warning: Supported source version 'RELEASE_7' from annotation processor 'com.chenenyu.router.compiler.processor.RouteProcessor' less than -source '1.8'
是否考虑将router的source version提高到1.8.

btw,这个warning不影响正常使用

ProGuard config

As RealRouter.java uses reflection, we need add ProGuard config as below:

# Router
-keep class **RouteTable { *; }
-keep class <app package name>.BuildConfig { *; }

gradle插件生成RouterBuildInfo信息不全

你好. 发现一个问题. 如果设置com.android.tools.build:gradle:3.0.0 那么gradle插件自动生成RouterBuildInfo.java里ALL_MODULES的值只有app, 没有其他Module的name.. 如果使用gradle2.3.3版本就没有问题. 在你的1.2分支的代码上就可以复现.. 请问你有什么解决办法吗? 期待你的回复

[Feature] 支持 js 与 Native 互相通信?

Hello chenenyu:

能否支持 JsUrlRouter ? 能否加入到您的 TODO-LIST 中去? 谢谢.

API maybe as below:

OtherObject  otherObj = new OtherObject();

Router.build(uri).go(context/fragment/otherObj ) // 支持任意对象
/**
* 一个既不是 Activity 也不是 Fragment 的类
*/
public class OtherObject extends Object {

	// 注解支持到方法级别
	@Route({"testOnCallFromJs001", "http://example.com/testOnCallFromJs001", "router://testOnCallFromJs001"}) 
	public void onCallFromJs001()
   {
		// dosth001
   }

	@Route({"testOnCallFromJs002", "http://example.com/testOnCallFromJs002", "router://testOnCallFromJs002"}) 
	public void onCallFromJs002()
   {
		// dosth001
   }
}

部分接口要求api等级过高

` @OverRide
public void go(Context context) {
Intent intent = getIntent(context);
if (intent == null) {
return;
}

    Bundle options = mRouteRequest.getActivityOptionsCompat() == null ?
            null : mRouteRequest.getActivityOptionsCompat().toBundle();

    if (context instanceof Activity) {
        ActivityCompat.startActivityForResult((Activity) context, intent,
                mRouteRequest.getRequestCode(), options);

        if (mRouteRequest.getEnterAnim() != 0 && mRouteRequest.getExitAnim() != 0) {
            // Add transition animation.
            ((Activity) context).overridePendingTransition(
                    mRouteRequest.getEnterAnim(), mRouteRequest.getExitAnim());
        }
    } else {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ContextCompat.startActivity(context, intent, options);
    }

`

这里的 ContextCompat.startActivity(context, intent, options); 建议修改为
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
context.startActivity(intent, options);
} else {
context.startActivity(intent);
}

Interceptor中调用Router.build().getFragment() 导致AbsRouter 中的RouteRequest被修改

场景如下:

新增了 全局的 Interceptor
Router.addGlobalInterceptor(new FunctionActivityInterceptor());

在Interceptor中调用Router.build().getFragment(),导致了AbsRouter中的RouteRequest变成了getFragment的RouterRequest。
由于在Interceptor调用getFragment需要skipInterceptors(不然会出现递归死循环),若没有找到Fragment,没法设置不跳过Interceptor,因为Router.build()返回的是IRouter,只有skipInterceptors,没有不跳过Interceptor的设置。

FunctionActivityInterceptor代码如下:

public class FunctionActivityInterceptor implements RouteInterceptor {
    @Override
    public boolean intercept(Context context, RouteRequest routeRequest) {
        Fragment fragment = (Fragment) Router.build(routeRequest.getUri()).with(routeRequest.getExtras()).skipInterceptors().getFragment(context);
        if (fragment != null) {
            return true;
        } else {
            return false;
        }
    }
}

针对插件化的路由方案

目前在插件方面有个问题 请教下,因为路由表里面存的 是activity 引用,对于插件 无法获取其activity 引用,相应的是类名全路径字符串了. 通过component 进行启动。请问这块有计划支持吗 目前我们准备采用变通方式 ,通过主工程 透明activity 进行中转

v1.2.1中使用Interceptor有什么要求

原先的Interceptor使用方式,在v1.2.1中,代码没进入这个Interceptor。
请问是使用方式有什么变化吗?
@Route(value = "ProfileEdit", interceptors = "Login") public class ProfileEditActivity extends Activity

@Interceptor("Login") public class LoginInterceptor implements RouteInterceptor

建议: 加入changelog

最近更新了0.8.0 0.8.1等等新版本
建议加入changelog,以便使用者决定是否升级使用新版本。

毕竟已经上线的应用,升级任意一个依赖都是有风险的。

Thanks

不支持Android Studio 3.0

使用com.android.tools.build:gradle:3.0.0-alpha1的情况下,注解似乎无效。例如@route("test"),使用Router.build("test").go(context)时提示:Can not find an Activity that matches the given uri:test

[help wanted]登录拦截以及登录后再跳转回具体页面

需求:

类似web中登录后跳转到具体页面,在app的某个位置NormalActivity(fragment/activity),点击进入另外一个需要登录才能访问的页面(NeedLoginActivity)。判断发现用户未登录,跳到登录页面(LoginActivity)。登录成功以后希望跳转到NeedLoginActivity,并且带有原始调用NeedLoginActivity时候的bundle requestCode等参数。

思路:

  1. 在NeedLoginActivity中添加登录拦截器
@Route(value = {"NeedLoginActivity"}, interceptors = {"Login"})
public class NeedLoginActivity
  1. 定义登录拦截器,并且在拦截器中判断是否登录
public class LoginInterceptor implements RouteInterceptor {

    @Override
    public boolean intercept(Context context, RouteRequest routeRequest) {
        boolean isUserLogin = App.getInstance().isUserLogin();
        if (!isUserLogin) {
            // 未登录则跳转到登录页面,不直接将routeRequest传递是因为routeRequest中bundle无法序列化
            Router.build("Login")
                    .with("routeExtras", routeRequest.getExtras())
                    .with("routePath", routeRequest.getUri().toString())
                    .with("routeRequestCode", routeRequest.getRequestCode())
                    .requestCode(RequestCode.USER_LOGIN)
                    .go(context);
            ToastUtils.showLong(R.string.login_request);
        }
        return !isUserLogin;
    }
}
  1. 在登录页面,登录成功以后
@Route({"Login"})
public class LoginActivity extends AppBaseActivity {

    @InjectParam
    Bundle routeBundle;
    @InjectParam
    String routePath;
    @InjectParam
    int routeRequestCode;
    
     /**
     * 登录成功,处理登录结果
     */
    private void loginSuccess(final LoginResult result) {
        App.getInstance().saveUserLogin(result);
       
        Intent intent = new Intent();
        intent.putExtra("routePath", routePath);
        intent.putExtra("routeBundle", routeBundle);
        intent.putExtra("routeRequestCode", routeRequestCode);

         setResult(Activity.RESULT_OK, intent);
         finish();
        }
    }
 
}
  1. 在NormalActivity的onActivityResult捕获LoginActivity中返回的route信息,并再次尝试跳转到NeedLoginActivity
@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == RequestCode.USER_LOGIN && resultCode == Activity.RESULT_OK && null != data) {
            Bundle routeBundle = data.getBundleExtra("routeBundle");
            String routePath = data.getStringExtra("routePath");
            int routeRequestCode = data.getIntExtra("routeRequestCode", 0);
            if (!StringUtils.isEmpty(routePath)) {
                IRouter iRouter = Router.build("routePath");
                if (null != routeBundle) {
                    iRouter.with(routeBundle);
                }
                if (0 != routeRequestCode) {
                    iRouter.requestCode(routeRequestCode);
                }
                iRouter.go(this);
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

遇到的问题

  1. route跳转会带有bundle requestcode anim等信息,需要挨个传递到LoginActivity,比较麻烦。直接传递RouteRequest会报RouteRequest中的bundle无法序列化的错误
  2. 如果跳转的初始页面是一个activity还ok,上述整个流程都可以走通,但是如果是一个fragment就会出现一个问题,那就是拦截器中intercept(Context context, RouteRequest routeRequest)方法中的content是这个fragment附属的activity,也就是说LoginActivity登录结果只能再附属的activity中onActivityResult获取,无法再该fragment的onActivityResult获取。

上述1只是麻烦一点,还可以解决。2的话有点麻烦。

@chenenyu 不知道我上述描述是否清晰,对于这个需求这个思路是否正确,另外就是在拦截器的intercept中是否可以获取到原始go()带有的content/fragment?
谢谢

无法传递int(非String)数据类型

@InjectParam(key = "id")
int id;
@InjectParam(key = "batch_id")
String batchId;

Bundle extras = getIntent().getExtras();
id = extras.getInt("id");
batchId = extras.getString("batch_id");

id无法获取到,batchId可以

处理h5打开app导致的死循环

我自定义了一个activity来处理h5打开app

       <activity
            android:name=".activity.RouterActivity"
            android:theme="@android:style/Theme.NoDisplay">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="swapshop" />
            </intent-filter>
        </activity>
public class RouterActivity extends Activity {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Uri uri = getIntent().getData();
        if (uri != null) {
            Router.build( uri).go(this, new RouteCallback() {
                @Override
                public void callback(RouteResult state, Uri uri, String message) {
                    if (state != RouteResult.SUCCEED) {
                        IMUIHelper.showToast(RouterActivity.this, "该版本不支持,请升级版本");
                    }
                }
            });
        }
        finish();
    }
}

当router处理没有定义的URI时,会一直调用RouterActivity来处理
怎么解决这个问题?

建议在Router.build可以自由指定拦截器的添加和跳过

  1. 建议在跳转的时候加入拦截器添加Router.build(uri).addInterceptors(String... interceptors),原因是有些activity可能只在某些特定的场景下才需要拦截器。

  2. 建议在 Router.build(url).skipInterceptors(String... interceptors)可以带参,制定跳过的拦截器,原因是在某些时候,我只需要跳过某个拦截器,另外的几个拦截器任然是需要的。

加入以上两个特性,可以更加灵活的使用拦截器。

Thanks

Does the lib support cross-module route?

The wiki page writes that route framework is significant for modular develop. Thats correct but how to make cross-module route rule by this lib? I have had a lab but did not find out the way. Do I miss something?

无法生成RouterBuildConfig类

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.chenenyu.router:gradle-plugin:latest.integration'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

apply plugin: 'com.android.application'
apply plugin: 'com.chenenyu.router'

配置完成后rebuild不能生成RouterBuildConfig类,而且不支持Instant Run

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.