fubardevelopment / webdavserver Goto Github PK
View Code? Open in Web Editor NEWWebDAV-Server for .NET using ASP.NET Core
Home Page: https://fubardevelopment.github.io/WebDavServer/
License: MIT License
WebDAV-Server for .NET using ASP.NET Core
Home Page: https://fubardevelopment.github.io/WebDavServer/
License: MIT License
I run the sample project in the solution but, even if I insert correct URL (http://localhost:5809/) I cannot be able to mount as network device.
I also try to force Kestrel use or not, to change from DotNet to SQLite... no changes.
I run the solution on Visual Studio Express 2019 on Windows 10.
Thanks
Increases HTTP compatibility
See RFC 7232: HTTP/1.1 Conditional Requests
Applies to:
Hi,
how ca i set /get the correct content type for the files.
Regards,
Michael
The docfx can only be used when the following issues are fixed:
I hesitate to use something like Sphinx, because it's C# support is provided by a third-party tool named sphinx-csharp and it doesn't support extracting the API from the xmldoc (or the source code).
The documentation can be downloaded from Microsoft: MS-WEBDAVE.
The extended error codes are returned using the X-MSDAVEXT_ERROR
header. A description of the header format can be found in the MS-WDV documentation, chapter 2.2.3.
Increases HTTP compatibility
The mount function is working good (Thanks !). I could mount two or more file systems on the same server.
the problem: its not documented. I was found an example on your tests and make it working.
This need to be documented somewhere in google:
fileSystem.Root.Task.ContinueWith(r =>
{
var root = r.Result;
foreach (var fs in _options.Children) // I was added to the configuration, a loop of Children-FileSystems
{
var q = root.GetChildAsync(fs.Key, new System.Threading.CancellationToken());
q.ContinueWith(f =>
{
var mountpoint = q.Result as ICollection ;
fileSystem.Mount(new System.Uri(fs.Key + "/", System.UriKind.Relative), new DotNetFileSystem(fs.Value, mountpoint, fs.Value.RootPath.TrimEnd('\\', '/'), _pathTraversalEngine, _lockManager, _propertyStoreFactory));
});
}
}) ;
Hi, it's me again.
While dealing with LibreOffice locking files which are named like .~lock.am Schlussodt#
I noticed that renaming such a file through WebDAV fails.
After a lot of debugging I discovered, that WebDavContext.ControllerRelativeUrl contains the full URL to the locking-file instead of just the controller URL. And, as you can probably imagine, this has many strange side-effects.
See following screenshots for further explaination of why this happens:
Expected behaviour while renaming heile.txt
:
Broken behaviour while renaming .~lock.am Schlussodt#
:
As you can see, the ending of path
and input
is different due to the escaping of the #
character which results in the remaining
variable containing the full path to the file.
Code:
Do you habe an idea how to fix this behaviour?
King regards,
Marcus
As soon as I start a copy or move action I get following error message:
Cannot consume scoped service 'FubarDev.WebDavServer.IWebDavContext' from singleton 'FubarDev.WebDavServer.Engines.Remote.IRemoteMoveTargetActionsFactory'
.
This seems to happen because the AddWebDav()
extension adds IRemoteMoveTargetActionsFactory
as singleton and IWebDavContext
as scoped service:
DefaultRemoteTargetActionsFactory
consumes the webdav context:Im registering my services as follows:
services.AddSingleton(Configuration);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IPropertyStoreFactory, RedisPropertyStoreFactory>();
services.AddScoped<IFileSystemFactory, VirtualFileSystemFactory>();
services.AddWebDav();
services.AddCors();
services.AddAuthentication(...);
services.AddMvcCore().[...].AddWebDav();
Have I missed something?
Multiple parallel accesses to the same directory might cause concurrent access to the .properties
file. Handle it gracefully by using something like Polly (Github project).
what is it different with nwebdav?
Is it possible to configure the server in such a way that a client must have a direct URL to access a file? I don't want them to be able to see or discover the contents of a collection.
Required for locking support
Applies to:
The current implementation might be overly complex.
If
headerIf
headerIf
header specifiedMaybe we need to increase the reliability by temporarily removing the lock from the clean-up task? Otherwise, the lock might be removed during the operation and a second client might interfer with the first one.
As you probably already know, the current stable version is not usable together with ASP.Net Core 3.0.
I'm talking about this error which appeared after a (necessary) update to 3.0 because of the deprecated empty constructor for XmlSerializerInputFormatter
:
Unhandled exception. System.MissingMethodException: Method not found: 'Void Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter..ctor()'.
at FubarDev.WebDavServer.AspNetCore.Formatters.WebDavXmlSerializerInputFormatter..ctor()
at FubarDev.WebDavServer.AspNetCore.Formatters.Internal.WebDavXmlSerializerMvcOptionsSetup.Configure(MvcOptions options)
at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
at Microsoft.Extensions.DependencyInjection.MvcCoreServiceCollectionExtensions.<>c.<AddMvcCoreServices>b__5_0(IServiceProvider s)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
...
You have already fixed this issue in your release/2.0
branch, which is great:
https://github.com/FubarDevelopment/WebDavServer/blob/release/2.0/src/FubarDev.WebDavServer.AspNetCore/Formatters/WebDavXmlSerializerInputFormatter.cs#L20
But I'm still wondering how to proceed with using this library with 3.0 now. Is your release/2.0
branch stable enough for production usage? Are there any NuGet packages available for it?
In case the release/2.0
branch shouldn't be used yet: What do you think about backporting the most essential fixes (like the above mentioned) to master
and releasing them? This would prevent any application which uses this library from breaking after the 3.0 update.
Hi,
is it possible to return custom live properties to the webdav-client to add additional information to the webdav entry?
After looking in the code, I couldn't find an easy way to do this, but maybe I've missed something.
Kind regards, and thank you for making this awesome library! 😄
Marcus
I think a good improvement would be to allow send a Content-Type: application/json; charset="utf-8"
and Accept: application/json; charset="utf-8"
header. An process request and response as json.
So the webdav server can be used by javascript more easy.
Increases HTTP compatibility
See also: Difference between Content-Range and Range headers?, especially the Answer from btimby.
This requires partial write support for documents.
The race condition might occur in the short time between validating the If
(-style) headers and performing the requested operation.
LOCK
/UNLOCK
(preferred)IEntry
Temporarily lock using the default ILockManager
implementation when the client didn't specify a lock to use.
The code is using the C# Helper method Path.Combine()
in multiple places. For example: https://github.com/FubarDevelopment/WebDavServer/blob/master/src/FubarDev.WebDavServer.FileSystem.DotNet/DotNetDirectory.cs#L101
Do you know that using this method might result in some unwanted behaviours and could cause serious security issues?
Like explained in the remarks of the API documentation (https://msdn.microsoft.com/de-de/library/fyy7a5kt%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) the method call
Path.Combine(@"C:\MyWebDavDir", @"C:\Passwords\VerySecretFile.txt")
will result in "C:\Passwords\VerySecretFile.txt".
Like in some of the methods in the DotNetFileSystem
classes, the second argument of Path.Combine is often user-defined and therefore it might be possible to leave the WebDav root directory and read/write to any file on the system. At least on Windows.
I din't check the full code to make sure this is actually possible, but I'd recommend to replace every call to Path.Combine with one to an own more secure implementation.
And by the way: Many thanks for this awesome library!
Kind regards, Marcus Wichelmann
Hi,
We are facing an issue in our project, when We need to throw and exception during a PutAsync action that is called just after the LockAsync action. However, even when the exception is bubbled up and it is a type not handled by the WebDavExceptionFilter, the consumer or client of the WebDav server does not receives the exception. By the way, the UnlockAsync action is always called, regardless the exception we are throwing.
On the other hand, if the exception is throw during the PutAsync action but before the LockAsync, then the consumer receives the exception.
Can you please tell us how could we propagate the the caller or consumer an exception type thrown from an action just after the lock?
Thank you very much in advance.
Regards,
Rodrigo
Increases HTTP compatibility
See RFC 7232: HTTP/1.1 Conditional Requests
Applies to:
Thanks for good product !
I am trying to make a read-only file system ,based on DotNetFileSystem but with a access list from database.
this code works (the DNFS taking the list of files from SQL, and the files from the disk).
I tried to find the Options
header list, on the source code, found all the HTTP Methods.
I am trying to remove the COPY
, MOVE
, etc, but could not remove them, as they scan for IHandler
without the option to disable it .
For now I was found this (ugly) way, but Windows is trying to update the files or create files like desktop.ini
, and similar.
public async Task<Stream> CreateAsync(CancellationToken cancellationToken) {
throw new ArgumentException("cant write");
}
I tried also to rewrite the AddWebDav
function, but its a ugly workaround.
How to implement a ReadOnly
attr, so the client will recognise the status and will not try to modify/lock the files ?
I'm developing a custom FileSystem implementation for an own virtual filesystem and don't want to support any locking.
Is it possible to completely disable the locking support?
For now I've written following dummy-implementation. But I'm unsure if this will be stable and if there is a much better (and cleaner) way to do that.
Dummy-Implementation:
public class DummyLockManager : ILockManager
{
public int Cost => 0;
public event EventHandler<LockEventArgs> LockAdded;
public event EventHandler<LockEventArgs> LockReleased;
public Task<IEnumerable<IActiveLock>> GetAffectedLocksAsync(string path, bool findChildren, bool findParents, CancellationToken cancellationToken)
=> Task.FromResult(Enumerable.Empty<IActiveLock>());
public Task<IEnumerable<IActiveLock>> GetLocksAsync(CancellationToken cancellationToken)
=> Task.FromResult(Enumerable.Empty<IActiveLock>());
public Task<LockResult> LockAsync(ILock l, CancellationToken cancellationToken)
=> Task.FromResult<LockResult>(null);
public Task<IImplicitLock> LockImplicitAsync(IFileSystem rootFileSystem, IReadOnlyCollection<IfHeaderList> ifHeaderLists, ILock lockRequirements, CancellationToken cancellationToken)
=> Task.FromResult<IImplicitLock>(null);
public Task<LockRefreshResult> RefreshLockAsync(IFileSystem rootFileSystem, IfHeader ifHeader, TimeSpan timeout, CancellationToken cancellationToken)
=> Task.FromResult<LockRefreshResult>(null);
public Task<LockReleaseStatus> ReleaseAsync(string path, Uri stateToken, CancellationToken cancellationToken)
=> Task.FromResult(LockReleaseStatus.Success);
}
Hi,
some clients (for example Linux Mint's file-explorer "Nemo") add the username to the WebDAV-URL like https://[email protected]:8080/...
.
This causes any Copy & Move-Operation to fail with an exception:
FubarDev.WebDavServer.AspNetCore.Filters.WebDavExceptionFilter - The destination server didn't return a response FubarDev.WebDavServer.Engines.Remote.RemoteTargetException: The destination server didn't return a response
at FubarDev.WebDavServer.Engines.Remote.RemoteHttpClientTargetActions.GetAsync(RemoteCollectionTarget collection, String name, CancellationToken cancellationToken)
at FubarDev.WebDavServer.Handlers.Impl.CopyMoveHandlerBase.RemoteExecuteAsync(IRemoteTargetActions handler, Uri sourceUrl, SelectionResult sourceSelectionResult, Uri targetUrl, DepthHeader depth, Boolean overwrite, CancellationToken cancellationToken)
at FubarDev.WebDavServer.Handlers.Impl.CopyMoveHandlerBase.ExecuteAsync(String sourcePath, Uri destination, DepthHeader depth, Boolean overwrite, RecursiveProcessingMode mode, Boolean isMove, CancellationToken cancellationToken)
at FubarDev.WebDavServer.Handlers.Impl.CopyMoveHandlerBase.ExecuteAsync(String sourcePath, Uri destination, DepthHeader depth, Boolean overwrite, RecursiveProcessingMode mode, Boolean isMove, CancellationToken cancellationToken)
Because of FubarDev.WebDavServer.Handlers.Impl.MoveHandler - https://webdav.domain.de:8080/ is not a base of https://[email protected]:8080/Folder/NewFolder
.
Code:
Could you please extend this check to handle corner-cases like that?
I'd also be very helpful if there was a way to disable this check completely when the Remote-Target functionallity is never needed because an URL-Check like this adds some unneccessary development-difficulties when a proxy is used or ports differ.
I get the following error message when using the release/2.0
branch with ASP.Net Core 3.0:
System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Compression.DeflateStream.WriteDeflaterOutput()
at System.IO.Compression.DeflateStream.WriteCore(ReadOnlySpan`1 buffer)
at System.IO.Compression.DeflateStream.Write(Byte[] array, Int32 offset, Int32 count)
at System.IO.Compression.GZipStream.Write(Byte[] array, Int32 offset, Int32 count)
at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionBody.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.Xml.XmlUtf8RawTextWriter.FlushBuffer()
at System.Xml.XmlUtf8RawTextWriter.Flush()
at System.Xml.XmlWellFormedWriter.Flush()
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces)
at FubarDev.WebDavServer.Formatters.WebDavXmlOutputFormatter.Serialize[T](Stream output, T data)
at FubarDev.WebDavServer.WebDavResult`1.ExecuteResultAsync(IWebDavResponse response, CancellationToken ct)
at FubarDev.WebDavServer.AspNetCore.WebDavIndirectResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|27_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
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)
...
Enabling the Kestrel option AllowSynchronousIO
fixes this issue, but that's of course only a temporary solution.
System.IO.FileNotFoundException HResult=0x80070002 Message=Could not load file or assembly '#Project#\bin\Debug\netcoreapp2.2\FubarDev.WebDavServer.XmlSerializers.dll'. The specified file could not be found. Source=<The source of the exception cannot be evaluated> Stack Trace: <Unable to evaluate tracking data>
Some applications have special behavior.
I use angular , I want set api token per Office Request.but I don't know set token when click ms-word:ofe Link and word open!!
Hi!
I'm using the fubar webdav server, with a Custom FIle System but using the InMemoryLock. It works perfectly with all the files except for office. It opens in read only mode, I have checked the headers to make sure the lock is returned in the Options request and Dav 2 header is present in all responses too. Is an known issue or it is something that can be solved somehow?
Thank you for the help you could provide
I am using version 2.0 and, despite the use of user tester, trying to connect through Windows Explorer continues to display the username and password input form. The user's homedir is present, as is the temporary folder "webdav" in the temp of the user with whom the service is running.
Hi,
I try to open a word document from the webdav server.
The first time i can successfully edit the file.
If i open it a second time, i get lock conficts.
In the logs i can see a unlock, when word is closed.
I send the custom header from #18.
Regards,
Michael
The creationdate
property should use the format defined in rfc3339#section-5.6.
Only the getlastmodified
property should use the format defined in rfc2616#section-3.3.1.
Currently, the lock manager always assumes that the paths are always the same for all clients and that the clients differ only in path visibility.
Good afternoon,
We recently notice that when we try to open and build a solution that includes the fubar packages in a machine that doesn't have the packages in cache, it doesn't build and can't find the packages in the configured package source https://www.myget.org/F/webdav-server/api/v3/index.json. Looks like is not there anymore?
Thank you in advance
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method FubarDev.WebDavServer.Sample.AspNetCore.Controllers.WebDavController.GetAsync (FubarDev.WebDavServer.Sample.AspNetCore), returned result FubarDev.WebDavServer.AspNetCore.WebDavIndirectResult in 10.6713ms. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Trace: Action Filter: Before executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Trace: Action Filter: After executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Trace: Before executing action result FubarDev.WebDavServer.AspNetCore.WebDavIndirectResult. Microsoft.AspNetCore.Mvc.StatusCodeResult:Information: Executing HttpStatusCodeResult, setting HTTP status code 200 The program „[17424] dotnet.exe” has exited with code -1073740940 (0xc0000374).
Previously I thought that this is the reason:
#49
but if it is normal behaviour I have no idea what is wrong.
I use Netcore 2.1 on Windows 10. Project run without IIS express.
Is it possible to to register the WebDavExceptionFilter
only for the MVC actions inside the ẀebDavControllerBase
?
In my case, the WebDav server is only a small part of a big application and it's a little bit annoying, that any exception thrown in other MVC actions is also handled by this exception filter and logged multiple times.
Maybe an ExceptionFilterAttribute
would be a good replacement?
As you have foreseen, the behaviour of your path logic is different with ASP.Net Core 3.0: 19f4504
This completely breaks the directory tree now.
Hi, is it possible to get a directory listing when i do a http get on a directory?
It looks like the GetHeadHandler
explicitly forbids this on get.
Regards
Michael
We are saving all our documents in an SQLServer Database Table - in our current app, which is a client application we can use office api to open and edit office documents.
Now we are migrating the client to a ASP.NET MVC Core Webapplication and need also to open and edit Word/Excel documents from the browser.
Is it possible with WebDAVServer to open/stream Word/Excel documents directly from the database and then also save them back to the database (we Need no filesystem and Folders only open the doc from the DB and save them back)?
robert
Hi!
Awesome library!!!
I'm currently referencing your NuGet package for version 1.0.1, and wanted to see something on the code, but I'm unable to find a branch or tag for said version.
Where can I find it?
Thank you in advance.
Regards,
Rodrigo
Hi,
how do i use a custom routing prefix for the webdav server.
If i add it to the controller route (like _dav/{*path}
), the server will not recognise it as baseuri and all change operations will fail with a missing part or locking error.
Regards,
Michael
Hello !
I have an issue when I open a Word file via Chrome
using the command ms-word:ofe|u|http://localhost:5000/Test.docx
. The document open in read-only mode.
Log returns me a HTTP status code 304
If I open the document using the file explorer
, the LOCK file is present and the main Word is in read-write mode.
In attach, you will find logs using Chrome
and file explorer
.
Best regards,
Goulpe
Increases HTTP compatibility
See RFC 7232: HTTP/1.1 Conditional Requests
Applies to:
Increases HTTP compatibility
See RFC 7232: HTTP/1.1 Conditional Requests
Applies to:
Hi,
First of all, thanks for the wonderful project! There is a thing that I couldn't figure out yet:
I implemented an IFileSystem
, IDocument
and so forth. When GET
ting large files I noticed that if the request is aborted by the client, the server keeps reading data using OpenReadAsync
from my subclass of Stream
(the read method keeps being called). The cancellationToken
doesn't seem to be triggered. Can we access HttpContext.RequestAborted
somehow? Or is there another preferred way to react to client-side cancellation of a request?
I tested it by cURL
ing the server (curl http://localhost:5809/_dav/file.dat
) and aborting using CTRL+C.
Thanks!
Hi!
I've tried to override GetHeadHandler and register it in Startup.cs after .AddWebDav(), but my GetHeadHandler isn't calling in debug mode.
Could you give an example, how to override your handlers?
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.