Repository: JanDeDobbeleer/oh-my-posh
Pull request #4369 (2023-10-19 01:00:27)

Update-folder-icon-insonicboom_dark.omp.json
Adjust the separate folder icon to not cut the home icon in path

### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md].
- [x] The commit message follows the [conventional commits][cc] guidelines.
- [x ] Tests for the changes have been added (for bug fixes / features).
- [ ] Docs have been added/updated (for bug fixes / features).

### Description

<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at bcf7e1d</samp>

Changed the color of the folder separator icon in the `sonicboom_dark` theme to fix a visibility issue. This theme is a JSON file for the oh-my-posh prompt customization tool.

### How

<!--
copilot:walkthrough
-->
### <samp>🤖 Generated by Copilot at bcf7e1d</samp>

* Change the folder separator icon color to black for better contrast ([link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4369/files?diff=unified&w=0#diff-482bc099f7e8f67390b807acf6cac1fefae7c5204f8b1aacb9373c7abc77cc69L44-R44))

<!---

Tips:

If you're not comfortable with working with Git,
we're working a guide (https://ohmyposh.dev/docs/contributing_git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 00063d39..0e717d08 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1964,7 +1964,9 @@
       "avatar_url": "https://avatars.githubusercontent.com/u/1389894?v=4",
       "profile": "http://creativewebspecialist.co.uk",
       "contributions": [
-        "code"
+        "code",
+        "design",
+        "doc"
       ]
     },
     {
@@ -2002,6 +2004,35 @@
       "contributions": [
         "code"
       ]
+    },
+    {
+      "login": "mateusz-bajorek",
+      "name": "Mateusz Bajorek",
+      "avatar_url": "https://avatars.githubusercontent.com/u/11185738?v=4",
+      "profile": "https://github.com/mateusz-bajorek",
+      "contributions": [
+        "code",
+        "design",
+        "doc"
+      ]
+    },
+    {
+      "login": "joshbduncan",
+      "name": "Josh Duncan",
+      "avatar_url": "https://avatars.githubusercontent.com/u/44387852?v=4",
+      "profile": "http://joshbduncan.com",
+      "contributions": [
+        "doc"
+      ]
+    },
+    {
+      "login": "princesaini",
+      "name": "Prince Saini",
+      "avatar_url": "https://avatars.githubusercontent.com/u/25565506?v=4",
+      "profile": "https://github.com/princesaini",
+      "contributions": [
+        "design"
+      ]
     }
   ],
   "contributorsPerLine": 7,
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index a47f4f3d..ae8a2ac2 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -27,7 +27,7 @@ jobs:
         with:
           go-version: 1.21
           cache-dependency-path: src/go.sum
-      - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d
+      - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65
         with:
           node-version: 17.6.0
         # Create Kind cluster to have a Kubernetes context for cloud-native-azure theme
diff --git a/.github/workflows/social.yml b/.github/workflows/social.yml
index b370f21f..83af6c27 100644
--- a/.github/workflows/social.yml
+++ b/.github/workflows/social.yml
@@ -9,7 +9,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Install Node ⬇️
-        uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d
+        uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65
         with:
           node-version: 18
       - name: Checkout code 👋
diff --git a/src/engine/segment.go b/src/engine/segment.go
index 80fafc1b..a2107745 100644
--- a/src/engine/segment.go
+++ b/src/engine/segment.go
@@ -232,6 +232,8 @@ const (
 	TIME SegmentType = "time"
 	// UI5 Tooling segment
 	UI5TOOLING SegmentType = "ui5tooling"
+	// UMBRACO writes the Umbraco version if Umbraco is present
+	UMBRACO SegmentType = "umbraco"
 	// UNITY writes which Unity version is currently active
 	UNITY SegmentType = "unity"
 	// UPGRADE lets you know if you can upgrade Oh My Posh
@@ -323,6 +325,7 @@ var Segments = map[SegmentType]func() SegmentWriter{
 	TEXT:          func() SegmentWriter { return &segments.Text{} },
 	TIME:          func() SegmentWriter { return &segments.Time{} },
 	UI5TOOLING:    func() SegmentWriter { return &segments.UI5Tooling{} },
+	UMBRACO:       func() SegmentWriter { return &segments.Umbraco{} },
 	UNITY:         func() SegmentWriter { return &segments.Unity{} },
 	UPGRADE:       func() SegmentWriter { return &segments.Upgrade{} },
 	VALA:          func() SegmentWriter { return &segments.Vala{} },
diff --git a/src/segments/node.go b/src/segments/node.go
index 3910caf8..79fad8f1 100644
--- a/src/segments/node.go
+++ b/src/segments/node.go
@@ -55,7 +55,7 @@ func (n *Node) loadContext() {
 		return
 	}
 	if n.language.env.HasFiles("yarn.lock") {
-		n.PackageManagerIcon = n.language.props.GetString(YarnIcon, "\uF61A")
+		n.PackageManagerIcon = n.language.props.GetString(YarnIcon, "\uF011B")
 		return
 	}
 	if n.language.env.HasFiles("package-lock.json") || n.language.env.HasFiles("package.json") {
diff --git a/src/segments/umbraco.go b/src/segments/umbraco.go
new file mode 100644
index 00000000..5c3209fd
--- /dev/null
+++ b/src/segments/umbraco.go
@@ -0,0 +1,159 @@
+package segments
+
+import (
+	"encoding/xml"
+	"path/filepath"
+	"strings"
+
+	"github.com/jandedobbeleer/oh-my-posh/src/platform"
+	"github.com/jandedobbeleer/oh-my-posh/src/properties"
+)
+
+type Umbraco struct {
+	props properties.Properties
+	env   platform.Environment
+
+	Modern  bool
+	Version string
+}
+
+type CSProj struct {
+	PackageReferences []struct {
+		Name    string `xml:"include,attr"`
+		Version string `xml:"version,attr"`
+	} `xml:"ItemGroup>PackageReference"`
+}
+
+type WebConfig struct {
+	AppSettings []struct {
+		Key   string `xml:"key,attr"`
+		Value string `xml:"value,attr"`
+	} `xml:"appSettings>add"`
+}
+
+func (u *Umbraco) Enabled() bool {
+	var location string
+
+	// Check if we have a folder called Umbraco or umbraco in the current directory or a parent directory
+	folders := []string{"umbraco", "Umbraco"}
+	for _, folder := range folders {
+		if file, err := u.env.HasParentFilePath(folder); err == nil {
+			location = file.ParentFolder
+			break
+		}
+	}
+
+	if len(location) == 0 {
+		u.env.Debug("No umbraco folder found in parent directories")
+		return false
+	}
+
+	files := u.env.LsDir(location)
+
+	// Loop over files where we found the Umbraco folder
+	// To see if we can find a web.config or *.csproj file
+	// If we do then we can scan the file to see if Umbraco has been installed
+	for _, file := range files {
+		if file.IsDir() {
+			continue
+		}
+
+		if strings.EqualFold(file.Name(), "web.config") {
+			return u.TryFindLegacyUmbraco(filepath.Join(location, file.Name()))
+		}
+
+		if strings.EqualFold(filepath.Ext(file.Name()), ".csproj") {
+			return u.TryFindModernUmbraco(filepath.Join(location, file.Name()))
+		}
+	}
+
+	return false
+}
+
+func (u *Umbraco) Template() string {
+	return "{{.Version}} "
+}
+
+func (u *Umbraco) Init(props properties.Properties, env platform.Environment) {
+	u.props = props
+	u.env = env
+}
+
+func (u *Umbraco) TryFindModernUmbraco(configPath string) bool {
+	// Check the passed in filepath is not empty
+	if len(configPath) == 0 {
+		u.env.Debug("UMBRACO: No .CSProj file path passed in")
+		return false
+	}
+
+	// Read the file contents of the csproj file
+	contents := u.env.FileContent(configPath)
+
+	// As XML unmarshal does not support case insenstivity attributes
+	// this is just a simple string replace to lowercase the attribute
+	contents = strings.ReplaceAll(contents, "Include=", "include=")
+	contents = strings.ReplaceAll(contents, "Version=", "version=")
+
+	// XML Unmarshal - map the contents of the file to the CSProj struct
+	csProjPackages := CSProj{}
+	err := xml.Unmarshal([]byte(contents), &csProjPackages)
+
+	if err != nil {
+		u.env.Debug("UMBRACO: Error while trying to parse XML of .csproj file")
+		u.env.Debug(err.Error())
+	}
+
+	// Loop over all the package references
+	for _, packageReference := range csProjPackages.PackageReferences {
+		if strings.EqualFold(packageReference.Name, "umbraco.cms") {
+			u.Modern = true
+			u.Version = packageReference.Version
+
+			return true
+		}
+	}
+
+	return false
+}
+
+func (u *Umbraco) TryFindLegacyUmbraco(configPath string) bool {
+	// Check the passed in filepath is not empty
+	if len(configPath) == 0 {
+		u.env.Debug("UMBRACO: No web.config file path passed in")
+		return false
+	}
+
+	// Read the file contents of the web.config
+	contents := u.env.FileContent(configPath)
+
+	// As XML unmarshal does not support case insenstivity attributes
+	// this is just a simple string replace to lowercase the attribute
+	contents = strings.ReplaceAll(contents, "Key=", "key=")
+	contents = strings.ReplaceAll(contents, "Value=", "value=")
+
+	// XML Unmarshal - web.config all AppSettings keys
+	webConfigAppSettings := WebConfig{}
+	err := xml.Unmarshal([]byte(contents), &webConfigAppSettings)
+
+	if err != nil {
+		u.env.Debug("UMBRACO: Error while trying to parse XML of web.config file")
+		u.env.Debug(err.Error())
+	}
+
+	// Loop over all the package references
+	for _, appSetting := range webConfigAppSettings.AppSettings {
+		if strings.EqualFold(appSetting.Key, "umbraco.core.configurationstatus") {
+			u.Modern = false
+
+			if len(appSetting.Value) == 0 {
+				u.Version = "Unknown"
+			} else {
+				u.Version = appSetting.Value
+			}
+
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/themes/atomic.omp.json b/themes/atomic.omp.json
index c2dc8e54..a0425066 100644
--- a/themes/atomic.omp.json
+++ b/themes/atomic.omp.json
@@ -94,7 +94,7 @@
         },
         {
           "background": "#0e8ac8",
-          "foreground": "#ec2729",
+          "foreground": "#ffffff",
           "leading_diamond": "\ue0b6",
           "style": "diamond",
           "template": "\ue738 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}",
diff --git a/themes/schema.json b/themes/schema.json
index 02a08af1..53979b8b 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -310,6 +310,7 @@
             "text",
             "terraform",
             "ui5tooling",
+            "umbraco",
             "unity",
             "upgrade",
             "wakatime",
@@ -1499,7 +1500,7 @@
                     "type": "string",
                     "title": "Yarn Icon",
                     "description": "Icon/text to use for Yarn",
-                    "default": " \uF61A"
+                    "default": " \uF011B"
                   },
                   "npm_icon": {
                     "type": "string",
@@ -3284,6 +3285,29 @@
               }
             }
           }
+        },
+        {
+          "if": {
+            "properties": {
+              "type": { "const": "umbraco" }
+            }
+          },
+          "then": {
+            "title": "Display something umbraco",
+            "description": "https://ohmyposh.dev/docs/segments/umbraco",
+            "properties": {
+              "properties": {
+                "properties": {
+                  "newprop": {
+                    "type": "string",
+                    "title": "New Property",
+                    "description": "the default text to display",
+                    "default": "Hello"
+                  }
+                }
+              }
+            }
+          }
         }
       ]
     }
diff --git a/themes/sonicboom_dark.omp.json b/themes/sonicboom_dark.omp.json
index dcd0c137..85d10945 100644
--- a/themes/sonicboom_dark.omp.json
+++ b/themes/sonicboom_dark.omp.json
@@ -41,7 +41,7 @@
           "foreground": "#43CCEA",
           "properties": {
             "folder_icon": "\ue5fe",
-            "folder_separator_icon": "<transparent> \ue0bd </>",
+            "folder_separator_icon": " <#000000>\ue0bd </>",
             "home_icon": "\ueb06",
             "style": "agnoster_short"
           },
diff --git a/website/docs/contributors.md b/website/docs/contributors.md
index 51920696..2d771cc7 100644
--- a/website/docs/contributors.md
+++ b/website/docs/contributors.md
@@ -283,11 +283,16 @@ Thanks goes to these wonderful people ([emoji key][acek]):
     </tr>
     <tr>
       <td align="center" valign="top" width="14.28%"><a href="https://github.com/deepak-dev-96"><img src="https://avatars.githubusercontent.com/u/134447761?v=4?s=100" width="100px;" alt="Deepak Dev"/><br /><sub><b>Deepak Dev</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=deepak-dev-96" title="Documentation">📖</a></td>
-      <td align="center" valign="top" width="14.28%"><a href="http://creativewebspecialist.co.uk"><img src="https://avatars.githubusercontent.com/u/1389894?v=4?s=100" width="100px;" alt="Warren Buckley"/><br /><sub><b>Warren Buckley</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=warrenbuckley" title="Code">💻</a></td>
+      <td align="center" valign="top" width="14.28%"><a href="http://creativewebspecialist.co.uk"><img src="https://avatars.githubusercontent.com/u/1389894?v=4?s=100" width="100px;" alt="Warren Buckley"/><br /><sub><b>Warren Buckley</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=warrenbuckley" title="Code">💻</a> <a href="#design-warrenbuckley" title="Design">🎨</a> <a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=warrenbuckley" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="14.28%"><a href="https://github.com/LunarMarathon"><img src="https://avatars.githubusercontent.com/u/113847439?v=4?s=100" width="100px;" alt="LunarMarathon"/><br /><sub><b>LunarMarathon</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=LunarMarathon" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="14.28%"><a href="https://ginglis.me"><img src="https://avatars.githubusercontent.com/u/43075615?v=4?s=100" width="100px;" alt="Gavin Inglis"/><br /><sub><b>Gavin Inglis</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ginglis13" title="Code">💻</a></td>
       <td align="center" valign="top" width="14.28%"><a href="http://jaliyaudagedara.blogspot.com"><img src="https://avatars.githubusercontent.com/u/5653381?v=4?s=100" width="100px;" alt="Jaliya Udagedara"/><br /><sub><b>Jaliya Udagedara</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jaliyaudagedara" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="14.28%"><a href="https://github.com/BPplays"><img src="https://avatars.githubusercontent.com/u/58504799?v=4?s=100" width="100px;" alt="BPplays"/><br /><sub><b>BPplays</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BPplays" title="Code">💻</a></td>
+      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mateusz-bajorek"><img src="https://avatars.githubusercontent.com/u/11185738?v=4?s=100" width="100px;" alt="Mateusz Bajorek"/><br /><sub><b>Mateusz Bajorek</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mateusz-bajorek" title="Code">💻</a> <a href="#design-mateusz-bajorek" title="Design">🎨</a> <a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mateusz-bajorek" title="Documentation">📖</a></td>
+    </tr>
+    <tr>
+      <td align="center" valign="top" width="14.28%"><a href="http://joshbduncan.com"><img src="https://avatars.githubusercontent.com/u/44387852?v=4?s=100" width="100px;" alt="Josh Duncan"/><br /><sub><b>Josh Duncan</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=joshbduncan" title="Documentation">📖</a></td>
+      <td align="center" valign="top" width="14.28%"><a href="https://github.com/princesaini"><img src="https://avatars.githubusercontent.com/u/25565506?v=4?s=100" width="100px;" alt="Prince Saini"/><br /><sub><b>Prince Saini</b></sub></a><br /><a href="#design-princesaini" title="Design">🎨</a></td>
     </tr>
   </tbody>
 </table>
diff --git a/website/docs/installation/macos.mdx b/website/docs/installation/macos.mdx
index 066a5596..7e522f2c 100644
--- a/website/docs/installation/macos.mdx
+++ b/website/docs/installation/macos.mdx
@@ -11,7 +11,7 @@ import Next from "./next.mdx";
 
 ## Set up your terminal
 
-As the standard terminal only support [256 colors][256-colors], we advise using
+As the standard terminal only supports [256 colors][256-colors], we advise using
 [iTerm2][iterm2] or any other modern day macOS terminal that supports ANSI characters.
 
 :::info
@@ -25,4 +25,5 @@ To display all icons, we recommend the use of a [Nerd Font][fonts].
 <Next />
 
 [256-colors]: /docs/configuration/colors#standard-colors
-[fonts]: /docs/installation/fonts
\ No newline at end of file
+[iterm2]: https://iterm2.com
+[fonts]: /docs/installation/fonts
diff --git a/website/docs/segments/node.mdx b/website/docs/segments/node.mdx
index e3b77423..3e2b1084 100644
--- a/website/docs/segments/node.mdx
+++ b/website/docs/segments/node.mdx
@@ -33,7 +33,7 @@ import Config from "@site/src/components/Config.js";
 | `display_mode`          | `string`  | <ul><li>`always`: The segment is always displayed</li><li>`files`: The segment is only displayed when one of the following files is present (**default**):<ul><li>`*.js`</li><li>`*.ts`</li><li>`package.json`</li><li>`.nvmrc`</li><li>`pnpm-workspace.yaml`</li><li>`.pnpmfile.cjs`</li><li>`.npmrc`</li><li>`.vue`</li></ul></li></ul> |
 | `version_url_template`  | `string`  | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                                                                                                                     |
 | `fetch_package_manager` | `boolean` | define if the current project uses Yarn or NPM - defaults to `false`                                                                                                                                                                                                                                                                      |
-| `yarn_icon`             | `string`  | the icon/text to display when using Yarn - defaults to ` \uF61A`                                                                                                                                                                                                                                                                          |
+| `yarn_icon`             | `string`  | the icon/text to display when using Yarn - defaults to ` \uF011B`                                                                                                                                                                                                                                                                          |
 | `npm_icon`              | `string`  | the icon/text to display when using NPM - defaults to ` \uE71E`                                                                                                                                                                                                                                                                           |
 
 ## Template ([info][templates])
diff --git a/website/docs/segments/umbraco.mdx b/website/docs/segments/umbraco.mdx
new file mode 100644
index 00000000..cc403fe0
--- /dev/null
+++ b/website/docs/segments/umbraco.mdx
@@ -0,0 +1,56 @@
+---
+id: umbraco
+title: Umbraco
+sidebar_label: Umbraco
+---
+
+## What
+
+Display current Umbraco Version if found inside the current working directory.
+The segment will only show based on the following logic
+
+* The current folder contains the folder named umbraco
+* Modern Umbraco (.NET Core)
+    * Check to see if current folder contains one or more .csproj files
+    * Open .csproj XML files and check to see if Umbraco is installed as a PackageReference
+    * Read the installed version
+* Legacy Umbraco (.NET Framework)
+    * Check to see if the current folder contains a web.config
+    * Open the XML and look for AppSettings keys
+    * If umbraco is installed it has a setting called umbraco.core.configurationstatus
+    * Read the value inside this AppSetting to get its version
+
+## Sample Configuration
+
+import Config from '@site/src/components/Config.js';
+
+<Config data={{
+  "type": "umbraco",
+  "background": "#ffffff",
+  "foreground": "#d886f1",
+  "style": "diamond",
+  "leading_diamond": "\ue0b6",
+  "trailing_diamond": "\ue0b4",
+  "template": "\udb81\udd49 {{ .Version }}",
+  "background_templates": [
+    "{{ if (.Modern) }}#3544B1{{ end }}",
+    "{{ if not (.Modern) }}#F79C37{{ end }}"
+  ]
+}}/>
+
+## Template ([info][templates])
+
+:::note default template
+
+```template
+{{ .Version }}
+```
+
+:::
+
+## Properties
+
+| Name           | Type      | Description                                                                                                         |
+| -------------- | --------- | ------------------------------------------------------------------------------------------------------------------- |
+| `.Modern`      | `boolean` | a boolean to detemine if this is modern Umbraco V9+ using modern .NET or if its legacy Umbraco using .NET Framework |
+| `.Version`     | `string`  | the version of umbraco found                                                                                       |
diff --git a/website/sidebars.js b/website/sidebars.js
index 22bfabad..dfeba6bb 100644
--- a/website/sidebars.js
+++ b/website/sidebars.js
@@ -120,6 +120,7 @@ module.exports = {
         "segments/text",
         "segments/time",
         "segments/ui5tooling",
+        "segments/umbraco",
         "segments/unity",
         "segments/upgrade",
         "segments/vala",


Test patch:
diff --git a/src/segments/brewfather_test.go b/src/segments/brewfather_test.go
index adbb5324..a394198a 100644
--- a/src/segments/brewfather_test.go
+++ b/src/segments/brewfather_test.go
@@ -36,6 +36,20 @@ func TestBrewfatherSegment(t *testing.T) {
 	FakeReading3DateString := fmt.Sprintf("%d", FakeReading3Date.UnixMilli())
 	FakeBottlingDateString := fmt.Sprintf("%d", FakeBottlingDate.UnixMilli())
 
+	// TODO: make this smarter
+
+	beerRecipeText := `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":`
+	bottlingDate := `,"bottlingDate":`
+	batchText := `,"name":"Batch","measuredAbv": 1.3}`
+	batchNumberFermenting := `{"batchNo":18,"status":"Fermenting","brewDate":`
+	manualType := `,"type":"manual"}]`
+
+	jsonFiller := FakeBrewDateString + bottlingDate + FakeBottlingDateString + beerRecipeText + FakeFermStartDateString + batchText
+
+	batchReadingJSON := `[{"id":"manual","temp":19.5,"comment":"","sg":1.066,"time":`
+	batchReadingJSON2 := `,"type":"manual"}, {"id":"manual","temp":21,"comment":"","sg":1.063,"time":`
+	batchReadingJSON3 := `,"type":"manual"}, {"id":"manual","temp":15,"comment":"","sg":1.050,"time":`
+
 	cases := []struct {
 		Case                      string
 		BatchJSONResponse         string
@@ -48,90 +62,81 @@ func TestBrewfatherSegment(t *testing.T) {
 		Error                     error
 	}{
 		{
-			Case: "Planning Status",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Planning","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
+			Case:                      "Planning Status",
+			BatchJSONResponse:         `{"batchNo":18,"status":"Planning","brewDate":` + jsonFiller,
 			BatchReadingsJSONResponse: `[]`,
 			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " Fake Beer 1.3%",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Brewing Status",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Brewing","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
+			Case:                      "Brewing Status",
+			BatchJSONResponse:         `{"batchNo":18,"status":"Brewing","brewDate":` + jsonFiller,
 			BatchReadingsJSONResponse: `[]`,
 			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " Fake Beer 1.3%",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Fermenting Status, no readings",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Fermenting","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
+			Case:                      "Fermenting Status, no readings",
+			BatchJSONResponse:         batchNumberFermenting + jsonFiller,
 			BatchReadingsJSONResponse: `[]`,
 			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " 19d Fake Beer 1.3%",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Fermenting Status, one reading",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Fermenting","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":19.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + `,"type":"manual"}]`,
+			Case:                      "Fermenting Status, one reading",
+			BatchJSONResponse:         batchNumberFermenting + jsonFiller,
+			BatchReadingsJSONResponse: batchReadingJSON + FakeReading1DateString + manualType,
 			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " 19d Fake Beer 1.3%: 1.066 19.5° →",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Fermenting Status, two readings, temp trending up",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Fermenting","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":19.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + `,"type":"manual"}, {"id":"manual","temp":21,"comment":"","sg":1.063,"time":` + FakeReading2DateString + `,"type":"manual"}]`,                                    //nolint:lll
+			Case:                      "Fermenting Status, two readings, temp trending up",
+			BatchJSONResponse:         batchNumberFermenting + jsonFiller,                                                                                                                                                                                                                        //nolint:lll
+			BatchReadingsJSONResponse: batchReadingJSON + FakeReading1DateString + batchReadingJSON2 + FakeReading2DateString + manualType,                                                                                                                                                       //nolint:lll
 			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " 19d Fake Beer 1.3%: 1.063 21° ↗",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Fermenting Status, three readings, temp trending hard down, include age of most recent reading",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Fermenting","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":19.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + `,"type":"manual"}, {"id":"manual","temp":21,"comment":"","sg":1.063,"time":` + FakeReading2DateString + `,"type":"manual"}, {"id":"manual","temp":15,"comment":"","sg":1.050,"time":` + FakeReading3DateString + `,"type":"manual"}]`, //nolint:lll
-			Template:                  "{{.StatusIcon}} {{.ReadingAge}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}",                                                       //nolint:lll
+			Case:                      "Fermenting Status, three readings, temp trending hard down, include age of most recent reading",
+			BatchJSONResponse:         batchNumberFermenting + jsonFiller,                                                                                                                                                                                                                                        //nolint:lll
+			BatchReadingsJSONResponse: batchReadingJSON + FakeReading1DateString + batchReadingJSON2 + FakeReading2DateString + batchReadingJSON3 + FakeReading3DateString + manualType,                                                                                                                          //nolint:lll
+			Template:                  "{{.StatusIcon}} {{.ReadingAge}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " 451 19d Fake Beer 1.3%: 1.05 15° ↓↓",
 			ExpectedEnabled:           true,
 		},
 		{
 			Case:                      "Bad batch json, readings fine",
 			BatchJSONResponse:         ``,
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":19.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + `,"type":"manual"}, {"id":"manual","temp":21,"comment":"","sg":1.063,"time":` + FakeReading2DateString + `,"type":"manual"}, {"id":"manual","temp":15,"comment":"","sg":1.050,"time":` + FakeReading3DateString + `,"type":"manual"}]`, //nolint:lll
-			Template:                  "{{.StatusIcon}} {{.ReadingAge}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}",                                                       //nolint:lll
+			BatchReadingsJSONResponse: batchReadingJSON + FakeReading1DateString + batchReadingJSON2 + FakeReading2DateString + batchReadingJSON3 + FakeReading3DateString + manualType,                                                                                                                          //nolint:lll
+			Template:                  "{{.StatusIcon}} {{.ReadingAge}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            "",
 			ExpectedEnabled:           false,
 		},
 		{
-			Case: "Conditioning Status",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Conditioning","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":19.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + `,"type":"manual"}, {"id":"manual","temp":21,"comment":"","sg":1.063,"time":` + FakeReading2DateString + `,"type":"manual"}, {"id":"manual","temp":15,"comment":"","sg":1.050,"time":` + FakeReading3DateString + `,"type":"manual"}]`, //nolint:lll
-			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}",                                                                       //nolint:lll
+			Case:                      "Conditioning Status",
+			BatchJSONResponse:         `{"batchNo":18,"status":"Conditioning","brewDate":` + jsonFiller,                                                                                                                                                                                          //nolint:lll
+			BatchReadingsJSONResponse: batchReadingJSON + FakeReading1DateString + batchReadingJSON2 + FakeReading2DateString + batchReadingJSON3 + FakeReading3DateString + manualType,                                                                                                          //nolint:lll
+			Template:                  "{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}", //nolint:lll
 			ExpectedString:            " 5d Fake Beer 1.3%",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Fermenting Status, test all unit conversions",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Fermenting","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":34.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + `,"type":"manual"}]`,
+			Case:                      "Fermenting Status, test all unit conversions",
+			BatchJSONResponse:         batchNumberFermenting + jsonFiller,
+			BatchReadingsJSONResponse: `[{"id":"manual","temp":34.5,"comment":"","sg":1.066,"time":` + FakeReading1DateString + manualType,
 			Template:                  "{{ if and (.Reading) (eq .Status \"Fermenting\") }}SG: ({{.Reading.Gravity}} Bx:{{.SGToBrix .Reading.Gravity}} P:{{.SGToPlato .Reading.Gravity}}), Temp: (C:{{.Reading.Temperature}} F:{{.DegCToF .Reading.Temperature}} K:{{.DegCToKelvin .Reading.Temperature}}){{end}}", //nolint:lll
 			ExpectedString:            "SG: (1.066 Bx:16.13 P:16.13), Temp: (C:34.5 F:94.1 K:307.7)",
 			ExpectedEnabled:           true,
 		},
 		{
-			Case: "Fermenting Status, test all unit conversions 2",
-			BatchJSONResponse: `
-			{"batchNo":18,"status":"Fermenting","brewDate":` + FakeBrewDateString + `,"bottlingDate":` + FakeBottlingDateString + `,"recipe":{"name":"Fake Beer"},"fermentationStartDate":` + FakeFermStartDateString + `,"name":"Batch","measuredAbv": 1.3}`, //nolint:lll
-			BatchReadingsJSONResponse: `[{"id":"manual","temp":3.5,"comment":"","sg":1.004,"time":` + FakeReading1DateString + `,"type":"manual"}]`,
+			Case:                      "Fermenting Status, test all unit conversions 2",
+			BatchJSONResponse:         batchNumberFermenting + jsonFiller,
+			BatchReadingsJSONResponse: `[{"id":"manual","temp":3.5,"comment":"","sg":1.004,"time":` + FakeReading1DateString + manualType,
 			Template:                  "{{ if and (.Reading) (eq .Status \"Fermenting\") }}SG: ({{.Reading.Gravity}} Bx:{{.SGToBrix .Reading.Gravity}} P:{{.SGToPlato .Reading.Gravity}}), Temp: (C:{{.Reading.Temperature}} F:{{.DegCToF .Reading.Temperature}} K:{{.DegCToKelvin .Reading.Temperature}}){{end}}", //nolint:lll
 			ExpectedString:            "SG: (1.004 Bx:1.03 P:1.03), Temp: (C:3.5 F:38.3 K:276.7)",
 			ExpectedEnabled:           true,
diff --git a/src/segments/git_test.go b/src/segments/git_test.go
index 80710927..5a95be67 100644
--- a/src/segments/git_test.go
+++ b/src/segments/git_test.go
@@ -18,7 +18,9 @@ import (
 )
 
 const (
-	branchName = "main"
+	branchName      = "main"
+	dotGit          = "dev/.git"
+	dotGitSubmodule = "dev/.git/modules/submodule"
 )
 
 func TestEnabledGitNotFound(t *testing.T) {
@@ -88,23 +90,23 @@ func TestEnabledInWorktree(t *testing.T) {
 			WorkingFolderContent:  TestRootPath + "dev/worktree.git\n",
 			ExpectedWorkingFolder: TestRootPath + "dev/.git/worktrees/folder_worktree",
 			ExpectedRealFolder:    TestRootPath + "dev/worktree",
-			ExpectedRootFolder:    TestRootPath + "dev/.git",
+			ExpectedRootFolder:    TestRootPath + dotGit,
 		},
 		{
 			Case:                  "submodule",
 			ExpectedEnabled:       true,
 			WorkingFolder:         "./.git/modules/submodule",
-			ExpectedWorkingFolder: TestRootPath + "dev/.git/modules/submodule",
-			ExpectedRealFolder:    TestRootPath + "dev/.git/modules/submodule",
-			ExpectedRootFolder:    TestRootPath + "dev/.git/modules/submodule",
+			ExpectedWorkingFolder: TestRootPath + dotGitSubmodule,
+			ExpectedRealFolder:    TestRootPath + dotGitSubmodule,
+			ExpectedRootFolder:    TestRootPath + dotGitSubmodule,
 		},
 		{
 			Case:                  "submodule with root working folder",
 			ExpectedEnabled:       true,
-			WorkingFolder:         TestRootPath + "repo/.git/modules/submodule",
-			ExpectedWorkingFolder: TestRootPath + "repo/.git/modules/submodule",
-			ExpectedRealFolder:    TestRootPath + "repo/.git/modules/submodule",
-			ExpectedRootFolder:    TestRootPath + "repo/.git/modules/submodule",
+			WorkingFolder:         TestRootPath + dotGitSubmodule,
+			ExpectedWorkingFolder: TestRootPath + dotGitSubmodule,
+			ExpectedRealFolder:    TestRootPath + dotGitSubmodule,
+			ExpectedRootFolder:    TestRootPath + dotGitSubmodule,
 		},
 		{
 			Case:                  "submodule with worktrees",
@@ -126,12 +128,12 @@ func TestEnabledInWorktree(t *testing.T) {
 		},
 	}
 	fileInfo := &platform.FileInfo{
-		Path:         TestRootPath + "dev/.git",
+		Path:         TestRootPath + dotGit,
 		ParentFolder: TestRootPath + "dev",
 	}
 	for _, tc := range cases {
 		env := new(mock.MockedEnvironment)
-		env.On("FileContent", TestRootPath+"dev/.git").Return(fmt.Sprintf("gitdir: %s", tc.WorkingFolder))
+		env.On("FileContent", TestRootPath+dotGit).Return(fmt.Sprintf("gitdir: %s", tc.WorkingFolder))
 		env.On("FileContent", filepath.Join(tc.WorkingFolder, tc.WorkingFolderAddon)).Return(tc.WorkingFolderContent)
 		env.On("HasFilesInDir", tc.WorkingFolder, tc.WorkingFolderAddon).Return(true)
 		env.On("HasFilesInDir", tc.WorkingFolder, "HEAD").Return(true)
diff --git a/src/segments/kubectl_test.go b/src/segments/kubectl_test.go
index 99713563..43130de5 100644
--- a/src/segments/kubectl_test.go
+++ b/src/segments/kubectl_test.go
@@ -13,7 +13,10 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-const testKubectlAllInfoTemplate = "{{.Context}} :: {{.Namespace}} :: {{.User}} :: {{.Cluster}}"
+const (
+	testKubectlAllInfoTemplate = "{{.Context}} :: {{.Namespace}} :: {{.User}} :: {{.Cluster}}"
+	contextMarker              = "currentcontextmarker"
+)
 
 func TestKubectlSegment(t *testing.T) {
 	standardTemplate := "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}"
@@ -40,7 +43,7 @@ func TestKubectlSegment(t *testing.T) {
 			Case:            "kubeconfig incomplete",
 			Template:        testKubectlAllInfoTemplate,
 			ParseKubeConfig: true,
-			Kubeconfig:      "currentcontextmarker" + lsep + "contextdefinitionincomplete",
+			Kubeconfig:      contextMarker + lsep + "contextdefinitionincomplete",
 			Files:           testKubeConfigFiles,
 			ExpectedString:  "ctx ::  ::  ::",
 			ExpectedEnabled: true,
@@ -101,7 +104,7 @@ func TestKubectlSegment(t *testing.T) {
 			Case:            "kubeconfig multiple current marker first",
 			Template:        testKubectlAllInfoTemplate,
 			ParseKubeConfig: true,
-			Kubeconfig:      "" + lsep + "currentcontextmarker" + lsep + "contextdefinition" + lsep + "contextredefinition",
+			Kubeconfig:      "" + lsep + contextMarker + lsep + "contextdefinition" + lsep + "contextredefinition",
 			Files:           testKubeConfigFiles,
 			ExpectedString:  "ctx :: ns :: usr :: cl",
 			ExpectedEnabled: true,
@@ -109,7 +112,7 @@ func TestKubectlSegment(t *testing.T) {
 		{
 			Case:     "kubeconfig multiple context first",
 			Template: testKubectlAllInfoTemplate, ParseKubeConfig: true,
-			Kubeconfig:      "contextdefinition" + lsep + "contextredefinition" + lsep + "currentcontextmarker" + lsep,
+			Kubeconfig:      "contextdefinition" + lsep + "contextredefinition" + lsep + contextMarker + lsep,
 			Files:           testKubeConfigFiles,
 			ExpectedString:  "ctx :: ns :: usr :: cl",
 			ExpectedEnabled: true,
@@ -185,7 +188,7 @@ contexts:
       namespace: ns
     name: ctx
 `,
-	"currentcontextmarker": `
+	contextMarker: `
 apiVersion: v1
 current-context: ctx
 `,
diff --git a/src/segments/path_test.go b/src/segments/path_test.go
index 3b3ab94a..8decb2fd 100644
--- a/src/segments/path_test.go
+++ b/src/segments/path_test.go
@@ -14,6 +14,15 @@ import (
 	mock2 "github.com/stretchr/testify/mock"
 )
 
+const (
+	homeDir        = "/home/someone"
+	homeDirWindows = "C:\\Users\\someone"
+	fooBarMan      = "\\foo\\bar\\man"
+	abc            = "/abc"
+	abcd           = "/a/b/c/d"
+	cdefg          = "/c/d/e/f/g"
+)
+
 func renderTemplateNoTrimSpace(env *mock.MockedEnvironment, segmentTemplate string, context any) string {
 	found := false
 	for _, call := range env.Mock.ExpectedCalls {
@@ -46,11 +55,6 @@ func renderTemplate(env *mock.MockedEnvironment, segmentTemplate string, context
 	return strings.TrimSpace(renderTemplateNoTrimSpace(env, segmentTemplate, context))
 }
 
-const (
-	homeDir        = "/home/someone"
-	homeDirWindows = "C:\\Users\\someone"
-)
-
 func TestParent(t *testing.T) {
 	cases := []struct {
 		Case                string
@@ -529,7 +533,7 @@ func TestAgnosterPathStyles(t *testing.T) {
 			Style:               AgnosterShort,
 			Expected:            ".. > bar > man",
 			HomePath:            homeDirWindows,
-			Pwd:                 homeDirWindows + "\\foo\\bar\\man",
+			Pwd:                 homeDirWindows + fooBarMan,
 			GOOS:                platform.WINDOWS,
 			PathSeparator:       "\\",
 			FolderSeparatorIcon: " > ",
@@ -677,7 +681,7 @@ func TestAgnosterPathStyles(t *testing.T) {
 			Style:               AgnosterShort,
 			Expected:            "~ > .. > bar > man",
 			HomePath:            homeDirWindows,
-			Pwd:                 homeDirWindows + "\\foo\\bar\\man",
+			Pwd:                 homeDirWindows + fooBarMan,
 			GOOS:                platform.WINDOWS,
 			PathSeparator:       "\\",
 			FolderSeparatorIcon: " > ",
@@ -687,7 +691,7 @@ func TestAgnosterPathStyles(t *testing.T) {
 			Style:               AgnosterShort,
 			Expected:            "~ > foo > bar > man",
 			HomePath:            homeDirWindows,
-			Pwd:                 homeDirWindows + "\\foo\\bar\\man",
+			Pwd:                 homeDirWindows + fooBarMan,
 			GOOS:                platform.WINDOWS,
 			PathSeparator:       "\\",
 			FolderSeparatorIcon: " > ",
@@ -774,26 +778,26 @@ func TestFullAndFolderPath(t *testing.T) {
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", Expected: "/"},
 		{Style: Full, Pwd: "/", Expected: "/"},
 		{Style: Full, Pwd: homeDir, Expected: "~"},
-		{Style: Full, Pwd: homeDir + "/abc", Expected: "~/abc"},
-		{Style: Full, Pwd: homeDir + "/abc", Expected: homeDir + "/abc", DisableMappedLocations: true},
-		{Style: Full, Pwd: "/a/b/c/d", Expected: "/a/b/c/d"},
+		{Style: Full, Pwd: homeDir + abc, Expected: "~/abc"},
+		{Style: Full, Pwd: homeDir + abc, Expected: homeDir + abc, DisableMappedLocations: true},
+		{Style: Full, Pwd: abcd, Expected: abcd},
 
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "~"},
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "/home|someone", DisableMappedLocations: true},
-		{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir + "/abc", Expected: "~|abc"},
-		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/a/b/c/d", Expected: "/a|b|c|d"},
+		{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir + abc, Expected: "~|abc"},
+		{Style: Full, FolderSeparatorIcon: "|", Pwd: abcd, Expected: "/a|b|c|d"},
 
 		{Style: Folder, Pwd: "/", Expected: "/"},
 		{Style: Folder, Pwd: homeDir, Expected: "~"},
 		{Style: Folder, Pwd: homeDir, Expected: "someone", DisableMappedLocations: true},
-		{Style: Folder, Pwd: homeDir + "/abc", Expected: "abc"},
-		{Style: Folder, Pwd: "/a/b/c/d", Expected: "d"},
+		{Style: Folder, Pwd: homeDir + abc, Expected: "abc"},
+		{Style: Folder, Pwd: abcd, Expected: "d"},
 
 		{Style: Folder, FolderSeparatorIcon: "|", Pwd: "/", Expected: "/"},
 		{Style: Folder, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "~"},
 		{Style: Folder, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "someone", DisableMappedLocations: true},
-		{Style: Folder, FolderSeparatorIcon: "|", Pwd: homeDir + "/abc", Expected: "abc"},
-		{Style: Folder, FolderSeparatorIcon: "|", Pwd: "/a/b/c/d", Expected: "d"},
+		{Style: Folder, FolderSeparatorIcon: "|", Pwd: homeDir + abc, Expected: "abc"},
+		{Style: Folder, FolderSeparatorIcon: "|", Pwd: abcd, Expected: "d"},
 
 		// for Windows paths
 		{Style: Folder, FolderSeparatorIcon: "\\", Pwd: "C:\\", Expected: "C:\\", PathSeparator: "\\", GOOS: platform.WINDOWS},
@@ -806,41 +810,41 @@ func TestFullAndFolderPath(t *testing.T) {
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: 2, Expected: "2 /"},
 		{Style: Full, Pwd: "/", StackCount: 2, Expected: "2 /"},
 		{Style: Full, Pwd: homeDir, StackCount: 2, Expected: "2 ~"},
-		{Style: Full, Pwd: homeDir + "/abc", StackCount: 2, Expected: "2 ~/abc"},
-		{Style: Full, Pwd: homeDir + "/abc", StackCount: 2, Expected: "2 " + homeDir + "/abc", DisableMappedLocations: true},
-		{Style: Full, Pwd: "/a/b/c/d", StackCount: 2, Expected: "2 /a/b/c/d"},
+		{Style: Full, Pwd: homeDir + abc, StackCount: 2, Expected: "2 ~/abc"},
+		{Style: Full, Pwd: homeDir + abc, StackCount: 2, Expected: "2 " + homeDir + abc, DisableMappedLocations: true},
+		{Style: Full, Pwd: abcd, StackCount: 2, Expected: "2 /a/b/c/d"},
 
 		// StackCountEnabled=false and StackCount=2
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", Template: "{{ .Path }}", StackCount: 2, Expected: "/"},
 		{Style: Full, Pwd: "/", Template: "{{ .Path }}", StackCount: 2, Expected: "/"},
 		{Style: Full, Pwd: homeDir, Template: "{{ .Path }}", StackCount: 2, Expected: "~"},
 
-		{Style: Full, Pwd: homeDir + "/abc", Template: "{{ .Path }}", StackCount: 2, Expected: homeDir + "/abc", DisableMappedLocations: true},
-		{Style: Full, Pwd: "/a/b/c/d", Template: "{{ .Path }}", StackCount: 2, Expected: "/a/b/c/d"},
+		{Style: Full, Pwd: homeDir + abc, Template: "{{ .Path }}", StackCount: 2, Expected: homeDir + abc, DisableMappedLocations: true},
+		{Style: Full, Pwd: abcd, Template: "{{ .Path }}", StackCount: 2, Expected: abcd},
 
 		// StackCountEnabled=true and StackCount=0
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: 0, Expected: "/"},
 		{Style: Full, Pwd: "/", StackCount: 0, Expected: "/"},
 		{Style: Full, Pwd: homeDir, StackCount: 0, Expected: "~"},
-		{Style: Full, Pwd: homeDir + "/abc", StackCount: 0, Expected: "~/abc"},
-		{Style: Full, Pwd: homeDir + "/abc", StackCount: 0, Expected: homeDir + "/abc", DisableMappedLocations: true},
-		{Style: Full, Pwd: "/a/b/c/d", StackCount: 0, Expected: "/a/b/c/d"},
+		{Style: Full, Pwd: homeDir + abc, StackCount: 0, Expected: "~/abc"},
+		{Style: Full, Pwd: homeDir + abc, StackCount: 0, Expected: homeDir + abc, DisableMappedLocations: true},
+		{Style: Full, Pwd: abcd, StackCount: 0, Expected: abcd},
 
 		// StackCountEnabled=true and StackCount<0
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: -1, Expected: "/"},
 		{Style: Full, Pwd: "/", StackCount: -1, Expected: "/"},
 		{Style: Full, Pwd: homeDir, StackCount: -1, Expected: "~"},
-		{Style: Full, Pwd: homeDir + "/abc", StackCount: -1, Expected: "~/abc"},
-		{Style: Full, Pwd: homeDir + "/abc", StackCount: -1, Expected: homeDir + "/abc", DisableMappedLocations: true},
-		{Style: Full, Pwd: "/a/b/c/d", StackCount: -1, Expected: "/a/b/c/d"},
+		{Style: Full, Pwd: homeDir + abc, StackCount: -1, Expected: "~/abc"},
+		{Style: Full, Pwd: homeDir + abc, StackCount: -1, Expected: homeDir + abc, DisableMappedLocations: true},
+		{Style: Full, Pwd: abcd, StackCount: -1, Expected: abcd},
 
 		// StackCountEnabled=true and StackCount not set
 		{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", Expected: "/"},
 		{Style: Full, Pwd: "/", Expected: "/"},
 		{Style: Full, Pwd: homeDir, Expected: "~"},
-		{Style: Full, Pwd: homeDir + "/abc", Expected: "~/abc"},
-		{Style: Full, Pwd: homeDir + "/abc", Expected: homeDir + "/abc", DisableMappedLocations: true},
-		{Style: Full, Pwd: "/a/b/c/d", Expected: "/a/b/c/d"},
+		{Style: Full, Pwd: homeDir + abc, Expected: "~/abc"},
+		{Style: Full, Pwd: homeDir + abc, Expected: homeDir + abc, DisableMappedLocations: true},
+		{Style: Full, Pwd: abcd, Expected: abcd},
 	}
 
 	for _, tc := range cases {
@@ -895,14 +899,14 @@ func TestFullPathCustomMappedLocations(t *testing.T) {
 		PathSeparator   string
 		Expected        string
 	}{
-		{Pwd: "/a/b/c/d", MappedLocations: map[string]string{"{{ .Env.HOME }}/d": "#"}, Expected: "#"},
-		{Pwd: "/a/b/c/d", MappedLocations: map[string]string{"/a/b/c/d": "#"}, Expected: "#"},
+		{Pwd: abcd, MappedLocations: map[string]string{"{{ .Env.HOME }}/d": "#"}, Expected: "#"},
+		{Pwd: abcd, MappedLocations: map[string]string{abcd: "#"}, Expected: "#"},
 		{Pwd: "\\a\\b\\c\\d", MappedLocations: map[string]string{"\\a\\b": "#"}, GOOS: platform.WINDOWS, PathSeparator: "\\", Expected: "#\\c\\d"},
-		{Pwd: "/a/b/c/d", MappedLocations: map[string]string{"/a/b": "#"}, Expected: "#/c/d"},
-		{Pwd: "/a/b/c/d", MappedLocations: map[string]string{"/a/b": "/e/f"}, Expected: "/e/f/c/d"},
-		{Pwd: homeDir + "/a/b/c/d", MappedLocations: map[string]string{"~/a/b": "#"}, Expected: "#/c/d"},
+		{Pwd: abcd, MappedLocations: map[string]string{"/a/b": "#"}, Expected: "#/c/d"},
+		{Pwd: abcd, MappedLocations: map[string]string{"/a/b": "/e/f"}, Expected: "/e/f/c/d"},
+		{Pwd: homeDir + abcd, MappedLocations: map[string]string{"~/a/b": "#"}, Expected: "#/c/d"},
 		{Pwd: "/a" + homeDir + "/b/c/d", MappedLocations: map[string]string{"/a~": "#"}, Expected: "/a" + homeDir + "/b/c/d"},
-		{Pwd: homeDir + "/a/b/c/d", MappedLocations: map[string]string{"/a/b": "#"}, Expected: homeDir + "/a/b/c/d"},
+		{Pwd: homeDir + abcd, MappedLocations: map[string]string{"/a/b": "#"}, Expected: homeDir + abcd},
 	}
 
 	for _, tc := range cases {
@@ -975,7 +979,7 @@ func TestPowerlevelMappedLocations(t *testing.T) {
 }
 
 func TestFolderPathCustomMappedLocations(t *testing.T) {
-	pwd := "/a/b/c/d"
+	pwd := abcd
 	env := new(mock.MockedEnvironment)
 	env.On("PathSeparator").Return("/")
 	env.On("Home").Return(homeDir)
@@ -992,7 +996,7 @@ func TestFolderPathCustomMappedLocations(t *testing.T) {
 		props: properties.Map{
 			properties.Style: Folder,
 			MappedLocations: map[string]string{
-				"/a/b/c/d": "#",
+				abcd: "#",
 			},
 		},
 	}
@@ -1349,16 +1353,16 @@ func TestGetPwd(t *testing.T) {
 		{MappedLocationsEnabled: true, Pwd: homeDir + "-test", Expected: homeDir + "-test"},
 		{MappedLocationsEnabled: true},
 		{MappedLocationsEnabled: true, Pwd: "/usr", Expected: "/usr"},
-		{MappedLocationsEnabled: true, Pwd: homeDir + "/abc", Expected: "~/abc"},
-		{MappedLocationsEnabled: true, Pwd: "/a/b/c/d", Expected: "#"},
+		{MappedLocationsEnabled: true, Pwd: homeDir + abc, Expected: "~/abc"},
+		{MappedLocationsEnabled: true, Pwd: abcd, Expected: "#"},
 		{MappedLocationsEnabled: true, Pwd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
 		{MappedLocationsEnabled: true, Pwd: "/z/y/x/w", Expected: "/z/y/x/w"},
 
 		{MappedLocationsEnabled: false},
-		{MappedLocationsEnabled: false, Pwd: homeDir + "/abc", Expected: homeDir + "/abc"},
+		{MappedLocationsEnabled: false, Pwd: homeDir + abc, Expected: homeDir + abc},
 		{MappedLocationsEnabled: false, Pwd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
-		{MappedLocationsEnabled: false, Pwd: homeDir + "/c/d/e/f/g", Expected: homeDir + "/c/d/e/f/g"},
-		{MappedLocationsEnabled: true, Pwd: homeDir + "/c/d/e/f/g", Expected: "~/c/d/e/f/g"},
+		{MappedLocationsEnabled: false, Pwd: homeDir + cdefg, Expected: homeDir + cdefg},
+		{MappedLocationsEnabled: true, Pwd: homeDir + cdefg, Expected: "~/c/d/e/f/g"},
 
 		{MappedLocationsEnabled: true, Pwd: "/w/d/x/w", Pswd: "/z/y/x/w", Expected: "/z/y/x/w"},
 		{MappedLocationsEnabled: false, Pwd: "/f/g/k/d/e/f/g", Pswd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
@@ -1381,7 +1385,7 @@ func TestGetPwd(t *testing.T) {
 			props: properties.Map{
 				MappedLocationsEnabled: tc.MappedLocationsEnabled,
 				MappedLocations: map[string]string{
-					"/a/b/c/d": "#",
+					abcd: "#",
 				},
 			},
 		}
@@ -1468,7 +1472,7 @@ func TestReplaceMappedLocations(t *testing.T) {
 		{Pwd: "/c/l/k/f", Expected: "f"},
 		{Pwd: "/f/g/h", Expected: "/f/g/h"},
 		{Pwd: "/f/g/h/e", Expected: "^/e"},
-		{Pwd: "/a/b/c/d", Expected: "#"},
+		{Pwd: abcd, Expected: "#"},
 		{Pwd: "/a/b/c/d/e", Expected: "#/e"},
 		{Pwd: "/a/b/c/d/e", Expected: "#/e"},
 		{Pwd: "/a/b/k/j/e", Expected: "e"},
@@ -1487,7 +1491,7 @@ func TestReplaceMappedLocations(t *testing.T) {
 			props: properties.Map{
 				MappedLocationsEnabled: false,
 				MappedLocations: map[string]string{
-					"/a/b/c/d": "#",
+					abcd:       "#",
 					"/f/g/h/*": "^",
 					"/c/l/k/*": "",
 					"~/j/*":    "",
diff --git a/src/segments/umbraco_test.go b/src/segments/umbraco_test.go
new file mode 100644
index 00000000..c26deead
--- /dev/null
+++ b/src/segments/umbraco_test.go
@@ -0,0 +1,128 @@
+package segments
+
+import (
+	"errors"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/jandedobbeleer/oh-my-posh/src/mock"
+	"github.com/jandedobbeleer/oh-my-posh/src/platform"
+
+	"github.com/stretchr/testify/assert"
+	mock2 "github.com/stretchr/testify/mock"
+)
+
+func TestUmbracoSegment(t *testing.T) {
+	cases := []struct {
+		Case             string
+		ExpectedEnabled  bool
+		ExpectedString   string
+		Template         string
+		HasUmbracoFolder bool
+		HasCsproj        bool
+		HasWebConfig     bool
+	}{
+		{
+			Case:             "No Umbraco folder found",
+			HasUmbracoFolder: false,
+			ExpectedEnabled:  false, // Segment should not be enabled
+		},
+		{
+			Case:             "Umbraco Folder but NO web.config or .csproj",
+			HasUmbracoFolder: true,
+			HasCsproj:        false,
+			HasWebConfig:     false,
+			ExpectedEnabled:  false, // Segment should not be enabled
+		},
+		{
+			Case:             "Umbraco Folder and web.config but NO .csproj",
+			HasUmbracoFolder: true,
+			HasCsproj:        false,
+			HasWebConfig:     true,
+			ExpectedEnabled:  true, // Segment should be enabled and visible
+			Template:         "{{ .Version }}",
+			ExpectedString:   "8.18.9",
+		},
+		{
+			Case:             "Umbraco Folder and .csproj but NO web.config",
+			HasUmbracoFolder: true,
+			HasCsproj:        true,
+			HasWebConfig:     false,
+			ExpectedEnabled:  true, // Segment should be enabled and visible
+			Template:         "{{ .Version }}",
+			ExpectedString:   "12.1.2",
+		},
+		{
+			Case:             "Umbraco Folder and .csproj with custom template",
+			HasUmbracoFolder: true,
+			HasCsproj:        true,
+			ExpectedEnabled:  true,
+			Template:         "Version:{{ .Version }} ModernUmbraco:{{ .Modern }}",
+			ExpectedString:   "Version:12.1.2 ModernUmbraco:true",
+		},
+	}
+
+	for _, tc := range cases {
+		// Prepare/arrange the test
+		env := new(mock.MockedEnvironment)
+		var sampleCSProj, sampleWebConfig string
+
+		if tc.HasCsproj {
+			content, _ := os.ReadFile("../test/umbraco/MyProject.csproj")
+			sampleCSProj = string(content)
+		}
+		if tc.HasWebConfig {
+			content, _ := os.ReadFile("../test/umbraco/web.config")
+			sampleWebConfig = string(content)
+		}
+
+		const umbracoProjectDirectory = "/workspace/MyProject"
+		env.On("Pwd").Return(umbracoProjectDirectory)
+		env.On("FileContent", filepath.Join(umbracoProjectDirectory, "MyProject.csproj")).Return(sampleCSProj)
+		env.On("FileContent", filepath.Join(umbracoProjectDirectory, "web.config")).Return(sampleWebConfig)
+		env.On("Debug", mock2.Anything)
+
+		if tc.HasUmbracoFolder {
+			fileInfo := &platform.FileInfo{
+				Path:         "/workspace/MyProject/Umbraco",
+				ParentFolder: "/workspace/MyProject",
+				IsDir:        true,
+			}
+
+			env.On("HasParentFilePath", "umbraco").Return(fileInfo, nil)
+		} else {
+			env.On("HasParentFilePath", "Umbraco").Return(&platform.FileInfo{}, errors.New("no such file or directory"))
+			env.On("HasParentFilePath", "umbraco").Return(&platform.FileInfo{}, errors.New("no such file or directory"))
+		}
+
+		dirEntries := []fs.DirEntry{}
+		if tc.HasCsproj {
+			dirEntries = append(dirEntries, &MockDirEntry{
+				name:  "MyProject.csproj",
+				isDir: false,
+			})
+		}
+
+		if tc.HasWebConfig {
+			dirEntries = append(dirEntries, &MockDirEntry{
+				name:  "web.config",
+				isDir: false,
+			})
+		}
+
+		env.On("LsDir", umbracoProjectDirectory).Return(dirEntries)
+
+		// Setup the Umbraco segment with the mocked environment & properties
+		umb := &Umbraco{
+			env: env,
+		}
+
+		// Assert the test results
+		// Check if the segment should be enabled and
+		// the rendered string matches what we expect when specifying a template for the segment
+		assert.Equal(t, tc.ExpectedEnabled, umb.Enabled(), tc.Case)
+		assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, umb), tc.Case)
+	}
+}
diff --git a/src/test/umbraco/MyProject.csproj b/src/test/umbraco/MyProject.csproj
new file mode 100644
index 00000000..9f990a6e
--- /dev/null
+++ b/src/test/umbraco/MyProject.csproj
@@ -0,0 +1,35 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+    <PropertyGroup>
+        <TargetFramework>net7.0</TargetFramework>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <PackageReference Include="uMarketingSuite" Version="1.23.0" />
+        <PackageReference Include="Umbraco.TheStarterKit" Version="11.0.0" />
+        <PackageReference Include="Umbraco.Cms" Version="12.1.2" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <!-- Opt-in to app-local ICU to ensure consistent globalization APIs across different platforms -->
+        <PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9"/>
+        <RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2.0.9" Condition="$(RuntimeIdentifier.StartsWith('linux')) or $(RuntimeIdentifier.StartsWith('win')) or ('$(RuntimeIdentifier)' == '' and !$([MSBuild]::IsOSPlatform('osx')))"/>
+    </ItemGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\uMarketingSuite.StarterKit\uMarketingSuite.StarterKit.csproj" />
+    </ItemGroup>
+
+    <PropertyGroup>
+        <!-- Razor files are needed for the backoffice to work correctly -->
+        <CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>
+    </PropertyGroup>
+
+    <PropertyGroup>
+        <!-- Remove RazorCompileOnBuild and RazorCompileOnPublish when not using ModelsMode InMemoryAuto -->
+        <RazorCompileOnBuild>false</RazorCompileOnBuild>
+        <RazorCompileOnPublish>false</RazorCompileOnPublish>
+    </PropertyGroup>
+
+</Project>
diff --git a/src/test/umbraco/web.config b/src/test/umbraco/web.config
new file mode 100644
index 00000000..7cb15417
--- /dev/null
+++ b/src/test/umbraco/web.config
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+    <!--
+        Define the Web.config template, which is used when creating the initial Web.config,
+        and then transforms from web.Template.[Debug|Release].config are applied.
+        Documentation for Web.config at: https://our.umbraco.com/documentation/Reference/Config/webconfig/
+    -->
+
+    <configSections>
+        <section name="clientDependency" type="ClientDependency.Core.Config.ClientDependencySection, ClientDependency.Core" requirePermission="false"/>
+
+        <sectionGroup name="umbracoConfiguration">
+            <section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core" requirePermission="false"/>
+            <section name="HealthChecks" type="Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Core" requirePermission="false"/>
+        </sectionGroup>
+
+        <sectionGroup name="imageProcessor">
+            <section name="security" requirePermission="false" type="ImageProcessor.Web.Configuration.ImageSecuritySection, ImageProcessor.Web"/>
+            <section name="processing" requirePermission="false" type="ImageProcessor.Web.Configuration.ImageProcessingSection, ImageProcessor.Web"/>
+            <section name="caching" requirePermission="false" type="ImageProcessor.Web.Configuration.ImageCacheSection, ImageProcessor.Web"/>
+        </sectionGroup>
+    </configSections>
+
+    <umbracoConfiguration>
+        <settings configSource="config\umbracoSettings.config"/>
+        <HealthChecks configSource="config\HealthChecks.config"/>
+    </umbracoConfiguration>
+
+    <clientDependency configSource="config\ClientDependency.config"/>
+
+    <appSettings>
+        <add key="Umbraco.Core.ConfigurationStatus" value="8.18.9"/>
+        <add key="Umbraco.Core.ReservedUrls" value=""/>
+        <add key="Umbraco.Core.ReservedPaths" value=""/>
+        <add key="Umbraco.Core.Path" value="~/umbraco"/>
+        <add key="Umbraco.Core.HideTopLevelNodeFromPath" value="true"/>
+        <add key="Umbraco.Core.TimeOutInMinutes" value="20"/>
+        <add key="Umbraco.Core.DefaultUILanguage" value="en-US"/>
+        <add key="Umbraco.Core.UseHttps" value="false"/>
+        <add key="Umbraco.Core.AllowContentDashboardAccessToAllUsers" value="true"/>
+        <add key="Umbraco.Core.ContentDashboardUrl-Allowlist" value=""/>
+        <add key="Umbraco.Core.HelpPage-Allowlist" value=""/>
+
+        <add key="ValidationSettings:UnobtrusiveValidationMode" value="None"/>
+        <add key="webpages:Enabled" value="false"/>
+        <add key="enableSimpleMembership" value="false"/>
+        <add key="autoFormsAuthentication" value="false"/>
+        <add key="dataAnnotations:dataTypeAttribute:disableRegEx" value="false"/>
+
+        <add key="owin:appStartup" value="UmbracoDefaultOwinStartup"/>
+
+        <add key="Umbraco.ModelsBuilder.Enable" value="true"/>
+        <add key="Umbraco.ModelsBuilder.ModelsMode" value="PureLive"/>
+        <add key="Umbraco.Web.PublishedCache.NuCache.Serializer" value="MsgPack"/>
+        <add key="Umbraco.Web.SanitizeTinyMce" value="true"/>
+    </appSettings>
+
+    <!--
+        Important: if you're upgrading Umbraco, do not clear the connectionString/providerName during your Web.config merge.
+    -->
+    <connectionStrings>
+        <remove name="umbracoDbDSN"/>
+        <add name="umbracoDbDSN" connectionString="" providerName=""/>
+    </connectionStrings>
+
+    <system.data>
+        <DbProviderFactories>
+            <remove invariant="System.Data.SqlServerCe.4.0"/>
+            <add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0"
+                description=".NET Framework Data Provider for Microsoft SQL Server Compact"
+                type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe"/>
+        </DbProviderFactories>
+    </system.data>
+
+    <system.net>
+        <mailSettings>
+            <!--
+                If you need Umbraco to send out system mails (like reset password and invite user),
+                you must configure your SMTP settings here - for example:
+            -->
+            <!--
+            <smtp from="noreply@example.com" deliveryMethod="Network">
+                <network host="localhost" port="25" enableSsl="false" userName="" password="" />
+            </smtp>
+            -->
+        </mailSettings>
+    </system.net>
+
+    <system.web>
+        <customErrors mode="RemoteOnly"/>
+
+        <trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true"/>
+
+        <httpRuntime requestValidationMode="2.0" enableVersionHeader="false" targetFramework="4.7.2" maxRequestLength="51200" fcnMode="Single"/>
+
+        <httpModules>
+            <add name="ScriptModule"
+                type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+            <add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,Umbraco.Web"/>
+            <add name="ClientDependencyModule" type="ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core"/>
+            <add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web"/>
+        </httpModules>
+
+        <httpHandlers>
+            <remove verb="*" path="*.asmx"/>
+            <add verb="*" path="*.asmx"
+                type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
+                validate="false"/>
+            <add verb="*" path="*_AppService.axd"
+                type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
+                validate="false"/>
+            <add verb="GET,HEAD" path="ScriptResource.axd"
+                type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
+                validate="false"/>
+            <add verb="*" path="DependencyHandler.axd" type="ClientDependency.Core.CompositeFiles.CompositeDependencyHandler, ClientDependency.Core "/>
+        </httpHandlers>
+
+        <compilation defaultLanguage="c#" debug="false" batch="true" targetFramework="4.7.2" numRecompilesBeforeAppRestart="50"/>
+
+        <authentication mode="Forms">
+            <forms name="yourAuthCookie" loginUrl="login.aspx" protection="All" path="/"/>
+        </authentication>
+
+        <authorization>
+            <allow users="?"/>
+        </authorization>
+
+        <!-- Membership Provider -->
+        <membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
+            <providers>
+                <clear/>
+                <add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco.Web"
+                    minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="10" useLegacyEncoding="false" enablePasswordRetrieval="false"
+                    enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed"
+                    allowManuallyChangingPassword="false"/>
+                <add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web"/>
+            </providers>
+        </membership>
+
+        <!-- Role Provider -->
+        <roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
+            <providers>
+                <clear/>
+                <add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider"/>
+            </providers>
+        </roleManager>
+
+    </system.web>
+
+    <system.webServer>
+        <validation validateIntegratedModeConfiguration="false"/>
+
+        <modules runAllManagedModulesForAllRequests="true">
+            <remove name="WebDAVModule"/>
+            <remove name="UmbracoModule"/>
+            <remove name="ScriptModule"/>
+            <remove name="ClientDependencyModule"/>
+            <remove name="FormsAuthentication"/>
+            <remove name="ImageProcessorModule"/>
+
+            <add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,Umbraco.Web"/>
+            <add name="ScriptModule" preCondition="managedHandler"
+                type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+            <add name="ClientDependencyModule" type="ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core"/>
+            <!-- FormsAuthentication is needed for login/membership to work on homepage (as per http://stackoverflow.com/questions/218057/httpcontext-current-session-is-null-when-routing-requests) -->
+            <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/>
+            <add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web"/>
+        </modules>
+
+        <handlers accessPolicy="Read, Write, Script, Execute">
+            <remove name="WebServiceHandlerFactory-Integrated"/>
+            <remove name="ScriptHandlerFactory"/>
+            <remove name="ScriptHandlerFactoryAppServices"/>
+            <remove name="ScriptResource"/>
+            <remove name="ClientDependency"/>
+            <remove name="MiniProfiler"/>
+            <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
+            <remove name="OPTIONSVerbHandler"/>
+            <remove name="TRACEVerbHandler"/>
+
+            <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode"
+                type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+            <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode"
+                type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+            <add name="ScriptResource" verb="GET,HEAD" path="ScriptResource.axd" preCondition="integratedMode"
+                type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+            <add verb="*" name="ClientDependency" preCondition="integratedMode" path="DependencyHandler.axd"
+                type="ClientDependency.Core.CompositeFiles.CompositeDependencyHandler, ClientDependency.Core"/>
+            <add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified"
+                preCondition="integratedMode"/>
+            <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler"
+                preCondition="integratedMode,runtimeVersionv4.0"/>
+        </handlers>
+
+        <staticContent>
+            <remove fileExtension=".air"/>
+            <mimeMap fileExtension=".air" mimeType="application/vnd.adobe.air-application-installer-package+zip"/>
+            <remove fileExtension=".svg"/>
+            <mimeMap fileExtension=".svg" mimeType="image/svg+xml"/>
+            <remove fileExtension=".woff"/>
+            <mimeMap fileExtension=".woff" mimeType="font/woff"/>
+            <remove fileExtension=".woff2"/>
+            <mimeMap fileExtension=".woff2" mimeType="font/woff2"/>
+            <remove fileExtension=".less"/>
+            <mimeMap fileExtension=".less" mimeType="text/css"/>
+            <remove fileExtension=".mp4"/>
+            <mimeMap fileExtension=".mp4" mimeType="video/mp4"/>
+            <remove fileExtension=".json"/>
+            <mimeMap fileExtension=".json" mimeType="application/json"/>
+        </staticContent>
+
+        <!-- Ensure the powered by header is not returned -->
+        <httpProtocol>
+            <customHeaders>
+                <remove name="X-Powered-By"/>
+            </customHeaders>
+        </httpProtocol>
+
+        <!-- Increase the default upload file size limit -->
+        <security>
+            <requestFiltering>
+                <requestLimits maxAllowedContentLength="52428800"/>
+            </requestFiltering>
+        </security>
+
+        <!--
+            If you wish to use IIS rewrite rules, see the documentation here: https://our.umbraco.com/documentation/Reference/Routing/IISRewriteRules
+        -->
+        <!--
+        <rewrite>
+            <rules></rules>
+        </rewrite>
+        -->
+    </system.webServer>
+
+    <runtime>
+        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+            <dependentAssembly>
+                <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-1.2.5.0" newVersion="1.2.5.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35"/>
+                <bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+                <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
+                <bindingRedirect oldVersion="4.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
+                <bindingRedirect oldVersion="4.0.0.0-4.0.1.1" newVersion="4.0.1.1"/>
+            </dependentAssembly>
+            <dependentAssembly>
+                <assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+                <bindingRedirect oldVersion="4.0.0.0-4.1.4.0" newVersion="4.1.4.0"/>
+            </dependentAssembly>
+        </assemblyBinding>
+    </runtime>
+
+    <location path="umbraco">
+        <system.webServer>
+            <urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false"/>
+        </system.webServer>
+    </location>
+    <location path="App_Plugins">
+        <system.webServer>
+            <urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false"/>
+        </system.webServer>
+    </location>
+
+    <imageProcessor>
+        <security configSource="config\imageprocessor\security.config"/>
+        <caching configSource="config\imageprocessor\cache.config"/>
+        <processing configSource="config\imageprocessor\processing.config"/>
+    </imageProcessor>
+
+    <system.codedom>
+        <compilers>
+            <compiler language="c#;cs;csharp" extension=".cs"
+                type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
+                warningLevel="4" compilerOptions="/langversion:7 /nowarn:1659;1699;1701"/>
+            <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
+                type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
+                warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
+        </compilers>
+    </system.codedom>
+
+</configuration>