" MicromOne

Pagine

How to Enable Text Selection and Right-Click Using JavaScript

Many websites disable text selection, the context menu, or keyboard shortcuts to prevent accidental copying or to customize the user experience. While these restrictions may serve a purpose, they can also interfere with legitimate activities such as taking notes, using translation tools, or accessing browser features.

This article demonstrates a simple JavaScript snippet that restores standard browser interactions by removing common client-side restrictions.


What This Script Does

The script performs several actions:

  • Re-enables text selection.

  • Restores the browser's right-click context menu.

  • Removes a common popup element if it exists.

  • Removes fixed-position overlays that may block page interaction.

  • Prevents page scripts from intercepting common mouse and clipboard events.

Because the script runs entirely in your browser, it only affects the current page during the current browsing session.


JavaScript Code

(() => {
    // Enable text selection
    const style = document.createElement("style");
    style.textContent = `
        * {
            user-select: text !important;
            -webkit-user-select: text !important;
            -moz-user-select: text !important;
            pointer-events: auto !important;
        }
    `;
    document.head.appendChild(style);

    // Remove popup
    document.querySelector("#notRemoverPopup")?.remove();

    // Remove fixed overlays
    document.querySelectorAll("[style*='z-index'], .modal, .overlay").forEach(el => {
        if (getComputedStyle(el).position === "fixed") {
            el.remove();
        }
    });

    // Restore context menu and clipboard events
    ["contextmenu","copy","cut","paste","selectstart","mousedown","mouseup","dragstart"].forEach(evt => {
        window.addEventListener(evt, e => e.stopImmediatePropagation(), true);
    });

    console.log("Restrictions removed.");
})();


How It Works

Restores Text Selection

The script injects CSS rules that override restrictions such as:

  • user-select: none

  • -webkit-user-select: none

This allows text to be highlighted again.

Removes a Popup

Some websites display a popup with the ID:

#notRemoverPopup

The script removes it from the page if it is present.

Removes Fixed Overlays

Many websites display fullscreen overlays using CSS such as:

position: fixed;
z-index: 9999;

The script searches for common overlay elements and removes them if they use fixed positioning.

Restores Browser Events

Websites sometimes intercept events like:

  • contextmenu

  • copy

  • cut

  • paste

  • selectstart

  • mousedown

  • mouseup

  • dragstart

The script stops these interception handlers from taking priority, allowing the browser's default behavior to work normally in many cases.


How to Run the Script

  1. Open the desired webpage.

  2. Press F12 to open Developer Tools.

  3. Select the Console tab.

  4. Paste the JavaScript code.

  5. Press Enter.

The changes apply only to the current page and disappear after a refresh.


Limitations

This technique only affects client-side JavaScript and CSS. It does not bypass server-side protections, authentication, or access controls. Some websites may also reload or recreate interface elements dynamically, requiring the script to be run again.

For developers, students, and power users, browser-side JavaScript can be a useful way to inspect how a page behaves and to restore standard browser functionality during debugging or testing. Understanding how event listeners, CSS properties, and DOM manipulation work is also a great way to learn more about modern web development.

If you frequently use this type of script, consider turning it into a userscript with extensions such as Tampermonkey so it can run automatically on pages where you have permission to use it.



(() => {
    "use strict";

    function hidePopup() {
        const popup = document.getElementById("notRemoverPopup");
        if (popup) {
            popup.remove(); // oppure: popup.style.display = "none";
        }
    }

    function enableRightClick() {
        document.oncontextmenu = null;
        document.onmousedown = null;
        document.onmouseup = null;
        document.onclick = null;

        document.addEventListener("contextmenu", e => {
            e.stopImmediatePropagation();
        }, true);

        document.addEventListener("mousedown", e => {
            if (e.button === 2) {
                e.stopImmediatePropagation();
            }
        }, true);

        document.querySelectorAll("*").forEach(el => {
            el.oncontextmenu = null;
            el.onmousedown = null;
            el.onmouseup = null;
            el.onclick = null;
        });
    }

    hidePopup();
    enableRightClick();

    new MutationObserver(() => {
        hidePopup();
    }).observe(document.body, {
        childList: true,
        subtree: true
    });

    console.log("Popup  off.");
})();


https://www.examtopics.com/discussions/microsoft/view/94167-exam-az-204-topic-1-question-33-discussion

How to Find and Manage Your Connections in XrmToolBox

If you work with Microsoft Dataverse or Dynamics 365, XrmToolBox is undoubtedly your ultimate Swiss Army knife. However, as environments multiply—from development and testing to production—managing your connections can quickly become overwhelming.

Whether you need to move your saved environments to a new computer or you are simply trying to find where XrmToolBox stores your credentials, this quick guide has got you covered.

Finding Connections Inside the App (The Easy Way)

When you launch XrmToolBox, accessing your environments is straightforward:
  • The Connect Button: Look at the top-left corner of the main toolbar. Clicking "Connect" opens the Connection Manager window.
  • Organization: From here, you can select an existing environment, edit connection properties, or click "New Connection" to link a new Dataverse environment using OAuth, Client Id, or Connection Strings.

Where is the Connection File Saved? (The Local Path)

If you are changing your laptop, formatting your PC, or want to share environments with a colleague, you need to find the actual physical files on your hard drive.
XrmToolBox stores your configurations inside the Windows user profile. Here is the exact path:
C:\Users\<YourUsername>\AppData\Roaming\MscrmTools\XrmToolBox\Settings\

Key Files to Look For:

  • ConnectionWizard.xml: This is the most critical file. It contains the list of your saved connections, organization URLs, and configurations.
  • XrmToolBox.Settings.xml: Stores your general application preferences and plugin layouts.
Tip: The AppData folder is hidden by default in Windows. To see it, open File Explorer, click on the View tab at the top, and check the box for Hidden items.

How to Backup or Move Your Connections

Moving your workspace to a new machine takes less than a minute:
  1. Close XrmToolBox on both your old and new computers.
  2. Navigate to the AppData path listed above on your old PC.
  3. Copy the ConnectionWizard.xml file.
  4. Paste it into the exact same folder on your new PC.
  5. Open XrmToolBox on the new machine—all your environments will be ready to go!
Knowing where your XrmToolBox connections live saves time and prevents the headache of re-authenticating dozens of environments. Keep a backup of your ConnectionWizard.xml in a secure place, and you will never lose your setup again.

How to Clone a Dynamics 365 CRM Environment

Managing a Dynamics 365 CRM system requires a safe space for testing. Whether you are deploying a new feature, training your team, or troubleshooting a bug, you should never do it directly in your production environment.
Cloning your environment is the best way to create a perfect sandbox copy. Here is a straightforward guide on how to safely clone your Dynamics 365 CRM environment using the Power Platform Admin Center.

Understand Your Copy Options

Before you click any buttons, you need to decide what kind of clone you need. Microsoft offers two choices:
  • Full Copy: This copies everything. You get all the customizations, schemas, and all the data from your source environment. This is ideal for troubleshooting specific user errors or final user acceptance testing (UAT).
  • Minimal Copy: This copies the structure but leaves the data behind. You get all the tables, workflows, code, and customizations, but no user records or data. This is perfect for starting a new development phase.

Prepare Your Target Environment

You cannot overwrite just any environment. Keep these rules in mind:
  • The target environment must be a Sandbox or Trial environment.
  • You cannot copy directly into a Production environment.
  • Both environments must be in the same geographic region and tenant.

Run the Clone Process

Once you are ready, follow these exact steps:
  1. Log into the Power Platform Admin Center.
  2. Click on Environments in the left-hand menu.
  3. Select the source environment you want to clone and click Copy from the top toolbar.
  4. In the side pane, choose the type of copy (Full or Minimal).
  5. Select the target environment you want to overwrite.
  6. Review your settings and click Copy to start the process.
Note: The environment will be unavailable while the cloning process takes place.

Critical Post-Clone Checklist

Once the clone is complete, the new environment automatically enters Administration Mode. This is a safety feature to prevent the cloned environment from interacting with your real-world systems.
Before you open the environment to your team, make sure to:
  • Turn off Administration Mode: Go to the environment settings to allow regular users to log in.
  • Check Email Router/Server-Side Sync: Disable or update email settings so the test environment doesn't accidentally send automated emails to real clients.
  • Update Integrations: If your CRM connects to SharePoint, Power BI, or external ERP systems, update the connections to point to test folders and test databases, not production ones.
Cloning a Dynamics 365 environment is a quick and powerful way to protect your production data while giving your team the freedom to build and test. By following these steps and double-checking your post-copy integrations, you can ensure a smooth, risk-free development process.

RAG vs Fine-Tuning for Codebases - How to Build Your Own AI Coding Assistant

When you want to train an AI to understand your custom codebase, you face a major decision: Should you use Retrieval-Augmented Generation (RAG) or Fine-Tuning?

Both approaches solve different problems. RAG helps your model find real-time facts in your documentation. Fine-Tuning teaches your model a specific coding style, syntax, or tone.
In this article, we will explore both methods with practical Python examples so you can choose the best one for your developer workflow.

Building a Code-Aware RAG System

Best for: Injecting real-time documentation, specific API keys, or rapidly changing functions into your LLM prompt.
RAG works like an open-book exam. When a developer asks a question, the system searches your documentation, extracts the relevant snippet, and hands it to the Large Language Model (LLM) to generate a precise answer.
Here is how to implement a basic RAG system using LangChain and Chroma DB:
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# 1. Load your internal codebase documentation
# Imagine "code_docs.txt" contains: "The calculate_bonus(hours) function multiplies hours by 15 if they exceed 40."
loader = TextLoader("code_docs.txt")
documents = loader.load()

# 2. Initialize the embedding model and index the documents into Chroma DB
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(documents, embeddings)

# 3. Configure the retriever to find the most relevant document snippet
retriever = vector_store.as_retriever(search_kwargs={"k": 1})

# 4. Search for relevant context based on the developer's query
user_query = "How do I use the function to calculate the company bonus?"
relevant_docs = retriever.invoke(user_query)
context = relevant_docs.page_content

# 5. Pass the retrieved context and the query to the LLM for a precise answer
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = f"Use the following codebase context to answer the question:\n{context}\n\nQuestion: {user_query}"
response = llm.invoke(prompt)

print(response.content)

How it works:

  • The Loader: Reads your text-based documentation or source code files.
  • The Vector Store: Converts your code into mathematical vectors to understand semantic meaning.
  • The LLM: Uses the injected context to answer without guessing or hallucinating.

Preparing a Dataset for Fine-Tuning

Best for: Teaching an AI your enterprise coding standards, strict naming conventions, or specific framework styles.
Fine-Tuning is like studying for weeks before an exam. You do not pass documents to the model during the prompt. Instead, you train the model on hundreds of examples so it inherently knows how to write code exactly like your team does.
Before you start training, you must format your code into a JSONL (JSON Lines) file. Here is how to prepare that dataset:
import json

# Define the training dataset matching the conversational format required by OpenAI
training_data = [
    {
        "messages": [
            {"role": "system", "content": "You are the lead AI coding assistant at TechCorp. Always write clean, documented Python code."},
            {"role": "user", "content": "Create a function to validate an email address."},
            {"role": "assistant", "content": "def validate_techcorp_email(email):\n    # TechCorp Standard: Check for basic domain presence\n    return '@techcorp.com' in email"}
        ]
    },
    {
        "messages": [
            {"role": "system", "content": "You are the lead AI coding assistant at TechCorp. Always write clean, documented Python code."},
            {"role": "user", "content": "Write a loop to print active user names."},
            {"role": "assistant", "content": "for user in active_users:\n    # TechCorp Standard: Log formatted username\n    print(f'Active User: {user}')"}
        ]
    }
]

# Save the dataset into a JSONL file ready for the fine-tuning API upload
with open("fine_tuning_dataset.jsonl", "w", encoding="utf-8") as file:
    for record in training_data:
        file.write(json.dumps(record, ensure_ascii=False) + "\n")

print("Success! 'fine_tuning_dataset.jsonl' is ready for upload to your LLM provider.")

How it works:

  • System Prompt: Sets the permanent identity and behavioral constraints of your custom model.
  • User/Assistant Pairs: Show the exact syntax, comments, and structure your company expects.
  • JSONL Output: This specific file structure can be directly uploaded to OpenAI, Hugging Face, or fireworks.ai to start the training job.

RAG vs Fine-Tuning: Which should you choose?

  • Choose RAG if: Your codebase changes daily, you have thousands of pages of documentation, and you need 100% accurate factual retrieval.
  • Choose Fine-Tuning if: Your code follows unique architectural patterns, you want to eliminate repetitive system prompts, or you need to train a smaller model to perform like a massive one.
For the ultimate setup, many engineering teams combine both: they fine-tune a model to write code in their specific language syntax, and use RAG to feed that model the latest documentation dynamically.

Solving Dynamics 365 Plugin Trace Log Truncation with a Buffered Tracing Service

A production issue occurs, Plugin Trace Log is enabled, and after reproducing the problem you open the trace...

...only to discover that the beginning of the execution has disappeared.

The reason is simple: Plugin Trace Log has a maximum size of approximately 10 KB (10,240 characters).

Once that limit is exceeded, Dynamics 365 does not stop logging. Instead, it silently discards the oldest trace entries and keeps only the most recent ones.

For simple plugins this isn't an issue.

For complex plugins with multiple validation steps, service calls, and business logic, losing the beginning of the trace often means losing the most useful information.

In one of our projects we solved this problem by introducing a custom implementation of ITracingService that buffers all trace messages and decides what should eventually be written to Dynamics.

Understanding the Default Behavior

Imagine a plugin producing a trace like this:

Plugin started
Reading configuration
Loading Target
Checking security
Loading related records
...
...
...
Calling external API
Updating records
Plugin completed

When the trace exceeds 10 KB, Dynamics transforms it into something similar to:

...
...
...
Calling external API
Updating records
Plugin completed

The entire startup sequence disappears.

Unfortunately that's exactly the part we usually need while debugging.

The Solution

Instead of writing directly to the platform tracing service, every message is first stored in memory.

Only at the end of the execution do we decide how to write it.

The implementation has two responsibilities:

  • buffer every trace message

  • generate an optimized trace that fits inside Dynamics limits

Additionally, for selected plugins, the entire trace can also be persisted into a custom Dataverse table.

The architecture looks like this:

Plugin
      │
      ▼
BufferedTracingService
      │
      ├────────► Custom Log Entity (complete log)
      │
      ▼
Optimized Trace
      │
      ▼
Dynamics Plugin Trace Log

Buffering the Trace

Instead of immediately calling the original tracing service, every message is stored inside an internal collection.

private readonly List<string> _buffer = new();

public void Trace(string format, params object[] args)
{
    var message = args?.Length > 0
        ? string.Format(format, args)
        : format;

    _buffer.Add(message);
}

Nothing is written immediately.

The plugin continues executing exactly as before.

Keeping the Most Useful Information

Simply cutting the trace after 9 KB wouldn't solve the problem.

We would still lose the final exception or the last executed operations.

Instead, the algorithm keeps:

  • the beginning

  • the end

  • removes only the middle section

The resulting trace becomes:

Plugin started
Reading configuration
Loading configuration
Checking user privileges

...[TRACE TRUNCATED]...

Updating child records
Calling external service
Plugin completed successfully

This is significantly more valuable because it contains both the initial execution context and the final operations.

Persisting the Complete Log

Sometimes even the optimized trace is not enough.

For particularly critical plugins we also wanted the entire execution log.

Instead of storing every plugin trace, only selected plugins are configured for persistence.

private static readonly HashSet<string> _pluginsToLog =
{
    "OnPostCreateOnPostUpdateSetManagement"
};

When one of these plugins finishes execution, the complete buffered log is stored inside a custom Dataverse table.

var logRecord = new Entity("dps_log")
{
    ["dps_description"] = fullLog,
    ["dps_userid"] = new EntityReference(
        "systemuser",
        userId)
};

_orgService.Create(logRecord);

This gives us an unlimited execution history while keeping the standard Plugin Trace Log readable.

Integrating with Existing Plugins

One of the nicest aspects of this approach is that existing plugin code doesn't change.

Instead of resolving the standard tracing service:

this.tracingService = new Lazy<ITracingService>(
    Get<ITracingService>);

we simply wrap it.

this.tracingService = new Lazy<ITracingService>(() =>
    new BufferedTracingService(
        Get<ITracingService>(),
        OrganizationServiceFactory.CreateOrganizationService(null),
        GetType().Name,
        Context.PrimaryEntityId));

Every existing call remains exactly the same.

context.TracingService.Trace("Processing Account {0}", account.Id);

No refactoring of business logic is required.

Flushing the Buffer

At the very end of plugin execution, the buffer is flushed.

(context.TracingService as BufferedTracingService)?.Flush();

I usually place this call inside the finally block of my custom PluginBase.

This guarantees that traces are written even when an exception is thrown.

Benefits

Dynamics 365's 10 KB Plugin Trace Log limit is unlikely to disappear anytime soon, but that doesn't mean we have to accept losing valuable diagnostic information.

A buffered tracing service gives us complete control over what gets preserved, making debugging much easier without changing existing plugin code.

In practice, this utility has become part of my standard plugin framework because it solves one of the most common frustrations when troubleshooting long-running Dataverse plugins.

Complete Source Code

Below is the full implementation of the BufferedTracingService used throughout this article.

The following implementation can be copied directly into your plugin framework. Adapt the custom log entity (dps_log) and fields to match your own Dataverse solution.

using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Text;

namespace Avanade
{
    public sealed class BufferedTracingService : ITracingService
    {
        private readonly ITracingService _inner;
        private readonly IOrganizationService _orgService;
        private readonly string _pluginName;
        private readonly Guid _triggerEntityId;
        private readonly List<string> _buffer = new List<string>();

        private const int MaxD365TraceBytes = 9500;
        private const string TruncationMarker = "\r\n...[TRACE TRUNCATED]...\r\n";

        public BufferedTracingService(
            ITracingService inner,
            IOrganizationService orgService,
            string pluginName,
            Guid triggerEntityId)
        {
            _inner = inner;
            _orgService = orgService;
            _pluginName = pluginName;
            _triggerEntityId = triggerEntityId;
        }

        public void Trace(string format, params object[] args)
        {
            var message = (args != null && args.Length > 0)
                ? string.Format(format, args)
                : format;
            _buffer.Add(message);
        }

        private static readonly HashSet<string> _pluginsToLog = new HashSet<string>
        {
            "OnPostCreateOnPostUpdateSetManagement",          
        };

        public void Flush()
        {
            if (_buffer.Count == 0) return;

            if (_pluginsToLog.Contains(_pluginName))
            {
                var fullLog = string.Join("\r\n", _buffer);
                try
                {
                    var logRecord = new Entity("dps_log")
                    {
                        ["dps_description"] = fullLog,
                        ["dps_userid"] = new EntityReference("systemuser", new Guid("ba9e89ba-017a-f111-bc81-00224889f7d8")),
                    };
                    _orgService.Create(logRecord);
                }
                catch { }
            }

            _inner.Trace(BuildTruncatedTrace());
        }

        private string BuildTruncatedTrace()
        {
            var encoding = Encoding.UTF8;
            int headBudget = 3000;
            int totalBudget = MaxD365TraceBytes;
            int markerBytes = encoding.GetByteCount(TruncationMarker);

            var headSb = new StringBuilder();
            int headBytes = 0;
            int headEndIndex = _buffer.Count;

            for (int i = 0; i < _buffer.Count; i++)
            {
                var line = _buffer[i] + "\r\n";
                int lb = encoding.GetByteCount(line);
                if (headBytes + lb > headBudget) { headEndIndex = i; break; }
                headSb.Append(line);
                headBytes += lb;
                headEndIndex = i + 1;
            }

            if (headEndIndex >= _buffer.Count)
                return headSb.ToString();

            var tailLines = new List<string>();
            int tailBytes = 0;
            int tailBudget = totalBudget - headBytes - markerBytes;
            int tailStartIndex = _buffer.Count;

            for (int i = _buffer.Count - 1; i >= headEndIndex; i--)
            {
                var line = _buffer[i] + "\r\n";
                int lb = encoding.GetByteCount(line);
                if (tailBytes + lb > tailBudget) break;
                tailLines.Insert(0, _buffer[i]);
                tailBytes += lb;
                tailStartIndex = i;
            }

            var sb = new StringBuilder();
            sb.Append(headSb);
            if (tailStartIndex > headEndIndex) sb.Append(TruncationMarker);
            foreach (var l in tailLines) sb.AppendLine(l);
            return sb.ToString();
        }
    }
}

PluginContext

this.tracingService = new Lazy<ITracingService>(() =>
    new BufferedTracingService(
        Get<ITracingService>(),
        this.OrganizationServiceFactory.CreateOrganizationService(null),
        this.GetType().Name,
        this.Context.PrimaryEntityId));

PluginBase

try
{
    ExecutePlugin(context);
}
finally
{
    (context.TracingService as BufferedTracingService)?.Flush();
}

The implementation is intentionally lightweight, requires virtually no changes to existing plugins, and dramatically improves the debugging experience. In production environments where traces frequently exceed the Dynamics 365 limit, this small utility quickly proves its value. It has become a standard component of my Dataverse plugin framework because it preserves the information that matters most when diagnosing complex issues.

Classical Search Algorithms in the Age of AI Why Planning Still Matters

Artificial Intelligence is often associated with deep learning, large language models, and reinforcement learning. However, long before neural networks dominated the conversation, researchers developed a family of techniques capable of solving complex decision-making problems with remarkable efficiency: classical search and automated planning.

Despite the recent excitement surrounding machine learning, planning algorithms continue to power mission-critical systems in robotics, aerospace, logistics, manufacturing, and game AI. In many structured environments, they remain faster, more reliable, and more interpretable than purely data-driven approaches.

This article explores the foundations of automated planning, the most influential planning languages and libraries, and the latest research trends shaping the future of intelligent decision-making.

What Is Automated Planning?

Automated planning is the branch of Artificial Intelligence concerned with finding a sequence of actions that transforms an initial state into a desired goal state.

Unlike machine learning, which learns behavior from data, planning relies on explicit knowledge of:

  • the current state of the environment,

  • available actions,

  • action preconditions,

  • action effects,

  • desired goals.

The objective is to automatically compute the optimal (or near-optimal) sequence of actions needed to achieve those goals.

Examples include:

  • Robot navigation

  • Autonomous spacecraft operations

  • Logistics optimization

  • Manufacturing scheduling

  • Strategy games

  • Intelligent agents

Classical Search: The Foundation

Planning problems are fundamentally search problems.

The planner explores a potentially enormous state space looking for a path from the initial state to a goal state.

Some of the most influential search algorithms include:

  • Breadth-First Search (BFS)

  • Depth-First Search (DFS)

  • Uniform Cost Search

  • Greedy Best-First Search

  • A* Search

  • Iterative Deepening A*

  • Heuristic Search

Among these, A* remains one of the most widely used algorithms because it combines optimality with efficiency through heuristic guidance.

Modern planners extend these ideas using sophisticated heuristics capable of navigating search spaces containing millions or even billions of possible states.

Planning Languages

To solve planning problems, researchers developed domain description languages that formally define actions and environments.

STRIPS

STRIPS (Stanford Research Institute Problem Solver) introduced one of the first practical representations for planning.

Each action specifies:

  • Preconditions

  • Add effects

  • Delete effects

Its simplicity made STRIPS the foundation of decades of planning research.

PDDL

The Planning Domain Definition Language (PDDL) became the standard language used in the International Planning Competition.

Compared to STRIPS, PDDL supports:

  • Typed objects

  • Numeric fluents

  • Temporal planning

  • Durative actions

  • Hierarchical domains

  • Cost optimization

Today, nearly every modern planner accepts PDDL.

ADL

The Action Description Language (ADL) extends STRIPS with expressive logical constructs such as:

  • Quantifiers

  • Conditional effects

  • Disjunction

  • Equality constraints

This additional expressiveness allows planners to model significantly more realistic environments.

Open-Source Planning Libraries

Several excellent open-source frameworks are available for researchers and developers.

EUROPA

Originally developed by NASA, EUROPA is a sophisticated planning and scheduling system used for mission planning.

Key features include:

  • Constraint-based planning

  • Temporal reasoning

  • Resource management

  • Scheduling

  • Extensible architecture

Its accompanying language, NDDL (New Domain Definition Language), allows engineers to model complex planning domains with temporal constraints.

LAPKT

The Lightweight Automated Planning Toolkit (LAPKT) is a modern C++ framework implementing numerous state-of-the-art planning algorithms.

It includes:

  • Forward search planners

  • Heuristic planners

  • Landmark heuristics

  • Relaxed planning graph heuristics

  • Experimental planning algorithms

Because of its modular architecture, LAPKT is widely used for academic research.

Planning as Heuristic Search

One of the most influential developments in automated planning was the realization that planning could be viewed as heuristic search.

Instead of blindly exploring the state space, planners estimate how "far" each state is from the goal.

Better heuristics dramatically reduce computation time.

Common heuristic techniques include:

  • Relaxed planning graphs

  • Landmark heuristics

  • Pattern databases

  • Abstraction heuristics

  • Delete relaxation

These methods allow modern planners to solve problems that would otherwise be computationally infeasible.

Constraint Satisfaction

Planning is closely related to Constraint Satisfaction Problems (CSPs).

Rather than searching only through actions, CSP techniques search through variable assignments while respecting constraints.

Typical applications include:

  • Timetabling

  • Scheduling

  • Resource allocation

  • Vehicle routing

  • Manufacturing optimization

Research by Roman Barták, Miguel Salido, Francesca Rossi, Edward Tsang, and David Pearson significantly advanced the theoretical foundations of tractable constraint satisfaction.

Today, many industrial planning systems integrate search algorithms with CSP solvers to achieve superior performance.

Goal-Oriented Action Planning (GOAP)

Game developers popularized Goal-Oriented Action Planning (GOAP) as a practical AI architecture.

Instead of scripting every NPC behavior, GOAP dynamically builds plans to satisfy goals.

For example, an enemy NPC may reason:

  • Find weapon

  • Locate ammunition

  • Take cover

  • Attack player

  • Retreat if injured

This approach produces adaptive and believable behaviors without manually coding every possible scenario.

Many modern game engines continue to employ GOAP alongside behavior trees and utility AI.

Monte Carlo Tree Search

Not all planning relies on deterministic search.

Monte Carlo Tree Search (MCTS), particularly when combined with Upper Confidence Bounds for Trees (UCT), explores the search space through simulation rather than exhaustive reasoning.

MCTS has been highly successful in:

  • Go

  • Chess

  • Robotics

  • Real-time strategy games

  • Decision-making under uncertainty

Unlike classical planners, MCTS balances exploration and exploitation through statistical sampling.

Classical Planning vs Deep Reinforcement Learning

Deep Reinforcement Learning (DRL) has achieved remarkable success in environments where explicit models are unavailable.

However, recent research has shown that classical planners can outperform Deep Q-Learning (DQN) in several structured domains, including Atari benchmarks, when accurate environment models are available.

This comparison highlights an important distinction:

Planning excels when the model is known.

Reinforcement learning excels when the model must be learned.

Rather than competing, the two paradigms increasingly complement one another.

Hybrid systems combine:

  • learned world models,

  • neural heuristics,

  • symbolic planning,

  • reinforcement learning,

to achieve greater efficiency and robustness.

Current Research Trends

Modern automated planning is evolving rapidly in several exciting directions:

  • Neuro-symbolic planning

  • Learned heuristics

  • Hierarchical task planning (HTN)

  • Multi-agent planning

  • Explainable AI planning

  • Planning under uncertainty

  • Temporal and probabilistic planning

  • Large Language Models integrated with symbolic planners

The convergence of symbolic reasoning and machine learning is creating a new generation of intelligent systems capable of reasoning, learning, and adapting simultaneously.

Recommended Resources

For readers interested in exploring automated planning in greater depth, the following resources provide an excellent starting point:

Software Libraries

  • EUROPA & NDDL (NASA)

  • LAPKT (Lightweight Automated Planning Toolkit)

Books and Surveys

  • Artificial Intelligence: A Modern Approach (Chapter 11)

  • Planning as Heuristic Search

  • Current Trends in Automated Planning

  • Comparison of STRIPS, PDDL, and ADL

  • Goal-Oriented Action Planning (GOAP)

  • New Trends in Constraint Satisfaction, Planning, and Scheduling (Barták, Salido & Rossi)

  • A Survey of Tractable Constraint Satisfaction Problems (Pearson & Jeavons)

  • Foundations of Constraint Satisfaction (Edward Tsang)

Related Topics

  • Monte Carlo Tree Search with UCT

  • Classical Planning vs Deep Q-Learning

  • Deep Reinforcement Learning

While deep learning dominates headlines, classical planning remains one of the most elegant and powerful branches of Artificial Intelligence. Search algorithms, heuristic reasoning, and symbolic planning continue to solve problems where transparency, optimality, and reliability are essential.

As AI moves toward increasingly hybrid architectures, the future will likely belong to systems that combine the strengths of symbolic planning with the adaptability of machine learning. Understanding classical search algorithms is therefore not just an academic exercise—it is a key step toward building the next generation of intelligent agents.


Building Modern Power Apps Solutions with the Dataverse Web API

Discovering a Hidden Dynamics 365 Customization Page and Leveraging PowerApps Samples

As a Dynamics 365 and Power Platform developer, I am always looking for tools, shortcuts, and resources that can simplify customization and development activities.

https://crm/tools/systemcustomization/systemCustomization.aspx?pid=05&amp;web=true

This page provides direct access to System Customization features and can be useful for administrators and developers who need to quickly navigate to customization settings without going through the standard application menus.
Why This Is Interesting

In many Dynamics 365 environments, especially on-premises deployments, certain legacy administration pages remain available even though they are not commonly accessed from the modern interface.

These pages can help:Quickly access entity customizations
Review solution components
Troubleshoot configuration issues
Validate customizations after deployments
Save time during development and testing activities

For experienced CRM developers, knowing these direct URLs can significantly improve productivity.
The Perfect Companion: Microsoft PowerApps Samples

When working on customizations, plugins, integrations, or Dataverse development, one of the best resources available is Microsoft's official PowerApps Samples repository on GitHub. The repository includes sample code for:Dataverse development
Model-driven apps
Canvas apps
Power Apps Component Framework (PCF)
Power Pages
AI Builder
Power Platform integrations [github.com]

Repository:
https://github.com/Microsoft/PowerApps-Samples

According to Microsoft, the repository contains hundreds of practical examples and developer resources that can accelerate solution development and help teams adopt Microsoft best practices. [github.com]
Practical Use Cases

Here are some scenarios where combining direct customization access with PowerApps Samples can be extremely useful:
Plugin Development

Use the customization page to inspect entities and relationships, then leverage the sample repository to build or enhance plugins.
Dataverse Integration

Review your data model in Dynamics 365 and use Microsoft-provided Dataverse samples as implementation references. [github.com]
PCF Controls

Customize the user experience in model-driven apps and use PCF examples from the repository to create richer interfaces. [github.com]
Solution Troubleshooting

When investigating unexpected behavior, quickly access customization settings while comparing implementations with proven Microsoft samples.

Even in the era of modern Power Platform experiences, some legacy Dynamics 365 URLs remain valuable tools for administrators and developers. Combined with the extensive collection of examples available in the PowerApps Samples GitHub repository, they can help accelerate development, simplify troubleshooting, and improve overall productivity.

Useful LinksPowerApps Samples: https://github.com/Microsoft/PowerApps-Samples
System Customization Page: https://crm/tools/systemcustomization/systemCustomization.aspx?pid=05&web=true

Exploring the Hidden IsAppMode Organization Setting in Microsoft Dataverse

While exploring the Organization table in Microsoft Dataverse, I found an interesting property that many developers have probably never noticed: IsAppMode.

If you're working with an on-premises Dynamics 365 environment, you can check its value with a simple SQL query:

SELECT isappmode
FROM organization

For Dataverse online environments, the same property is available through the Organization table exposed by the Dataverse Web API.

What is IsAppMode?

According to Microsoft documentation, the IsAppMode attribute indicates whether Microsoft Dynamics 365 can be loaded in a browser window without the traditional address bar, toolbar, and menu bar. This capability was originally designed for application-style experiences and kiosk scenarios rather than standard browser navigation.

The property is defined as:

  • Logical name: isappmode

  • Type: Boolean

  • Default value: false

Although modern model-driven apps rarely depend on this setting directly, it remains part of the Organization metadata and can be useful when comparing environments or investigating legacy deployments.

Why should developers care?

The Organization table contains hundreds of environment-wide settings controlling platform behavior. Most developers focus on tables, plugins, Power Automate, or JavaScript customizations, but these system properties often explain differences between environments.

Exploring Organization attributes can help when:

  • troubleshooting unexpected behavior;

  • comparing development and production environments;

  • documenting tenant configuration;

  • understanding legacy Dynamics 365 implementations.

Retrieving the value through the Web API

You can retrieve the property using the Dataverse Web API:

GET /api/data/v9.2/organizations?$select=name,isappmode

The response includes the current value for your environment.


K-Means vs DBSCAN: Understanding Clustering Through Visualization

 (naftaliharris.com)

Clustering is one of the most fundamental tasks in machine learning. Unlike supervised learning, where models learn from labeled examples, clustering algorithms attempt to discover hidden structures within unlabeled data.

Among the many clustering techniques available today, two algorithms stand out for their popularity and contrasting philosophies: K-Means and DBSCAN. While both aim to group similar data points together, they approach the problem in completely different ways.

Understanding these differences becomes much easier when visualized, which is why interactive demonstrations of clustering algorithms have become valuable learning tools for data scientists and engineers.

What Is Clustering?

Imagine plotting thousands of customer records based on purchasing behavior. Without any labels, you might still notice natural groups emerging:

  • Budget-conscious customers

  • Premium buyers

  • Occasional shoppers

Clustering algorithms attempt to identify these groups automatically by analyzing the spatial distribution of the data.

The challenge lies in defining what exactly constitutes a "cluster."

Different algorithms answer this question differently.

K-Means: Clusters Around Centers

K-Means is based on a simple intuition:

Points belonging to the same cluster should be close to a central point.

This central point is called a centroid.

How K-Means Works

The algorithm follows an iterative process:

  1. Choose the number of clusters (K)

  2. Initialize K centroids

  3. Assign each point to its nearest centroid

  4. Recalculate centroid positions based on assigned points

  5. Repeat until the centroids stop moving

The result is a partition of the dataset into K distinct groups.

Why K-Means Is Popular

K-Means offers several advantages:

  • Easy to understand

  • Fast on large datasets

  • Computationally efficient

  • Works well when clusters are compact and roughly spherical

For many business applications such as customer segmentation, document categorization, and market analysis, K-Means often provides surprisingly strong results.

The Limitations of K-Means

Despite its simplicity, K-Means has notable drawbacks.

1. You Must Choose K in Advance

The algorithm requires the number of clusters before training begins.

In real-world datasets, this information is often unknown.

2. Sensitive to Initialization

Different starting centroid positions can lead to different final solutions.

Two runs on the same dataset may produce slightly different clusters.

3. Struggles With Complex Shapes

K-Means assumes clusters are organized around centers.

When clusters form rings, spirals, or irregular structures, the algorithm often fails to identify them correctly.

DBSCAN: Clusters as Dense Regions

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) takes a completely different approach.

Instead of looking for centers, DBSCAN looks for areas of high density.

The underlying idea is simple:

If a point belongs to a cluster, it should have many neighboring points nearby.

How DBSCAN Works

The algorithm relies on two parameters:

  • eps (ε): neighborhood radius

  • minPoints: minimum number of nearby points required

A point becomes a core point if enough neighbors exist within its radius.

From there, DBSCAN expands clusters by connecting nearby dense regions together.

Points that do not belong to any dense region are labeled as noise.

Why DBSCAN Is Powerful

DBSCAN solves several problems that challenge K-Means.

No Need to Specify the Number of Clusters

The algorithm discovers clusters automatically based on density.

Handles Arbitrary Shapes

Whether the data forms circles, crescents, rings, or irregular structures, DBSCAN can often identify them correctly.

Detects Outliers Naturally

Noise points are not forced into clusters.

This makes DBSCAN particularly useful for anomaly detection and noisy real-world datasets.

Where DBSCAN Struggles

While DBSCAN is powerful, it is not perfect.

Parameter Selection

Choosing good values for ε and minPoints can be difficult.

Small changes may significantly alter the clustering result.

Varying Densities

If one cluster is extremely dense and another is sparse, a single parameter configuration may not work well for both.

Border Points

Points located between clusters may belong to multiple valid regions.

Their final assignment can sometimes depend on processing order.

K-Means vs DBSCAN

FeatureK-MeansDBSCAN
Requires number of clustersYesNo
Handles arbitrary shapesNoYes
Detects outliersNoYes
Sensitive to initializationYesNo
Sensitive to density parametersNoYes
Works well on spherical clustersExcellentGood
Works well on noisy dataLimitedExcellent

Which Algorithm Should You Use?

The answer depends entirely on your data.

Choose K-Means when:

  • The number of clusters is known

  • Clusters are compact and well separated

  • Speed is important

  • The dataset is large

Choose DBSCAN when:

  • Cluster shapes are unknown

  • Noise and outliers are present

  • The number of clusters is not known beforehand

  • Density naturally defines the groups

In practice, experienced data scientists often experiment with multiple clustering algorithms before selecting the best one.

K-Means and DBSCAN represent two fundamentally different views of clustering.

K-Means assumes that clusters revolve around centers, making it fast and efficient for structured datasets.

DBSCAN assumes that clusters emerge from dense regions of data, allowing it to discover complex shapes and identify noise automatically.

By visualizing these algorithms step by step, it becomes clear that clustering is not just about grouping points—it is about defining what a group actually means.