What's new in the Microsoft FluentUI library for Blazor versions 1.3 and 1.4
In this post I'll give you an overview of what's new and changed in versions 1.3 and 1.4 of the Microsoft Fluent UI for Blazor library. Me and the team were so busy with adding exciting new features that I didn't have time to blog about them earlier. I'll describe the features both from an end-user as from a code perspective.
In short, the two big end-user additions (besides some bug fixes) are:
- Fluent UI System Icons support
- Design Token support
And the repository and code changes:
- Add missing xml comments
- Add
FocusAsyncmethods to
Fluent UI System Icons support
The Fluent UI System Icons are a (still growing) collection of familiar, friendly and modern icons from Microsoft. At the moment there are more than 2020 distinct icons available in both filled and outlined versions and in various sizes. In total the collections consists of well over 11k icons in SVG format. All of them have been added to the library in an easy to use way by addition of the
<FluentIcon> component. Just putting this in your .razor page:
<FluentIcon Name=@FluentIcons.Accessibility Size=IconSize.Size32 Filled=true />
Will give you this:
Couple of things to unwrap here on the parameters used:
Nameis a string. To make it easier to select an icon, all names have been added as constants. IntelliSense will help you find the right one. It is also using the new .NET 6
EditorRequiredfeature. If you don't pass a value for the
Name, Visual Studio will point that out to you in design time and raise a compile error when building.
Sizeis using an
enumthat holds all the possible valid sizes. Note the not all sizes are available for all icons. If you get an error at run-time, supply a different size or remove the parameter to fall back to the default size (
Filledis a bool to choose a filled (true) or a regular/outlined (false) version of an icon
Other parameters (not shown in the example above) for this component are:
UseAccentColor (bool). This parameter defaults to
trueand determines if the accent color is used for the fill or the outline when rendering the icon. When setting this to false, the icon will be rendered in black.
NeutralCultureName (string). Some icons offer alternative versions for specific languages. By supplying the two letter neutral language code, you can indicate that you would like to use that specific version of an icon. If there is no language specific version, the component will fall back to rendering the original version. Example:
Neutral @FluentIcons.TextBold iconsFilled:Regular:French @FluentIcons.TextBold icons (
Slot (string). With the slot parameter you can indicate where an icon needs to be rendered in the context of another component. For example when combining a <FluentButton> with a <FluentIcon>, you can use the slot to put the icon in font of the button text:
<FluentButton @onclick="HandleSearch">Search<FluentIcon Name="@FluentIcons.Search" Size="@IconSize.Size16" Filled=false Slot="start"></FluentIcon></FluentButton>(note that the icon component is inserted after the button text) . This will render:
The temporary demo site has a page to search through all the available icons and sizes.
In earlier and other libraries you will often find icons being included by means of fonts. This comes with the disadvantage that the whole font needs to be downloaded even if you are only using 1 icon. I therefore stepped away from using that method in this library and opted for taking the SVG route. Because the icons are SVG files that are stored in the
wwwroot folder in a RCL (Razor Class Library), they are being treated like ordinary static files on the server. They don’t get downloaded until requested and only the icons you are actually using will be downloaded. Sounds like a win-win to me!
Design Token support
The Fluent UI Web Components are built on FAST's Adaptive UI technology, which enables design customization and personalization, while automatically maintaining accessibility. This is accomplished through setting various "Design Tokens". In previous versions of this library, the only way to manipulate the design tokens was through using the
<FluentDesignSystemProvider> component. This Blazor component (and it's underlying Web Component) exposed a little over 60 variables that could be used to change things like typography, color, sizes, UI spacing, etc. FAST has been extended a while ago and now has a much more granular way of working with individual design tokens instead of just through a design system provider model. See https://docs.microsoft.com/en-us/fluent-ui/web-components/design-system/design-tokens for more information on how Design Tokens work.
In total there are now over 160 distinct tokens defined in the Adaptive UI model and as of version 1.4 of this library you can use all these in Blazor as well! The implementation has been in the works for multiple months but I think the end result is quite flexible. It allows for usage both from code as in a declarative way in your .razor pages. The two ways of working with design tokens are described below (taken from the repository readme):
Option 1: Using Design Tokens from C# code
Given the following .razor page fragment:
<FluentButton @ref="ref1" Appearance="Appearance.Filled">A button</FluentButton> <FluentButton @ref="ref2" Appearance="Appearance.Filled">Another button</FluentButton> <FluentButton @ref="ref3" Appearance="Appearance.Filled">And one more</FluentButton> <FluentButton @ref="ref4" Appearance="Appearance.Filled" @onclick=OnClick>Last button</FluentButton>
You can use Design Tokens to manipulate the styles from C# code as follows:
[Inject] private BaseLayerLuminance BaseLayerLuminance { get; set; } = default!; [Inject] private AccentBaseColor AccentBaseColor { get; set; } = default!; [Inject] private BodyFont BodyFont { get; set; } = default!; [Inject] private StrokeWidth StrokeWidth { get; set; } = default!; [Inject] private ControlCornerRadius ControlCornerRadius { get; set; } = default!; private FluentButton? ref1; private FluentButton? ref2; private FluentButton? ref3; private FluentButton? ref4; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { //Set to dark mode await BaseLayerLuminance.SetValueFor(ref1!.Element, (float)0.15); //Set to Excel color await AccentBaseColor.SetValueFor(ref2!.Element, "#185ABD".ToSwatch()); //Set the font await BodyFont.SetValueFor(ref3!.Element, "Comic Sans MS"); //Set 'border' width for ref4 await StrokeWidth.SetValueFor(ref4!.Element, 7); //And change conrner radius as well await ControlCornerRadius.SetValueFor(ref4!.Element, 15); StateHasChanged(); } } public async Task OnClick() { //Remove the wide border await StrokeWidth.DeleteValueFor(ref4!.Element); }
As can be seen in the code above (with the ref4.Element), it is posible to apply multiple tokens to the same component.
For Design Tokens that work with a color value, you must call the ToSwatch() extension method on a string value or use one of the Swatch constructors. This makes sure the color is using a format that Design Tokens can handle. A Swatch has a lot of commonality with the System.Drawing.Color struct. Instead of the values of the components being between 0 and 255, in a Swatch they are expressed as a value between 0 and 1.
The Design Tokens are manipulated through JavaScript interop working with an ElementReference. There is no JavaScript element until after the component is rendered. This means you can only work with the Design Tokens from code after the component has been rendered in OnAfterRenderAsync and not in any earlier lifecycle methods.
Option 2: Using Design Tokens as components
The Design Tokens can also be used as components in a .razor page directely. It looks like this:
<BaseLayerLuminance Value="(float?)0.15"> <FluentCard BackReference="@context"> <div class="contents"> Dark <FluentButton Appearance="Appearance.Accent">Accent</FluentButton> <FluentButton Appearance="Appearance.Stealth">Stealth</FluentButton> <FluentButton Appearance="Appearance.Outline">Outline</FluentButton> <FluentButton Appearance="Appearance.Lightweight">Lightweight</FluentButton> </div> </FluentCard> </BaseLayerLuminance>
To make this work, a link needs to be created between the Design Token component and its child components. This is done with the BackReference="@context" construct.
Only one Design Token component at a time can be used this way. If you need to set more tokens, use the code approach as described in Option 1 above.
Besides these two new options, the original
<FluentDesignSystemProvider> component is still there and can be used as always. There are no plans to remove this anytime soon.
XML Comments
All components and all component parameters now have xml comments. This means that tools who support this, like Visual Studio IntelliSense, will show you information about methods and parameters when editing your razor pages and code, making it a bit easier to discover and understand functionallity:
FocusAsync to FluentInputBase
It was not possible before to programmatically set focus to an
<input> derived component like the
<FluentTextField> or
<FluentNumberField>. The base class
<FluentInputBase> has now been extended to expose this method.


We firmly believe that the internet should be available and accessible to anyone, and are committed to providing a website that is accessible to the widest possible audience, regardless of circumstance and ability.
To fulfill this, we aim to adhere as strictly as possible to the World Wide Web Consortium’s (W3C) Web Content Accessibility Guidelines 2.1 (WCAG 2.1) at the AA level. These guidelines explain how to make web content accessible to people with a wide array of disabilities. Complying with those guidelines helps us ensure that the website is accessible to all people: blind people, people with motor impairments, visual impairment, cognitive disabilities, and more.
This website utilizes various technologies that are meant to make it as accessible as possible at all times. We utilize an accessibility interface that allows persons with specific disabilities to adjust the website’s UI (user interface) and design it to their personal needs.
Additionally, the website utilizes an AI-based application that runs in the background and optimizes its accessibility level constantly. This application remediates the website’s HTML, adapts Its functionality and behavior for screen-readers used by the blind users, and for keyboard functions used by individuals with motor impairments.
If you’ve found a malfunction or have ideas for improvement, we’ll be happy to hear from you. You can reach out to the website’s operators by using the following email info@atasteofky.com
Our website implements the ARIA attributes (Accessible Rich Internet Applications) technique, alongside various different behavioral changes, to ensure blind users visiting with screen-readers are able to read, comprehend, and enjoy the website’s functions. As soon as a user with a screen-reader enters your site, they immediately receive a prompt to enter the Screen-Reader Profile so they can browse and operate your site effectively. Here’s how our website covers some of the most important screen-reader requirements, alongside console screenshots of code examples:
Screen-reader optimization: we run a background process that learns the website’s components from top to bottom, to ensure ongoing compliance even when updating the website. In this process, we provide screen-readers with meaningful data using the ARIA set of attributes. For example, we provide accurate form labels; descriptions for actionable icons (social media icons, search icons, cart icons, etc.); validation guidance for form inputs; element roles such as buttons, menus, modal dialogues (popups), and others. Additionally, the background process scans all of the website’s images and provides an accurate and meaningful image-object-recognition-based description as an ALT (alternate text) tag for images that are not described. It will also extract texts that are embedded within the image, using an OCR (optical character recognition) technology. To turn on screen-reader adjustments at any time, users need only to press the Alt+1 keyboard combination. Screen-reader users also get automatic announcements to turn the Screen-reader mode on as soon as they enter the website.
These adjustments are compatible with all popular screen readers, including JAWS and NVDA.
Keyboard navigation optimization: The background process also adjusts the website’s HTML, and adds various behaviors using JavaScript code to make the website operable by the keyboard. This includes the ability to navigate the website using the Tab and Shift+Tab keys, operate dropdowns with the arrow keys, close them with Esc, trigger buttons and links using the Enter key, navigate between radio and checkbox elements using the arrow keys, and fill them in with the Spacebar or Enter key.Additionally, keyboard users will find quick-navigation and content-skip menus, available at any time by clicking Alt+1, or as the first elements of the site while navigating with the keyboard. The background process also handles triggered popups by moving the keyboard focus towards them as soon as they appear, and not allow the focus drift outside of it.
Users can also use shortcuts such as “M” (menus), “H” (headings), “F” (forms), “B” (buttons), and “G” (graphics) to jump to specific elements.
We aim to support the widest array of browsers and assistive technologies as possible, so our users can choose the best fitting tools for them, with as few limitations as possible. Therefore, we have worked very hard to be able to support all major systems that comprise over 95% of the user market share including Google Chrome, Mozilla Firefox, Apple Safari, Opera and Microsoft Edge, JAWS and NVDA (screen readers), both for Windows and for MAC users.
Despite our very best efforts to allow anybody to adjust the website to their needs, there may still be pages or sections that are not fully accessible, are in the process of becoming accessible, or are lacking an adequate technological solution to make them accessible. Still, we are continually improving our accessibility, adding, updating and improving its options and features, and developing and adopting new technologies. All this is meant to reach the optimal level of accessibility, following technological advancements. For any assistance, please reach out to info@atasteofky.com


Automate the exchange of data between NDJSON and cloud applications, databases and files on Windows, MacOS and Linux
Fast, reliable and background exchange of high volumes of NDJSON data between over 75 data sources.
we serve over 20000 companies
Exchange Data
Exchange business data in an automated and reliable way within and across applications for optimal data integration
NDJSON is a file format based upon JavaScript. A NDJSON file consists of one record in JSON-format per line. No array grouping or record separator is used.
An integrated, scaleable and reliable lights-out NDJSON data exchange solution
- Synchronize and copy data within and across platforms using a single SQL-language.
- Invantive Data Hub runs NDJSON background jobs from the task scheduler of choice such as Windows Task Scheduler or the Linux cron daemon.
- Combine data from dozens of cloud data sources and choose from the industry-largest number of connected tables.
- High performance by parallel data streaming and integrated incremental and synchronization NDJSON loading strategies.
- Available for Windows, MacOS and Linux running a single or dozens of CPU-cores.
- Personal support and extensive community from Dutch market leader.
The NDJSON driver for Invantive Data Hub has advanced optimizations for great real-time NDJSON data performance.
Office for Entrepreneurs€ 59 /mo
- Fixed low rate for up to 100 companies, each on any (cloud)platform from 75 available.
- You pay as low as € 0.59 per company and platform. Also therefore: Guaranteed Lowest Prices!
- Includes NDJSON connector for Power BI, Power Query and Azure Data Factory.
- Includes Invantive Cloud for Power BI, Power Query, Tableau and Azure Data Factory.
- Includes also Excel and Word add-in.
- Includes also Get My Report.
- No Power BI, Power Query, Tableau and Azure Data Factory user limit.
- At most 2 interactive users on Invantive's interactive products.
- Upgrade to 10 users on Invantive interactive products: € 119.
- No use? No invoice.
- Terminable at any time.
All Invantive subscriptions include online forum support and interactive contact such as chat and phone. For each company, a free 1-hour introduction is available and recommended for quick results. Specific conditions, acceptance criteria and fair use rules apply. Service only available in selected countries, including all EU members, the United Kingdom, the United States, Canada, Vietnam and Taiwan.


Any fool can write code that a computer can understand. Good programmers write code that humans can understand. Martin Fowler
Complex code is hard to understand code because classes and methods do so many different things it’s impossible to understand how it works without stepping through the code to understand exactly what is going on. – Hosk
When writing code you need to keep in mind – Will I be able to understand this code 6 months later when I have forgotten the business logic – Hosk
This started out as a small blog post, which seems to have kept growing and growing, so be prepared for a long read. I have a few CRM developer articles which you can find in the section Hosk’s CRM Developer Articles. It has an article on code readability and why experience is important in CRM development which I recommend you to read.
Before reading the article below I would like you to remember coding is an art, which is one of the reasons it takes a time to learn. Seeing coding as an art helps to explain why there is no right or wrong way to write code and good code/bad code is open to interpretation. So the thoughts below are my thoughts on coding and the processes and standards I use, yours might be different but I would love to hear them so please leave a comment.
Complex code
Most developers have been in the situation where you get assigned to a new project and one your first tasks is to resolve a bug. project.
The first step usually when bug fixing is recreating the bug, so I will assume you have done that so now it’s time to look at the code to try to fix the bug.
- scan the code
- getting a rough idea of the structure of the code
- work out the flow
- understand the data sources
- Work out what parts of the code are changing the data.
The code is so complex and confusing the most efficient way to understand it is to debug the code, stepping through it line by line, hoping to get some understanding what’s happening and trying to find the elusive cause of the bug.
The code is one big pile of spaghetti code which you are afraid to change, if you are good (and have time) you will do some code refactoring but most likely you will cautiously poke a change towards the code with a long stick, cross fingers it fixes it before slowly backing away hoping to never see the code again.
Why complex code created
Junior developers create complex code for simple problemsSenior developers create simple code for complex problemsA rushed developer creates code to refactor later
Common reasons for complex code
- Written by a junior developer who is learning
- Quick bug fixes
- Time constraints
- Refactor Later
- No Peer Reviews
Inexperienced/Junior Developer
Time constraints
When developers rush they create code and more code but they do not create better quality code. Rushed code creates what is called technical debt, which will give you problems later (e.g. when you have to debug or enhance the code). A note for project managers, pushing developers to extremely tight schedules creates more code
Quick Bug Fixes
When developers add quick bug fixes or bug fixes in general it’s easy to wedge in some code and increase the complexity by veering away from creating simple code.
Refactor Later
Developers know they should write better code/simpler code but they write some code which works and fixes the bug/provides the functionality needed and they promise to “Refactor later”. You already know how this story ends, the developer is too busy, something urgent pops up and the code is never refactored.
No Peer Reviews
The most effective way to reduce the amount of complex code or bad code is to have a senior developer check the code with a peer review (could also be known as a code review). The developer won’t let their standards drop and will produce better code when they know it is going to be inspected by another developer.
Peer reviews will also find some bugs in the code and are a great way to guide junior developers into converting complex code into simple code with pointers from the senior developer.
The smells of complex code
- Large methods – Monster methods
- confusingly named classes, methods and variables
- methods which do lots of things
- not consistent
- tight coupling
- dependent code
- poorly structured code
Large Monster methods
I’m sure all developers have come across a project where there is one monster method that runs for lines and lines and lines. They are often full of bug fixes and usually one developers knows the method (the poor soul has had to debug it many times) and often all the bugs flow their way.
People are scared of the monster methods and rightly so because no one can understand it and no one wants to change it.
Plugins are a common breeding ground for monster methods. I have seen numerous plugins where all the code is directly inside one big method in a plugin.
Developers should not be afraid of changing code
Badly named classes, methods and variables
Methods doing more than one thing
Not consistent
Complex code/poor code will be inconsistent, this can usually occur when a developer has copied the code from various different sources or you have a number of developers working on a project where there is no standards being applied.
The difficulty inconsistently structured code brings is it makes the code hard to understand because there is no common structure, the code has a different flow.
Code and customizations are difficult to understand and not being consistent makes the job even harder.
Tightly coupled/dependant code
Tightly coupled code is code which can’t be reused because it is dependent on other code in the project. The cause is often because the methods are doing more than one thing and are really a number of methods (if they were refactored) squashed into one.
Dependant code often can’t be reused even within the same project.
Poorly structured code
Code should be structured and organised in a logical manner. A simple form of structuring is splitting the business logic and queries into separate methods.
Code structuring makes the code easier to understand and splits into smaller logical areas, this will help in code reuse and bug fixing (because you are isolating the bug)
CRM Customization smells
Giant workflows
The CRM GUI for workflows can make it difficult to work with workflows but when you have a giant workflow it can be almost impossible. There is a limit of four nested if statements in CRM (it’s true for CRM 2011, I’m dangerously assuming it’s still the case in CRM2013/CRM2015 but I could be wrong) and when you have a workflow which is hitting this limit, it’s a sign the workflow is too complex
Read more about four nested if statement limitation
Big workflows are very difficult to maintain and making changes can be very challenging, if you have workflows which are very big you should consider breaking these down into child workflows.
Lots of different customizations overlapping
CRM customizations allow you to provide functionality in lots of different ways.
- Plugins
- Custom Plugins
- Javascript
- Business rules
- Workflows
- WCF webservices
- Console apps
Some customizations are better suited to certain problems and best practices/experience will guide you as to which customization you should use.
I have seen problems where developers have used business rules and Javascript together because business rules don’t trigger Javascript on change events. By using the different customizations together you are adding to the complexity of the solution and making it difficult for developers to understand the flow.
You can get similar problems when workflows and plugins are used in conjunction with workflows running after the plugin (because plugin is synchronous and workflow is asynchronous) and the workflow overwrites the plugin set value.
I’m not saying using plugins and workflow is wrong and should never be used but care should be taken when they overlap it can create a solution which is difficult to understand and debugging can be puzzling.
When deciding what customizations to use, some consideration of what customizations already exist should be taken into account. The simpler the solution the easier it will be to maintain and extend the solution later. When I mention solutions I am referring to all the customizations as a whole.
Javascript files with duplicated methods
The most common method of structuring Javascript code is having one Javascript file for each entity, CRM pushes people into this model by making you choose a file to upload for the form. This isn’t incorrect because there will be Javascript methods only suitable for each form because they will be manipulating fields on the form.
This can cause people to copy methods from one entity Javascript file to another entity Javascript file.
What happens later if a bug is found in one of these duplicated methods, usually it gets fixed on one form. Then you have duplicated code, some of which is fixed and some which isn’t.
No common Javascript files
Following on from the point above, if there are common Javascript functions then put them in a common Javascript file rather than copying the same function many times.
All the code in the plugin
My personal view is you should have no code in a plugin, it should all be moved out to separate classes.
The first reason is you have created a big monster method, which is hard to understand, debug and enhance.
Testing code in a plugin is difficult because you need to mock all the plugin code, if you remove the code from the plugin, you can test the code by just passing in a OrganisationService (e.g. a connection to CRM).
You cannot reuse any code inside a plugin
Copy and paste code (plugins and Javascript)
Complex code means people cannot reuse the code, so they often end up copying parts of tightly coupled code from one area in CRM to another. This can often lead to messy/poor code but can also allow bugs to slip in with code which isn’t relevant or needed.
The problems with complex code and customizations
The code is hard to read
When writing code you need to keep in mind -Will I be able to understand this code 6 months later when I have forgotten the business logic.
Complex code is hard to understand often because it’s not structured and modularized. Understanding code which is logically structured into separate classes and small focused methods is easy because the code does what you expect.
Complex code has large methods which do many things, the classes and method names are confusing because it’s difficult to apply a name to a class/method which does many different actions.
Well structured code is like a tidy room, with everything tidied away into draws, bookshelves and wardrobes. Easy to understand and use. Things are easy to find. If you add a new item to the tidy room, you can place it with the other similar items
Complex code is like a messy student room, everything is on the floor. It’s hard to understand the where everything is or should be. Objects are to find because you are not sure where to look. If you add a new object to the messy room, where do you put it and will mess up the organisation of the room.
Slightly improved code is where the messy student buys a big wardrobe and a chest of drawers and chucks groups of things. You know you need to look in the chest of drawers but if the socks are not in their own drawer it’s going to take you time to find them among the other clothes.
The code is hard to debug
Complex code is hard to debug because it’s because it isn’t structured logically (because it’s in big methods) and the code isn’t easy to understand. Often the only way to understand what the code is doing is slowly stepping through it.
The code is hard to enhance
Complex code creates complex bugs
No Reuse
Complex code is tightly coupled and big methods are very difficult to reuse. It means developers have to write more code, which means more testing.
More code will increase the chance of more bugs.
A lack of reuse in code will result in developers copying parts of code which can result in copy and paste bugs.
Duplicate code will result in bugs where some of the duplicated code is bug fixed and other parts get forgotten about.
Encourages more of the same
Junior developers and developers in general will copy working code. The good developers will refactor the code, the poor developer will just leave it as it is.
Copying complex code will create more complex code.
If developers see other people creating complex/bad code then they will too. It’s letting standards drop and everyone will pay for it later down the line when bug fixing takes twice as long
Junior developers will copy it
Developers should set high standards and great code for Junior developers to learn from.
If everyone is creating simple well-structured code, the junior developers will follow their lead.
Creating complex code/quick code really causes problems for a project later. Finding and fixing bugs takes a lot longer because the code is harder to understand and fixing the bug is difficult because the code is in large methods and not well structured.
The difficulty in fixing large methods is they do many things and you have to make sure the method still does all those actions and changes.
If you compare this to fixing a small focused method, you only need to make sure it still does the one action.
Complex code creates problems for the project later on where it will become harder to maintain the code whilst fixing bugs and enhancing. Complex code will mean people take longer to get up to speed on a project, whilst they learn how this individual project is setup and works.
I’m sure lots of developers have worked on legacy projects with complex code and it’s not an enjoyable experience, so make sure you are not creating projects like that.


Web terminals (DEPRECATED) (FREE)
- Deprecated in GitLab 14.5.
- Disabled on self-managed in GitLab 15.0.
WARNING: This feature was deprecated in GitLab 14.5.
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to enable the feature flag named
- Read more about the non-deprecated Web Terminals accessible through the Web IDE.
- Read more about the non-deprecated Web Terminals accessible from a running CI job.
With the introduction of the Kubernetes integration, GitLab can store and use credentials for a Kubernetes cluster. GitLab uses these credentials to provide access to web terminals for environments.
NOTE: Only users with at least the Maintainer role for the project access web terminals.
How it works
A detailed overview of the architecture of web terminals and how they work can be found in this document. In brief:
- GitLab relies on the user to provide their own Kubernetes credentials, and to appropriately label the pods they create when deploying.
- When a user navigates to the terminal page for an environment, they are served a JavaScript application that opens a WebSocket connection back to GitLab.
- The WebSocket is handled in Workhorse, rather than the Rails application server.
- Workhorse queries Rails for connection details and user permissions. Rails queries Kubernetes for them in the background using Sidekiq.
- Workhorse acts as a proxy server between the user's browser and the Kubernetes API, passing WebSocket frames between the two.
- Workhorse regularly polls Rails, terminating the WebSocket connection if the user no longer has permission to access the terminal, or if the connection details have changed.
GitLab and GitLab Runner take some precautions to keep interactive web terminal data encrypted between them, and everything protected with authorization guards. This is described in more detail below.
- Interactive web terminals are completely disabled unless
[session_server]is configured.
- Every time the runner starts, it generates an
x509certificate that is used for a
wss(Web Socket Secure) connection.
- For every created job, a random URL is generated which is discarded at the end of the job. This URL is used to establish a web socket connection. The URL for the session is in the format
(IP|HOST):PORT/session/$SOME_HASH, where the
PORTare the configured
- Every session URL that is created has an authorization header that needs to be sent, to establish a
- The session URL is not exposed to the users in any way. GitLab holds all the state internally and proxies accordingly.
Enabling and disabling terminal support
NOTE: AWS Classic Load Balancers do not support web sockets. If you want web terminals to work, use AWS Network Load Balancers. Read AWS Elastic Load Balancing Product Comparison for more information.
As web terminals use WebSockets, every HTTP/HTTPS reverse proxy in front of
Workhorse must be configured to pass the
Connection and
Upgrade headers
to the next one in the chain. GitLab is configured by default to do so.
However, if you run a load balancer in front of GitLab, you may need to make some changes to your configuration. These guides document the necessary steps for a selection of popular reverse proxies:
Workhorse doesn't let WebSocket requests through to non-WebSocket endpoints, so
it's safe to enable support for these headers globally. If you prefer a
narrower set of rules, you can restrict it to URLs ending with
This approach may still result in a few false positives.
If you installed from source, or have made any configuration changes to your Omnibus installation before upgrading to 8.15, you may need to make some changes to your configuration. Read Upgrading Community Edition and Enterprise Edition from source for more details.
To disable web terminal support in GitLab, stop passing
Connection and
Upgrade hop-by-hop headers in the first HTTP reverse
proxy in the chain. For most users, this is the NGINX server bundled with
Omnibus GitLab, in which case, you need to:
- Find the
nginx['proxy_set_headers']section of your
- Ensure the whole block is uncommented, and then comment out or remove the
For your own load balancer, just reverse the configuration changes recommended by the above guides.
When these headers are not passed through, Workhorse returns a
400 Bad Request response to users attempting to use a web terminal. In turn,
they receive a
Connection failed message.
Limiting WebSocket connection time
By default, terminal sessions do not expire. To limit the terminal session lifetime in your GitLab instance:
- On the top bar, select Main menu > Admin.
- Select Settings > Web terminal.
- Set a
max session time.


Please take some time to read John's Brilliant poem in response to Brenda's word prompt 'Writing'
Here's the link to his beautiful hib: https://hubpages.com/literature/The-Art … anted-Pen.
Thank you so much, John, for sharing this lovely poem. I enjoyed reading it and found it very inspirational.
Hello John!
Excellent response to the word prompt, Writing. As always, you have created a wonderful poem. I do agree with your message that writing is addictive. I enjoyed reading about Georgina’ s writing journey and eventual success.
Thank you for sharing.
And thank you Misbah for sharing John’s response.
For some reason your link isn't working.
Guess another glitch???
Here it is again...
https://hubpages.com/literature/The-Art … hanted-Pen
Yes, seems like some bug. Forums aren't letting me create hyperlinks as well. Don't know why. Thank you for sharing the link to John's work again. Much Gratitude!
Blessings always!
Let's hope they get this fixed quickly.
Oh no...quick isn't a word they know.
Yes, I had the same problem with the link but thought it was just me. Thanks for resharing it, Brenda.
Ssshh... They'll hear that we've found a solution to this difficulty. They don't like it when we communicate
I wonder if they sent the cyber cookie monster.
If this trend continues, the day will come when that cyber cookie monster will devour the entire forum discussion.
Don't worry Misbah...
We'll find a way to curb his hunger....
Maybe John can use his magic pen.
Misbah, thank you for sharing John's poem. If only I could purchase one of those pens on Amazon. John is so creative; I don't think he has ever been stumped, by Brenda or in his poems from the porch.
Linda, I think those pens would sell out fast. Thank you for reading my work. I hope to bring back Poems From the Porch soon.
Linda...got to say I agree.
It's hard to stump John...he can write on any topic.
Great talent. Maybe he has the only magic pen.
Aww..Misbah. Thank you so much for sharing and for your very kind words. I am so happy you found the poem inspirational.
Thanks Misbah for sharing John's post.
John, this is a wonderful poem about a girl getting addicted to writing with the help of Higher Powers and eventually rising to fame. I loved it thoroughly. Thank you for the awesome share, which is a marvelous response to the word prompt, "Writing."
I really like the way you responded to this prompt. Writing Georgina's story in a poem is very clever, John. Well done!
Thanks for posting John's poem, Misbah.
Master strokes by a master writer. It is always a pleasure to read John's writings. He does it the way it's supposed to be done.
I guess I hadn't thought about all those articles on writing.
My thought process...
We are writers ~ therefore we Know writing.
Your poem ~ Georgina's Enchanted Pen" you tells us how Georgiana begins when she's trying to satisfy that urge to write.
She picks up her pen, hoovering over the page, waiting for the words to flow.
When an idea surfaces, her fingers cannot stop. Her muse is on a roll.
She forces herself to take a break but the words creep into her dreams.
When she awakes she uses her enchanted pen to pick up where she left off.
She wrote until her pen ran out of ink then proofread her work seeing it wasn't bad.
Her words soon get published & she rises to fame.
It was though a helping hand had guided that magical pen.
Great writing here!
There are times we get an idea & just can't stop until we're finished.
I know what it's like to have those words follow me in my dreams.
I'll post a link in the word prompt article.
Thanks for reading and analysing the poem, Brenda. I had no idea what I was going to write when I started, but my pen just flowed as though it was enchanted lol. Sometimes, I get an idea for something I am writing in a dream and have to jot it down straight away. Glad you enjoyed the poem, and thanks for putting the link on your word prompt article.
John's is a masterful poem about the almost mystical drive of Georgina following her muse to publishing success and fame. A brilliant piece of writing! Thanks Brenda for sharing it!
Thanks for sharing and this is really a very interesting poem by John. Well done.
Salam Misbah,
The link is not working.
Great work there John. I loved your poem. It only goes to prove passion leads to success. Georgina's story is awe inspiring. She really must have had some divine help to achieve fame and glory with her first book. Your creativity is admirable John. A very good response to this week's word prompt. thanks for sharing Misbah.
Vidya, it is always great to receive your comments. I am glad you found Georgina’s story to be inspiring even though it may be a little
hard to believe that she would achieve success with her first book.
Your poem was wonderful, John. It does happen at times, that once we get an idea and we start writing, the words and the story just seem to flow. I like both the optimism and the joy you express in your poem of being in the zone of creativity. I think that often we impose our own limitations instead of just writing for the joy of it and we talk ourselves out of this creative process. Children seem to be natural storytellers but most adults have a hard time with this process. Sometimes, we become our worst critics which inhibits our flow of thoughts and our abilities. Great job with this prompt and helping us to get out of the mental blocks of our own making.
Great response to the word prompt challenge, Jodah. And I agree that the most difficult part of writing is the beginning. Georgina's story is very inspiring.
Stay safe and healthy...
Thank you for reading this, Moon. It is good that you found the story inspiring. Stay well.
by Rosina S Khan 2 weeks ago
This was lovely poetry in response to Brenda's prompt, "Beginnings" penned by John Hansen. Here is the link to his poetry:https://hubpages.com/literature/The-Lov … BeginningsI feel happy and hopeful that the man sought out a gipsy's love potion and spell to rekindle his love with...
by Rosina S Khan 4 weeks ago
It is wonderful that John has dedicated a poem to his cats. Here is the link:https://hubpages.com/literature/The-Fel … About-CatsThis is a very lovely poetry about each of your cats. It was fun to read about their daily activities. It was indeed very enjoyable, John except that one deceased...
by Gianella Labrador 10 months ago
Sharing John's Response for this Weekly Word Prompt on Puzzles.Here is the link:https://hubpages.com/literature/The-Jig … ut-PuzzlesHe dedicates the first two to Brenda and Ron.Great response John as always! Your muse never fail to amaze us. I hope it never disappoint you too from here...
by Pamela Oglesby 4 hours ago
John has published a very cute poem about pigs.https://hubpages.com/literature/My-Pigs … ket-A-Poem
by John Hansen 13 days ago
Chitrangada gives us two wonderful poems that meet the prompt "beginnings" perfectly, I love the quotes as well.https://hubpages.com/literature/Beginni … Hopes-Poem
by Ravi Rajan 3 days ago
John, your interesting poem about the two preachers reminds me of an interesting quote on religion said by Aristotle"Religion was invented when the first con man met the first fool."That said, we will have good and bad preachers as long we have people. We will always have charlatans who...
Copyright © 2023 The Arena Media Brands, LLC and respective content providers on this website. HubPages® is a registered trademark of The Arena Platform, Inc. Other product and company names shown may be trademarks of their respective owners. The Arena Media Brands, LLC and respective content providers to this website may receive compensation for some links to products and services on this website.
Copyright © 2023 Maven Media Brands, LLC and respective owners.
As a user in the EEA, your approval is needed on a few things. To provide a better website experience, hubpages.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.
For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://corp.maven.io/privacy-policyShow Details
|HubPages Device ID
|This is used to identify particular browsers or devices when the access the service, and is used for security reasons.
|This is necessary to sign in to the HubPages Service.
|Google Recaptcha
|This is used to prevent bots and spam. (Privacy Policy)
|This is used to detect comment spam. (Privacy Policy)
|HubPages Google Analytics
|This is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
|HubPages Traffic Pixel
|This is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
|Amazon Web Services
|This is a cloud services platform that we used to host our service. (Privacy Policy)
|Google Hosted Libraries
|Javascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
|Google Custom Search
|This is feature allows you to search the site. (Privacy Policy)
|Google Maps
|Some articles have Google Maps embedded in them. (Privacy Policy)
|Google Charts
|This is used to display charts and graphs on articles and the author center. (Privacy Policy)
|Google AdSense Host API
|This service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
|Google YouTube
|Some articles have YouTube videos embedded in them. (Privacy Policy)
|Some articles have Vimeo videos embedded in them. (Privacy Policy)
|This is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
|Facebook Login
|You can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
|This supports the Maven widget and search functionality. (Privacy Policy)
|Google AdSense
|This is an ad network. (Privacy Policy)
|Google DoubleClick
|Google provides ad serving technology and runs an ad network. (Privacy Policy)
|Index Exchange
|This is an ad network. (Privacy Policy)
|This is an ad network. (Privacy Policy)
|Facebook Ads
|This is an ad network. (Privacy Policy)
|Amazon Unified Ad Marketplace
|This is an ad network. (Privacy Policy)
|This is an ad network. (Privacy Policy)
|This is an ad network. (Privacy Policy)
|Rubicon Project
|This is an ad network. (Privacy Policy)
|This is an ad network. (Privacy Policy)
|Say Media
|We partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
|Remarketing Pixels
|We may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
|Conversion Tracking Pixels
|We may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
|Author Google Analytics
|This is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
|ComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
|Amazon Tracking Pixel
|Some articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)
|This is a data management platform studying reader behavior (Privacy Policy)


At 01:25 PM 10/23/00, you wrote: >Microsoft has a decent script debugger that handles Javascript and VB >Script, but it's a pain to use because if you turn it on, it will force >you to debug every JS error you run into while you surf. > >http://msdn.microsoft.com/jscript/ and go to "Script Debugger" in the >menu if you want to check it out. This has been relocated to http://msdn.microsoft.com/scripting/ on their site. Bill Mason data at data1701d.com Dateline: Starfleet http://www.data1701d.com http://profile.guru.com/billmason http://www.freeagent.com/billmason http://bmason.freelancers.net


Inspired by strangers. Who muck things up.
So you've got a stranger in your world, interacting with your main character. Do they influence that world just by being there? Do they change things? Like really muck stuff up?
In Part I of our favourite inter-dimensional reporter's visit to Ilium, things seem to be going okay. With Vergil's help, she seems to have brought Neas out of his shell — even coaxed a few actual answers out of him for her interview. Smooth, yeah? In and out, right?
Not so fast.
When a stranger visits your world, it's a two way street. Their guide influences them, but they influence their guide too. They plant ideas, stir up memories, and maybe even impact where the story goes from there.
They are mucking with the laws of space, time, and fiction, after all.
Rule number one: tread carefully!
“Goose-it! Get behind that column, pronto!”
I jump! I just catch the buzz—like bees, wind, and my computer fan mixed together—before lights with riders roar by my hiding spot. Neas has disappeared in the fog.
He’s back before I can see where he hid. “Yikes,” he says. “You still itchin’? Perfect. See those two bogeys? The ones whizzin’ down the road? Those markin’s mean they work for that gooser I was tellin’ you ‘bout earlier. Gore. Yeah. And you hear that whizzin’ when they flew by? Soundin’ kinda like Vergil?”
“Like me, Sir?”
“Yeah… that’s my favorite sound. The whizzin’ a hoverboard makes when it boosts across the road. Always wanted to try ridin’ one… yet another thing Mentor won’t let me try. But they’re hard as heck to find, you know? And bikes ain’t the same, no matter what Acamas says. I can see it now… wind blowin’ through my hair, boosters flyin’ me higher and higher, then… BAM! All of Ilium right in front of me. The stars and the spires and everythin’ in-between. Yeah…”
“That sounds pretty cool,” I smile. I can see it—shoot, I have seen it. But I won’t spoil the surprise for him. Aeneas, Ilium's future unwilling savior, doesn’t need pro-tips from a—uh—‘porter’ like me. “Yeah, that sounds really cool. Kind of brings me to my next question—what's your dream?”
“Hmm… my… my dream?”
“Like, what do you want most from your life?”
“Oh! Okay, okay. Sorry, pal. Thought you were gettin’ all personal again, dang it.”
“Oh! Okay, okay. Sorry, pal. Thought you were gettin’ all personal again, dang it.”
I mean, I was, but he has a different idea of personal, I guess. He goes on.
“Don’t tell Mentor this, but I’ve always dreamed of… of seein’ the world. The world outside the Wall, you get me? The mountains… the forests… the deserts… even the, um… the coats!”
“I believe you mean ‘coasts’, Sir.”
“Goose-it, Vergil! But, um, yeah. The coasts. The water, you know? Always wanted to try swimmin’. Feelin’ the cool water on my skin. With the sun all beamin’ down, kinda like Vergil’s spotlight… but… but bigger… and brighter! Yeah. Goin’ swimmin’… very pigeon.”
I love it—his beaming face, the power behind his voice—that’s what I do intergalactic interviews for. It’s totally ‘pigeon.’ But the poor robot looks like it’s getting nervous with all this travel-talk. “We have water too, Sir,” it says. “Right by our home.”
“Vergil… that’s not the same, buddy. Vergil’s talkin’ ‘bout the sewers… that’s where we live, you know. And yeah, sure… we got tons of water. But it ain’t exactly the swimmin’ type. Hey… hey porter… you want me to level with ya?”
Level with me—tell me something, true, right? “Yeah. I'm listening.”
“I kinda. You know. Envy you or somethin’. Bein’ able to travel all over the world. Visitin’ people. Truth is… I’m tired of hidin’ down here. Tired of livin’ in the dark. My dream—you gettin’ this or what?—is to get my own ship… a pirate ship’d be perfect… and get outta this place. Get outta this place for good. And see the world…”
“Sir… you would leave us? Leave our home?”
“Vergil… c’mon!”
Vergil’s spotlight dims. It swivels away from Neas and looks off in the distance. I want to hug it.
“I would miss you, Sir. My circuits are not meant for processing such…”
“Stop itchin’ buddy! You’d be comin’ too of course! We’d all go. Me and you and the boys. We’d get outta this place and travel the world in our own pirate ship. Yeah. That’s my dream.”
“That's an awesome dream,” I grin. “Hey, last question.” I pause this one to watch his face straight-on. “What's your biggest fear?”
“That's an awesome dream,” I grin. “Hey, last question.” I pause this one to watch his face straight-on. “What's your biggest fear?”
Neas bites his lip.
It’s not a fair question to ask a stranger. It’s a worse question to ask a stranger when you’ve read his life story before he’s lived it. I open my mouth—
“Hey, no one’s gonna know—and—” But you can’t talk that kind of thing out of a person. I stop walking for a second, lean against a nearby column, and just wait with a soft smile. Next move’s his.
Neas swallows hard.
“Well, porter. With all those goosers I was goin’ on ‘bout before… Gore, the spooks, jukes, and even those bogeys in the towers… might think I got a lot to be afraid of. But… truth is… I really just don’t wanna be alone, you get me? Mentor, Acamas, Byron and the others… I may make fun of’em and everythin’, but…those guys’re like my brothers, you know? Like family. Only family I’ve ever had. Don’t know what I’d do without’em.”
“…you do have me, Sir. I will never leave you.”
“I know, buddy. I know.”
I glance away at my feet. It’s strange, bringing fears and dreams to the light, and then standing over them as they hit you, full-blast, with all their scents and graspings and feelings. It’s worse that I already know his fears will come true. I croak: “Hey, thanks for sharing. You’re a good interviewee.”
“Yeah, yeah.”
He’s shrugged and sealed it all off again—he doesn’t ‘give a goose.’ But I’m feeling queasy—and it’s not because of the scent, a bit like blood and old burger, that’s rising from the narrow alleyway we’re squeezing into. I’m hearing screams, laughs, the clinking of glasses and raucous music from the gaudy building on the right.
“Well. There it is.”
We’re in the back alley behind Gore’s pub, about two yards away from the dumpster—
From the dumpster where Neas gets caught. And beaten. And today is his—
I know this scene. My eyes widen—I’m trying to open my mouth to warn him. We’re literally minutes away from the beginning of his story—
Dangit! His family!
“Go home, right now!” I cry. “Go home, save your family!”
But the words I hear, in my voice, are, “Oh, shoot, I gotta get home. I’ve got a family interview in ten minutes.” No I don’t!
“Sure you don’t wanna stay for dinner?" Neas asks. "Heard that melonhead’s plannin’ a big performance tonight… gonna be tons of food left for us to…”
“No, you need to get out of here right now!” becomes “No, I gotta jet right now.” Jet? Whodahell says that?
“Oh. Um… yeah, okay. Stay, don’t stay… don’t really give a goose. Just more for me anyways.”
I’m stomping, cursing. I’m trying to make signs or something to warn him. But I see my reflection in a murky puddle of I-don’t-wanna-know besides us, and in that reflection I’ve got a reassuring, apologetic smile, and I’m waving as I step away. It’s a rule about interdimensional interviews: I can’t change the story. It’s a rule I’ve never tried to break before, but this poor kid, on his birthday—! My gut’s twisting; I’d have clenched teeth and hot, frustrated tears if the forces of this reality would let me.
I’m almost out of the alleyway—I stop, shoulders sagging, when he calls to me.
“Hey porter? You, um… you won’t forget ‘bout me or anythin’, will ya? You know… when you’re out there, portin’ in some other gooser’s city?”
“No. You’re a pretty unforgettable character,” I sigh. He can’t see the sad smile. “Hey, Neas?”
“Happy—happy birthday.”
He grins that smirky, friendly grin. The last I’m going to see of him as the rules take me around the corner and leave him to his fate.
“Well, c’mon buddy! Let’s goose-it while we still can. I’m hungry!”
His voice fades, and I’m gone as his story begins.
Lastly, an inter-dimensional message from your favourite inter-dimensional reporter, Petre Pan:
I'd love to help your book get more 'chatter' around the internet by interviewing one of your characters. E-mail me - petrepan(at)gmail(dot)com - with the "place" your character wants to meet me, and I'll send you a few questions to answer in your character's voice. This fun collaboration gives you writing practice, and hopefully generates you a little extra readership. For unpublished authors, this is also a great way to deepen your character!
Don't forget to check out the Blog Hop, and join in, too!
<!-- start LinkyTools script -->
<script src="http://www.linkytools.com/basic_linky_include.aspx?id=188544" type="text/javascript"></script>
<!-- end LinkyTools script -->