tamhinsf / channelsurf Goto Github PK
View Code? Open in Web Editor NEWMove from Slack to Microsoft Teams and manage your Teams environment
Move from Slack to Microsoft Teams and manage your Teams environment
I'm at the last step of the process and can't get over this hump! We've successfully logged in, selected the team to have the .zip file associated with, but this path error comes up.
Any assistance as to why the given path's format is not supported would be great! I am not an administrator or programmer so please do be gentle!
Unhandled Exception: System.NotSupportedException: The given path's format is not supported.
at System.IO.Path.GetFullPath(String path)
at System.IO.Compression.ZipFileExtensions.ExtractToDirectory(ZipArchive source, String destinationDirectoryName)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName)
at ChannelSurfCli.Utils.Files.DecompressSlackArchiveFile(String zipFilePath, String tempPath) in C:\Users\xxxxx\ChannelSurf-master\ChannelSurfCli\Utils\Files.cs:line 26
at ChannelSurfCli.Program.Main(String[] args) in C:\Users\xxxxx\ChannelSurf-master\ChannelSurfCli\Program.cs:line 135
AFAIK, ms teams now does support private teams. Can this tool support that?
Good day,
This is hardly the best way to do this but I needed to get it to work quickly, it turns this message:
<@SD578SDSS> joined the channel
into this:
@Steven_User Joined the channel
Call From code:
static List<Models.Combined.AttachmentsMapping> GetAndUploadMessages(Models.Combined.ChannelsMapping channelsMapping, string basePath,
List<ViewModels.SimpleUser> slackUserList, String aadAccessToken, String selectedTeamId,
bool copyFileAttachments)
{
.
.
.
var messageTs = (string)obj.SelectToken("ts");
var messageText = (string)obj.SelectToken("text");if (messageText.IndexOf("<@") > -1)
{
messageText = ReplaceQuotedUsersInMessage(messageText, slackUserList);
}
.
.
.
}
Procedure:
static string ReplaceQuotedUsersInMessage(string MessageText, List<ViewModels.SimpleUser> slackUserList)
{for (int i = 0; i < slackUserList.Count; i++)
{
if (MessageText.IndexOf("<@") > -1)
{
MessageText = MessageText.Replace(string.Concat("<@", slackUserList[i].userId, ">"), string.Concat("@", slackUserList[i].real_name.Replace(" ","_")));
}
else
{
break;
}
}return MessageText;
}
I'm able to login and successfully create channels, but I seem to be missing a permissions setting as I'm getting an error - Folder creation failure: Microsoft.Graph.ServiceException: Code: accessDenied
Here is a way to convert timestamps into pretty datetimes:
if (messageTs != null)
{
System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
dateTime = dateTime.AddSeconds(Convert.ToDouble(messageTs));
dateTime = dateTime.ToLocalTime();
messageTs = Convert.ToString(dateTime);
}
Let's get started! Sign in to Microsoft with your Teams credentials:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ***** to authenticate.
You've successfully signed in. Welcome ********
C:\Users\jdoe\source\repos\ChannelSurf\ChannelSurfCli>
This is where I am stuck in the command prompt.
The instructions says "Select the target Microsoft Team you want to create or re-create your channels into. You can also choose to create a new Microsoft Team."
Where do I select the target team??? Am I missing something obvious?
I also tried to write a (HipChat to) Teams migration utility (https://github.com/Lombiq/HipChat-to-Microsoft-Teams-Migration-Utility) but I couldn't get attachments working. Apparently this is not possible via the API, despite it appearing as being working: https://techcommunity.microsoft.com/t5/Microsoft-Teams/Graph-API-Issues-while-creating-new-chat-thread/m-p/242558
Do posting file attachments to Teams messages still work for you?
Thank you!
While running the script to migrate existing channels, I'm getting this error. This is a duplicate of #24 which has been closed prematurely without a solution in place
Let's get started! Sign in to Microsoft with your Teams credentials: To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXX to authenticate. You've successfully signed in. Welcome [email protected] Groups
----- <snip> -------
You're currently a member of these Teams
WARNING: If you don't have permission to create new channels for a given Team, your attempt to create or migrate channels will fail
[0] XXXXX
[1] XXXXXX
[2] XXXXXX
Enter the destination Team number or type "new" to create a new Team: 1
Team ID is XXXX
Creating temp directory for Slack archive decompression
Temp path is C:\Users\name\AppData\Local\Temp\tmp123C.tmp
Slack archive decompression done
Scanning channels.json
Scanning channels.json - done
Creating channels in MS Teams
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at ChannelSurfCli.Utils.Channels.CreateChannelsInMsTeams(String aadAccessToken, String teamId, List`1 slackChannels, String basePath) in C:\Users\name\path\ChannelSurf\ChannelSurfCli\Utils\Channels.cs:line 90
at ChannelSurfCli.Program.Main(String[] args) in C:\Users\name\path\ChannelSurf\ChannelSurfCli\Program.cs:line 144
Originally posted by @haxplorer in #24 (comment)
Good day,
First off thank you very much for this it helped my tremendously.
I found a small mistake in your code in the procedure: static void CreateSlackMessageHtmlArchiveFile the write to HTML was taking the first 250 lines every time instead of being incremented with messageIndexPosition.
Also the HTML file being produced did not have any CR LF in the file causing it to become unmanageable "wide".
StringBuilder fileBody =new StringBuilder();
fileBody.Append("");
for (int i = messageIndexPosition; i < messageIndexPosition + numOfMessagesToTake; i++)
{
var messageAsHtml = MessageToHtml(messageList[i], channelsMapping);
fileBody.AppendLine(messageAsHtml);
}
fileBody.AppendLine("");
messageIndexPosition += numOfMessagesToTake;
w.WriteLine(fileBody);
Hi, I'm getting an error: Object reference not set to an instance of an object. See detailed error below. Can you tell me what I would need to change in order to fix this error? Thank you!
Let's get started! Sign in to Microsoft with your Teams credentials:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.
You've successfully signed in. Welcome [email protected]
Groups {"@odata.context":"https://graph.microsoft.com/beta/$metadata#teams","@odata.count":3,"value":[{"id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","displayName":"XXXXXXXX","description":"XXXXXXXX","internalId":null,"classification":null,"specialization":null,"visibility":null,"webUrl":null,"isArchived":false,"memberSettings":null,"guestSettings":null,"messagingSettings":null,"funSettings":null,"discoverySettings":null},{"id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","displayName":"XXXXXXX","description":"XXXXXXX","internalId":null,"classification":null,"specialization":null,"visibility":null,"webUrl":null,"isArchived":false,"memberSettings":null,"guestSettings":null,"messagingSettings":null,"funSettings":null,"discoverySettings":null},{"id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","displayName":"XXXXXXXXX","description":"XXXXXXXXXX","internalId":null,"classification":null,"specialization":null,"visibility":null,"webUrl":null,"isArchived":false,"memberSettings":null,"guestSettings":null,"messagingSettings":null,"funSettings":null,"discoverySettings":null}]}
You're currently a member of these Teams
WARNING: If you don't have permission to create new channels for a given Team, your attempt to create or migrate channels will fail
[0] XXXXXXXX XXXXXXXX
[1] XXXXXXXX XXXXXXXX
[2] XXXXXXXX XXXXXXXX
Enter the destination Team number or type "new" to create a new Team: 0
Team ID is xxxxxxxxxxxxxxxxxxxx
Creating temp directory for Slack archive decompression
Temp path is C:\Users\abc\AppData\Local\Temp\tmpABF9.tmp
Slack archive decompression done
Scanning channels.json
Scanning channels.json - done
Creating channels in MS Teams
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at ChannelSurfCli.Utils.Channels.CreateChannelsInMsTeams(String aadAccessToken, String teamId, List`1 slackChannels, String basePath) in C:\Users\abc\Desktop\ChannelSurf-master\ChannelSurfCli\Utils\Channels.cs:line 90
at ChannelSurfCli.Program.Main(String[] args) in C:\Users\abc\Desktop\ChannelSurf-master\ChannelSurfCli\Program.cs:line 144
C:\Users\abc\Desktop\ChannelSurf-master\ChannelSurfCli>
File C:\Users\Joern\AppData\Local\Temp\tmp10D3.tmp\dummy_31_mechanik\2018-07-02.json
Unhandled Exception: System.AggregateException: One or more errors occurred. (Code: UnknownError
Inner error
) ---> Microsoft.Graph.ServiceException: Code: UnknownError
Inner error
at Microsoft.Graph.HttpProvider.d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Graph.BaseRequest.d__36.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Graph.BaseRequest.d__321.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()
at ChannelSurfCli.Utils.FileAttachments.d__3.MoveNext() in C:\work\meisterwerk\channelsurf\ChannelSurfCli\Utils\FileAttachments.cs:line 122
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at ChannelSurfCli.Utils.Messages.CreateSlackMessageJsonArchiveFile(String basePath, ChannelsMapping channelsMapping, List1 messageList, String aadAccessToken, String selectedTeamId) in C:\work\meisterwerk\channelsurf\ChannelSurfCli\Utils\Messages.cs:line 234 at ChannelSurfCli.Utils.Messages.GetAndUploadMessages(ChannelsMapping channelsMapping, String basePath, List
1 slackUserList, String aadAccessToken, String selectedTeamId, Boolean copyFileAttachments) in C:\work\meisterwerk\channelsurf\ChannelSurfCli\Utils\Messages.cs:line 201
at ChannelSurfCli.Utils.Messages.ScanMessagesByChannel(List1 channelsMapping, String basePath, List
1 slackUserList, String aadAccessToken, String selectedTeamId, Boolean copyFileAttachments) in C:\work\meisterwerk\channelsurf\ChannelSurfCli\Utils\Messages.cs:line 19
at ChannelSurfCli.Program.Main(String[] args) in C:\work\meisterwerk\channelsurf\ChannelSurfCli\Program.cs:line 168
Content of the JSON in question is:
[
{
"type": "message",
"user": "A4U3A01V",
"text": "Greg, Martin, did you receive the package in he mail today? Is it the „Full Assembly“?",
"client_msg_id": "A425C095-4FE7-4D5E-8D62-A12D0BF39E35",
"ts": "1530557117.000091"
}
]
I've carefully followed the instructions on https://github.com/tamhinsf/ChannelSurf, at least as far as combining the JSON exports from "dailies" to full channels (successful) and attempting to convert those to HTML (not successful). I've run into a problem with the links to pasted images and attached files.
Neither of those things are transferred to the HTML. Avatar pictures are included, but images pasted into messages and attached files are simply dropped. If anyone is interested, I can copy the relevant code snippets here. Any suggestions?
Hi Team,
I have installed required .net framework and trying to configure the teams through CMD a explained under "Using" section - however
I am running through below error - can you please help?
Let's get started! Sign in to Microsoft with your Teams credentials:
Unhandled Exception: System.ArgumentException: 'authority' should be in Uri format
Parameter name: authority
at Microsoft.IdentityModel.Clients.ActiveDirectory.Authenticator.DetectAuthorityType(String authority)
at Microsoft.IdentityModel.Clients.ActiveDirectory.Authenticator..ctor(String authority, Boolean validateAuthority)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext..ctor(String authority)
at ChannelSurfCli.Program.UserLogin()
Thanks,
Tom
Hi,
I successfully build the the project but i can't run it in debug mode. It is probably related to my Visual studio installation.
I've VS 2017 Community 15.8.2 and i've installed .NET Core SDK,
The error i get is :
Le programme '[13724] dotnet.exe' s'est arrêté avec le code -2147450730 (0x80008096).
The program ... stopped with the code ...
I am surprised that I can't find the exe itself after I build, can somebody share the .exe file ?
Thank you,
You'll need to rewrite history to get rid of this..
can you use this tool to migrate conversations between Teams channels?
Readme.md says 'Copy Slack file attachments into Teams', but this hasn't worked.
It's brought all the channels and messages over in html files beautifully, but no images.
Any ideas what I might have missed?
Thanks.
One or more errors occurred. (AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Please advise.
I am stuck on issue that is already reported here and seen no response activity since 2020 https://github.com/tamhinsf/ChannelSurf/issues/25 .
My question is is this worth troubleshooting further, or is this dead end?
kgoudped MINGW64 /c/chef-repo/cookbooks/ChannelSurf/ChannelSurfCli (master)
$ dotnet run ./hbm.zip
Welcome to Channel Surf!
This tool makes it easy to bulk create channels in an existing Microsoft Team.
All we need a Slack Team export ZIP file whose channels you wish to re-create.
Or, you can define new channels in a file called channels.json.
Tenant is xxxxxxxxxxxxxxxxxxxxx
Application ID is xxxxxxxxxxxx
Redirect URI is https://channelsurf-cli
Your tenant admin consent URL is https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token&client_id=xxxxxxxxxxxxxxxxxx
efd9fd543013&redirect_uri=https://channelsurf-cli&prompt=admin_consent&nonce=xxxxxxxxxx
Let's get started! Sign in to Microsoft with your Teams credentials:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ES7M4EZE5 to authenticate.
You've successfully signed in. Welcome [email protected]
Groups {"@odata.context":"https://graph.microsoft.com/beta/$metadata#groups","value":[{"id":"d8af8e22-5850-4360-a07f-6a68a91e8c1d","displayName":"Slack Migration","description":"Slack Migration","isArchived":false},{"id":"27f33ef8-bcde-470d-913d-ec4255df9459","displayName":"DevOps","description":"Testing DevOps team access","isArchived":false},{"id":"5cc4cf1a-86b9-4401-96f0-975e4419e292","displayName":"Slack Migration Team Leads","description":"Slack Migration Team Leads","isArchived":false},{"id":"36a36700-5d24-464c-a2c5-a3ce98ffc1d5","displayName":"fg-devops-team","description":"fg-devops-team","isArchived":false},{"id":"4039224d-71d3-4d62-b5e8-f67bbd42896c","displayName":"import","description":"import","isArchived":false}]}
You're currently a member of these Teams
WARNING: If you don't have permission to create new channels for a given Team, your attempt to create or migrate channels will fail
[0] Slack Migration Slack Migration
[1] DevOps Testing DevOps team access
[2] Slack Migration Team Leads Slack Migration Team Leads
[3] fg-devops-team fg-devops-team
[4] import import
Enter the destination Team number or type "new" to create a new Team: 1
Team ID is xxxxxxxxxxxxxxxxxx
Creating temp directory for Slack archive decompression
Temp path is C:\Users\kgoudped\AppData\Local\Temp\tmp4158.tmp
Slack archive decompression done
Scanning channels.json
Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'C:\Users\kgoudped\AppData\Local\Temp\tmp4158.tmp\channels.json'.
at System.IO.Win32FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, FileStream parent)
at System.IO.Win32FileSystem.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, FileStream parent)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
at ChannelSurfCli.Utils.Channels.ScanSlackChannelsJson(String combinedPath) in C:\chef-repo\cookbooks\ChannelSurf\ChannelSurfCli\Utils\Channels.cs:line 20
at ChannelSurfCli.Program.Main(String[] args) in C:\chef-repo\cookbooks\ChannelSurf\ChannelSurfCli\Program.cs:line 140
The migration process seems to be running mostly smoothly. I only get a few messages about already existing items like:
Folder creation failure: Microsoft.Graph.ServiceException: Code: nameAlreadyExists
Message: The specified item name already exists.
Channel folder exists
This channel already exists in MS Teams: General
Which may be related to the fact that both MS Teams and Slack have the default "General" channel and that I've already done several migration tries now.
I also get a couple of these, which might be related to the same "already existing items" cases, I'm not sure:
Inner error
at Microsoft.Graph.HttpProvider.<SendAsync>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Graph.BaseRequest.<SendRequestAsync>d__36.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Graph.BaseRequest.<SendAsync>d__32`1.MoveNext()
Anyway, it does its thing including Trying to upload file to MS Teams SPo Folder
, Upload of attachment to MS Teams completed
, Migrating messages in channel
, asks me whether to create some HTMLs and ends with
Scanning messages in Slack channels - done
Tasks complete. Press any key to exit
I see that the channels are created.
In the files tab, I see a folder channelsurf
which contains folder messages
, which in turn contains folders html
and json
, which then contains 0.html
and 0.json
respectively. (And some bigger channels may contain also 1.html
and 1.json
etc.)
Those .html
files contain the chat messages.
But the channels themselves do not contain any imported messages. I tried also to log out and back in again. And tried to open Teams in both the web browser and the Teams app, still nothing.
Any ideas?
Could this be related to the users not matcing? As I'm trying this in a test team, where no other users have been added. But it should at least show my own messages, right? How are the users matched?
I'm running into this when loading the project into Visual Studio:
Severity Code Description Project File Line Suppression State
Error MSB4018 The "ResolvePackageAssets" task failed unexpectedly.
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.ThrowHelper.ThrowKeyNotFoundException()
at System.Collections.Generic.Dictionary2.get_Item(TKey key) at Microsoft.NET.Build.Tasks.LockFileExtensions.CollectDependencies(IDictionary
2 libraryLookup, IEnumerable1 dependencies, HashSet
1 exclusionList)
at Microsoft.NET.Build.Tasks.LockFileExtensions.CollectDependencies(IDictionary2 libraryLookup, IEnumerable
1 dependencies, HashSet1 exclusionList) at Microsoft.NET.Build.Tasks.LockFileExtensions.GetPlatformExclusionList(LockFileTarget lockFileTarget, LockFileTargetLibrary platformLibrary, IDictionary
2 libraryLookup)
at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheWriter.ComputePackageExclusions()
at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheWriter..ctor(ResolvePackageAssets task)
at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheReader.CreateReaderFromDisk(ResolvePackageAssets task, Byte[] settingsHash)
at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheReader..ctor(ResolvePackageAssets task)
at Microsoft.NET.Build.Tasks.ResolvePackageAssets.ReadItemGroups()
at Microsoft.NET.Build.Tasks.ResolvePackageAssets.ExecuteCore()
at Microsoft.NET.Build.Tasks.TaskBase.Execute()
at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at Microsoft.Build.BackEnd.TaskBuilder.d__26.MoveNext() ChannelSurfCli C:\Program Files\dotnet\sdk\7.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets 266
Any advice appreciated
All channels are migrated except the private channels.
Private channels exist in the slack export file but are not being migrated.
I'm not sure what the issue is. Any help?
Enter the destination Team number or type "new" to create a new Team: 5
Team ID is 3b8796bd-1b29-4a57-b166-d7c994f64631
Creating temp directory for Slack archive decompression
Temp path is C:\Users\MYUSERNAME\AppData\Local\Temp\tmpD93A.tmp
Unhandled Exception: System.NotSupportedException: The given path's format is not supported.
at System.IO.Path.GetFullPath(String path)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
at System.IO.Compression.ZipFile.Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName)
at ChannelSurfCli.Utils.Files.DecompressSlackArchiveFile(String zipFilePath, String tempPath) in C:\Temp\ChannelSurfCli\Utils\Files.cs:line 26
at ChannelSurfCli.Program.Main(String[] args) in C:\Temp\ChannelSurfCli\Program.cs:line 135
I imported one rather small channel and I'm looking at the HTML file of messages compilation ChannelSurf created for me. The message order is a mess...
The first message is from the 18th of February which is more than half in the whole discussion history. The messages are displayed successively until 4th of March (which is not the last day of messages), then jumps back to 21st of January. Then, after a few messages, jumps to the 27th of February (and, no, it's not the same thread). Then again, back to the 7th of February, and then back to the 15th of January which, at last, is the actual first messages of the channel history.
And after that, the jumping goes on and on. And it's not explainable by threads. Although, another issue – which would be a new feature request, I guess – is that the threads are not distinguishable visually, in the imported compiled HTML. All the messages are listed in one, plain list.
The content export ZIP from Slack contains the JSON files named by the dates, and they seem sorted correctly. So, there is nothing there for me to fix, it's ChannelSurf that mixes all the dates.
Hi! I followed the exact instructions, and I received this error. Below is the complete error:
Unhandled Exception: System.AggregateException: One or more errors occurred. (AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'. Trace ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Correlation ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Timestamp: 2023-01-21 02:07:21Z) ---> Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'. Trace ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Correlation ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Timestamp: 2023-01-21 02:07:21Z ---> System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized). ---> System.Exception: {"error":"invalid_client","error_description":"AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.\r\nTrace ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\nCorrelation ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\nTimestamp: 2023-01-21 02:07:21Z","error_codes":[7000218],"timestamp":"2023-01-21 02:07:21Z","trace_id":"4f9d1c92-20bf-4ce3-ab3e-388353615e01","correlation_id":"fb10b266-a606-4ee8-a2c3-82875c3a4460","error_uri":"https://login.microsoftonline.com/error?code=7000218"} --- End of inner exception stack trace --- at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpClientWrapper.<GetResponseAsync>d__30.MoveNext() --- End of inner exception stack trace --- at Microsoft.IdentityModel.Clients.ActiveDirectory.AdalHttpClient.<GetResponseAsync>d__21
1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AdalHttpClient.d__201.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<SendHttpMessageAsync>d__67.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<SendTokenRequestAsync>d__64.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenByDeviceCodeHandler.<SendTokenRequestAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<RunAsync>d__55.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.<AcquireTokenByDeviceCodeAsync>d__24.MoveNext() --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task
1.GetResultCore(Boolean waitCompletionNotification)
at ChannelSurfCli.Program.UserLogin() in C:\codes\ChannelSurfCli\Program.cs:line 191
at ChannelSurfCli.Program.Main(String[] args) in C:\codes\ChannelSurfCli\Program.cs:line 108`
I thought it would be nice to import the Slack messages into MS teams as messages, so I developed a bit of (ugly!) code to do so. I stuck this method in messages.cs, and jammed the call to it into CreateSlackMessageHtmlArchiveFile. The best part about these posts as opposed to those from a webhook is that they're searchable. It will churn along happily, posting messages to the appropriate team channel, until it hits the Activity Limit for the API returning
REASON: {
"error": {
"code": "ActivityLimitReached",
"message": "Failed to execute Skype backend request PostMessageRequest.",
"innerError": {
"request-id": "blahblahblah",
"date": "2018-04-30T18:39:45"
}
}
}
As you can see below, I back off new posts exponentially when the activity limit is reached, but, after a while the access token expires and the app needs to be restarted. I tried batching the requests, but I hit the limit sooner that way for some reason. I am currently playing around with increasing the expiration of the access token in Azure Ad, increasing the default expiration from 1 to 23 hours. I think the way to handle this is using the refresh token to get another access token, but this is beyond me so far. I'll keep looking into it. Hope this helps someone, and sorry if I'm just cluttering things up with this issue; I've never posted to github before and am not sure the proper forum for this sort of thing.
CreateSlackMessageHtmlArchiveFile:
for (int i = 0; i < numOfMessagesToTake; i++)
{
var messageAsHtml = MessageToHtml(messageList[messageIndexPosition + i], channelsMapping);
fileBody.AppendLine(messageAsHtml);
rInt = r.Next(100, 1000);
System.Threading.Thread.Sleep(rInt);
string check = postMessage(aadAccessToken, selectedTeamId, channelsMapping.id, messageAsHtml);
}
public static string postMessage(string aadAccessToken, string teamID, string channelID, string bodyContent)
{
int sleeper = 1;
Helpers.httpClient.DefaultRequestHeaders.Clear();
Helpers.httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", aadAccessToken);
Helpers.httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// this might break on some platforms
dynamic messageBody = new JObject();
dynamic newMessage = new JObject();
dynamic rootMessage = new JObject();
messageBody.contentType = 2;
messageBody.content = bodyContent;
rootMessage.body = messageBody;
newMessage.rootMessage = rootMessage;
var createMsGroupPostData = JsonConvert.SerializeObject(newMessage);
var httpResponseMessage =
Helpers.httpClient.PostAsync(O365.MsGraphBetaEndpoint + "groups/" + teamID + "/Channels/" + channelID + "/chatThreads",
new StringContent(createMsGroupPostData, Encoding.UTF8, "application/json")).Result;
Console.WriteLine(httpResponseMessage.ReasonPhrase);
//need to back off the requests if tooManyRequests
while (!httpResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine(httpResponseMessage.ReasonPhrase);
Console.WriteLine("ERROR: Message Not Posted");
Console.WriteLine("REASON: " + httpResponseMessage.Content.ReadAsStringAsync().Result);
JObject j = JObject.Parse(httpResponseMessage.Content.ReadAsStringAsync().Result);
Console.WriteLine(j["error"]["code"].ToString());
if(j["error"]["code"].ToString() == "ActivityLimitReached")
{
}
if (j["error"]["code"].ToString() == "AuthenticationTokenExpired")
{
// need to re-authenticate when token expires - made authenticationcontext public static
//tried to set auth token expiry to 23 hours
//string newToken = Program.authenticationContext.AcquireTokenSilentAsync(O365.MsGraphBetaEndpoint, Program.Configuration["AzureAd:ClientId"]).Result.AccessToken;
//return newToken;
}
Console.WriteLine("Retrying Message Post in " + Convert.ToString(sleeper) + " seconds");
System.Threading.Thread.Sleep(sleeper * 1000);
httpResponseMessage =
Helpers.httpClient.PostAsync(O365.MsGraphBetaEndpoint + "groups/" + teamID + "/Channels/" + channelID + "/chatThreads",
new StringContent(createMsGroupPostData, Encoding.UTF8, "application/json")).Result;
sleeper = sleeper * 2;
}
return "1";
}
int messageBatchSize = 20;
Random r = new Random();
int rInt = r.Next(100, 1000);
dynamic wrapper = new JObject();
JArray requests = new JArray();
//for (int i = 0; i < messageBatchSize; i++)
//{
// var messageAsHtml = MessageToHtml(messageList[messageIndexPosition + i], channelsMapping);
// //hitting activity limit. cannot batch requests added random 100 - 1000 ms delay here, and exponential backoff in postMessage on failure
// requests.Add(buildMessageBatch(i + 1, selectedTeamId, channelsMapping.id, messageAsHtml));
// //
//}
////trying to post a batch of messages - what is the upper limit?
//wrapper.requests = requests;
//rInt = r.Next(100, 500);
//System.Threading.Thread.Sleep(rInt);
//postMessageBatch(aadAccessToken, wrapper);
public static string postMessageBatch(string aadAccessToken, JObject wrapper)
{
int i = 2;
int sleeper = 1;
Helpers.httpClient.DefaultRequestHeaders.Clear();
Helpers.httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", aadAccessToken);
Helpers.httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var createMsGroupPostData = JsonConvert.SerializeObject(wrapper);
//Console.WriteLine(createMsGroupPostData);
var httpResponseMessage =
Helpers.httpClient.PostAsync(O365.MsGraphBetaEndpoint + "$batch",
new StringContent(createMsGroupPostData, Encoding.UTF8, "application/json")).Result;
String content = httpResponseMessage.Content.ReadAsStringAsync().Result;
JObject responseData = JObject.Parse(content);
JArray a = JArray.Parse(content);
string responses = JsonConvert.SerializeObject(responseData);
//var responses = responseData["responses"];
//var response = responses.Children();
//Console.WriteLine(response[0]);
System.Threading.Thread.Sleep(5000);
// batching requests does not throw an error code in this manner. Begin the Whackamole
//need to back off the requests if tooManyRequests
while (!httpResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("ERROR: Message Not Posted");
Console.WriteLine("REASON: " + httpResponseMessage.Content.ReadAsStringAsync().Result);
Console.WriteLine("Retrying Message Post");
System.Threading.Thread.Sleep(sleeper * 1000);
httpResponseMessage =
Helpers.httpClient.PostAsync(O365.MsGraphBetaEndpoint + "$batch",
new StringContent(createMsGroupPostData, Encoding.UTF8, "application/json")).Result;
sleeper = sleeper * 2;
}
return "1";
}
public static JObject buildMessageBatch(int i, string teamID, string channelID, string bodyContent)
{
// this might break on some platforms
dynamic messageBody = new JObject();
dynamic newMessage = new JObject();
dynamic rootMessage = new JObject();
dynamic request = new JObject();
dynamic dependsOn = new JArray();
dynamic headers = new JObject();
dynamic requestBody = new JObject();
messageBody.contentType = 2;
messageBody.content = bodyContent;
rootMessage.body = messageBody;
requestBody.rootMessage = rootMessage;
headers["Content-Type"] = "application/json";
request.headers = headers;
request.body = requestBody;
request.id = Convert.ToString(i);
if (i != 1)
{
dependsOn.Add(Convert.ToString(i - 1));
request.dependsOn = dependsOn;
}
request.method = "POST";
request.url = "/groups/" + teamID + "/Channels/" + channelID + "/chatThreads";
///requests.Add(request);
//wrapper.requests = requests;
//var createMsGroupPostData = JsonConvert.SerializeObject(wrapper);
//Console.WriteLine(createMsGroupPostData);
return request;
}
Hi,
Really hoping someone might be able to help me out with this one.
I'm very new to this kind of thing. But i was at the final stage and have received this.
C:\Users\Cassidy's PC\Desktop\ChannelSurf-master\ChannelSurfCli>dotnet run dotnet run C:\Users\Cassidy's PC\Desktop\Virtual Dream Slack export Feb 10 2018 - Feb 26 2019.zip
Welcome to Channel Surf!
This tool makes it easy to bulk create channels in an existing Microsoft Team.
All we need a Slack Team export ZIP file whose channels you wish to re-create.
Or, you can define new channels in a file called channels.json.
Tenant is virtualdreaming.onmicrosoft.com
Application ID is 4c7fcc93-2bff-4171-8673-33c7fa041bb4
Redirect URI is https://channelsurf-cli
Your tenant admin consent URL is https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token&client_id=4c7fcc93-2bff-4171-8673-33c7fa041bb4&redirect_uri=https://channelsurf-cli&prompt=admin_consent&nonce=f4a8cab6-a8a9-4688-8238-6cf87bc3cbc8
Let's get started! Sign in to Microsoft with your Teams credentials:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ************ to authenticate.
You've successfully signed in. Welcome [email protected]
Groups {"@odata.context":"https://graph.microsoft.com/beta/$metadata#groups","value":[{"id":"f59eb0c4-0744-4ea8-aded-f2ad197a39fa","displayName":"Virtual Dream","description":"Virtual Reality and 360 Production Services","isArchived":false}]}
You're currently a member of these Teams
WARNING: If you don't have permission to create new channels for a given Team, your attempt to create or migrate channels will fail
[0] Virtual Dream Virtual Reality and 360 Production Services
Enter the destination Team number or type "new" to create a new Team: 0
Team ID is f59eb0c4-0744-4ea8-aded-f2ad197a39fa
Creating temp directory for Slack archive decompression
Temp path is C:\Users\Cassidy's PC\AppData\Local\Temp\tmp6C32.tmp
Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'C:\Users\Cassidy's PC\Desktop\ChannelSurf-master\ChannelSurfCli\dotnet'.
at System.IO.Win32FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, FileStream parent)
at System.IO.Win32FileSystem.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, FileStream parent)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
at System.IO.Compression.ZipFile.Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName)
at ChannelSurfCli.Utils.Files.DecompressSlackArchiveFile(String zipFilePath, String tempPath) in C:\Users\Cassidy's PC\Desktop\ChannelSurf-master\ChannelSurfCli\Utils\Files.cs:line 26
at ChannelSurfCli.Program.Main(String[] args) in C:\Users\Cassidy's PC\Desktop\ChannelSurf-master\ChannelSurfCli\Program.cs:line 135
C:\Users\Cassidy's PC\Desktop\ChannelSurf-master\ChannelSurfCli>
Hi,
Microsoft changed the App Registrations.
ChannelSurfCLI is a "legacy" application which is no longer supported.
I receive the answer "403" forbidden when launching it after successful login.
When I recreate the app registration in the new registrations, the request body is missing either "client_assertion" or "client_secret"
I can create a client secret in the app, but adding this value to appsettings.json it doesn't change anything.
Could anyone please help?
I've run into a problem with this tool. I am able to run the program and connect to my azure tenant. However, when it gets to line 121's in program.cs it uses' Environment.Exit variable which im assuming is due to having a blank selectedTeamID.
I am wondering where i might have gone wrong to miss this variable.
I've run both commands
Both lead to the same result.
i am able to complete the below instructions
However, i do not see a way to complete the following
I also stuck on this step. I already cleared for all step following manual but I have no idea what should I do after this to import my export slack data to Team.
Hi Guys, I am stuck at the place right after the authentication. I can successfully sign in in the command prompt. like below
“Let's get started! Sign in to Microsoft with your Teams credentials:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code *** to authenticate.
You've successfully signed in. Welcome ***”
Then nothing happens afterwards...
Any idea why?
The thing I am suspecting now is the permission to "read/write all groups". To get that permission, it needs grant by the admin of the organization...how do you guys get that...
I appreciate your help.
Originally posted by @mengyuw-github in #16 (comment)
Once the Slack messages are imported as HTML files inside the files tab of teams is there any way to display the messages rather than having them simply downloaded?
When I first ran the ChannelSurfCli with my Slack Export, I received the following error:
$ dotnet run aquaexport.zip
It was not possible to find any compatible framework version
The specified framework 'Microsoft.NETCore.App', version '1.1.2' was not found.
- The following frameworks were found:
3.0.0 at [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
You can resolve the problem by installing the specified framework and/or SDK.
The .NET Core frameworks can be found at:
- https://aka.ms/dotnet-download
I was able to fix this by downloading and installing the .NET Core 1.0.5 & 1.1.2 SDK 1.0.4 file from here.
After this point, I ran the command again, but this time I received the following errors. Any help with this would be greatly appreciated!
****************************************************************************************************
Welcome to Channel Surf!
This tool makes it easy to bulk create channels in an existing Microsoft Team.
All we need a Slack Team export ZIP file whose channels you wish to re-create.
Or, you can define new channels in a file called channels.json.
****************************************************************************************************
**************************************************
Tenant is aquahairextensions.onmicrosoft.com
Application ID is b359b3a9-db48-48c7-9d71-990f3c6ac605
Redirect URI is https://channelsurf-cli
**************************************************
****************************************************************************************************
Your tenant admin consent URL is https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token&client_id=b359b3a9-db48-48c7-9d71-990f3c6ac605&redirect_uri=https://channelsurf-cli&prompt=admin_consent&nonce=77e9590f-3fe3-45ca-999b-015aeb7230cb
****************************************************************************************************
****************************************************************************************************
Let's get started! Sign in to Microsoft with your Teams credentials:
Unhandled Exception: System.AggregateException: One or more errors occurred. (The type initializer for 'System.Net.Http.CurlHandler' threw an exception.) ---> System.TypeInitializationException: The type initializer for 'System.Net.Http.CurlHandler' threw an exception. ---> System.TypeInitializationException: The type initializer for 'Http' threw an exception. ---> System.TypeInitializationException: The type initializer for 'HttpInitializer' threw an exception. ---> System.TypeInitializationException: The type initializer for 'CryptoInitializer' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'System.Security.Cryptography.Native.OpenSsl': The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
at Interop.CryptoInitializer.EnsureOpenSslInitialized()
at Interop.CryptoInitializer..cctor()
--- End of inner exception stack trace ---
at Interop.HttpInitializer..cctor()
--- End of inner exception stack trace ---
at Interop.Http..cctor()
--- End of inner exception stack trace ---
at Interop.Http.GetSupportedFeatures()
at System.Net.Http.CurlHandler..cctor()
--- End of inner exception stack trace ---
at System.Net.Http.CurlHandler..ctor()
at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpMessageHandlerFactory.GetMessageHandler(Boolean useDefaultCredentials)
at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpClientWrapper.<GetResponseAsync>d__30.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AdalHttpClient.<GetResponseAsync>d__21`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AdalHttpClient.<GetResponseAsync>d__20`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireDeviceCodeHandler.<RunHandlerAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.<AcquireDeviceCodeAsync>d__23.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.<AcquireDeviceCodeAsync>d__22.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at ChannelSurfCli.Program.UserLogin() in /Users/marketing/Downloads/ChannelSurfCli/Program.cs:line 189
at ChannelSurfCli.Program.Main(String[] args) in /Users/marketing/Downloads/ChannelSurfCli/Program.cs:line 108
I've followed the steps provided through "Using ChannelSurfCli". When I run either command, I get back:
C:\Users\mine\source\repos\ChannelSurf>dotnet run C:\Powershell\Slack\channels.json
Couldn't find a project to run. Ensure a project exists in C:\Users\mine\source\repos\ChannelSurf, or pass the path to the project using --project.
I've double check and my build is successful. I'm not sure what I'm overlooking. I appreciate your help!
Hi,
when I try to start channelsurf, I get the following error message
Unhandled Exception: System.AggregateException: One or more errors occurred. (AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
What did I do wrong?
Many thanks for your help
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.