Month: September 2024
How to Report the Information Stored in Recoverable Items
This article explains how to use the Microsoft Graph PowerShell SDK to report Recoverable Items in a form that is usable for eDiscovery investigators and other highly-privileged use. The script fetches details of items found in folders like Deletions, Purges, Versions, and SubstrateHolds. Because accessing mailbox data is a sensitive action, consider restricting access to confidential mailboxes using RBAC for applications.
https://office365itpros.com/2024/09/17/report-recoverable-items/
This article explains how to use the Microsoft Graph PowerShell SDK to report Recoverable Items in a form that is usable for eDiscovery investigators and other highly-privileged use. The script fetches details of items found in folders like Deletions, Purges, Versions, and SubstrateHolds. Because accessing mailbox data is a sensitive action, consider restricting access to confidential mailboxes using RBAC for applications.
https://office365itpros.com/2024/09/17/report-recoverable-items/ Read More
How to use two releases of MATLAB (R2017a and R2022b) simultaneously on my laptop?
I had one relaese of MATLAB R2022b installed on my system but it is missing the optimtool. Then I treid to install R2017a, it is not working. Instrad it gives me the license error. Further when I uninstall the 2nd one, then the system gives me the message " Deactivate the license. If you deactivate the license, all releases will not work on this system". How to solve this issue?I had one relaese of MATLAB R2022b installed on my system but it is missing the optimtool. Then I treid to install R2017a, it is not working. Instrad it gives me the license error. Further when I uninstall the 2nd one, then the system gives me the message " Deactivate the license. If you deactivate the license, all releases will not work on this system". How to solve this issue? I had one relaese of MATLAB R2022b installed on my system but it is missing the optimtool. Then I treid to install R2017a, it is not working. Instrad it gives me the license error. Further when I uninstall the 2nd one, then the system gives me the message " Deactivate the license. If you deactivate the license, all releases will not work on this system". How to solve this issue? matlab r2022b, matlab r2017a, two releases of matlab MATLAB Answers — New Questions
how to find LPC feature from speech to recognize human emotions in matlab? Please, can anyone help?
Can anyone provide LPC feature extraction matlab algorithm or code for speech emotion recognition?Can anyone provide LPC feature extraction matlab algorithm or code for speech emotion recognition? Can anyone provide LPC feature extraction matlab algorithm or code for speech emotion recognition? lpc feature MATLAB Answers — New Questions
Filename truncated in MATLAB
I am using a command:
[TestDefinitionFiles,testDefinitionFolder] = uigetfile(‘*.xlsx’,’Select one or more test definitions that you to execute’,’MultiSelect’,’on’);
When I load the excel file (Disabled_to_MoveMotor), I see it in TestDefinitionFiles as
Why is the name truncated or is anything wrong from the user’s side?
Thanks.I am using a command:
[TestDefinitionFiles,testDefinitionFolder] = uigetfile(‘*.xlsx’,’Select one or more test definitions that you to execute’,’MultiSelect’,’on’);
When I load the excel file (Disabled_to_MoveMotor), I see it in TestDefinitionFiles as
Why is the name truncated or is anything wrong from the user’s side?
Thanks. I am using a command:
[TestDefinitionFiles,testDefinitionFolder] = uigetfile(‘*.xlsx’,’Select one or more test definitions that you to execute’,’MultiSelect’,’on’);
When I load the excel file (Disabled_to_MoveMotor), I see it in TestDefinitionFiles as
Why is the name truncated or is anything wrong from the user’s side?
Thanks. excel, matlab MATLAB Answers — New Questions
PowerGUI and Rapid Accelerator: A new block names […] cannot be added
I built an electrical simulation in Simulink using Simscape Specialized Technology with fixed-step simulations. The powergui block is in the main system. When I want to run the simulation in Rapid Accelerator mode, it compiles successfully with MSVC++. At the stage "Connect to Rapid Accelerator Process and Simulate" it outputs:
A new block named ‘MainSimulation/powergui/EquivalentModel19’ cannot be added
How can I get past that and/or further understand the problem?
(The ultimate goal is to deploy this as a Desktop app, so Rapid Accelerator mode is required)I built an electrical simulation in Simulink using Simscape Specialized Technology with fixed-step simulations. The powergui block is in the main system. When I want to run the simulation in Rapid Accelerator mode, it compiles successfully with MSVC++. At the stage "Connect to Rapid Accelerator Process and Simulate" it outputs:
A new block named ‘MainSimulation/powergui/EquivalentModel19’ cannot be added
How can I get past that and/or further understand the problem?
(The ultimate goal is to deploy this as a Desktop app, so Rapid Accelerator mode is required) I built an electrical simulation in Simulink using Simscape Specialized Technology with fixed-step simulations. The powergui block is in the main system. When I want to run the simulation in Rapid Accelerator mode, it compiles successfully with MSVC++. At the stage "Connect to Rapid Accelerator Process and Simulate" it outputs:
A new block named ‘MainSimulation/powergui/EquivalentModel19’ cannot be added
How can I get past that and/or further understand the problem?
(The ultimate goal is to deploy this as a Desktop app, so Rapid Accelerator mode is required) powergui, rapid accelerator MATLAB Answers — New Questions
Share OSU OSA benefits bewtween partners
Hello,
My company is serving a global customer. This customer has separated projects lead be other partners but on the same product Dynamics Finance.
How is it possible to claim for OSU OSA within our project only ?
Thank you.
Pierre-Olivier
Hello, My company is serving a global customer. This customer has separated projects lead be other partners but on the same product Dynamics Finance.How is it possible to claim for OSU OSA within our project only ?Thank you. Pierre-Olivier Read More
Consecutive task
Hi,
I have a task that I want to be performed consecutively, so if there’s a holiday in the middle, the software will postpone the beginning of the task to the next day when it can be performed continuously.
How do I do this?
Hi,I have a task that I want to be performed consecutively, so if there’s a holiday in the middle, the software will postpone the beginning of the task to the next day when it can be performed continuously.How do I do this? Read More
Microsoft Bookings: Allow double bookings of a staff member
Hello community,
I hope someone can help me here, as I was unable to find any answers to this and documentation to Microsoft Bookings feels somewhat barebones.
What I want to achieve:
I want to have a bookings page, where customers can book appointments with one single staff member and I want to have up to three appointments to happen at the same time, all with the same one staff member.
I don’t want to use 1:N or group appointments, because the lack some basic functionality, e.g. they act as a single appointment with three slots and not as three distinct appointments. Because of this, the staff member only gets a single E-Mail for the first booking, but not for the others, that are booked later at the same time slot.
Using dummy users is not a solution for me, as I want all of the bookings to be in the same Outlook calender of the one staff member, because we don’t really use the bookings calender (would be just another tool to log into).
So is there any way to enable a limited number of simultaneous 1:1-bookings for the same staff member?
Thanks!
Hello community, I hope someone can help me here, as I was unable to find any answers to this and documentation to Microsoft Bookings feels somewhat barebones. What I want to achieve:I want to have a bookings page, where customers can book appointments with one single staff member and I want to have up to three appointments to happen at the same time, all with the same one staff member. I don’t want to use 1:N or group appointments, because the lack some basic functionality, e.g. they act as a single appointment with three slots and not as three distinct appointments. Because of this, the staff member only gets a single E-Mail for the first booking, but not for the others, that are booked later at the same time slot. Using dummy users is not a solution for me, as I want all of the bookings to be in the same Outlook calender of the one staff member, because we don’t really use the bookings calender (would be just another tool to log into). So is there any way to enable a limited number of simultaneous 1:1-bookings for the same staff member? Thanks! Read More
Issues with Microsoft Lists
For the past few weeks, our users have been experiencing strange issues with the Microsoft Lists application. It’s possible that more people have encountered these problems and may have a solution. In some cases, clearing the SharePoint cookies helps, but unfortunately, not always.
When entering numbers in a number column, a 0 is automatically added, turning 100 into 1000.A choice column, where additional choices can be added during input, often no longer shows these externally input values in the filter window.When opening a list for the first time, it often fails to display, and the page needs to be refreshed before it becomes visible.
For the past few weeks, our users have been experiencing strange issues with the Microsoft Lists application. It’s possible that more people have encountered these problems and may have a solution. In some cases, clearing the SharePoint cookies helps, but unfortunately, not always.When entering numbers in a number column, a 0 is automatically added, turning 100 into 1000.A choice column, where additional choices can be added during input, often no longer shows these externally input values in the filter window.When opening a list for the first time, it often fails to display, and the page needs to be refreshed before it becomes visible. Read More
How to show a figure in the MATLAB App designer with both X and Y axis from signal in simulink real-time model?
How can we customize the x-axis of the instrumented axes in MATLAB App (with model running on Speedgoat)? I wanted to plot Speed vs Torque (signals from Simulink model) (in the axes) instead of separately plotting them with respect to time.How can we customize the x-axis of the instrumented axes in MATLAB App (with model running on Speedgoat)? I wanted to plot Speed vs Torque (signals from Simulink model) (in the axes) instead of separately plotting them with respect to time. How can we customize the x-axis of the instrumented axes in MATLAB App (with model running on Speedgoat)? I wanted to plot Speed vs Torque (signals from Simulink model) (in the axes) instead of separately plotting them with respect to time. simulink, appdesigner MATLAB Answers — New Questions
Memory efficient alternative for meshgrid?
I am generating a meshgrid to be able to calculate my result fast:
% x, y, z are some large vectors
[a,b,c] = meshgrid(x,y,z);
% s, t are constants, M some matrix
result = (((c*s – b*t).^2)./(a.^2 + b.^2 + c.^2)).*M;
This is actually working quite nicely. Unfortunately, for very large x,y,z, the meshgrid function is running out of memory.
How do I rewrite the meshgrid function to be memory efficient?
I had thought of three loops like this:
result = zeros(length(x), length(y), length(z));
for i = 1:lenght(x)-1
for j = y = 1:lenght(y)-1
for k = z = 1:lenght(z)-1
b = ??
c = ??
result(i,j,k) = (((c*s – b*t).^2)./(x(i)^2 + y(j)^2 + z(k).^2));
end
end
end
result = result.*M;
What are the values for b and c?
How can I turn the outer for into a parfor?I am generating a meshgrid to be able to calculate my result fast:
% x, y, z are some large vectors
[a,b,c] = meshgrid(x,y,z);
% s, t are constants, M some matrix
result = (((c*s – b*t).^2)./(a.^2 + b.^2 + c.^2)).*M;
This is actually working quite nicely. Unfortunately, for very large x,y,z, the meshgrid function is running out of memory.
How do I rewrite the meshgrid function to be memory efficient?
I had thought of three loops like this:
result = zeros(length(x), length(y), length(z));
for i = 1:lenght(x)-1
for j = y = 1:lenght(y)-1
for k = z = 1:lenght(z)-1
b = ??
c = ??
result(i,j,k) = (((c*s – b*t).^2)./(x(i)^2 + y(j)^2 + z(k).^2));
end
end
end
result = result.*M;
What are the values for b and c?
How can I turn the outer for into a parfor? I am generating a meshgrid to be able to calculate my result fast:
% x, y, z are some large vectors
[a,b,c] = meshgrid(x,y,z);
% s, t are constants, M some matrix
result = (((c*s – b*t).^2)./(a.^2 + b.^2 + c.^2)).*M;
This is actually working quite nicely. Unfortunately, for very large x,y,z, the meshgrid function is running out of memory.
How do I rewrite the meshgrid function to be memory efficient?
I had thought of three loops like this:
result = zeros(length(x), length(y), length(z));
for i = 1:lenght(x)-1
for j = y = 1:lenght(y)-1
for k = z = 1:lenght(z)-1
b = ??
c = ??
result(i,j,k) = (((c*s – b*t).^2)./(x(i)^2 + y(j)^2 + z(k).^2));
end
end
end
result = result.*M;
What are the values for b and c?
How can I turn the outer for into a parfor? meshgrid, parfor MATLAB Answers — New Questions
Can I input an array of derivatives to the integrator and obtain an array as output?
I am new to Simulink/Matlab. I have a 2-element array of time-derivatives as input to a Simulink integrator block and I want to get a corresponding array as output. Is this even admissible? If so, how do I specify the dimensions of the inputs and outputs to the integrator block?
I get the following error when I try to build the model.
Error in port widths or dimensions. Invalid dimension has been specified for ‘Input Port 1’ of ‘<foo>/Integrator’. I have seen some people ask similar questions
Thanks.I am new to Simulink/Matlab. I have a 2-element array of time-derivatives as input to a Simulink integrator block and I want to get a corresponding array as output. Is this even admissible? If so, how do I specify the dimensions of the inputs and outputs to the integrator block?
I get the following error when I try to build the model.
Error in port widths or dimensions. Invalid dimension has been specified for ‘Input Port 1’ of ‘<foo>/Integrator’. I have seen some people ask similar questions
Thanks. I am new to Simulink/Matlab. I have a 2-element array of time-derivatives as input to a Simulink integrator block and I want to get a corresponding array as output. Is this even admissible? If so, how do I specify the dimensions of the inputs and outputs to the integrator block?
I get the following error when I try to build the model.
Error in port widths or dimensions. Invalid dimension has been specified for ‘Input Port 1’ of ‘<foo>/Integrator’. I have seen some people ask similar questions
Thanks. array input to integrator MATLAB Answers — New Questions
Integral and inverse integral
Hi,
I would like to calculate the probability of failure using the convolution therom as described in this paper https://www.researchgate.net/publication/314278481_Reliability_Index_for_Non-normal_Distribution_of_Limit_State_Functions
First I wanted to write the code using examples of this paper (Please look at the attached screenshots). Unfortunately, I didn’t get the same results. I found a probabilty of failure Pf=3.82 10^-08 instead of 5.55 10^-02.
In addition, I am struggling to write the inverse function to derive the reliabilty index. I always leads to errors?
Can anyone explain the mistake?
Sigma= 1;
Mu=5;
PDF_Norm=@(x) exp(-0.5.*((x-Mu)/Sigma).^2)/(Sigma*sqrt(2*pi));
a=2;
b=1;
Gamma=@(x) x.^(a-1).*exp(-x/b)/((b^a).*gamma(a));
FUN=@(x) PDF_Norm(x).*Gamma(-x);
Pf=integral(@(x) FUN(x),-Inf,0);
sym x
Beta=finverse(F,x);Hi,
I would like to calculate the probability of failure using the convolution therom as described in this paper https://www.researchgate.net/publication/314278481_Reliability_Index_for_Non-normal_Distribution_of_Limit_State_Functions
First I wanted to write the code using examples of this paper (Please look at the attached screenshots). Unfortunately, I didn’t get the same results. I found a probabilty of failure Pf=3.82 10^-08 instead of 5.55 10^-02.
In addition, I am struggling to write the inverse function to derive the reliabilty index. I always leads to errors?
Can anyone explain the mistake?
Sigma= 1;
Mu=5;
PDF_Norm=@(x) exp(-0.5.*((x-Mu)/Sigma).^2)/(Sigma*sqrt(2*pi));
a=2;
b=1;
Gamma=@(x) x.^(a-1).*exp(-x/b)/((b^a).*gamma(a));
FUN=@(x) PDF_Norm(x).*Gamma(-x);
Pf=integral(@(x) FUN(x),-Inf,0);
sym x
Beta=finverse(F,x); Hi,
I would like to calculate the probability of failure using the convolution therom as described in this paper https://www.researchgate.net/publication/314278481_Reliability_Index_for_Non-normal_Distribution_of_Limit_State_Functions
First I wanted to write the code using examples of this paper (Please look at the attached screenshots). Unfortunately, I didn’t get the same results. I found a probabilty of failure Pf=3.82 10^-08 instead of 5.55 10^-02.
In addition, I am struggling to write the inverse function to derive the reliabilty index. I always leads to errors?
Can anyone explain the mistake?
Sigma= 1;
Mu=5;
PDF_Norm=@(x) exp(-0.5.*((x-Mu)/Sigma).^2)/(Sigma*sqrt(2*pi));
a=2;
b=1;
Gamma=@(x) x.^(a-1).*exp(-x/b)/((b^a).*gamma(a));
FUN=@(x) PDF_Norm(x).*Gamma(-x);
Pf=integral(@(x) FUN(x),-Inf,0);
sym x
Beta=finverse(F,x); integral, convolution MATLAB Answers — New Questions
Bug in saving .fig (but not .png or .pdf) from when specifiying YAxis.Exponent as -6
In my livescript (MATLAB R2023b), I programatically save some of my plots via saveas(). I’m currently saving as a .pdf, a .png, and a .fig.
When I first specify that that the plot should have a YAxis exponent of -6 (it defaults to -5), my plots look as expected in the produced/displayed MATLAB .fig, and in the saved .pdf and .png. BUT…when I open the saved .fig, it shows an exponent of 10^2147483647. Not 10^-6 as everything else does.
I’ve been able to reproduce this in a .m file as well, so it doesn’t seem to be related to the .mlx.
This is how I’m saving the plots:
set(gcf, ‘visible’, ‘on’); % have to do this bc livescripts sets off, but then the figs open as invisible later
saveas(gcf,plotFullFilename,’fig’)
saveas(gcf,plotFullFilename,’png’)
exportgraphics(gcf,allPlotsFilename,’append’,true)
This is how I set the exponent:
axA.YAxis.Exponent = -6;
axB.YAxis.Exponent = -6;
If I comment out the exponent code and let it default to a yaxis exponent to -5, then the .fig saves with an exponent of -5.
But I don’t want a y-axis exponent of -5. I want it in engineering notation, e.g. an exponent of -6. This looks like a bug to me. Any ideas?In my livescript (MATLAB R2023b), I programatically save some of my plots via saveas(). I’m currently saving as a .pdf, a .png, and a .fig.
When I first specify that that the plot should have a YAxis exponent of -6 (it defaults to -5), my plots look as expected in the produced/displayed MATLAB .fig, and in the saved .pdf and .png. BUT…when I open the saved .fig, it shows an exponent of 10^2147483647. Not 10^-6 as everything else does.
I’ve been able to reproduce this in a .m file as well, so it doesn’t seem to be related to the .mlx.
This is how I’m saving the plots:
set(gcf, ‘visible’, ‘on’); % have to do this bc livescripts sets off, but then the figs open as invisible later
saveas(gcf,plotFullFilename,’fig’)
saveas(gcf,plotFullFilename,’png’)
exportgraphics(gcf,allPlotsFilename,’append’,true)
This is how I set the exponent:
axA.YAxis.Exponent = -6;
axB.YAxis.Exponent = -6;
If I comment out the exponent code and let it default to a yaxis exponent to -5, then the .fig saves with an exponent of -5.
But I don’t want a y-axis exponent of -5. I want it in engineering notation, e.g. an exponent of -6. This looks like a bug to me. Any ideas? In my livescript (MATLAB R2023b), I programatically save some of my plots via saveas(). I’m currently saving as a .pdf, a .png, and a .fig.
When I first specify that that the plot should have a YAxis exponent of -6 (it defaults to -5), my plots look as expected in the produced/displayed MATLAB .fig, and in the saved .pdf and .png. BUT…when I open the saved .fig, it shows an exponent of 10^2147483647. Not 10^-6 as everything else does.
I’ve been able to reproduce this in a .m file as well, so it doesn’t seem to be related to the .mlx.
This is how I’m saving the plots:
set(gcf, ‘visible’, ‘on’); % have to do this bc livescripts sets off, but then the figs open as invisible later
saveas(gcf,plotFullFilename,’fig’)
saveas(gcf,plotFullFilename,’png’)
exportgraphics(gcf,allPlotsFilename,’append’,true)
This is how I set the exponent:
axA.YAxis.Exponent = -6;
axB.YAxis.Exponent = -6;
If I comment out the exponent code and let it default to a yaxis exponent to -5, then the .fig saves with an exponent of -5.
But I don’t want a y-axis exponent of -5. I want it in engineering notation, e.g. an exponent of -6. This looks like a bug to me. Any ideas? saveas, save figure, livescript, bug, exponent MATLAB Answers — New Questions
Formula (VBA generated) fills the entire column of selected cell
Hello everyone
I’m currently experiencing an issue with my Excel (365). The code is supposed to insert a formula into a cell when I double-click it, but it fills the entire column of the selected cell with the formula.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim r As Integer
If Not Intersect(Target, Me.Range(“F3:R65”)) Is Nothing And IsEmpty(Target.Value) Then
r = Target.Row
Target.Formula = “=IF($C” & r & “>$D” & r & “,$D” & r & “+1-$C” & r & “,$D” & r & “-$C” & r & “)”
Cancel = True
End If
End Sub
Before:
After (Double-clicked cell I15):
Hello everyoneI’m currently experiencing an issue with my Excel (365). The code is supposed to insert a formula into a cell when I double-click it, but it fills the entire column of the selected cell with the formula. Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim r As Integer
If Not Intersect(Target, Me.Range(“F3:R65”)) Is Nothing And IsEmpty(Target.Value) Then
r = Target.Row
Target.Formula = “=IF($C” & r & “>$D” & r & “,$D” & r & “+1-$C” & r & “,$D” & r & “-$C” & r & “)”
Cancel = True
End If
End Sub Before:After (Double-clicked cell I15): Read More
Sqlserver- Not Null Cases
Hi,
Please help me on below requirement.
In my table, we have 5 columns, and ID is the key column.
And I need a logic like
1. If Reason1 is null & Reason2 is not null then New_Txt
2. If Reason1 is not null and Reason2 is not null then Old_txt
If Reason2 is not null and Reason1 is Not null then New_Txt
( It have to generate 2 diff rows)
Base Table:
IDR1R2Old_txtNew_txt11200 PRO0003AB11200P03Q08GD11200Q08Q09HE
Required OutPut Like :
IDR1R2Old_TxtNew_Txt11200NullP03 B11200P03Q08G 11200P03Q08 D11200Q08Q09H 11200Q08Q09 E
Hi, Please help me on below requirement.In my table, we have 5 columns, and ID is the key column.And I need a logic like1. If Reason1 is null & Reason2 is not null then New_Txt2. If Reason1 is not null and Reason2 is not null then Old_txt If Reason2 is not null and Reason1 is Not null then New_Txt ( It have to generate 2 diff rows)Base Table:IDR1R2Old_txtNew_txt11200 PRO0003AB11200P03Q08GD11200Q08Q09HE Required OutPut Like : IDR1R2Old_TxtNew_Txt11200NullP03 B11200P03Q08G 11200P03Q08 D11200Q08Q09H 11200Q08Q09 E Read More
Access Projects through Planner
Hello,
since the new Planner update in Teams I can see projects of groups that I’m not even part of. Where is the accessibility to Projects controlled?
Thanks
Timo Schuldt
Hello, since the new Planner update in Teams I can see projects of groups that I’m not even part of. Where is the accessibility to Projects controlled? ThanksTimo Schuldt Read More
Building Retrieval Augmented Generation on VSCode & AI Toolkit
Retrieval Augmented Generation (RAG) on VS Code AI Toolkit:
AI toolkit allows users to quickly deploy models locally or in the cloud, test and integrate them via a user-friendly playground or REST API, fine-tune models for specific requirements, and deploy AI-powered features either in the cloud or embedded within device applications.
In the previous blogs, we learnt how to get started with AI Toolkit by installing and creating basic application. Please refer to the blogs for detailed insights and updates if this is your first time using the VS Code AI Toolkit.
Visual Studio Code AI Toolkit: Run LLMs locally
Visual Studio AI Toolkit: Building GenAI Applications
Retrieval Augmented Generation (RAG):
LLMs are trained on a specific dataset from various domains. When you want to work with LLMs, there might be information that is specific to your dataset or domain which the LLMs doesn’t have enough knowledge about. Generated language might also need to be referenced based on the domain and use case. RAG is used for these use cases to increase the applicability to specific domains and datasets. e.g. The LLM might know about legal services in general but if you want to reference specific statutes in US Law and get references to them then RAG might be a good approach to do this. A similar approach can be applied for any other country specific laws as well.
Retrieval-Augmented Generation (RAG) is a hybrid approach in natural language processing (NLP) that combines two key elements: retrieval of relevant information from external data sources and generation of text based on this retrieved information.
Retrieval: These models retrieve relevant text from a large repository of documents when generating responses or completing tasks. They excel at providing factual and specific information. A better retrieval mechanism leads to a more accurate and relevant response.
Instead of relying solely on learned patterns and data, RAG incorporates a retrieval step. This involves searching or retrieving specific relevant snippets from a large database of documents related to the input query or task. RAG improves the accuracy and relevancy of the response based on the domain specific document repository.
Generation: These models generate responses from scratch based on learned patterns and data that they are being trained on. They can create fluent and contextually appropriate text but may struggle with accuracy and factual correctness when dealing with specific queries. e.g. if we ask the model for current dollar rate, then the language model can only generate the response based on the data that it is trained on and it is likely to be inaccurate. The information contained in the model is based on the documents it is trained on and for current events such as news and currency prices which are dynamic, it will be accurate only until the training date cutoff. So, connecting it to a reliable source then allows us to extend the model to get it from the right source. Similarly, in-case the model answers from its pretrained data, it may not be able to quote the reference for the data. This can be limiting in certain cases if user doesn’t know the source of the answer. With RAG the source can be referenced as the answer is generated.
Some Applications:
Question Answering: RAG can excel in tasks where precise answers backed by evidence are required, such as in open-domain question answering systems.
Content Creation: It can also be used to generate content that is both informative and accurate, leveraging retrieved knowledge to enhance the generation process.
Summarization: RAG can also be used to create both abstractive and extractive summaries. Extractive summaries identify the important sentences from the document(s) and generate a summary based on their relative importance. Abstractive summaries identify the most important ideas and content and synthesize them in their own words.
In this series, lets create a basic RAG application.
Let’s discuss the architecture in two parts, first part would be creation of database and second is retrieval.
Creation of Database
We will use a PDF file that will be used for RAG implementation. We will first extract text from the PDF file and then convert that into smaller pieces of documents, which are often referred as ‘chunks ‘and the process of doing so is known as ‘chunking’. This process helps the language model to extract the right document without exceeding the context limit. Chunk overlap and chunk size must be balanced well for a getting good results.
Once we have document chunks, we will next proceed to convert them into embeddings. Embeddings are a foundational concept in NLP. Embeddings enable machines to understand and process human language more effectively by representing words or phrases as vectors in a continuous space where semantic relationships are encoded.
How Embeddings Work?
Vector Representation: Each word or phrase is represented as a vector of real numbers. For example, in a 300-dimensional embedding space, each word might be represented by a vector with 300 numerical values.
Semantic Similarity: Words with similar meanings are represented by vectors that are closer together in the embedding space. For instance, vectors for “dog” and “cat” would be closer than vectors for “dog” and “car”.
Learned from Data: Embeddings are learned from large amounts of textual data using techniques like Word2Vec, GloVe (Global Vectors for Word Representation), or through neural network-based approaches such as Transformer models.
Applications: Embeddings are widely used in NLP tasks such as sentiment analysis, machine translation, text classification, and more. They allow models to generalize better to data they have not seen before and capture intricate relationships between words.
Once we have the embeddings, we store these in a unique database called as vector database.
Vector Databases
Vector databases are specialized for storing and retrieving vector data efficiently, making them an essential component in applications that rely on similarity-based search and analysis of high-dimensional data vectors. ChromaDB, is such an AI-native open-source vector database which will be used in this tutorial. For learning more about ChromaDB, Click here.
We will be utilizing ChromaDB from the Langchain framework in this tutorial.
Setting up a virtual environment (venv) is highly recommended while following this blog. Python is a prerequisite, if not installed please install the latest version of python on the machine. For detailed steps click here. Once the environment is setup, ChromaDB needs to be installed using the python package installer “pip”.
In the VSCode terminal type the following command,
pip install chromadb
We will also utilize LangChain, a widely used OS framework for developing GenAI applications. Langchain is an Opensource Framework which is used as an orchestrator to build customizable AI applications especially those application which use LLMs/SLMs . Langchain provides tools and abstractions that make it easier to customize, control, and integrate LLMs into applications.
The following are some of the major components of Langchain.
Prompts: Prompts are the text instructions or questions that you provide to the LLM. Well-crafted prompts are crucial for getting accurate and relevant responses from the LLM. LangChain provides templates to structure prompts and make them more reusable.
LLMs: Large Language models (LLMs) like GPT-4o, LLaMA, and others are pre-trained models with vast knowledge and capabilities. LangChain seamlessly integrates with popular LLM providers. You can also use your own custom-trained models.
Chains: Chains are responsible for orchestrating the flow of data and interactions between different components.
Types of Chains:
Sequential Chains: Execute components in a linear order.
Parallel Chains: Execute components concurrently.
Conditional Chains: Execute components based on certain conditions.
Generative Chains: Generate text or other outputs.
Custom Chains: You can create your own custom chains to suit specific use cases
Callbacks:
Monitoring and Logging: Callbacks provide a way to track the progress of your application and log important events.
Customizations: You can implement custom callbacks to perform actions like sending notifications or storing data.
Indexes:
Document Retrieval: Indexes are used to store and retrieve documents that can be used as context for LLMs.
Vector Databases: LangChain supports various vector databases for efficient document retrieval.
Agents:
Autonomous Actions: Agents are capable of taking actions based on the information they gather from the environment.
Decision-Making: Agents use LLMs to make decisions and complete tasks.
Memory:
Context Preservation: Memory allows LLMs to maintain context and remember information from previous interactions.
Types of Memory:
Conversation Memory: Stores the history of a conversation.
Document Memory: Stores information from documents.
Episodic Memory: Stores information about past events.
Tools:
External Integration: Tools enable LLMs to interact with external resources like search engines, calculators, or APIs.
Expanding Capabilities: Tools can enhance the functionality of your applications.
By effectively combining these components, you can create a wide range of applications, including chatbots, question-answering systems, text summarization tools, and more.
To install, type the following command,
pip install langchain
LangChain Community contains third-party integrations that implement the base interfaces defined in LangChain Core, making them ready-to-use in any LangChain application.
Type the following command in VSCode terminal to install the Langchain community,
pip install langchain-community
Let’s now begin by importing the required libraries into our coding editor. It is recommended to use a notebook file (.ipynb) for this part. Head to Visual Studio code, and then create a new file, name is as dbmaker.ipynb, we must be having a notebook file now, Select the Kernel to the virtual environment that we have created earlier or use the python version installed on the local machine.
Now import the following libraries,
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.document_loaders import DirectoryLoader,PyMuPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
It is quite important to understand the use of the above statements, so let’s look at these one by one,
Chroma:
Module: langchain_community.vectorstores
Purpose: Chroma is a vector store that allows you to store and retrieve high-dimensional vectors. It is used to store embeddings of documents or text and retrieve them based on similarity searches.
Usage: Typically used in applications that require efficient similarity searches, such as document retrieval or question-answering systems.
HuggingFaceEmbeddings:
Module: langchain_community.embeddings
Purpose: HuggingFaceEmbeddings provides a way to generate embeddings using models from the Hugging Face library. These embeddings are numerical representations of text that capture semantic meaning.
Usage: Used to convert text into embeddings that can be stored in a vector store like Chroma for similarity searches.
DirectoryLoader:
Module: langchain_community.document_loaders
Purpose: DirectoryLoader is used to load documents from a specified directory. It can handle various file types and is useful for batch processing of documents.
Usage: Commonly used to load a large number of documents from a directory for further processing, such as embedding generation or text splitting.
PyMuPDFLoader:
Module: langchain_community.document_loaders
Purpose: PyMuPDFLoader is a specialized document loader that uses the PyMuPDF library to load and process PDF documents.
Usage: Used to extract text from PDF files, which can then be processed further, such as generating embeddings or splitting text.
RecursiveCharacterTextSplitter:
Module: langchain.text_splitter
Purpose: RecursiveCharacterTextSplitter is used to split text into smaller chunks based on character count. It recursively splits text to ensure that chunks are of manageable size while preserving semantic meaning.
Usage: Useful in scenarios where large documents need to be broken down into smaller, more manageable pieces for processing, such as embedding generation or indexing.
Once we have done these imports successfully, it’s time now to specify the directory of the documents and also to specify the embedding model.
#Directory of the PDF Files
dir = ‘docs/’
# OS Embedding model from Huggingface
embeddings = HuggingFaceEmbeddings(model_name=’all-MiniLM-L6-v2′)
This line defines a variable ‘dir’ that holds the path to a directory containing PDF files. This directory path will be used later to load and process the PDF files stored in this location.
The model that will be used in this tutorial is all-MiniLM-L6-v2, which is a pre-trained model from Hugging Face.
The embeddings object will be used to convert text into numerical embeddings. These embeddings capture the semantic meaning of the text and can be used for various tasks such as similarity searches, clustering, or feeding into other machine learning models.
It’s now time to load the documents from the library, so let’s create a function to achieve this,
#Loading the documents
def load_docs(dir):
loader=DirectoryLoader(dir,loader_cls=PyMuPDFLoader,use_multithreading=True,max_concurrency=128,show_progress=True,silent_errors=True)
documents=loader.load()
return documents
Now let’s step through the code and explain what we are doing here,
The load_docs function is designed to load documents from the specified directory. It uses the DirectoryLoader class to handle the loading process, with specific configurations to optimize performance and handle unforeseen errors gracefully.
The load_docs function is designed to accept one Parameter that is the directory. The directory path where the PDF files are located.
Initialize DirectoryLoader:
dir: The directory containing the PDF files.
loader_cls=PyMuPDFLoader: Specifies that the PyMuPDFLoader class should be used to load the PDF files. This loader is specialized for handling PDF documents.
use_multithreading=True: Enables multithreading to speed up the loading process.
max_concurrency=128: Sets the maximum number of concurrent threads to 128. This allows for parallel processing of multiple files.
show_progress=True: Displays a progress bar to indicate the loading progress.
silent_errors=True: Suppresses error messages, allowing the loading process to continue even if some files fail to load.
Load Documents:
documents = loader.load(): Calls the load method of the DirectoryLoader instance to load the documents from the specified directory.
Return Documents:
return documents: Returns the loaded documents.
This function will be now used while we create chunks, throughout this tutorial we will be following functional paradigm in order to use them efficiently wherever needed.
To create chunks, lets now design a function.
#Splitting the documents into chunks
def split_docs(documents,chunk_size=1000,chunk_overlap=100):
text_splitter=RecursiveCharacterTextSplitter(chunk_size=chunk_size,chunk_overlap=chunk_overlap)
docs=text_splitter.split_documents(documents)
return docs
The split_docs function is designed to split a list of documents into smaller chunks. This is useful for processing large documents in manageable pieces, especially for tasks like embedding generation or indexing. This helps a lot especially while there is a need to send limited context to the model when there is a token limit.
Parameters of split_docs:
documents: A list of documents to be split. Each document is typically a string or a structured object containing text.
chunk_size (default 1000): The maximum number of characters in each chunk.
chunk_overlap (default 100): The number of characters that overlap between consecutive chunks. This helps to maintain context across chunks.
The chunk size and chunk overlap needs to be tweaked according to the use case, but for this tutorial we are keeping it to a default standard value.
Steps
Initialize RecursiveCharacterTextSplitter:
chunk_size=chunk_size: Sets the maximum size of each chunk.
chunk_overlap=chunk_overlap: Sets the number of overlapping characters between chunks.
The RecursiveCharacterTextSplitter is designed to split text into chunks while preserving semantic meaning as much as possible.
Split Documents:
docs = text_splitter.split_documents(documents): Calls the split_documents method of the text_splitter instance to split the input documents into smaller chunks.
Return Chunks:
return docs: Returns the list of document chunks.
We have now completed the task of designing functions that will further help us in performing the tasks that we intend to do inorder to create a vector database.
Its time to utilise the functions and create the vector database,
documents=load_docs(dir)
len(documents)
doc=split_docs(documents)
print(len(doc))
Let’s call the load_docs function with the directory path, to load the documents from the specified directory. The loaded documents are stored in the documents variable. Then, to check the length of the documents, we can use the len() function.
Now call the split_docs function with the loaded documents to split them into smaller chunks. The resulting chunks are stored in the doc variable. The length of the doc list is printed, indicating how many chunks were created from the original documents.
As we have the chunked embeddings ready, its now time to store these into a vector database. As we have already discussed we will be using the ChromaDB in this tutorial.
save_to=Chroma.from_documents(documents=doc,embedding=embeddings,persist_directory=’./ai-toolkit’)
The above line of code initializes a Chroma vector store from a list of document chunks and their corresponding embeddings. The vector store is then saved to a specified directory for persistence.
Parameters
documents=doc: The list of document chunks that were created by the split_docs function.
embedding=embeddings: The embedding model used to generate embeddings for the document chunks. This is an instance of HuggingFaceEmbeddings.
persist_directory=’./ai-toolkit’: The directory where the vector store will be saved. This allows the vector store to be persisted and loaded later.
Our database is now ready and we can ask a sample search query to this. Although we haven’t still configured the small language model to this, but we can still try to see how the retriever works, so let’s ask a sample query,
query=”What is Fine tuning”
We have defined our query, now its time to search it in our newly created ‘ai-toolkit’ named vector database. In order to do this, we will need to take the following steps,
Initialize a Chroma vector store by loading it from the specified directory.
Perform a similarity search on the vector store using the provided query.
Print the entire list of search results to the console.
Print the content of the first document or chunk in the search results.
The code is as follows,
db1=Chroma(persist_directory=’./ai-toolkit’,embedding_function=embeddings)
results=db1.similarity_search(query)
print(results)
print(results[0].page_content)
Upon successful execution, now there will be some results appearing in the output cell.
In this article we have learned the concepts about RAG and created embedding successfully. In the next part of this article, we will take look at how we can use RAG with these embeddings in ChromaDB to get better results using AI toolkit for VSCode and Phi-3 Model downloaded locally
Meanwhile you can take a look at the following resources about RAG and AI Toolkit
AI Toolkit for VSCode Documentation
AI Toolkit for Visual Studio Code (Github)
RAG in AI studio (Concepts)
RAG in AI Search
Phi-3 Cookbook
Microsoft Tech Community – Latest Blogs –Read More
DocAider: Automated Documentation Maintenance for Open-source GitHub Repositories
Project Overview
Comprehensive documentation is crucial for end users in open-source software projects, but manual creation and maintenance are time-consuming and costly. Traditional documentation generators like Pydoc rely on predefined rules and in-line code information. However, emerging generative AI techniques, particularly Large Language Models (LLMs), offer new possibilities for enhanced documentation generation. Developed in partnership with Microsoft and UCL, DocAider aims to create an AI-powered documentation tool that automatically generates and updates code documentation. The tool leverages Github Actions workflows to trigger documentation tasks upon pull requests (PRs) opening, providing valuable insights into continuous documentation maintenance. This approach addresses the challenges of automating documentation and ensures that project documentation remains current with minimal human intervention. This project aims to leverage LLM technologies, combined with Microsoft Semantic Kernel, Microsoft Autogen, and Azure AI Studio, to mitigate the burden of maintaining up-to-date documentation.
This system uses a multi-agent architecture where multiple agents work together to complete the task. It offers two innovative features: a recursive update mechanism, which ensures that changes ripple throughout all related documentation, and continuous monitoring and updating code via pull requests.
DocAider offers a promising solution for software engineers, with the potential to automatically maintain clean and up-to-date documentation. It allows developers to concentrate more on coding while simplifying the onboarding process for new team members. Additionally, it helps reduce costs and boosts overall efficiency.
Project Journey
This project was completed over 3 months. The few weeks, the team focused on the requirements engineering portion of the project, where we set functional and non-functional requirements, created context and architecture diagrams and broke the project down with the stakeholders, so that it was easy for us to implement in the following months, making sure we included the most important features and requirements. This process also allowed the team to see how much is realistically achievable, and what should be kept as optional if time allowed us to complete.
During implementation, our team employed agile methodologies, Git practices, and continuous integration and testing. We chose agile as our development approach because it facilitated constant communication between the team and stakeholders. This strategy proved crucial to our product’s success. Bi-weekly meetings with stakeholders allowed us to report progress, plan upcoming tasks and clarify the requirements. Additionally, we held weekly internal meetings for team members to showcase their work and assess overall progress.
Technical Details
DocAider is an LLM-powered tool that generates and updates documentation automatically. It performs the documentation tasks using a customised GitHub Actions workflow and runs in the background. We developed DocAider by integrating Semantic Kernel and AutoGen. The tools facilitate the development of AI-based software. Furthermore, we deployed and managed Azure OpenAI LLMs on Azure AI Studio. To obtain good results, we used the GPT-4-0125-preview model to create documentation for the source code. The temperature parameter was set between 0 and 0.2 for more deterministic and factual LLM responses.
Documentation Generation
AutoGen provides multiple conversation patterns to orchestrate AI agents, such as sequential chats, group chats, nested chats, etc. We used the sequential chats to create documentation. The figure shows our multi-agent architecture, which reduces LLM hallucinations in two ways: appropriate code context information and self-improvement. Four agents perform different tasks in sequence and an agent manager controls the multi-agent conversation.
Code Context Agent creates a graph representation of the entire repository, mapping the relationships between function calls. It then generates comprehensive information about the codebase using the actual source code and the relationship graph.
Documentation Generation Agent produces baseline documentation taking into account the contextual information passed from the previous agent. The documentation contains three basic sections: overview, class/function/method descriptions and input/output examples.
Review Agent assesses the baseline documentation, and suggests the improvements.
Revise Agent modifies the baseline documentation according to the suggestions and returns the improved documentation to Agent Manager.
Agent Manager controls the conversation process and responds to function calling requests from LLM-configured agents.
By using Semantic Kernel, we built skilled agents for performing specific tasks. AutoGen facilitates agent interactions to complete complex workflows. The LLM function calling capability helps to reduce programming efforts and makes agents flexible. An agent can autonomously execute external functions defined in the associated plugins to complete a variety of tasks.
Documentation Update
To maintain consistency and accuracy across all related documentation when a class/function in a file is changed, the Documentation Update feature performs the update recursively. If a class/function is modified, the system will automatically update the documentation for all dependent files. This includes documentation of the source file, as well as documentation of files that use functions dependent on the changed class/function. This recursive update feature ensures that all related documentation remains up–to–date with the latest changes in the code.
Additionally, Documentation update on PR Comment allows reviewers to trigger the documentation updates on specified files by commenting in a specific format. The reviewer can specify which file needs an update and provide instructions on what changes should be made. The system will then process this comment and update the documentation as instructed. This feature ensures that precise and targeted documentation updates can be made based on reviewer feedback, improving the overall quality and relevance of the documentation. Furthermore, it removes the need for developers to manually change documentation according to reviewers’ comments. The comment triggering this process needs to be in this format:
“Documentation {file_path}: {comment}”. For example, “Documentation main.py: Add more I/O examples”.
Results and Outcome
Our evaluation process involved three stages: a case study executing our system on a well–known repository to showcase our system, a comparison of our system against RepoAgent, and a quantitative analysis. Through this process, we could determine our system’s performance.
Case Study:
The section presents results from applying our tool to generate and update documentation for the Graphviz repository’s Python files. The system produced well-structured documentation, including overviews, global variables, function/class descriptions, and I/O examples, providing clear explanations of file purposes and usage guidelines. When updates were made to the base.py file, adding logging functionality and a new method, the system successfully incorporated these changes while preserving existing content. The system also demonstrated its ability to handle recursive updates, propagating changes from the ParameterBase class in base.py to dependent files like engine.py. Additionally, it responded effectively to a PR comment, requesting more input/output examples, showcasing its capacity to incorporate reviewer feedback. Overall, the multi-agent system proved capable of generating, updating, and maintaining comprehensive documentation across all files in a software repository.
Comparison with RepoAgent
We compared DocAider, a multi-agent documentation system, with RepoAgent, another LLM-based documentation generation tool. While RepoAgent produces lengthy paragraphs, DocAider generates concise, bullet-pointed documentation, aligning with developers’ preferences for brevity. DocAider’s multi-agent approach potentially enhances accuracy and reduces hallucinations compared to RepoAgent’s single-agent system. DocAider also implements a Reviewer and Revisor agent to suggest and apply improvements. A notable feature of DocAider is its HTML-based front-end interface, which improves documentation accessibility and organization – factors highly valued by developers.
While our system is well-designed and offers unique features like recursive updates, RepoAgent stands out by providing thorough I/O examples for every function. However, LLMs can make incorrect assumptions as function complexity increases, leading to factual inaccuracies or nonsensical outputs. To mitigate this, we restrict the LLM from making such assumptions, resulting in some functions/classes lacking I/O examples.
Quantitive Analysis
We conducted a quantitative analysis of DocAider’s performance across six popular GitHub repositories: collarama, fake-useragent, graphiz, photon, progress, and pywhat. These repositories were selected based on their popularity (over 1000 stars each) and size (small to medium, limited to 20 files per repository). All of them varied in the number of functions and classes. Scores are normalised between 0 and 1, reflecting the presence of these attributes in the documentation. For instance, a score of 1 for Function/Class Description indicates that every class and function in the repository is described in the documentation, while a score of 0.5 for I/O examples means that only half of the functions have I/O examples provided in the documentation.
DocAider achieved perfect scores (1.0) for function/class descriptions across all repositories, demonstrating consistent performance. For parameters/attributes, most repositories received perfect scores, with only collamara scoring slightly lower at 0.94 due to two functions lacking parameter documentation. I/O examples showed the most variation, with scores ranging from 0.54 (photon and progress) to 0.88 (collamara). Lower scores were often due to specific function types without return values (e.g., class init methods) or complex logic that made example generation challenging. Return value documentation was consistently strong, with all repositories scoring 1.0.
Overall, DocAider is proficient in many areas, such as generating function/class descriptions and handling most documentation aspects. However, there is room for improvement in consistently documenting I/O examples, particularly for functions with more complex logic.
Lessons Learned
The development of DocAider provided valuable insights across several key areas. Firstly, the adoption of a multi-agent approach proved crucial in managing system’s complexity. Initially, a single-agent design led to issues such as hallucinations and incomplete documentation. By transitioning to a multi-agent architecture, the team was able to distribute tasks across specialized agents, each handling specific aspects of the documentation process. This approach significantly improved the accuracy and reliability of the documentation while also enhancing system scalability. The success of this strategy highlighted the importance of modular design and task specialization in complex AI-driven systems. Secondly, prompt engineering emerged as a critical and unexpectedly challenging aspect of the project. The quality of generated documentation was heavily dependent on the prompts given to the Large Language Models (LLMs). Initial struggles with overly broad or contextually lacking prompts led to irrelevant or inaccurate outputs. Through iterative testing and refinement, the team developed more precise and context-aware prompts, significantly improving documentation quality. This experience underscored the complexity and importance of effective prompt engineering in applications requiring high accuracy and relevance. Lastly, the team learned the critical importance of managing dependency versions. An incident where a new version of Semantic Kernel (1.3.0) caused the software to crash in Docker due to API changes highlighted the need for version consistency across development and deployment environments. This experience emphasized the importance of carefully managing and aligning dependency versions to ensure system stability and functionality.
Team Contributions
Jakupov Dias (Team Leader): Team management, Stakeholder communication, development of Documentation Update, Recursive Update, Update on PR comment, prompt engineering.
Chengqi Ke: development of Retrieval Augmented Generation and multi-agent communication using Semantic Kernel and AutoGen.
Fatima Hussain: development of GitHub workflows, evaluation of DocAider’s performance and effectiveness.
Tanmay Thaware: development of Retrieval Augmented Generation, evaluation of DocAider’s performance.
Tomas Kopunec: development of Abstract Syntax Tree, Recursive Update and HTML front-end .
Zena Wang: development of GitHub workflows and handled deployment, packaging the tool into a Docker image.
Future Work
Conclusion
DocAider successfully automated the creation and upkeep of accurate, up-to-date documentation, significantly reducing the manual workload for developers. By leveraging AI tools like Microsoft AutoGen, Semantic Kernel, and Azure AI Studio, the project addressed key challenges in maintaining consistent, real-time documentation.
While budget constraints, missing I/O examples, and the limitations of LLMs posed challenges, the project established a solid foundation for future improvements. Beyond solving the immediate need for documentation management, DocAider raised the bar for efficiency and accuracy in software development, showcasing the potential of AI-driven solutions for more advanced applications.
Call To Action
We invite you to explore DocAider further and consider how its innovative approach to documentation maintenance can be applied in your projects. Here are some steps you can take and explore the tools we used:
Connect with Us: Feel free to reach out to our team for more information or collaboration opportunities.
AutoGen: https://www.microsoft.com/en-us/research/project/autogen/
Semantic Kernel: https://learn.microsoft.com/en-us/semantic-kernel/overview/?tabs=Csharp
Special Thanks to Contributors
Each contributor’s continuous support and involvement all plays a crucial role in the success of the project, here, we present a special thanks to all following contributors.
Lee Stott, Principal Cloud Advocate Manager at Microsoft
Diego Colombo, Principal Software Engineer at Microsoft
Jens Krinke, Senior Lecturer and Academic Supervisor
Team
The team involved in developing this project included 6 members. All of us are Masters students at UCL studying Software Systems Engineering
Dias Jakupov – Team Leader – Full Stack Developer
GitHub URL: https://github.com/Dias2406/
LinkedIn URL: https://www.linkedin.com/in/dias-jakupov-a05258221/
Chengqi Ke – Full Stack Developer
GitHub URL: https://github.com/CQ-Ke/
LinkedIn URL: http://linkedin.com/in/chengqi-ke-9b91a8313/
Tomas Kopunec – Full Stack Developer
GitHub URL: https://github.com/TomasKopunec/
LinkedIn URL: https://www.linkedin.com/in/tomas-kopunec-425b0199/
Fatima Hussain – Full Stack Developer
GitHub URL: https://github.com/fatimahuss/
LinkedIn URL: http://linkedin.com/in/fatima-noor-hussain/
Tanmay Thaware – Full Stack Developer
GitHub URL: https://github.com/tanmaythaware/
LinkedIn URL: http://linkedin.com/in/tanmaythaware/
Zena Wang – Full Stack Developer
GitHub URL: https://github.com/ZenaWangqwq/
LinkedIn URL: https://www.linkedin.com/in/zena-wang-b63a8822b/
Microsoft Tech Community – Latest Blogs –Read More