Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
152038 stories
·
33 followers

Deterministic Voice Forms with Blazor and Local LLMs

1 Share
Deterministic Voice Forms with Blazor and Local LLMs
Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Top 13 Open-Source Automation Tools for 2026

1 Share
Discover 13 open-source automation tools for 2026 to streamline DevOps, cut manual work, and scale secure, reliable infrastructure.
Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

How can you swap two adjacent blocks of memory using only forward iterators?

1 Share

Last time, we noted that the std::rotate function requires only forward iterators. The algorithm we explored last time involved a clever sequence of reversals, but reversals require bidirectional iterators (one to iterator forward from the beginning and another to iterate backward from the end). How do you do it when you can only iterate forward?

Let’s set up the problem again. Suppose we want to swap these two blocks A and B.

A B  
first mid last

We can early-out in the vacuous cases where either the A or B block is empty. For those cases, we can return without doing anything.

We start by swapping the elements at first and mid, then incrementing both pointers and repeating. Here’s what it looks after swapping a handful of items:

B1 A2 A1 B2  
   
  first   mid last

Let’s first take the case where the A block is bigger than the B block. In that case, the entire B block gets swapped to the start of the buffer, and a B-sized chunk of the first part of the A block (let’s call it A1) got swapped to the end of the buffer. There’s still a leftover chunk of the A block, call it A2, that hasn’t moved yet.

B A2 A1  
   
  first   mid
last

Okay, so the B block is in its final position, but the A1 and A2 blocks need to be swapped. Hey, I know how to swap two adjacent blocks: I call std::rotate on myself recursively! Since this is a tail recursive call, I can just move mid back to its original position at the start of the function and restart the algorithm.

B A2 A1  
 
  first mid last
    recursive rotate to swap A1 and A2
B A1 A2  

The other case is where the A block is smaller than the B block.

A B  
first mid last

In this case, we swap until we have used up all of the A elements. The entire A block gets swapped to the middle of the buffer, and an A-sized chunk of the start of the B block (call it B1) goes to the start of the buffer, with the leftover part of B (call it B2) stays at the end of the buffer.

B1 A B2  
 
  first mid last

Again, we can finish with a recursive rotate call, this time to swap A and B2.

B1 A B2  
      recursive rotate to swap A and B2
B1 B2 A  

In both cases, the recursive call is strictly smaller than the original call because we know that both A and B are nonempty: If either was empty, we would have performed a nop early-exit. Therefore, at least one element will be swapped before we reach the recursive call, and we consequently know that the recursion will eventually terminate.

The final case is where the A and B blocks are the same size. In that case, we have swapped all the B elements to the first half and all the A elements to the second half.

B A  
 
  first mid
last

If we are lucky to get here, then we are done!

Note that we don’t need a special case handler for the equal-sized blocks case. We can treat as either the first or second case and let the early-out in the recursive call realize that there is nothing to do.

The number of swaps is n. You can calculate this recursively, since we perform k swaps to move the smaller block, and the recursive call (by induction) performs nk swaps, for a total of n. You can also calculate this directly by observing that at each step, one element gets swapped into its final position (namely, at *first, just before we increment it).

Even though this algorithm and the bidirectional-iterator version both perform n swaps, the bidirectional-iterator version has better locality of reference, so it is preferred if available.

Next time, we’ll apply this to our original problem.

Bonus chatter: You don’t need to do a preliminary std::distance to figure out whether block A or block B is smaller. You can just start swapping elements, and make a note of which happens first: Does first reach the original mid (which means that the A block is smaller) or does mid reach last (which means that the B block is smaller). This “figure it out as you go” doesn’t change the complexity, but it does lower the constant a little bit because you don’t have to iterate through all of the larger block just to realize that it’s took big.

The post How can you swap two adjacent blocks of memory using only forward iterators? appeared first on The Old New Thing.

Read the whole story
alvinashcraft
14 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Create Clutter-Free Layouts with Row and Column Spanning in Blazor DataGrid

1 Share

Create Clutter-Free Layouts with Row and Column Spanning in Blazor DataGrid

TL;DR: Struggling with cluttered grids? Row and column spanning in Blazor DataGrid solves this by merging cells intelligently. Learn how to enable AutoSpan, handle merge/unmerge operations, and apply best practices for performance and usability.

Modern web apps demand clean, readable tables. When the same value repeats across rows or columns, grids can look cluttered and hard to scan. Syncfusion’s Blazor DataGrid solves this with row and column spanning, automatically merging duplicate values into a single cell. The result? A cleaner, more user-friendly table, without extra coding.

This feature has been introduced as part of the Syncfusion® 2025 Volume 4 release, which brings exciting updates across the suite.

In this guide, you’ll learn:

  • What row and column spanning are?
  • How to enable and customize them?
  • How to control spanning programmatically?
  • Key limitations and best practices.

Don’t worry if you’re new to this; everything is explained in a simple, easy-to-understand way.

What are row and column spanning?

Row and Column spanning is enabled by using the AutoSpan property on your SfGrid tag. When adjacent cells share the same value, the grid merges them into a single cell.

The table below lists the available AutoSpanMode options:

Settings Description
AutoSpanMode.None No merging(default).
AutoSpanMode.Row Merges matching cells horizontally in the same row.
AutoSpanMode.Column Merges matching cells vertically in the same column.
AutoSpanMode.HorizontalAndVertical Combines both row and column spans (rows first, then columns).

Here are some example use cases:

  • Row spanning: A TV guide where one show runs across multiple time slots.
  • Column spanning: A work schedule where “Meeting” repeats down consecutive hours.

How to enable row spanning

Row spanning merges identical values across multiple columns in the same row. For example, if Evening News appears twice in a row, the grid combines them into one wider cell.

Here’s how you can do it in code:

@using Syncfusion.Blazor.Grids

<SfGrid DataSource="@TeleCastDataList"
        GridLines="GridLine.Both"
        AutoSpan="AutoSpanMode.Row"
        AllowSelection="false"
        EnableHover="false">
    <GridColumns>
        <GridColumn Field=@nameof(TelecastData.Channel) HeaderText="Channel" Width="200" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(TelecastData.Genre) HeaderText="Genre" Width="120" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(TelecastData.Program12AM) HeaderText="12:00 AM" Width="150"></GridColumn>
        <!-- ... other time slot columns ... -->
    </GridColumns>
</SfGrid>

Note: Try it out with the row spanning demo and refer to the documentation for more insights.

Watch how the feature works in action:

Row spanning in Blazor DataGrid
Row spanning in Blazor DataGrid

How to enable column spanning

Column spanning merges identical values vertically across consecutive rows. For example, lunch might cover multiple hourly slots for one employee.

Code snippet to achieve this:

@using Syncfusion.Blazor.Grids

<SfGrid DataSource="@EmployeeTimeSheet"
        AutoSpan="AutoSpanMode.Column">
    <GridColumns>
        <!-- ... column definitions ... -->
    </GridColumns>
</SfGrid>

Matching entries in a column are displayed in a taller cell, allowing you to see the pattern, as shown below.

Column spanning in Blazor DataGrid
Column spanning in Blazor DataGrid

Note: Try it out with the column spanning demo and refer to the documentation for more information.

Skipping spanning for specific columns

Need spanning everywhere except one column? For example, if you don’t want prime-time TV slots to merge, set the AutoSpan property to AutoSpanMode.None in that column to override the grid settings.

<GridColumn Field=@nameof(TelecastData.Program8PM)
            HeaderText="8:00 PM"
            AutoSpan="AutoSpanMode.None">
</GridColumn>

Note: For more insights, refer to the documentation on disabling row and column spanning.

Merging cells programmatically

Auto spanning is great, but sometimes you need manual control. Syncfusion provides the following methods for custom merging:

Here’s a basic code example with buttons to merge and unmerge single or multiple cells:

@using Syncfusion.Blazor.Grids

<SfButton OnClick="MergeCellsAsync">Merge Cell</SfButton>
<SfButton OnClick="UnMergeCell">UnMerge Cell</SfButton>

<SfButton OnClick="MergeMultipleCellsAsync">Merge Multiple Cells</SfButton>
<SfButton OnClick="UnMergeCells">UnMerge Multiple Cells</SfButton>

<SfButton OnClick="UnMergeAllCells">UnMerge All Cells</SfButton>

<SfGrid @ref="Grid" DataSource="@EmployeeTimeSheet" GridLines="GridLine.Both" AllowSelection="false" EnableHover="false">
    <GridColumns>
        <GridColumn Field=@nameof(EmployeeDetails.EmployeeID) HeaderText="Employee ID" Width="150" TextAlign="TextAlign.Right" IsPrimaryKey="true" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.EmployeeName) HeaderText="Employee Name" Width="180" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_9_00) HeaderText="9:00 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_9_30) HeaderText="9:30 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_10_00) HeaderText="10:00 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_10_30) HeaderText="10:30 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_11_00) HeaderText="11:00 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_11_30) HeaderText="11:30 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_12_00) HeaderText="12:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_12_30) HeaderText="12:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_1_00) HeaderText="1:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_1_30) HeaderText="1:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_2_00) HeaderText="2:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_2_30) HeaderText="2:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_3_00) HeaderText="3:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_3_30) HeaderText="3:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_4_00) HeaderText="4:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_4_30) HeaderText="4:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_5_00) HeaderText="5:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
    </GridColumns>
</SfGrid>
@code
{
    public List<EmployeeDetails>? EmployeeTimeSheet { get; set; }
    public SfGrid<EmployeeDetails>? Grid;

    protected override void OnInitialized()
    {
        EmployeeTimeSheet = EmployeeDetails.GetAllRecords();
    }

    public async Task MergeCellsAsync()
    {
        await Grid.MergeCellsAsync(new MergeCellInfo
        {
            RowIndex = 1,
            ColumnIndex = 5,
            ColumnSpan = 2,
        });
    }

    public async Task UnMergeCell()
    {
        await Grid.UnmergeCellsAsync(new UnmergeCellInfo
        {
            RowIndex = 1,
            ColumnIndex = 5,
        });
    }

    public async Task MergeMultipleCellsAsync()
    {
        await Grid.MergeCellsAsync(new[]
        {
            new MergeCellInfo { RowIndex = 0, ColumnIndex = 2, ColumnSpan = 2 },
            new MergeCellInfo { RowIndex = 5, ColumnIndex = 3, ColumnSpan = 3 },
            new MergeCellInfo { RowIndex = 7, ColumnIndex = 4, ColumnSpan = 2 }
        });
    }

    public async Task UnMergeCells()
    {
        await Grid.UnmergeCellsAsync(new[]
        {
            new UnmergeCellInfo { RowIndex = 0, ColumnIndex = 2 },
            new UnmergeCellInfo { RowIndex = 5, ColumnIndex = 3 },
            new UnmergeCellInfo { RowIndex = 7, ColumnIndex = 4 }
        });
    }

    public async Task UnMergeAllCells()
    {
        await Grid.UnmergeAllAsync();
    }
}

Tips and limitations

Before you implement row and column spanning, it’s important to understand a few constraints and best practices to ensure smooth functionality:

This feature has limitations with:

  • AutoFill (that drag-to-fill feature).
  • Grouping (can’t merge across group headers).
  • Some frozen column setups.
  • Detail templates when doing column spans.

Here are some quick tips to optimize your grid:

  • Use row spanning for timelines or event schedules.
  • Use column spanning for tasks or shifts.
  • Combine with frozen columns for better context.
  • Test with large datasets for performance.

Syncfusion Blazor components can be transformed into stunning and efficient web apps.

Conclusion

Thank you for reading! Row and column spanning in Syncfusion Blazor DataGrid, introduced in the Essential Studio® 2025 Volume 4 release, helps you create cleaner, more readable tables with just a few lines of code. It’s perfect for schedules, lists, or any data with repeats. Try it out in the demos.

Check out our Release Notes and What’s New pages to see the other updates in this release, and leave your feedback in the comments section below. We would love to hear from you.

If you’re a Syncfusion user, you can download the setup from the license and downloads page. Otherwise, you can download a free 30-day trial.

You can also contact us through our support forumsupport portal, or feedback portal for queries. We are always happy to assist you!

Read the whole story
alvinashcraft
18 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

An Introductory Walk-through of the Progress Agentic RAG Dashboard

1 Share

With Progress Agentic RAG, you can index appropriate data to provide an LLM more relevant, accurate information. And you can do this in a no-code interface. Let’s explore the dashboard together!

Large language models (LLMs) can only rely on the data they were trained on. Still, organizations often need AI assistants that can answer questions about specific or internal documentation that isn’t publicly available. Retrieval-augmented generation (RAG) addresses this by fetching relevant documents from a knowledge base and using them to enrich an LLM’s response.

For more information on RAG and how it works, refer to our previous articles on the topic: Understanding RAG (Retrieval-Augmented Generation) and What Are Embeddings?.

Let’s look at how to put this into practice with Progress Agentic RAG. While Agentic RAG is often used as an API-driven platform designed for developers, it also provides a powerful no-code interface. This allows users to create Knowledge Boxes, index data and deploy RAG-enabled search engines without writing a single line of code.

In this article, we’ll use Progress Agentic RAG to index a real document (the Progress Software Q3 2025 Earnings Report) and demonstrate how the platform retrieves accurate, source-cited answers to natural language questions.

Home

When you first log into Progress Agentic RAG, you land on the Home dashboard for a Knowledge Box. A Knowledge Box is a searchable knowledge base, a container for all the documents and data we want to query.

Progress Agentic RAG Knowledge Box

The dashboard provides a quick overview of our Knowledge Box:

  • Storage: Shows the index size, number of resources, text blocks and vectors.
  • Usage: Displays search queries and ask queries over the last 30 days and 12 months.
  • Resources: Lists recently processed files with quick access to view all resources.

The left navigation bar gives us access to the core features: Upload data, Resources list, Synchronize, Search, Widgets and Advanced settings. For this walk-through, we’ll focus on uploading data and searching.

Upload Data

When we click on Upload data in the left navigation bar, we’ll see several options for adding content to our Knowledge Box. These include:

  • File: Upload individual files (PDFs, Word docs, Excel, PowerPoint, text files and more).
  • Folder: Upload an entire folder of documents at once.
  • Links: Add web pages by URL.
  • Text resources: Paste raw text directly.
  • Sitemap: Crawl and index an entire website via its sitemap.
  • Q&A: Add question-answer pairs manually.

Progress Agentic RAG Upload data

For this article, we’ll upload a single PDF: the Progress Software Q3 2025 Earnings Report.

Progress Agentic RAG report

We’re deliberately using a small, very recent source that LLMs are unlikely to have seen, making retrieval clearly observable.

We’ll click on the File upload option and upload our PDF. Once the PDF is uploaded, Progress Agentic RAG will begin the processing to extract the text, chunk it appropriately, generate embeddings, and index everything for semantic search. Once processed, the file will then appear in the Resources list:

Progress Agentic RAG Resources list

With our data indexed, we can now query it. This is where the power of RAG becomes apparent. We aren’t just searching for keywords; we’re asking the AI to read, understand and synthesize answers based only on the document we provided.

Let’s look at three examples using the earnings report we just uploaded.

Query 1. Extracting Specific Financials

First, let’s ask for hard numbers. A standard keyword search might highlight where “revenue” appears, but RAG can construct a complete sentence answering the specific question.

Question: “What was Progress Software’s total revenue for the three months ended August 31, 2025, and what was the year-over-year growth rate?”

Answer: Progress Software’s total revenue for the three months ended August 31, 2025, was $249,795,000, and the year-over-year growth rate was 40%.

Progress Agentic RAG search results

The answer includes numbered citations that link back to specific sections of the source document. Clicking through reveals exactly where in the PDF this information appears:

Progress Agentic RAG highlighted sources

How cool is that! This traceability is critical for enterprise use cases that require verifying the accuracy of AI-generated responses.

Query 2: Understanding Strategic Context

Next, let’s ask a question that isn’t purely numerical and instead requires understanding the CEO’s quote and its intent.

Question: “According to CEO Yogesh Gupta, what product capabilities is Progress investing in and why?”

Answer: According to CEO Yogesh Gupta, Progress is investing in AI capabilities, including agentic RAG technology. This investment aims to empower customers to extract greater value from their data using GenAI.

Progress Agentic RAG search results with semantic understanding

This query demonstrates semantic understanding. The system locates the CEO’s quote within the document and extracts the relevant context about AI capabilities and agentic RAG technology, even though the question doesn’t use those exact terms.

Query 3: Finding Forward-Looking Guidance

Lastly, let’s examine how RAG handles forward-looking financial projections, which are often presented in separate guidance tables.

Question: “What is Progress Software’s updated fiscal year 2025 revenue guidance range?”

Answer: Progress Software’s updated fiscal year 2025 revenue guidance range is $975 million to $981 million.

Progress Agentic RAG search results parsing data

Here, the system synthesizes information from the guidance tables in the report, demonstrating its ability to parse structured financial data and return precise figures.

Wrap-up

In just a few minutes, we went from a raw PDF to a fully searchable, AI-powered knowledge base. Progress Agentic RAG handles the heavy lifting (document processing, chunking, embedding generation and retrieval) so we can focus on asking questions and getting answers.

The no-code interface makes it accessible to anyone, but Progress Agentic RAG also offers a comprehensive API for developers who want to integrate RAG capabilities into their own applications. We’ll explore the API-driven approach more in upcoming articles.

For more details, check out the following resources:

Read the whole story
alvinashcraft
24 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Optimizer Rules I Wish SQL Server Had

1 Share

Optimizer Rules I Wish SQL Server Had


Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 25% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

The post Optimizer Rules I Wish SQL Server Had appeared first on Darling Data.

Read the whole story
alvinashcraft
33 seconds ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories