azuread / scimreferencecode Goto Github PK
View Code? Open in Web Editor NEWReference code to build a SCIM endpoint to automate provisioning
License: MIT License
Reference code to build a SCIM endpoint to automate provisioning
License: MIT License
The last two tests in the postman collection (Get all users and Get all groups). Assert that an empty resource array is returned on the body. Whilst scim specifies that this array is not a requirement when no results are returned see https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.
I noticed in the sample schema, that the userName attribute (as well as I believe in the SCIM specifications..) that the userName attribute is required, however, it (the remove Patch request) does not verify this. Where is the appropriate place to check these requirements?
Should it be in the base library code that has been provided (by querying the schema identifier stored in IProvider.Schema) or should it be done directly in the individual IProvider implementations?..
The junk data test suite the server ignores any junk data sent on a request and creates the resource regardless. Sending a 400 request and not creating the resource is an equally viable option.
My following response will fail the Postman because it expects the /Users
resource to be listed first. Is this an actual requirement or for AD SCIM application or is this just an oversight with the test?
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:ListResponse"
],
"startIndex": 1,
"itemsPerPage": 100,
"totalResults": 1000,
"Resources": [
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
],
"id": "Group",
"description": "Group",
"name": "Group",
"schema": "urn:ietf:params:scim:schemas:core:2.0:Group",
"endpoint": "/Groups",
"meta": {
"resourceType": "ResourceType",
"location": "scim/v2/ResourceTypes/Groups"
}
},
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
],
"id": "User",
"description": "User Account",
"name": "User",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User",
"endpoint": "/Users",
"schemaExtensions": [
{
"schema": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
"required": false
}
],
"meta": {
"resourceType": "ResourceType",
"location": "scim/v2/ResourceTypes/User"
}
}
]
}
Hi,
Could there be more examples in the WebHostSample project please?
At least one for Users which has the best practice of extending the main library, with static data. And then it can be adapted to be used in other applications.
Thanks,
Hi, pertaining to this test -- Put a user misspelled attribute.
The RFC states that we should return 400, when the schema is violated:
https://tools.ietf.org/html/rfc7644
| 400 (Bad | GET, POST, | Request is unparsable, |
| Request) | PUT, PATCH, | syntactically incorrect, or |
| | DELETE | violates schema.
However your test expects a 200, and thus fails.
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
pm.test("Body does not contains Addresses", function () {
pm.expect(pm.response.text()).to.not.include("Addresses");
});
Can you shed some light on whether this is accurate or am I misunderstanding something.
All other user routes work because the target /Users
(with a capital "U"); however the GET empty Users test in the Endpoint tests targets the /users
route (lower case "u").
This is causing the test to fail for me because our application respects the case-sensitivity of the resource.
While the SCIM specification explains that the JSON attributes should be treated case-insensitively, it does not say anything explicitly about the case-sensitivity of the Resource
route paths. The RFC only shows examples with /Users
and /Groups
(no mention of /users
or /groups
)
I'm curious if treating this route case-insensitively is a hard requirement for Azure AD SCIM applications or if this was a bug in the postman test.
Your test suite tries to PATCH a group with the following call:
PATCH http://{{Server}}{{Port}}/{{Api}}/Groups/{{groupid}}
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
],
"Operations": [
{
"name": "addMember",
"op": "add",
"path": "members",
"value": [
{
"displayName":"new User",
"value":"{{id4}}"
}
]
}
]
}
However, it seems that 'displayName' should be 'display' as per
https://tools.ietf.org/html/rfc7644.
This causes my endpoint to seemingly correctly output:
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:Error"
],
"status": 400,
"scimType": "invalidPath",
"detail": "invalidPath: no attribute named 'displayName' from 'members'"
}
Which in turn causes a subsequent test to fail as the user is not a member of that group.
Can you confirm this is an error, and should I open a pull request to fix?
Thanks!
Hello,
I am trying to figure out what the properties of Filter mean. When trying to serialize a list of filters, I get an exception. After adding a WriteLine debug line, I found that a GUID cannot be parsed:
var expression = "a eq 1";
Filter.TryParse(expression, out var filters);
Console.WriteLine(Filter.ToString(filters));
System.InvalidOperationException : A value is invalid.
Stack Trace:
at Microsoft.SCIM.Filter.Validate(Nullable`1 dataType, String value) in /home/iinuwa/Development/csharp/SCIMReferenceCode/Microsoft.SystemForCrossDomainIdentityManagement/Protocol/Filter.cs:line 399
at Microsoft.SCIM.Filter.set_ComparisonValue(String value) in /home/iinuwa/Development/csharp/SCIMReferenceCode/Microsoft.SystemForCrossDomainIdentityManagement/Protocol/Filter.cs:line 132
at Microsoft.SCIM.Filter.ToString(IReadOnlyCollection`1 filters) in /home/iinuwa/Development/csharp/SCIMReferenceCode/Microsoft.SystemForCrossDomainIdentityManagement/Protocol/Filter.cs:line 300
I think there's a design flaw around pagination. The provider implementation in WebHostSample seems to be responsible for pagination (although it does not currently .Skip(), it just .Take()s), but ProviderBase (in SystemForCrossDomainIdentityManagement) is responsible for setting TotalResults. ProviderBase cannot know the correct value for TotalResults if the result it receives from the implementation is already paginated.
The specification says (https://datatracker.ietf.org/doc/html/rfc7644#page-25) that "totalResults [should specify] the total number of results matching the client query". In the example provided by IETF, GET /Users?startIndex=1&count=10 yields
{
"totalResults":100,
"itemsPerPage":10,
"startIndex":1,
"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"Resources":[{
...
}]
}
As well as correcting TotalResults, an ideal implementation would also be mindful of efficiency concerns. That might enable the provider to return TotalResults along with the results, so that the implementation can decide whether to use the same query or a different one to ascertain its value.
For example, it might be more efficient to do this
// UserProvider
var results = _db.UserProfiles
.Where(u => u.ClientId == "xyz")
.Skip(startIndex)
.Take(count)
.Select(some DTO);
var totalResults = _db.UserProfiles
.Count(u => u.ClientId == "xyz");
than this
// UserProvider
var allResources = _db.UserProfiles
.Where(u => u.ClientId == "xyz")
.Select(some DTO);
// ProviderBase
var results = allResources
.Skip(startIndex)
.Take(count);
var totalResults = allResources.Count();
I don't seem to be able to submit a PR to the wiki. The PR would be to add the following to Step 7 of deploy page.
Also add ASPNETCORE_ENVIRONMENT with the value of "Development". Note that you will need to get a token using the /scim/token endpoint for testing as described on the testing page.
Hi Guys,
I had implemented Scim Application with our internal system APIs to sync users only, facing an issue
ProviderBase class abstract methods QueryAsync, RetrieveAsync calling weirdly
When I perform on-demand provision user
I have mapped objectid with externalid with matching precedence 1
QueryAsync this method calls 3 times with the same Attribute path externalid but with different ids
RetrieveAsync this method calls with inappropriate externalid, not with objectid that's why it creates a user every time instead of updating when the user already exists.
When using Mac / Linux you may see warnings in your build. These warnings should not block use of the code. We welcome contributions from the community to help address the warnings.
Example warnings:
When patching Roles, it looks like the wrong enum-type is beeing used for this check:
if
(
!string.Equals(
Microsoft.SCIM.AttributeNames.PhoneNumbers,
operation.Path.AttributePath,
StringComparison.OrdinalIgnoreCase)
)
{
return roles;
}
Shouldn't the correct enum-value be: Microsoft.SCIM.AttributeNames.Roles ?
Hi, looking to stand up a SCIM Endpoint to integrate with Azure AD, and trying to get all these tests to pass against it.
Noticed that this test:
Get ResourceTypes
GET http://{{Server}}{{Port}}/{{Api}}/ResourceTypes
Fails with the following message:
User endpoint exists | TypeError: Cannot read property 'endpoint' of undefined
Response body seems correct however:
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:ListResponse"
],
"totalResults": 2,
"startIndex": 1,
"itemsPerPage": 2,
"Resources": [
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
],
"id": "User",
"meta": {
"resourceType": "ResourceType",
"location": "/ResourceTypes/User"
},
"name": "User",
"endpoint": "/Users",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User"
},
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
],
"id": "Group",
"meta": {
"resourceType": "ResourceType",
"location": "/ResourceTypes/Group"
},
"name": "Group",
"endpoint": "/Groups",
"schema": "urn:ietf:params:scim:schemas:core:2.0:Group"
}
]
}
Changing the test condition to:
pm.test("User endpoint exists", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.Resources[0].endpoint).to.eql("/Users");
});
from
pm.test("User endpoint exists", function () {
var jsonData = pm.response.json();
pm.expect(jsonData[0].endpoint).to.eql("/Users");
});
fixes this. I'd be happy to open a PR to fix this?
In the page https://github.com/AzureAD/SCIMReferenceCode/wiki/Test-Your-SCIM-Endpoint there is a link named https://aka.ms/ProvisioningPostman pointing to https://www.postman.com/collections/d9541c318fbe2c83b62c that json file is not matching the last one on master https://github.com/AzureAD/SCIMReferenceCode/blob/master/PostmanCollection.json which contains at least one bug-fix #19
NuGet package not available. and I want to use it in my repo and it is really helpfull.
From my understanding, as per the SCIM specification, the ServiceProviderConfig discover endpoint path should be
/ServiceProviderConfig
, not /serviceConfiguration
.
Is this a bug in the postman test?
Hi,
Not an Issue, but rather a question...
I was searching for a nuget package for integrating SCIM into an enterprise application. There is Microsoft.SystemForCrossDomainIdentityManagement package which seems older and not being maintained.
Is there any plan to create a nuget package for the SCIM that we could integrate for the enterprise application that uses Azure AD?
Hi guys, can you explain which requests handled rootcontroller and for what?
I have gotten the sample code to work well however it only really works against one azure ad tenant and also only with the azure issued token and not the "Secret Token" (which I believe to be the long-lived bearer token?).
It would be fantastic with sample code that allows for multiple tenants aswell as using a secret token.
On the default branch, the README.md contains a link to a getting started article, which it identifies as [here](docs/get-started.md)
However there is no docs directory and no file get-started.md on that branch.
I am trying to validate incoming POST ~/scim/Users
requests and return more detailed 400 bad request responses as per HTTP Status and Error Response Handling such as:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"scimType":"invalidValue"
"detail":"Attribute 'emails[type eq \"work\"].value' is required",
"status": "400"
}
However, ErrorResponse does not extend Resource
, so I cannot return one from within my Task<Resource> CreateAsync(...)
implementation - are detailed error types currently supported?
I can see that the sample InMemoryUserProvider throws raw HttpResponseException
instances, is it possible to enrich these with detailed error types to support more expressive failures to SCIM clients?
Thanks in advance!
Hi,
I've noticed a couple of problems with patch operations on group members.
case OperationName.Remove:
if (null == group.Members)
{
break;
}
if (operation?.Value?.FirstOrDefault()?.Value == null)
{
group.Members = Enumerable.Empty<Member>();
break;
}
Thanks,
Steve
PatchName(this Core2EnterpriseUser user, PatchOperation2 operation) method in Core2EnterpriseUserExtensions class only updates givenName and familyName, skipping the name.formatted.
The test in question submits the following payload to /Groups PATCH
{
"id": "{{1stgroupid}}",
"Operations": [
{
"op":"add",
"path": "members",
"value": "string id 1"
}
],
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
]
}
However, I don't think value can be a string, it should probably be like this example from the RFC:
https://tools.ietf.org/html/rfc7644
The following example shows how to add a member to a group. Some
text was removed for readability (indicated by "..."):PATCH /Groups/acbf3ae7-8463-...-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"{ "schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[
{
"op":"add",
"path":"members",
"value":[
{
"display": "Babs Jensen",
"$ref":
"https://example.com/v2/Users/2819c223...413861904646",
"value": "2819c223-7f76-453a-919d-413861904646"
}
]
}
]
}
Can you please let me know if this test should pass as is or not. The test expects a 204 which seems incorrect -- result should be 400 with this payload.
I'm having troubles with the code running on a Azure App Service, that revolves around Json Converters. It seems like the conversions are being converted in Sample project differently that in the SCIM foundation project. Has anyone else seen this behavior?
An unhandled exception was thrown by the application.System.InvalidCastException: Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'System.Collections.Generic.Dictionary2[System.String,System.Object]'.at Microsoft.SCIM.TrustedJsonFactory.Create(String json) in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\TrustedJsonFactory.cs:line 14at Microsoft.SCIM.JsonFactory.Create(String json, Boolean acceptLargeObjects) in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\JsonFactory.cs:line 35at Microsoft.SCIM.JsonSerializer.ToJson() in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\JsonSerializer.cs:line 76at Microsoft.SCIM.Schematized.ToJson() in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\Schematized.cs:line 111at Microsoft.SCIM.Core2UserBase.ToJson() in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\Core2UserBase.cs:line 168at Microsoft.SCIM.Schematized.Serialize() in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\Schematized.cs:line 118at Microsoft.SCIM.Schematized.ToString() in C:\source\Microsoft.SystemForCrossDomainIdentityManagement\Schemas\Schematized.cs:line 126at System.Convert.ToString(Object value, IFormatProvider provider)at System.Convert.ToString(Object value)at Microsoft.AspNetCore.Mvc.MvcCoreLoggerExtensions.ActionMethodExecuting(ILogger logger, ControllerContext context, Object[] arguments)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()--- End of stack trace from previous location where exception was thrown ---at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT
1.ProcessRequestAsync()
I have been trying to use the sample code provided here but it seems that there are filter expressions (that are used in the postman collection and are documented as supported in the documentation) that seems to not be supported. The request that I am trying is the 'filter eq and (val or val)' in the 'User tests with garbage' folder in the Postman collection.
Upon sending this request, an exception is thrown since there are some filter expressions that are not supported as a filter in the FilterExpression class (line 269 onwards, exception happening in the default case for the switch statement such as 'sw', 'ew' and 'pr'.
The code from RequestExtensions class quoted below does not make sense, since request?.Headers.TryGetValues(...) call is a "dead code" that has no effect.
And judging by this code I doubt that "correlationIdentifier" is being used to any meaningful purpose in this project.
public static bool TryGetRequestIdentifier(this HttpRequestMessage request, out string requestIdentifier) { request?.Headers.TryGetValues("client-id", out IEnumerable<string> _); requestIdentifier = Guid.NewGuid().ToString(); return true; }
Being used like this:
if (!request.TryGetRequestIdentifier(out correlationIdentifier)) { throw new HttpResponseException(HttpStatusCode.InternalServerError); }
The comments in ConfigureService for production say that you should not "rely on a token generated by Azure AD".
Is that comment correct?
The tutorial says that the only valid option for non-gallery apps is to use a long-lived bearer token.
I can create a JWT access_token to my SCIM API with 3 year expire date, and paste that in the Secret Token field. But that is just a glorified 'shared secret' - how is that safer than using the /scim/token development endpoint?
If I leave 'secret token' blank, at least I can verify the issuer in the AAD generated token and know that I am called from the correct Tenant, instead of having a fixed token that could be compromised.
NB my question is similar to issues #35 and #37 and Rickards post on SO. However the fact remains that ConfigureService in SCIMReferenceCode only contains code on how not to do things..
The documentation say to use "API" as the variable name but the correct variable name is "Api" as Postman is case sensitive.
At least my Postman is case sensitive
When an existing user is patched with a phone number that's not already in the list a null reference exception will occur.
This checks if the phone number already exists, if not then the SingleOrDefault() will assign null
to phoneNumber
.
A few lines later (after retrieving the value of the patch operation) the phone number is updated while phoneNumber
is null
.
The same structure is used for patching email adresses, roles, addresses etc.
The patch body looked like this:
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
],
"Operations": [
{
"op": "Add",
"path": "phoneNumbers[type eq \"work\"].value",
"value": "1120"
}
]
}
Phone numbers did exist but not of type 'work'.
As I am new to SCIM I am having trouble finding out how to call the SCIM endpoints when I deploy them to Azure App Service.
I would like to test the 3 different Authorization Methods described here https://docs.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#authorization-for-provisioning-connectors-in-the-application-gallery
But I am unsure how to proceed to make this work
I have Azure B2C tenants that I would like to provision in other connected directories.
Can I use B2C as a source?
When searching nuget, I found a package named Microsoft.SystemForCrossDomainIdentityManagement, but it seems older than this project. Is it possible to consume the SCIM assembly from a sample web hosting project from a well-known nuget package, instead of using the source?
The ReferenceCode doesn't support SCIM Custom Schema extensions.
Over the method AddCustomAttribute() on Core2GroupBase or Core2UserBase you are able to add custom attributes.
However this attribut will not be serialized or deserialized trought the middleware.
I am trying to build SCIM API using this and not able to find any guides which I can follow through to implementation
Any help will be appreciatable.
The test called 'Post enterprise user' in the Postman collection of tests, specifies this as part of it's body:
"primary": false
}
],
"Department": "some department",
"displayName": "Kimberly Baker",
"emails": [
The department attribute is part of the extension schema. Should it be wrapped like in the other Post Enterprise User test:
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { "Department": "bob", "Manager" : { "Value": "SuzzyQ" } }
This test
Post emp1 with string "True"
Posts the following body
{
"userName": "emp1",
"active": "True",
}
However the RFC defines the active field as a boolean. Is "True" expected to work in order to support an Azure AD integration? I am happy to open a pull request to address this.
Current implementation of the json serialization and de serialization forces user to add newtonsoft to the controllers globally which is a problem if someone tries to integrate the scim endpoints into their application that's using the default text.json library (starting from .net core 3.1) which doesn't support DataContract. In this case adding newtonsoft globally is a big no.
We can use the ActionFilterAttribute Class to ensure the scim endpoints use newtonsoft and the other endpoints keep working as it is.
The following request in the postman test exists in the User Tests:
{{Protocol}}://{{Server}}{{Port}}/{{Api}}/Users/?filter=DisplayName+eq+%22BobIsAmazing%22
The extra /
after the resource is causing issues. Is this extra /
something our application should be expected to ignore?
This sample app "Microsoft.SCIM.WebHostSample" is not running. when making it as "set as start up project" it is launching in browser and saying it don't have web page in it and it makes all sens since we don't have any view page in this sample.
Can anyone please guide how you are running this sample as it don't have any view.
After the library update to support SCIM metadata, the group provider was not updated.
InMemoryGroupProvider.cs is missing the code to update accordingly 'Metadata.Created' and 'Metadata.LastModified' on the following methods:
I had to face this issue while adding Microsoft.SystemForCrossDomainIdentityManagement package in my .Net Standard app.
For now, I just moved to .Net Framework but I need .Net Standard support for it.
Warning NU1701 Package 'Microsoft.SystemForCrossDomainIdentityManagement 2.0.5.95' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETStandard,Version=v2.0'. This package may not be fully compatible with your project.
The test cases provided for Postman has mismatched data field names and as a result, The returned response from the api has null values for those mismatched fields.
Example:
Look at the ExternalIdentifier
and ElectronicMailAddresses
fields. Both are null in the response because the request had these fields as externalId
and emails
respectively.
The test case for EnterpriseUser has more mismatched fields.
Hi, in code I only see TokenController.cs, but cannot find other controllers (ie. ConstantController.cs)
Hi,
First of all thanks for sharing such a nice and efficient scim server implementation code. Every thing works fine except /schemas and /ResourceTypes endpoints.
Looks these endpoints are set to return empty collection. Could you please help me these endpoints working ?
public abstract class ProviderBase : IProvider
{
private static readonly Lazy<IReadOnlyCollection<TypeScheme>> TypeSchema =
new Lazy<IReadOnlyCollection<TypeScheme>>(
() => **Array.Empty<TypeScheme>()**); // looks this is set as empty
private static readonly Lazy<IReadOnlyCollection<Core2ResourceType>> Types =
new Lazy<IReadOnlyCollection<Core2ResourceType>>(
() =>
Array.Empty<Core2ResourceType>()); // looks this is set as empty
public virtual bool AcceptLargeObjects
{
get;
set;
}
public virtual IReadOnlyCollection<Core2ResourceType> ResourceTypes
{
get
{
return ProviderBase.Types.Value;
}
}
public virtual IReadOnlyCollection<TypeScheme> Schema
{
get
{
return ProviderBase.TypeSchema.Value;
}
}
...
}
Apologies if this is not the correct place to raise this.
I have noticed what I think are some minor issues with the Postman tests:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.