Giter VIP home page Giter VIP logo

technotes's Issues

Android Instant Run

Instant Run 官方介绍
Instant Run 功能演示视频
What’s New in Android Studio 2.0

Instant Run功能可以让开发者像写html网页一样写Android原生代码,能做到一边修改代码,一边在模拟器或者实际设备上看到修改代码后的结果。iOS平台有Playground实现类似的功能。

依赖

  • Gradle 2.0.0+
  • Android Studio Instant Run开关
    Settings->Build,Execution,Deployment->Instant Run--->enable section √ (常见问题1:应用build-安装后启动报错)

image
看到运行符号旁边的闪电就可以了。

运行
模拟器打开要修改的目标页面 - 修改目标页面的代码 - Instant Run.

局限
当前Instant Run仅仅适用于布局的修改。即我们可以把一次修改到运行看作一个“周期”,在这个周期里面你仅仅修改了xml布局文件,或者说和逻辑代码不相关的文件,那么你点击运行的时候才会触发Instant Run,否则的话,Android Studio还是依然会重新编译运行。对此,官方文档的说明如下:

Not all code changes are supported by Instant Run currently.
Here are some code changes that Instant Run does not currently support:

  • Add/remove/change
  • annotations
  • Add/remove/change
  • an instance field
  • Add/remove/change a static field
  • Add/remove a static method signature
  • Change a static method signature
  • Add/remove an instance method
  • Change an instance method signature
  • Changing which parent class the current class inherits from
  • Change the list of implemented interfaces
  • Changing static initializer of a class

Here is the current list of supported code change scenarios:
screen shot 2016-04-28 at 10 12 05 am

Over the coming months, we plan to expand the Instant Run enable more change types, and continue to make your edit, build, run cycle faster.

如何提高Android代码的可测试性?

使用MVP架构,对视图逻辑(view层)和业务逻辑(presenter层)进行拆分,就可以对UI、业务代码分别进行测试。UI测试引入Espresso,业务层单元测试引入junit,生成测试mock对象引入mockito,为了支撑mockito引入dexmaker,hamcrest的引入使得测试代码的匹配更接近自然语言,可读性更高,更加灵活。

HTTPS安全在哪里?

HTTPS安全在哪里?

这篇文章很生动~

使 HTTP 后面增加一个S(Security)的技术,正是 对称加密 + 非对称加密 + CA 认证 这三种技术的混合体。当然这个主要是 HTTPS 的基本原理,真正实际中的 HTTPS 的协议是比以上的描述更为复杂一些的,并且其中任何一步稍有闪失,整个流程都将不再安全。

这也是为什么 HTTPS 协议从 SSL 1.0升级到 SSL 3.0,再被 TLS 1.0 现在被 TLS 1.3取代,其背后都是一个个细节上的优化,以防有任何闪失。

TLS 协议相比 SSL 协议增加了传输层的安全保证。

移动跨平台设计方案开源动态跟踪

构建F8 App / React Native开发指南

在 2015 年的 F8 会议上,React Native for Android 发布。这一年的 F8 app iOS 版本是用 React Native 开发的,而 Android 版本还是原生开发。 在这年之前,iOS 和 Android 都是原生开发。React Native for Android 发布,意味着我们有机会削减 app 的业务逻辑和 UI 代码了。一些 Facebook 的团队使用 React Native,重用了大约 85% 的代码 。

React Native 还使得可以和 UI 设计师一起进行可视化组件的快速原型设计。

http://f8-app.liaohuqiu.net/tutorials/building-the-f8-app/planning/

iOS UIWebView URL拦截

在做app开发时,通常会因为页面的javascript文件比较大导致加载速度很慢,可以考虑将javascript文件打包在app里,当UIWebView需要加载该脚本时就从app本地读取,但UIWebView并不支持加载本地资源。下面的思路可以尝试一下:

iCab Mobile(一款iOS平台的网页浏览器)要实现一个拦截管理器来过滤页面上的广告及其他东西。它有一个简单的基于URL过滤规则的列表(通常由用户维护),当页面包含的资源(图片、js以及css等),文件的URL存在于规则列表中时,资源就不会被加载。

但看一下UIWebView类的API,会发现我们没有办法知道UIWebView正在加载什么资源,更糟的是,当你希望过滤掉某些资源文件的时候,没有方法可以强制UIWebView不去加载这些文件,

正如上面所说,实现拦截器不能靠UIWebView,因为UIWebView没有提供任何有用的API。

对UIWebView的所有请求,要找到一个能中断所有HTTP 请求的切入点,我们需要先了解一下Cocoa的URL Loading System,因为UIWebView是使用URL Loading System从web端取数据的。我们需要的切入点NSURLCache类就是URL Loading System的一部分。虽然目前iOS系统不会在磁盘上缓存任何数据(后面的iOS系统版本或许会有不同),因此在UIWebView开始加载前,NSURLCache管理的缓存数据通常为空,但UIWebView仍然会检测所请求资源文件是否存在于缓存。所以我们需要做的只是继承NSURLCache并重载其方法:

  • (NSCachedURLResponse_)cachedResponseForRequest:(NSURLRequest_)request
    UIWebView请求所有资源时都会调用这个方法。因为我们只需要在这个方法里判断请求的URL是否是我们想拦截的。如果是则创建一个没有内容的假response,否则只需调用super方法即可。

如下是实现细节:

`1.继承NSURLCache:

FilteredWebCache.h:

@interface FilteredWebCache : NSURLCache
{
}
@end`
子类的主要代码

`FilteredWebCache.m:

import "FilteredWebCache.h"

import "FilterManager.h"

@implementation FilteredWebCache
'- (NSCachedURLResponse_)cachedResponseForRequest:(NSURLRequest_)request
{
NSURL *url = [request URL];
BOOL blockURL = [[FilterMgr sharedFilterMgr] shouldBlockURL:url];
if (blockURL) {
NSURLResponse *response =
[[NSURLResponse alloc] initWithURL:url
MIMEType:@"text/plain"
expectedContentLength:1
textEncodingName:nil];
NSCachedURLResponse *cachedResponse =
[[NSCachedURLResponse alloc] initWithResponse:response
data:[NSData dataWithBytes:" " length:1]];
[super storeCachedResponse:cachedResponse forRequest:request];
[cachedResponse release];
[response release];
}
return [super cachedResponseForRequest:request];
}
@end`

首先判断URL是否需拦截(判断通过FilterManager类实现,类实现在此不列出)。如果需要,创建一个无内容的响应对象并把它存在cache中。有人可能会认为只需要返回假的响应对象就够了,没必要缓存它。但这样会因响应对象被系统释放而导致app crash。不知道为何为会这样,可能是iOS的bug(Mac OS X 10.5.x也存在同样问题,而10.4.x及更早的系统上没有问题),也可能是URL Loading System内部类之间的依赖所致。所以我们先缓存响应对象。确保所有响应都是真实存在于缓存中,这也iOS希望的,最重要的是不会crash.

更新:因为假的响应是以大于0的大小来初始化的,看起来缓存它也是必要的。

2.创建新的缓存:

接下来需要创建一个新的缓存并告诉iOS系统使用新的缓存代替默认的,这样当URL Loading System检测资源缓存时才会调用上面的代码。这要在任意UIWebView开始加载页面前做,显然应该放在app启动的时候:

NSString _path = ...// the path to the cache file
NSUInteger discCapacity = 10_1024_1024;
NSUInteger memoryCapacity = 512_1024;
FilteredWebCache *cache =
[[FilteredWebCache alloc] initWithMemoryCapacity: memoryCapacity
diskCapacity: discCapacity diskPath:path];
[NSURLCache setSharedURLCache:cache];
[cache release];
这里需要提供一个缓存存储路径。缓存文件由NSURLCache对象自动生成,我们无需事先创建文件,但要定义缓存文件所存位置(必须是应用程序“沙盒”内,如“tmp”目录或是“Document”目录)

这就是实现UIWebView基于URL进行请求过滤的所有内容,看起来其实并不复杂。

注:如果过滤规则在app运行过程中会改变,你需要从缓存中删除假的响应。NSURLCache提供了删除方法,所以这不是问题。如果过滤规则不会改变,则无需关心

FlatBuffers

为什么Android开发者应该使用FlatBuffers替代JSON?

FlatBuffers是什么?

FlatBuffers是一个高效的跨平台序列化类库,可以在C++、C#、C、Go、Java、JavaScript、PHP和Python中使用。是Google开发的,是为了应用在游戏开发,以及其他注重性能的应用上。

为什么要使用FlatBuffers?

不需要解析/拆包就可以访问序列化数据 — FlatBuffers与其他库不同之处就在于它使用二进制缓冲文件来表示层次数据,这样它们就可以被直接访问而不需解析与拆包,同时还支持数据结构进化(前进、后退兼容性)。

内存高效速度快 — 访问数据时只需要访问内存中的缓冲区。它不需要多余的内存分配(至少在C++是这样,其他语言中可能会有变动)。FlatBuffers还适合配合mmap或数据流使用,只需要缓冲区的一部分存储在内存中。访问时速度接近原结构访问,只有一点延迟(一种虚函数表vtable),是为了允许格式升级以及可选字段。FlatBuffers适合那些花费了大量时间和空间(内存分配)来访问和构建序列化数据的项目,比如游戏以及其他对表现敏感的应用。可以参考这里的基准。

灵活 — 由于有可选字段,你不但有很强的升级和回退兼容性(对于历史悠久的游戏尤其重要,不用为了每个版本升级所有数据),在选择要存储哪些数据以及设计数据结构时也很自由。

轻量的code footprint — FlatBuffers只需要很少量的生成代码,以及一个表示最小依赖的很小的头文件,很容易集成。细节上可以看上面的基准页。

强类型 — 编译时报错,而不需要自己写重复的容易出错的运行时检查。它可以自动生成有用的代码。

使用方便 — 生成的C++代码允许精简访问与构建代码。还有可选的用于实现图表解析、类似JSON的运行时字符串展示等功能的方法。(后者比JSON解析库更快,内存效率更高)

代码跨平台且没有依赖 — C++代码可以运行在任何近代的gcc/clang和VS2010上。同时还有用于测试和范例的构建文件(Android中.mk文件,其他平台是cmake文件)。

Android应用架构选型(MVC MVVM MVP Flux Clean)

业务在不断推进,团队的多人协作效果并不是很好,业务内容庞大且繁杂,不同成员迥异的实现风格使得项目的维护成本越来越高,是时候做一次架构上的重构了。

大致的目标如下:

  • 易用性
    迁移的成本需要适当控制,不能给开发人员过重的额外代价,不然新架构根本推不动;可以考虑部分代码自动生成
  • 可测试性
    将UI代码与业务代码进行拆分,UI层和业务层可以分别进行单元测试 #47
  • 可维护性
    架构分层界限清晰,各个模块的实现职责都非常明确且单一
  • 可扩展性
    工程分离为平台部分和SDK部分,该部分独立实现独立维护,新增业务模块依赖SDK和基础平台进行独立开发,以独立模块的方式进行集成

目前流行的移动应用架构大致有如下几种:

RxJava on Android

The introduction to Reactive Programming you've been missing

RxJava 是 ReactiveX 的一部分,一组开源库。它们有许多不同的库,包括 JavaScript, Groovy, Ruby, Java, C#,以及其他。然而,它们都有着同样的概念,这就是 functional 编程。

ReactiveXReactive Extensions的缩写,一般简写为Rx。
ReactiveX 是一个使用可观察数据流进行异步编程的编程接口,ReactiveX结合了观察者模式、迭代器模式和函数式编程的精华

为什么用RxJava

我们都知道移动开发是困难的。移动用户期望即时响应,而且还有在不同的线程间来回切换的需求。除了主线程,你还要做网络连接,同时你还需要在后台处理其他的各种不同的事情。最重要的是,你不能阻塞 UI 线程。

RxJava 是解决这类问题的好方法,因为他能够使得线程间的切换比较容易。这已经集成在框架里面了。异步操作非常笨重而且容易出错,RxJava 使得你不用再这样做了,这也是你能把不同的线程组合在一起的原因。

我觉得 imperative 编程是我们不应该采用的方法。当然,面向对象编程已经流行很多年了。它已经深入到了现代程序员的骨髓里了。每个人都盲目的使用它,但是它不是我们开发软件的必需品

Functional 编程是 RxJava 里面的概念,而且我觉得用这种方法,代码更加健壮,而且永远不需要维护状态了。代码更加可靠而且你知道它一定工作。

如何提高Android代码的可测试性?

使用MVP架构,对视图逻辑(view层)和业务逻辑(presenter层)进行拆分,就可以对UI、业务代码分别进行测试。UI测试引入Espresso,业务层单元测试引入junit,生成测试mock对象引入mockito,为了支撑mockito引入dexmaker,hamcrest的引入使得测试代码的匹配更接近自然语言,可读性更高,更加灵活。

Android 应用多进程实现方案

一般情况下,一个应用程序就是一个进程,这个进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的资源和内存空间,别的进程是不能任意访问其他进程的内存和资源的。那如何让自己的应用拥有多个进程?很简单,我们的四大组件在AndroidManifest文件中注册的时候,有个属性是android:process,1.这里可以指定组件的所处的进程。默认就是应用的主进程。指定为别的进程之后,系统在启动这个组件的时候,就先创建(如果还没创建的话)这个进程,然后再创建该组件。你可以重载Application类的onCreate方法,打印出它的进程名称,就可以清楚的看见了。再设置android:process属性时候,有个地方需要注意:如果是android:process=":deamon",以:开头的名字,则表示这是一个应用程序的私有进程,否则它是一个全局进程。私有进程的进程名称是会在冒号前自动加上包名,而全局进程则不会。一般我们都是有私有进程,很少使用全局进程。

使用多进程显而易见的好处就是分担主进程的内存压力。我们的应用越做越大,内存越来越多,将一些独立的组件放到不同的进程,它就不占用主进程的内存空间了。当然还有其他好处,有心人会发现Android后台进程里有很多应用是多个进程的,因为它们要常驻后台,特别是即时通讯或者社交应用,不过现在多进程已经被用烂了。典型用法是在启动一个不可见的轻量级私有进程,在后台收发消息,或者做一些耗时的事情,或者开机启动这个进程,然后做监听等。还有就是防止主进程被杀守护进程,守护进程和主进程之间相互监视,有一方被杀就重新启动它。(无效)

坏处的话,多占用了系统的空间,大家都这么用的话系统内存很容易占满而导致卡顿。消耗用户的电量。应用程序架构会变复杂,应为要处理多进程之间的通信。这里又是另外一个问题了。

Objective-C Tips for Good

Objective-C语言并不直接操作对象,而总是借助指针。事实上,当我们提到Objective-C语言中的『对象』时,我们往往指的是『指向对象的指针』;但是由于我们总是通过指针来操作对象,所以就简称为『对象』了。『对象总是借助指针被操作

Android里面的Deep linking

Deep Linking(深度链接)作为移动开发者可能对这个概念有点陌生,但是对于它的实现原理,说出来大家肯定都知道。Deep Linking可以唤起指定应用并向其传递数据,根据传递的数据显示特定内容页的详细信息;它不再受制于应用,只通过一个链接便可唤起应用并跳转到指定页面;它使应用之间产生了联系,使应用不再孤立存在。

Android应用启动加速

应用启动加速并非无从下手,大致思路描述如下:

模块解耦 - Android平台依赖注入框架使用(Dagger)

依赖注入(也叫做控制反转)已在一些流行的框架中(如 Spring 和 Google Guice)占有重要的位置。然而这些框架仅仅是针对标准JVM而设计的,并不支持诸如Android之类的移动环境。当RoboGuice正尝试提升Guice在Android的体验之时,Dagger通过专注于一种简化的功能集以一种不同的方式达到了更好的性能。

Dagger最早由Jake Wharton开发与维护,后来转给Google维护。

就目前来看,Dagger支持的功能仅是Google Guice的子集。考虑到这两个框架的负责人员存在重叠,所以这是可以理解的。然而,Dagger拥有更小型的配置,并且非常明确是针对Android开发的,而它最明显的不足是缺少对于方法和字段的注入支持。

Dagger牺牲了这项功能却提升了错误检查及探测方面的能力。通常依赖注入错误要等到应用开始运行期间才能得到运行时报告。Dagger却包含了注解的编译时检查,对于不完整的绑定会触发编译错误。这个功能将使得在Android上的应用开发变得更加轻松。

另一项较大的不同之处是,相比于其他流行的框架,Dagger只有较少的支持范围。Dagger仅支持@singleton注解。同样这也是可以预料的,因为Android开发的需求有别于标准的Web开发(Web开发伴随着请求和会话的范围)。

Android Webview URL资源加载拦截

定制user-scheme(如zl://xxxxx/1234),实现html页面加载离线资源。
如: 页面使用标签的 src = zl://resourceid/xxxx 访问离线资源file:///android_asset/drawable/test.png"

SubWebViewClient.java

// 这个回调可以通知主程序WebView处理的资源(css,js,image等)请求,并允许主程序进行处理后返回数据。
// 如果主程序返回的数据为null,WebView会自行请求网络加载资源,否则使用主程序提供的数据。
//(非UI线程)
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@OverRide
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return null;
}
return WebResourceSchemeController.handle(super.shouldInterceptRequest(view, request), request.getUrl().toString());
}

具体处理:

@OverRide
public WebResourceResponse webResourceIntercept() {
try {
InputStream localCopy = context.getAssets().open("drawable/test.png");
// 页面使用标签的 src = zl://resourceid/xxxx 访问离线资源file:///android_asset/drawable/test.png"
// url映射到本地路径的页面,在替换scheme之外,还需去掉url所带的参数
response = new WebResourceResponse("image/png", "UTF-8", localCopy);
} catch (IOException e) {
e.printStackTrace();
}
return response;
}

Retrolambda

写在前面

  • Retrolambda 是 Java 6/7 对 Lambda 表达式的非官方兼容方案,它的向后兼容性和稳定性是无法保障的,因此对于企业项目,使用 Retrolambda 是有风险的。
  • Lambda 是把双刃剑,它让你的代码简洁的同时,降低了代码的可读性。

Android Dex分包处理

Dex分包处理。第一次开启App的时候 install dex + dexopt 时间很长,所以第一次开启的时候另启进程专门做这个事情,防止主线程因为时间长而发生ANR。至于自己去配置主dex是为了以防自动分包ClassNotFound异常。

待分析开源项目https://github.com/yydcdut/PhotoNoter

Android进程守护

洗洗睡吧。
如果实在要做,建议引导用户添加白名单。

设备未ROOT情况下,大致的解决方案如下:

  • Service设置成START_STICKY,kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样

当系统内存非常紧张并且轮到 Service 进程被杀的时候,这时候在非 root 的 Android 手机/平板 都是无力回天的。一般来说系统杀掉 Service,过 5 - 10 秒会再次启动 Service(如果有应急机制)。

其实问题的实质就是:系统重启Service 后,如何保持与重启前一样?

设置 onStartCommand() 的返回值(这里牵扯到 Service 的启动方式)。onStartCommand() 有其中两个返回值:
START_STICKY:kill 后会被重启,但重启后调用 onStartCommand(Intent,int,int),但是传进来的 Intent这个参数为 null;
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

  • ​通过 startForeground将进程设置为前台进程,做前台服务,优先级和前台应用一个级别​,除非在系统内存非常缺,否则此进程不会被 kill

是的,用户能看见你。

  • 双进程Service:守护进程和主进程之间相互监视,其中一个Service被清理后,另外没被清理的进程可以立即重启进程

清理工具清理后无效。

  • QQ黑科技:在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死

仅能保护自己不被清理工具清理后台时杀死。

  • Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。鉴于目前提到的在Android-Service层做双守护都会失败,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在:
  1. 用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。

  2. 在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。

  3. 主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。

    开源方案:NativeSubprocess
    注意: Android 5.0上采用fork的方式是无法起作用的,当父进程被杀死的时候,对应fork出来的子进程会被系统主动调用waitpid将其停止并回收.在fork进程这个调用上,iOS也可以调用fork,但是只要你设备没有越狱,fork是直接返回错误的。

  • 联系厂商,加入白名单

XCoder from 0 to 1

记录个人iOS平台学习路径

整体思路:

  • 1.了解iOS平台历史、现状及发展方向
  • 2. 了解iOS技术生态,熟悉相关概念
  • 3. 快速实践,了解开发环境
  • 4. 学习Objective-C
  • 5. 实践
  • 6. 开源项目学习

GitBook 《iOS要点摘录》

Android任务列表中滑动删除应用后都发生了什么?

简单来说,这和多次按返回键退出应用一样,系统会杀掉后台进程,但优势也不是这样。
从最近任务中移除一个条目会移除这个app存在的后台进程。但是它并不会直接结束service,当他们在任务列表中被清除的时候,其实他们自己有相应的api(onTaskRemoved被调用)处理service是否应当被结束。也就是说,你使用的e-mail接收的app即使你在任务列表中把它清除了,它的service也会接收e-mail信息。
当然如果你想要完全停止一个app,你可以通过设置->应用管理 ->进入应用信息页面,点击强制退出。强制退出会让该app的所有进程被杀掉,所有的service停止,所有的通知被移除,所有的提醒被关闭等。该app除了被再次调用的情况下,不会再被启动。
也就是说,是由app来决定在任务列表清楚的时候,后台进程是否被杀掉。

what-actually-happens-when-you-swipe-an-app-out-of-the-recent-apps-list

事件总线(EventBus)分析

文档: http://greenrobot.org/eventbus/documentation/

在安卓中处理不同组件之间的事件传递依靠广播机制,即Intent/BroadcastReceiver机制,其原理类似于传感网中的Ad hoc网络模式,所有组件处在一种无序状态;

事件总线机制则引入中心控制节点来集中管理事件,类似于移动通信网络中的基站功能。

总线这个概念来自于计算机,计算机中各种功能部件如CPU,显卡之类不会采用两两互联的方式,那样布线会非常复杂,实际是使用总线作为公共通信干线,挂载上所有的功能部件。

事件总线框架采用订阅/发布模型

在这个模型中包含以下元素

1.事件类,这是要传递的事件对象。
2.事件总线,是中心控制节点,负责管理事件的注册,接收发布的事件,并完成事件匹配以进行事件处理。
3.发布者,负责分发事件。
4.订阅者,负责事件处理并注册到事件总线。

事件总线模型比广播机制的优势在于

1.简化了组件之间的通信
2.实现了事件分发和事件处理的解耦,因此二者可以在不同线程中实现。
3.扩展了事件类,实际上事件类就是根类Object,而不必藏身在Intent中了。

事件总线模型不能完全替代广播机制,因为广播机制可以完成跨App间组件调用。

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.