# Best IQ Option Robot Software for Signals Binary Today

• Best IQ Option Robot Software for Signals Binary Today
• Top Binary Options Apps - Reviews of Mobile Trading
• Binary Options Signals - Top Providers Reviewed
• Binary Options Conqueror 5 – MT2 Trading Market
• PRO SIGNAL ROBOT The Most Profitable Binary Option Robot
• Online trading platform for binary options on forex, stock ...
• Binary Options Greg's Forex Trading
• IQ Option Signals - Best Signals. Up to 1 Year for FREE!
• Binary options software: Pz binary options mq4 indicators
##### An introduction to Linux through Windows Subsystem for Linux

I'm working as an Undergraduate Learning Assistant and wrote this guide to help out students who were in the same boat I was in when I first took my university's intro to computer science course. It provides an overview of how to get started using Linux, guides you through setting up Windows Subsystem for Linux to run smoothly on Windows 10, and provides a very basic introduction to Linux. Students seemed to dig it, so I figured it'd help some people in here as well. I've never posted here before, so apologies if I'm unknowingly violating subreddit rules.

# An introduction to Linux through Windows Subsystem for Linux

## Introduction and motivation

So you're thinking of installing a Linux distribution, and are unsure where to start. Or you're an unfortunate soul using Windows 10 in CPSC 201. Either way, this guide is for you. In this section I'll give a very basic intro to some of options you've got at your disposal, and explain why I chose Windows Subsystem for Linux among them. All of these have plenty of documentation online so Google if in doubt.
• Dual-booting with Windows and a Linux distro
• Will basically involve partitioning your drive and installing Linux from an external bootable USB through your computer's boot menu. You'll get the full Linux experience.
• Lots of Linux flavors to choose from. For beginners, Ubuntu and Linux Mint are generally recommended. I have Ubuntu 18.04 LTS, I'd recommend Ubuntu 20.04 LTS since it's newer, but it's all up to you.
• However, it can be a pain to constantly be switching between operating systems. Maybe you wanna make the full jump to Linux, maybe you don't.
• Life pro tip: if you go down this route, disable Window 10's Fast Startup feature as it will get very screwy with a dual-boot. I've also included a helpful guide in Appendix B.
• Using a virtual machine (VM) to run Linux
• Devours RAM and is generally pretty slow, would not recommend.
• Using terminal emulators
• These provide commands and functionality similar to a Linux terminal, but are still running on Windows architecture.
• These days, the most commonly-used Linux terminal is called bash. bash stands for Bourne Again Shell (no, Bourne is not a typo), and is likely what you'll be using as well.
• Terminal emulators generally don't include a package manager, i.e. you can't download new bash programs, so pretty limited for general usage. BUT you can install a package manager externally, kind of hacky but can work.
• Examples of terminal emulators include PuTTY, Git Bash, msys2 and mingw.
• Using Windows Subsystem for Linux (either WSL 1 or WSL 2)
• WSL provides a compatibility layer for running GNU/Linux programs natively on Windows 10. It has integration features certain Windows 10 development apps (notably Visual Studio Code) as well.
• You've got two options, WSL 1 and WSL 2. WSL 2 was recently released and features a real Linux kernel, as opposed to an simulated kernel in WSL. This means WSL 2 offers significant performance advantages, but still lacks some of WSL 1's features.
• WSL 1 is what I currently use, and thus what I'll be talking about in this guide. I'm not necessarily recommending it, frankly I regret not doing a dual-boot sooner and ditching Windows, but a dual-boot isn't for everyone and takes a lot of time you might not have right now.
• Getting WSL initially setup is easy, but making it run smoothly requires some effort, and some features (like audio playback or displaying GUIs) require workarounds you can research if interested. WSL will also not work properly with low-level system tools.
With that out of the way, let's get started with setting up WSL 1 on your Windows 10 machine.

## Setting up WSL

So if you've read this far I've convinced you to use WSL. Let's get started with setting it up. The very basics are outlined in Microsoft's guide here, I'll be covering what they talk about and diving into some other stuff.

### 1. Installing WSL

Press the Windows key (henceforth Winkey) and type in PowerShell. Right-click the icon and select run as administrator. Next, paste in this command:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
Now you'll want to perform a hard shutdown on your computer. This can become unecessarily complicated because of Window's fast startup feature, but here we go. First try pressing the Winkey, clicking on the power icon, and selecting Shut Down while holding down the shift key. Let go of the shift key and the mouse, and let it shutdown. Great! Now open up Command Prompt and type in
wsl --help
If you get a large text output, WSL has been successfully enabled on your machine. If nothing happens, your computer failed at performing a hard shutdown, in which case you can try the age-old technique of just holding down your computer's power button until the computer turns itself off. Make sure you don't have any unsaved documents open when you do this.

### 2. Installing Ubuntu

Great! Now that you've got WSL installed, let's download a Linux distro. Press the Winkey and type in Microsoft Store. Now use the store's search icon and type in Ubuntu. Ubuntu is a Debian-based Linux distribution, and seems to have the best integration with WSL, so that's what we'll be going for. If you want to be quirky, here are some other options. Once you type in Ubuntu three options should pop up: Ubuntu, Ubuntu 20.04 LTS, and Ubuntu 18.04 LTS.
![Windows Store](https://theshepord.github.io/intro-to-WSL/docs/images/winstore.png) Installing plain-old "Ubuntu" will mean the app updates whenever a new major Ubuntu distribution is released. The current version (as of 09/02/2020) is Ubuntu 20.04.1 LTS. The other two are older distributions of Ubuntu. For most use-cases, i.e. unless you're running some software that will break when upgrading, you'll want to pick the regular Ubuntu option. That's what I did.
Once that's done installing, again hit Winkey and open up Ubuntu. A console window should open up, asking you to wait a minute or two for files to de-compress and be stored on your PC. All future launches should take less than a second. It'll then prompt you to create a username and password. I'd recommend sticking to whatever your Windows username and password is so that you don't have to juggle around two different usepassword combinations, but up to you.
sudo apt-get update
And then
sudo apt-get upgrade
apt-get is the Ubuntu package manager, this is what you'll be using to install additional programs on WSL.

### 3. Making things nice and crispy: an introduction to UNIX-based filesystems

The two above steps are technically all you need for running WSL on your system. However, you may notice that whenever you open up the Ubuntu app your current folder seems to be completely random. If you type in pwd (for Print Working Directory, 'directory' is synonymous with 'folder') inside Ubuntu and hit enter, you'll likely get some output akin to /home/. Where is this folder? Is it my home folder? Type in ls (for LiSt) to see what files are in this folder. Probably you won't get any output, because surprise surprise this folder is not your Windows home folder and is in fact empty (okay it's actually not empty, which we'll see in a bit. If you type in ls -a, a for All, you'll see other files but notice they have a period in front of them. This is a convention for specifying files that should be hidden by default, and ls, as well as most other commands, will honor this convention. Anyways).
So where is my Windows home folder? Is WSL completely separate from Windows? Nope! This is Windows Subsystem for Linux after all. Notice how, when you typed pwd earlier, the address you got was /home/. Notice that forward-slash right before home. That forward-slash indicates the root directory (not to be confused with the /root directory), which is the directory at the top of the directory hierarchy and contains all other directories in your system. So if we type ls /, you'll see what are the top-most directories in your system. Okay, great. They have a bunch of seemingly random names. Except, shocker, they aren't random. I've provided a quick run-down in Appendix A.
For now, though, we'll focus on /mnt, which stands for mount. This is where your C drive, which contains all your Windows stuff, is mounted. So if you type ls /mnt/c, you'll begin to notice some familiar folders. Type in ls /mnt/c/Users, and voilà, there's your Windows home folder. Remember this filepath, /mnt/c/Users/. When we open up Ubuntu, we don't want it tossing us in this random /home/ directory, we want our Windows home folder. Let's change that!

### 4. Changing your default home folder

Type in sudo vim /etc/passwd. You'll likely be prompted for your Ubuntu's password. sudo is a command that gives you root privileges in bash (akin to Windows's right-click then selecting 'Run as administrator'). vim is a command-line text-editing tool, which out-of-the-box functions kind of like a crummy Notepad (you can customize it infinitely though, and some people have insane vim setups. Appendix B has more info). /etc/passwd is a plaintext file that historically was used to store passwords back when encryption wasn't a big deal, but now instead stores essential user info used every time you open up WSL.
Anyway, once you've typed that in, your shell should look something like this: ![vim /etc/passwd](https://theshepord.github.io/intro-to-WSL/docs/images/vim-etc-passwd.png)
Using arrow-keys, find the entry that begins with your Ubuntu username. It should be towards the bottom of the file. In my case, the line looks like
theshep:x:1000:1000:,,,:/home/pizzatron3000:/bin/bash
See that cringy, crummy /home/pizzatron3000? Not only do I regret that username to this day, it's also not where we want our home directory. Let's change that! Press i to initiate vim's -- INSERT -- mode. Use arrow-keys to navigate to that section, and delete /home/ by holding down backspace. Remember that filepath I asked you to remember? /mnt/c/Users/. Type that in. For me, the line now looks like
theshep:x:1000:1000:,,,:/mnt/c/Users/lucas:/bin/bash
Next, press esc to exit insert mode, then type in the following:
:wq
The : tells vim you're inputting a command, w means write, and q means quit. If you've screwed up any of the above sections, you can also type in :q! to exit vim without saving the file. Just remember to exit insert mode by pressing esc before inputting commands, else you'll instead be writing to the file.
Great! If you now open up a new terminal and type in pwd, you should be in your Window's home folder! However, things seem to be lacking their usual color...

### 5. Importing your configuration files into the new home directory

Your home folder contains all your Ubuntu and bash configuration files. However, since we just changed the home folder to your Window's home folder, we've lost these configuration files. Let's bring them back! These configuration files are hidden inside /home/, and they all start with a . in front of the filename. So let's copy them over into your new home directory! Type in the following:
cp -r /home//. ~
cp stands for CoPy, -r stands for recursive (i.e. descend into directories), the . at the end is cp-specific syntax that lets it copy anything, including hidden files, and the ~ is a quick way of writing your home directory's filepath (which would be /mnt/c/Users/) without having to type all that in again. Once you've run this, all your configuration files should now be present in your new home directory. Configuration files like .bashrc, .profile, and .bash_profile essentially provide commands that are run whenever you open a new shell. So now, if you open a new shell, everything should be working normally. Amazing. We're done!

### 6. Tips & tricks

Here are two handy commands you can add to your .profile file. Run vim ~/.profile, then, type these in at the top of the .profile file, one per line, using the commands we discussed previously (i to enter insert mode, esc to exit insert mode, :wq to save and quit).
alias rm='rm -i' makes it so that the rm command will always ask for confirmation when you're deleting a file. rm, for ReMove, is like a Windows delete except literally permanent and you will lose that data for good, so it's nice to have this extra safeguard. You can type rm -f to bypass. Linux can be super powerful, but with great power comes great responsibility. NEVER NEVER NEVER type in rm -rf /, this is saying 'delete literally everything and don't ask for confirmation', your computer will die. Newer versions of rm fail when you type this in, but don't push your luck. You've been warned. Be careful.
export DISPLAY=:0 if you install XLaunch VcXsrv, this line allows you to open graphical interfaces through Ubuntu. The export sets the environment variable DISPLAY, and the :0 tells Ubuntu that it should use the localhost display.

## Appendix A: brief intro to top-level UNIX directories

tl;dr only mess with /mnt, /home, and maybe maybe /usr. Don't touch anything else.
• bin: binaries, contains Ubuntu binary (aka executable) files that are used in bash. Here you'll find the binaries that execute commands like ls and pwd. Similar to /usbin, but bin gets loaded earlier in the booting process so it contains the most important commands.
• boot: contains information for operating system booting. Empty in WSL, because WSL isn't an operating system.
• dev: devices, provides files that allow Ubuntu to communicate with I/O devices. One useful file here is /dev/null, which is basically an information black hole that automatically deletes any data you pass it.
• etc: no idea why it's called etc, but it contains system-wide configuration files
• home: equivalent to Window's C:/Users folder, contains home folders for the different users. In an Ubuntu system, under /home/ you'd find the Documents folder, Downloads folder, etc.
• lib: libraries used by the system
• lib64 64-bit libraries used by the system
• mnt: mount, where your drives are located
• opt: third-party applications that (usually) don't have any dependencies outside the scope of their own package
• proc: process information, contains runtime information about your system (e.g. memory, mounted devices, hardware configurations, etc)
• run: directory for programs to store runtime information.
• srv: server folder, holds data to be served in protocols like ftp, www, cvs, and others
• sys: system, provides information about different I/O devices to the Linux Kernel. If dev files allows you to access I/O devices, sys files tells you information about these devices.
• tmp: temporary, these are system runtime files that are (in most Linux distros) cleared out after every reboot. It's also sort of deprecated for security reasons, and programs will generally prefer to use run.
• usr: contains additional UNIX commands, header files for compiling C programs, among other things. Kind of like bin but for less important programs. Most of everything you install using apt-get ends up here.
• var: variable, contains variable data such as logs, databases, e-mail etc, but that persist across different boots.
Also keep in mind that all of this is just convention. No Linux distribution needs to follow this file structure, and in fact almost all will deviate from what I just described. Hell, you could make your own Linux fork where /mnt/c information is stored in tmp.

## Appendix B: random resources

EDIT: implemented various changes suggested in the comments. Thanks all!

##### Red Hat OpenShift Container Platform Instruction Manual for Windows Powershell

Introduction to the manual
This manual is made to guide you step by step in setting up an OpenShift cloud environment on your own device. It will tell you what needs to be done, when it needs to be done, what you will be doing and why you will be doing it, all in one convenient manual that is made for Windows users. Although if you'd want to try it on Linux or MacOS we did add the commands necesary to get the CodeReady Containers to run on your operating system. Be warned however there are some system requirements that are necessary to run the CodeReady Containers that we will be using. These requirements are specified within chapter Minimum system requirements.
This manual is written for everyone with an interest in the Red Hat OpenShift Container Platform and has at least a basic understanding of the command line within PowerShell on Windows. Even though it is possible to use most of the manual for Linux or MacOS we will focus on how to do this within Windows.
If you follow this manual you will be able to do the following items by yourself:
● Updating OpenShift
● Configuring the DNS
● Accessing the OpenShift cluster
● Deploying the Mediawiki application
What is the OpenShift Container platform?
Red Hat OpenShift is a cloud development Platform as a Service (PaaS). It enables developers to develop and deploy their applications on a cloud infrastructure. It is based on the Kubernetes platform and is widely used by developers and IT operations worldwide. The OpenShift Container platform makes use of CodeReady Containers. CodeReady Containers are pre-configured containers that can be used for developing and testing purposes. There are also CodeReady Workspaces, these workspaces are used to provide any member of the development or IT team with a consistent, secure, and zero-configuration development environment.
The OpenShift Container Platform is widely used because it helps the programmers and developers make their application faster because of CodeReady Containers and CodeReady Workspaces and it also allows them to test their application in the same environment. One of the advantages provided by OpenShift is the efficient container orchestration. This allows for faster container provisioning, deploying and management. It does this by streamlining and automating the automation process.
What knowledge is required or recommended to proceed with the installation?
To be able to follow this manual some knowledge is mandatory, because most of the commands are done within the Command Line interface it is necessary to know how it works and how you can browse through files/folders. If you either don’t have this basic knowledge or have trouble with the basic Command Line Interface commands from PowerShell, then a cheat sheet might offer some help. We recommend the following cheat sheet for windows:
Https://www.sans.org/security-resources/sec560/windows\_command\_line\_sheet\_v1.pdf
Another option is to read through the operating system’s documentation or introduction guides. Though the documentation can be overwhelming by the sheer amount of commands.
MacOS
Https://www.makeuseof.com/tag/mac-terminal-commands-cheat-sheet/
Linux
https://ubuntu.com/tutorials/command-line-for-beginners#2-a-brief-history-lesson https://www.guru99.com/linux-commands-cheat-sheet.html
http://cc.iiti.ac.in/docs/linuxcommands.pdf
Aside from the required knowledge there are also some things that can be helpful to know just to make the use of OpenShift a bit simpler. This consists of some general knowledge on PaaS like Dockers and Kubernetes.
Docker https://www.docker.com/
Kubernetes https://kubernetes.io/

# System requirements

## Minimum System requirements

The minimum system requirements for the Red Hat OpenShift CodeReady Containers has the following minimum hardware:
Hardware requirements
Code Ready Containers requires the following system resources:
● 4 virtual CPU’s
● 9 GB of free random-access memory
● 35 GB of storage space
● Physical CPU with Hyper-V (intel) or SVM mode (AMD) this has to be enabled in the bios
Software requirements
The minimum system requirements for the Red Hat OpenShift CodeReady Containers has the following minimum operating system requirements:
Microsoft Windows
On Microsoft Windows, the Red Hat OpenShift CodeReady Containers requires the Windows 10 Pro Fall Creators Update (version 1709) or newer. CodeReady Containers does not work on earlier versions or other editions of Microsoft Windows. Microsoft Windows 10 Home Edition is not supported.
macOS
On macOS, the Red Hat OpenShift CodeReady Containers requires macOS 10.12 Sierra or newer.
Linux
On Linux, the Red Hat OpenShift CodeReady Containers is only supported on Red Hat Enterprise Linux/CentOS 7.5 or newer and on the latest two stable Fedora releases.
When using Red Hat Enterprise Linux, the machine running CodeReady Containers must be registered with the Red Hat Customer Portal.
Ubuntu 18.04 LTS or newer and Debian 10 or newer are not officially supported and may require manual set up of the host machine.

## Required additional software packages for Linux

The CodeReady Containers on Linux require the libvirt and Network Manager packages to run. Consult the following table to find the command used to install these packages for your Linux distribution:
Table 1.1 Package installation commands by distribution
Linux Distribution Installation command
Fedora Sudo dnf install NetworkManager
Red Hat Enterprise Linux/CentOS Su -c 'yum install NetworkManager'
Debian/Ubuntu Sudo apt install qemu-kvm libvirt-daemonlibvirt-daemon-system network-manage

# Installation

## Getting started with the installation

To install CodeReady Containers a few steps must be undertaken. Because an OpenShift account is necessary to use the application this will be the first step. An account can be made on “https://www.openshift.com/”, where you need to press login and after that select the option “Create one now”
After making an account the next step is to download the latest release of CodeReady Containers and the pulled secret on “https://cloud.redhat.com/openshift/install/crc/installer-provisioned”. Make sure to download the version corresponding to your platform and/or operating system. After downloading the right version, the contents have to be extracted from the archive to a location in your $PATH. The pulled secret should be saved because it is needed later. The command line interface has to be opened before we can continue with the installation. For windows we will use PowerShell. All the commands we use during the installation procedure of this guide are going to be done in this command line interface unless stated otherwise. To be able to run the commands within the command line interface, use the command line interface to go to the location in your$PATH where you extracted the CodeReady zip.
If you have installed an outdated version and you wish to update, then you can delete the existing CodeReady Containers virtual machine with the $crc delete command. After deleting the container, you must replace the old crc binary with a newly downloaded binary of the latest release. C:\Users\[username]\$PATH>crc delete
When you have done the previous steps please confirm that the correct and up to date crc binary is in use by checking it with the $crc version command, this should provide you with the version that is currently installed. C:\Users\[username]\$PATH>crc version
To set up the host operating system for the CodeReady Containers virtual machine you have to run the $crc setup command. After running crc setup, crc start will create a minimal OpenShift 4 cluster in the folder where the executable is located. C:\Users\[username]>crc setup  ## Setting up CodeReady Containers Now we need to set up the new CodeReady Containers release with the$crc setup command. This command will perform the operations necessary to run the CodeReady Containers and create the ~/.crc directory if it did not previously exist. In the process you have to supply your pulled secret, once this process is completed you have to reboot your system. When the system has restarted you can start the new CodeReady Containers virtual machine with the $crc start command. The$crc start command starts the CodeReady virtual machine and OpenShift cluster.
You cannot change the configuration of an existing CodeReady Containers virtual machine. So if you have a CodeReady Containers virtual machine and you want to make configuration changes you need to delete the virtual machine with the $crc delete command and create a new virtual machine and start that one with the configuration changes. Take note that deleting the virtual machine will also delete the data stored in the CodeReady Containers. So, to prevent data loss we recommend you save the data you wish to keep. Also keep in mind that it is not necessary to change the default configuration to start OpenShift. C:\Users\[username]\$PATH>crc setup
Before starting the machine, you need to keep in mind that it is not possible to make any changes to the virtual machine. For this tutorial however it is not necessary to change the configuration, if you don’t want to make any changes please continue by starting the machine with the crc start command.
C:\Users\[username]\$PATH>crc start  \ it is possible that you will get a Nameserver error later on, if this is the case please start it with* crc start -n 1.1.1.1 # Configuration It is not is not necessary to change the default configuration and continue with this tutorial, this chapter is here for those that wish to do so and know what they are doing. However, for MacOS and Linux it is necessary to change the dns settings. ## Configuring the CodeReady Containers To start the configuration of the CodeReady Containers use the command crc config. This command allows you to configure the crc binary and the CodeReady virtual machine. The command has some requirements before it’s able to configure. This requirement is a subcommand, the available subcommands for this binary and virtual machine are: get, this command allows you to see the values of a configurable property set/unset, this command can be used for 2 things. To display the names of, or to set and/or unset values of several options and parameters. These parameters being: ○ Shell options ○ Shell attributes ○ Positional parameters view, this command starts the configuration in read-only mode. These commands need to operate on named configurable properties. To list all the available properties, you can run the command$crc config --help.
Throughout this manual we will use the $crc config command a few times to change some properties needed for the configuration. There is also the possibility to use the crc config command to configure the behavior of the checks that’s done by the$crc start end $crc setup commands. By default, the startup checks will stop with the process if their conditions are not met. To bypass this potential issue, you can set the value of a property that starts with skip-check or warn-check to true to skip the check or warning instead of ending up with an error. C:\Users\[username]\$PATH>crc config get C:\Users\[username]\$PATH>crc config set C:\Users\[username]\$PATH>crc config unset C:\Users\[username]\$PATH>crc config view C:\Users\[username]\$PATH>crc config --help

## Configuring the Virtual Machine

You can use the CPUs and memory properties to configure the default number of vCPU’s and amount of memory available for the virtual machine.
To increase the number of vCPU’s available to the virtual machine use the $crc config set CPUs . Keep in mind that the default number for the CPU’s is 4 and the number of vCPU’s you wish to assign must be equal or greater than the default value. To increase the memory available to the virtual machine, use the$crc config set memory . Keep in mind that the default number for the memory is 9216 Mebibytes and the amount of memory you wish to assign must be equal or greater than the default value.
C:\Users\[username]\$PATH>crc config set CPUs C:\Users\[username]\$PATH>crc config set memory >

## Configuring the DNS

### Window / General DNS setup

There are two domain names used by the OpenShift cluster that are managed by the CodeReady Containers, these are:
crc.testing, this is the domain for the core OpenShift services.
apps-crc.testing, this is the domain used for accessing OpenShift applications that are deployed on the cluster.
Configuring the DNS settings in Windows is done by executing the crc setup. This command automatically adjusts the DNS configuration on the system. When executing crc start additional checks to verify the configuration will be executed.

### macOS DNS setup

MacOS expects the following DNS configuration for the CodeReady Containers
● The CodeReady Containers creates a file that instructs the macOS to forward all DNS requests for the testing domain to the CodeReady Containers virtual machine. This file is created at /etc/resolvetesting.
● The oc binary requires the following CodeReady Containers entry to function properly, api.crc.testing adds an entry to /etc/hosts pointing at the VM IPaddress.

### Linux DNS setup

CodeReady containers expect a slightly different DNS configuration. CodeReady Container expects the NetworkManager to manage networking. On Linux the NetworkManager uses dnsmasq through a configuration file, namely /etc/NetworkManageconf.d/crc-nm-dnsmasq.conf.
To set it up properly the dnsmasq instance has to forward the requests for crc.testing and apps-crc.testing domains to “192.168.130.11”. In the /etc/NetworkManageconf.d/crc-nm-dnsmasq.conf this will look like the following:
● Server=/crc. Testing/192.168.130.11
● Server=/apps-crc. Testing/192.168.130.11

# Accessing the Openshift Cluster

## Accessing the Openshift web console

To gain access to the OpenShift cluster running in the CodeReady virtual machine you need to make sure that the virtual machine is running before continuing with this chapter. The OpenShift clusters can be accessed through the OpenShift web console or the client binary(oc).
First you need to execute the $crc console command, this command will open your web browser and direct a tab to the web console. After that, you need to select the htpasswd_provider option in the OpenShift web console and log in as a developer user with the output provided by the crc start command. It is also possible to view the password for kubeadmin and developer users by running the$crc console --credentials command. While you can access the cluster through the kubeadmin and developer users, it should be noted that the kubeadmin user should only be used for administrative tasks such as user management and the developer user for creating projects or OpenShift applications and the deployment of these applications.
C:\Users\[username]\$PATH>crc console C:\Users\[username]\$PATH>crc console --credentials

## Accessing the OpenShift cluster with oc

To gain access to the OpenShift cluster with the use of the oc command you need to complete several steps.
Step 1.
Execute the $crc oc-env command to print the command needed to add the cached oc binary to your PATH: C:\Users\[username]\$PATH>crc oc-env
Step 2.
Execute the printed command. The output will look something like the following:
PS C:\Users\OpenShift> crc oc-env $Env:PATH = "CC:\Users\OpenShift\.crc\bin\oc;$Env:PATH" # Run this command to configure your shell: # & crc oc-env | Invoke-Expression
This means we have to execute* the command that the output gives us, in this case that is:
C:\Users\[username]\$PATH>crc oc-env | Invoke-Expression  \this has to be executed every time you start; a solution is to move the oc binary to the same path as the crc binary* To test if this step went correctly execute the following command, if it returns without errors oc is set up properly C:\Users\[username]\$PATH>.\oc
Step 3
Now you need to login as a developer user, this can be done using the following command:
$oc login -u developer https://api.crc.testing:6443 Keep in mind that the$crc start will provide you with the password that is needed to login with the developer user.
C:\Users\[username]\$PATH>oc login -u developer https://api.crc.testing:6443  Step 4 The oc can now be used to interact with your OpenShift cluster. If you for instance want to verify if the OpenShift cluster Operators are available, you can execute the command $oc get co
Keep in mind that by default the CodeReady Containers disables the functions provided by the commands $machine-config and$monitoringOperators.

## Creating and managing an application

There are a few ways to create and manage applications. Within this demonstration we’ll show how to create an application from the previously imported image.

### Creating the application

To create an image with the previously imported image go back to the console and topology. From here on select container image.
https://preview.redd.it/6506ea4iitv51.png?width=869&format=png&auto=webp&s=c0231d70bb16c76cd131e6b71256e93550cc8b37
For the option image you'll want to select the “image stream tag from internal registry” option. Give the application a name and then create the deployment.
https://preview.redd.it/tk72idniitv51.png?width=813&format=png&auto=webp&s=a4e662cf7b96604d84df9d04ab9b90b5436c803c
If everything went right during the creating process you should see the following, this means that the application is successfully running.

### Scaling the application

In OpenShift there is a feature called autoscaling. There are two types of application scaling, namely vertical scaling, and horizontal scaling. Vertical scaling is adding only more CPU and hard disk and is no longer supported by OpenShift. Horizontal scaling is increasing the number of machines.
One of the ways to scale an application is by increasing the number of pods. This can be done by going to a pod within the view as seen in the previous step. By either pressing the up or down arrow more pods of the same application can be added. This is similar to horizontal scaling and can result in better performance when there are a lot of active users at the same time.
https://preview.redd.it/s6i1vbcrltv51.png?width=602&format=png&auto=webp&s=e62cbeeed116ba8c55704d61a990fc0d8f3cfaa1
In the picture above we see the number of nodes and pods and how many resources those nodes and pods are using. This is something to keep in mind if you want to scale up your application, the more you scale it up, the more resources it will take up.

https://preview.redd.it/quh037wmitv51.png?width=194&format=png&auto=webp&s=5e326647b223f3918c259b1602afa1b5fbbeea94

### Network

Since OpenShift Container platform is built on Kubernetes it might be interesting to know some theory about its networking. Kubernetes, on which the OpenShift Container platform is built, ensures that the Pods within OpenShift can communicate with each other via the network and assigns them their own IP address. This makes all containers within the Pod behave as if they were on the same host. By giving each pod its own IP address, pods can be treated as physical hosts or virtual machines in terms of port mapping, networking, naming, service discovery, load balancing, application configuration and migration. To run multiple services such as front-end and back-end services, OpenShift Container Platform has a built-in DNS.
One of the changes that can be made to the networking of a Pod is the Route. We’ll show you how this can be done in this demonstration.
The Route is not the only thing that can be changed and or configured. Two other options that might be interesting but will not be demonstrated in this manual are:
- Ingress controller, Within OpenShift it is possible to set your own certificate. A user must have a certificate / key pair in PEM-encoded files, with the certificate signed by a trusted authority.
- Network policies, by default all pods in a project are accessible from other pods and network locations. To isolate one or more pods in a project, it is possible to create Network Policy objects in that project to indicate the allowed incoming connections. Project administrators can create and delete Network Policy objects within their own project.
There is a search function within the Container Platform. We’ll use this to search for the network routes and show how to add a new route.
https://preview.redd.it/8jkyhk8pitv51.png?width=769&format=png&auto=webp&s=9a8762df5bbae3d8a7c92db96b8cb70605a3d6da
You can add items that you use a lot to the navigation
https://preview.redd.it/t32sownqitv51.png?width=1598&format=png&auto=webp&s=6aab6f17bc9f871c591173493722eeae585a9232
https://preview.redd.it/pm3j7ljritv51.png?width=291&format=png&auto=webp&s=bc6fbda061afdd0780bbc72555d809b84a130b5b
Now that we’ve added Routes to the navigation, we can start the creation of the Route by clicking on “Create route”.
https://preview.redd.it/5lgecq0titv51.png?width=1603&format=png&auto=webp&s=d548789daaa6a8c7312a419393795b52da0e9f75
Fill in the name, select the service and the target port from the drop-down menu and click on Create.
https://preview.redd.it/qczgjc2uitv51.png?width=778&format=png&auto=webp&s=563f73f0dc548e3b5b2319ca97339e8f7b06c9d6
As you can see, we’ve successfully added the new route to our application.
Storage
OpenShift makes use of Persistent Storage, this type of storage uses persistent volume claims(PVC). PVC’s allow the developer to make persistent volumes without needing any knowledge about the underlying infrastructure.
Within this storage there are a few configuration options:
• Reclaim
• Recycle
• Delete
It is however important to know how to manually reclaim the persistent volumes, since if you delete PV the associated data will not be automatically deleted with it and therefore you cannot reassign the storage to another PV yet.
To manually reclaim the PV, you need to follow the following steps:
Step 1: Delete the PV, this can be done by executing the following command
$oc delete  Step 2: Now you need to clean up the data on the associated storage asset Step 3: Now you can delete the associated storage asset or if you with to reuse the same storage asset you can now create a PV with the storage asset definition. It is also possible to directly change the reclaim policy within OpenShift, to do this you would need to follow the following steps: Step 1: Get a list of the PVs in your cluster $oc get pv
This will give you a list of all the PV’s in your cluster and will display their following attributes: Name, Capacity, Accesmodes, Reclaimpolicy, Statusclaim, Storageclass, Reason and Age.
Step 2: Now choose the PV you wish to change and execute one of the following command’s, depending on your preferred policy:
$oc patch pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'  In this example the reclaim policy will be changed to Retain. $oc patch pv  -p '{"spec":{"persistentVolumeReclaimPolicy":"Recycle"}}'
In this example the reclaim policy will be changed to Recycle.
$oc patch pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}'  In this example the reclaim policy will be changed to Delete. Step 3: After this you can check the PV to verify the change by executing this command again: $oc get pv

### Monitoring

Within Red Hat OpenShift there is the possibility to monitor the data that has been created by your containers, applications, and pods. To do so, click on the menu option in the top left corner. Check if you are logged in as Developer and click on “Monitoring”. Normally this function is not activated within the CodeReady containers, because it uses a lot of resources (Ram and CPU) to run.
https://preview.redd.it/an0wvn6zitv51.png?width=228&format=png&auto=webp&s=51abf8cc31bd763deb457d49514f99ee81d610ec
Once you have activated “Monitoring” you can change the “Time Range” and “Refresh Interval” in the top right corner of your screen. This will change the monitoring data on your screen.
https://preview.redd.it/e0yvzsh1jtv51.png?width=493&format=png&auto=webp&s=b2c563635cfa60ea7ce2f9c146aa994df6aa1c34
Within this function you can also monitor “Events”. These events are records of important information and are useful for monitoring and troubleshooting within the OpenShift Container Platform.
https://preview.redd.it/l90vkmp3jtv51.png?width=602&format=png&auto=webp&s=4e97f14bedaec7ededcdcda96e7823f77ced24c2

## User management

According to the documentation of OpenShift is a user, an entity that interacts with the OpenShift Container Platform API. These can be a developer for developing applications or an administrator for managing the cluster. Users can be assigned to groups, which set the permissions applied to all the group’s members. For example, you can give API access to a group, which gives all members of the group API access.
There are multiple ways to create a user depending on the configured identity provider. The DenyAll identity provider is the default within OpenShift Container Platform. This default denies access for all the usernames and passwords.
First, we’re going to create a new user, the way this is done depends on the identity provider, this depends on the mapping method used as part of the identity provider configuration.
for more information on what mapping methods are and how they function:
https://docs.openshift.com/enterprise/3.1/install_config/configuring_authentication.html
With the default mapping method, the steps will be as following
$oc create user  Next up, we’ll create an OpenShift Container Platform Identity. Use the name of the identity provider and the name that uniquely represents this identity in the scope of the identity provider: $oc create identity :
The is the name of the identity provider in the master configuration. For example, the following commands create an Identity with identity provider ldap_provider and the identity provider username mediawiki_s.
$oc create identity ldap_provider:mediawiki_s  Create a useidentity mapping for the created user and identity: $oc create useridentitymapping :
For example, the following command maps the identity to the user:
$oc create useridentitymapping ldap_provider:mediawiki_s mediawiki  Now were going to assign a role to this new user, this can be done by executing the following command: $oc create clusterrolebinding  \ --clusterrole= --user=
There is a --clusterrole option that can be used to give the user a specific role, like a cluster user with admin privileges. The cluster admin has access to all files and is able to manage the access level of other users.
Below is an example of the admin clusterrole command:
$oc create clusterrolebinding registry-controller \ --clusterrole=cluster-admin --user=admin  ## What did you achieve? If you followed all the steps within this manual you now should have a functioning Mediawiki Application running on your own CodeReady Containers. During the installation of this application on CodeReady Containers you have learned how to do the following things: ● Installing the CodeReady Containers ● Updating OpenShift ● Configuring a CodeReady Container ● Configuring the DNS ● Accessing the OpenShift cluster ● Deploying an application ● Creating new users With these skills you’ll be able to set up your own Container Platform environment and host applications of your choosing. # Troubleshooting Nameserver There is the possibility that your CodeReady container can't connect to the internet due to a Nameserver error. When this is encountered a working fix for us was to stop the machine and then start the CRC machine with the following command: C:\Users\[username]\$PATH>crc start -n 1.1.1.1
Should you run into a problem with Hyper-V it might be because your user is not an admin and therefore can’t access the Hyper-V admin user group.
1. Click Start > Control Panel > Administration Tools > Computer Management. The Computer Management window opens.
2. Click System Tools > Local Users and Groups > Groups. The list of groups opens.
3. Double-click the Hyper-V Administrators group. The Hyper-V Administrators Properties window opens.
4. Click Add. The Select Users or Groups window opens.
5. In the Enter the object names to select field, enter the user account name to whom you want to assign permissions, and then click OK.
6. Click Apply, and then click OK.

# Terms and definitions

These terms and definitions will be expanded upon, below you can see an example of how this is going to look like together with a few terms that will require definitions.
Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. Openshift is based on Kubernetes.
Clusters are a collection of multiple nodes which communicate with each other to perform a set of operations.
Containers are the basic units of OpenShift applications. These container technologies are lightweight mechanisms for isolating running processes so that they are limited to interacting with only their designated resources.
CodeReady Container is a minimal, preconfigured cluster that is used for development and testing purposes.
CodeReady Workspaces uses Kubernetes and containers to provide any member of the development or IT team with a consistent, secure, and zero-configuration development environment.

# Sources

##### ResultsFileName = 0×0 empty char array Why? Where are my results?

Edit: Turns out I was missing a needed toolbox.
Hello,
I am not getting any errors and I do not understand why I am not getting any output. I am trying to batch process a large number of ecg signals. Below is my code and the two relevant functions. Any help greatly appreciated. I am very new.
d = importSections("Dx_sections.csv"); % set the number of recordings n = height(d); % settings HRVparams = InitializeHRVparams('test_physionet') for ii = 1:n % Import waveform (ECG) [record, signals] = read_edf(strcat(d.PID(ii), '/baseline.edf')); myecg = record.ECG; Ann = []; [HRVout, ResultsFileName] = Main_HRV_Analysis(myecg,'','ECGWaveform',HRVparams) end function [HRVout, ResultsFileName ] = Main_HRV_Analysis(InputSig,t,InputFormat,HRVparams,subID,ann,sqi,varargin) % ====== HRV Toolbox for PhysioNet Cardiovascular Signal Toolbox ========= % % Main_HRV_Analysis(InputSig,t,InputFormat,HRVparams,subID,ann,sqi,varargin) % OVERVIEW: % % INPUT: % InputSig - Vector containing RR intervals data (in seconds) % or ECG/PPG waveform % t - Time indices of the rr interval data (seconds) or % leave empty for ECG/PPG input % InputFormat - String that specifiy if the input vector is: % 'RRIntervals' for RR interval data % 'ECGWaveform' for ECG waveform % 'PPGWaveform' for PPG signal % HRVparams - struct of settings for hrv_toolbox analysis that can % be obtained using InitializeHRVparams.m function % HRVparams = InitializeHRVparams(); % % % OPTIONAL INPUTS: % subID - (optional) string to identify current subject % ann - (optional) annotations of the RR data at each point % indicating the type of the beat % sqi - (optional) Signal Quality Index; Requires a % matrix with at least two columns. Column 1 % should be timestamps of each sqi measure, and % Column 2 should be SQI on a scale from 0 to 1. % Use InputSig, Type pairs for additional signals such as ABP % or PPG signal. The input signal must be a vector containing % signal waveform and the Type: 'ABP' and\or 'PPG'. % % OUTPUS: % results - HRV time and frequency domain metrics as well % as AC and DC, SDANN and SDNNi % ResultsFileName - Name of the file containing the results % % NOTE: before running this script review and modifiy the parameters % in "initialize_HRVparams.m" file accordingly with the specific % of the new project (see the readme.txt file for further details) % EXAMPLES % - rr interval input % Main_HRV_Analysis(RR,t,'RRIntervals',HRVparams) % - ECG wavefrom input % Main_HRV_Analysis(ECGsig,t,'ECGWavefrom',HRVparams,'101') % - ECG waveform and also ABP and PPG waveforms % Main_HRV_Analysis(ECGsig,t,'ECGWaveform',HRVparams,[],[],[], abpSig, % 'ABP', ppgSig, 'PPG') % % DEPENDENCIES & LIBRARIES: % HRV Toolbox for PhysioNet Cardiovascular Signal Toolbox % https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox % % REFERENCE: % Vest et al. "An Open Source Benchmarked HRV Toolbox for Cardiovascular % Waveform and Interval Analysis" Physiological Measurement (In Press), 2018. % % REPO: % https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox % ORIGINAL SOURCE AND AUTHORS: % This script written by Giulia Da Poian % Dependent scripts written by various authors % (see functions for details) % COPYRIGHT (C) 2018 % LICENSE: % This software is offered freely and without warranty under % the GNU (v3 or later) public license. See license file for % more information %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if nargin < 4 error('Wrong number of input arguments') end if nargin < 5 subID = '0000'; end if nargin < 6 ann = []; end if nargin < 7 sqi = []; end if length(varargin) == 1 || length(varargin) == 3 error('Incomplete Signal-Type pair') elseif length(varargin) == 2 extraSigType = varargin(2); extraSig = varargin{1}; elseif length(varargin) == 4 extraSigType = [varargin(2) varargin(4)]; extraSig = [varargin{1} varargin{3}]; end if isa(subID,'cell'); subID = string(subID); end % Control on signal length if (strcmp(InputFormat, 'ECGWaveform') && length(InputSig)/HRVparams.Fs< HRVparams.windowlength) ... || (strcmp(InputFormat, 'PPGWaveform') && length(InputSig)/HRVparams.Fs 300 s VLF = [0.0033 .04]; % Requires at least 300 s window LF = [.04 .15]; % Requires at least 25 s window HF = [0.15 0.4]; % Requires at least 7 s window HRVparams.freq.limits = [ULF; VLF; LF; HF]; HRVparams.freq.zero_mean = 1; % Default: 1, Option for subtracting the mean from the input data HRVparams.freq.method = 'lomb'; % Default: 'lomb' % Options: 'lomb', 'burg', 'fft', 'welch' HRVparams.freq.plot_on = 0; % The following settings are for debugging spectral analysis methods HRVparams.freq.debug_sine = 0; % Default: 0, Adds sine wave to tachogram for debugging HRVparams.freq.debug_freq = 0.15; % Default: 0.15 HRVparams.freq.debug_weight = .03; % Default: 0.03 % Lomb: HRVparams.freq.normalize_lomb = 0; % Default: 0 % 1 = Normalizes Lomb Periodogram, % 0 = Doesn't normalize % Burg: (not recommended) HRVparams.freq.burg_poles = 15; % Default: 15, Number of coefficients % for spectral estimation using the Burg % method (not recommended) % The following settings are only used when the user specifies spectral % estimation methods that use resampling : 'welch','fft', 'burg' HRVparams.freq.resampling_freq = 7; % Default: 7, Hz HRVparams.freq.resample_interp_method = 'cub'; % Default: 'cub' % 'cub' = cublic spline method % 'lin' = linear spline method HRVparams.freq.resampled_burg_poles = 100; % Default: 100 %% 11. SDANN and SDNNI Analysis Settings HRVparams.sd.on = 1; % Default: 1, SD analysis 1=On or 0=Off HRVparams.sd.segmentlength = 300; % Default: 300, windows length in seconds %% 12. PRSA Analysis Settings HRVparams.prsa.on = 1; % Default: 1, PRSA Analysis 1=On or 0=Off HRVparams.prsa.win_length = 30; % Default: 30, The length of the PRSA signal % before and after the anchor points % (the resulting PRSA has length 2*L) HRVparams.prsa.thresh_per = 20; % Default: 20%, Percent difference that one beat can % differ from the next in the prsa code HRVparams.prsa.plot_results = 0; % Default: 0 HRVparams.prsa.scale = 2; % Default: 2, scale parameter for wavelet analysis (to compute AC and DC) %% 13. Peak Detection Settings % The following settings are for jqrs.m HRVparams.PeakDetect.REF_PERIOD = 0.250; % Default: 0.25 (should be 0.15 for FECG), refractory period in sec between two R-peaks HRVparams.PeakDetect.THRES = .6; % Default: 0.6, Energy threshold of the detector HRVparams.PeakDetect.fid_vec = []; % Default: [], If some subsegments should not be used for finding the optimal % threshold of the P&T then input the indices of the corresponding points here HRVparams.PeakDetect.SIGN_FORCE = []; % Default: [], Force sign of peaks (positive value/negative value) HRVparams.PeakDetect.debug = 0; % Default: 0 HRVparams.PeakDetect.ecgType = 'MECG'; % Default : MECG, options (adult MECG) or featl ECG (fECG) HRVparams.PeakDetect.windows = 15; % Befautl: 15,(in seconds) size of the window onto which to perform QRS detection %% 14. Entropy Settings % Multiscale Entropy HRVparams.MSE.on = 1; % Default: 1, MSE Analysis 1=On or 0=Off HRVparams.MSE.windowlength = []; % Default: [], windows size in seconds, default perform MSE on the entire signal HRVparams.MSE.increment = []; % Default: [], window increment HRVparams.MSE.RadiusOfSimilarity = 0.15; % Default: 0.15, Radius of similarity (% of std) HRVparams.MSE.patternLength = 2; % Default: 2, pattern length HRVparams.MSE.maxCoarseGrainings = 20; % Default: 20, Maximum number of coarse-grainings % SampEn an ApEn HRVparams.Entropy.on = 1; % Default: 1, MSE Analysis 1=On or 0=Off HRVparams.Entropy.RadiusOfSimilarity = 0.15; % Default: 0.15, Radius of similarity (% of std) HRVparams.Entropy.patternLength = 2; % Default: 2, pattern length %% 15. DFA Settings HRVparams.DFA.on = 1; % Default: 1, DFA Analysis 1=On or 0=Off HRVparams.DFA.windowlength = []; % Default [], windows size in seconds, default perform DFA on the entair signal HRVparams.DFA.increment = []; % Default: [], window increment HRVparams.DFA.minBoxSize = 4 ; % Default: 4, Smallest box width HRVparams.DFA.maxBoxSize = []; % Largest box width (default in DFA code: signal length/4) HRVparams.DFA.midBoxSize = 16; % Medium time scale box width (default in DFA code: 16) %% 16. Poincaré plot HRVparams.poincare.on = 1; % Default: 1, Poincare Analysis 1=On or 0=Off %% 17. Heart Rate Turbulence (HRT) - Settings HRVparams.HRT.on = 1; % Default: 1, HRT Analysis 1=On or 0=Off HRVparams.HRT.BeatsBefore = 2; % Default: 2, # of beats before PVC HRVparams.HRT.BeatsAfter = 16; % Default: 16, # of beats after PVC and CP HRVparams.HRT.GraphOn = 0; % Default: 0, do not plot HRVparams.HRT.windowlength = 24; % Default 24h, windows size in hours HRVparams.HRT.increment = 24; % Default 24h, sliding window increment in hours HRVparams.HRT.filterMethod = 'mean5before'; % Default mean5before, HRT filtering option %% 18. Output Settings HRVparams.gen_figs = 0; % Generate figures HRVparams.save_figs = 0; % Save generated figures if HRVparams.save_figs == 1 HRVparams.gen_figs = 1; end % Format settings for HRV Outputs HRVparams.output.format = 'csv'; % 'csv' - creates csv file for output % 'mat' - creates .mat file for output HRVparams.output.separate = 0; % Default : 1 = separate files for each subject % 0 = all results in one file HRVparams.output.num_win = []; % Specify number of lowest hr windows returned % leave blank if all windows should be returned % Format settings for annotations generated HRVparams.output.ann_format = 'binary'; % 'binary' = binary annotation file generated % 'csv' = ASCII CSV file generated end

##### An introduction to Linux through Windows Subsystem for Linux

I'm working as an Undergraduate Learning Assistant and wrote this guide to help out students who were in the same boat I was in when I first took my university's intro to computer science course. It provides an overview of how to get started using Linux, guides you through setting up Windows Subsystem for Linux to run smoothly on Windows 10, and provides a very basic introduction to Linux. Students seemed to dig it, so I figured it'd help some people in here as well. I've never posted here before, so apologies if I'm unknowingly violating subreddit rules.

# Getting Windows Subsystem for Linux running smoothly on Windows 10

## Introduction and motivation

So you're thinking of installing a Linux distribution, and are unsure where to start. Or you're an unfortunate soul using Windows 10 in CPSC 201. Either way, this guide is for you. In this section I'll give a very basic intro to some of options you've got at your disposal, and explain why I chose Windows Subsystem for Linux among them. All of these have plenty of documentation online so Google if in doubt.
• Dual-booting with Windows and a Linux distro
• Will basically involve partitioning your drive and installing Linux from an external bootable USB through your computer's boot menu. You'll get the full Linux experience.
• Lots of Linux flavors to choose from. For beginners, Ubuntu and Linux Mint are generally recommended. I have Ubuntu 18.04 LTS, I'd recommend Ubuntu 20.04 LTS since it's newer, but it's all up to you.
• However, it's a pain to setup and to constantly be switching between operating systems, so up to you. Maybe you wanna make the full jump to Linux, maybe you don't.
• Life pro tip: if you go this route, disable Window 10's Fast Startup feature as it will get very screwy with a dual-boot.
• Using a virtual machine (VM) to run Linux
• Devours RAM and is generally pretty slow, would not recommend.
• Using bash emulation software, like Putty or Git Bash
• bash stands for Bourne Again Shell (no, Bourne is not a typo), it's the most commonly used Linux shell these days
• bash emulators generally don't include a package manager, i.e. you can't download new bash programs, so pretty limited for general usage. BUT you can install a package manager externally, kind of hacky but can work.
• Using Windows Subsystem for Linux (either WSL 1 or WSL 2)
• WSL provides a compatibility layer for running Linux natively on Windows 10. It has integration features certain Windows 10 development apps (notably Visual Studio Code) as well.
• You've got two options, WSL 1 and WSL 2. WSL 2 was recently released and features a real Linux kernel, as opposed to an simulated kernel in WSL. This means WSL 2 offers significant performance advantages, but still lacks some of WSL 1's features.
• WSL 1 is what I currently use, and thus what I'll be talking about in this guide. I'm not necessarily recommending it, frankly I regret not doing a dual-boot sooner and ditching Windows, but a dual-boot isn't for everyone and takes a lot of time you might not have right now.
• Getting WSL initially setup is easy, but making it run smoothly requires some effort, and some features (like audio playback or displaying GUIs) require workarounds you can research if interested.
With that out of the way, let's get started with setting up WSL 1 on your Windows 10 machine.

## Setting up WSL

So if you've read this far I've convinced you to use WSL. Let's get started with setting it up. The very basics are outlined in Microsoft's guide here, I'll be covering what they talk about and diving into some other stuff.

### 1. Installing WSL

Press the Windows key (henceforth Winkey) and type in PowerShell. Right-click the icon and select run as administrator. Next, paste in this command:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
Now you'll want to perform a hard shutdown on your computer. This can become unecessarily complicated because of Window's fast startup feature, but here we go. First try pressing the Winkey, clicking on the power icon, and selecting Shut Down while holding down the shift key. Let go of the shift key and the mouse, and let it shutdown. Great! Now open up Command Prompt and type in
wsl --help
If you get a large text output, WSL has been successfully enabled on your machine. If nothing happens, your computer failed at performing a hard shutdown, in which case you can try the age-old technique of just holding down your computer's power button until the computer turns itself off. Make sure you don't have any unsaved documents open when you do this.

### 2. Installing Ubuntu

Great! Now that you've got WSL installed, let's download a Linux distro. Press the Winkey and type in Microsoft Store. Now use the store's search icon and type in Ubuntu. Ubuntu is a Debian-based Linux distribution, and seems to have the best integration with WSL, so that's what we'll be going for. If you want to be quirky, here are some other options. Once you type in Ubuntu three options should pop up: Ubuntu, Ubuntu 20.04 LTS, and Ubuntu 18.04 LTS.
![Windows Store](https://theshepord.github.io/intro-to-WSL/docs/images/winstore.png) Installing plain-old "Ubuntu" will mean the app updates whenever a new major Ubuntu distribution is released. The current version (as of 09/02/2020) is Ubuntu 20.04.1 LTS. The other two are older distributions of Ubuntu. For most use-cases, i.e. unless you're running some software that will break when upgrading, you'll want to pick the regular Ubuntu option. That's what I did.
Once that's done installing, again hit Winkey and open up Ubuntu. A console window should open up, asking you to wait a minute or two for files to de-compress and be stored on your PC. All future launches should take less than a second. It'll then prompt you to create a username and password. I'd recommend sticking to whatever your Windows username and password is so that you don't have to juggle around two different usepassword combinations, but up to you.
sudo apt-get update
And then
sudo apt-get upgrade
apt-get is the Ubuntu package manager, this is what you'll be using to install additional programs on WSL.

### 3. Making things nice and crispy: an introduction to UNIX-based filesystems

The two above steps are technically all you need for running WSL on your system. However, you may notice that whenever you open up the Ubuntu app your current folder seems to be completely random. If you type in pwd (for Present Working Directory, 'directory' is synonymous with 'folder') inside Ubuntu and hit enter, you'll likely get some output akin to /home/. Where is this folder? Is it my home folder? Type in ls (for LiSt) to see what files are in this folder. Probably you won't get any output, because surprise surprise this folder is not your Windows home folder and is in fact empty (okay it's actually not empty, which we'll see in a bit. If you type in ls -a, a for All, you'll see other files but notice they have a period in front of them, which tells bash that they should be hidden by default. Anyways).
So where is my Windows home folder? Is WSL completely separate from Windows? Nope! This is Windows Subsystem for Linux after all. Notice how, when you typed pwd earlier, the address you got was /home/. Notice that forward-slash right before home. That forward-slash indicates the root directory (not to be confused with the /root directory), which is the directory at the top of the directory hierarchy and contains all other directories in your system. So if we type ls /, you'll see what are the top-most directories in your system. Okay, great. They have a bunch of seemingly random names. Except, shocker, they aren't random. I've provided a quick run-down in Appendix A.
For now, though, we'll focus on /mnt, which stands for mount. This is where your C drive, which contains all your Windows stuff, is mounted. So if you type ls /mnt/c, you'll begin to notice some familiar folders. Type in ls /mnt/c/Users, and voilà, there's your Windows home folder. Remember this filepath, /mnt/c/Users/. When we open up Ubuntu, we don't want it tossing us in this random /home/ directory, we want our Windows home folder. Let's change that!

### 4. Changing your default home folder

Type in sudo vim /etc/passwd. You'll likely be prompted for your Ubuntu's password. sudo is a command that gives you root privileges in bash (akin to Windows's right-click then selecting 'Run as administrator'). vim is a command-line text-editing tool, kinda like an even crummier Notepad, which is a pain to use at first but bear with me and we can pull through. /etc/passwd is a plaintext file that does not store passwords, as the name would suggest, but rather stores essential user info used every time you open up WSL.
Anyway, once you've typed that in, your shell should look something like this: ![vim /etc/passwd](https://theshepord.github.io/intro-to-WSL/docs/images/vim-etc-passwd.png)
Using arrow-keys, find the entry that begins with your Ubuntu username. It should be towards the bottom of the file. In my case, the line looks like
theshep:x:1000:1000:,,,:/home/pizzatron3000:/bin/bash
See that cringy, crummy /home/pizzatron3000? Not only do I regret that username to this day, it's also not where we want our home directory. Let's change that! Press i to initiate vim's -- INSERT -- mode. Use arrow-keys to navigate to that section, and delete /home/ by holding down backspace. Remember that filepath I asked you to remember? /mnt/c/Users/. Type that in. For me, the line now looks like
theshep:x:1000:1000:,,,:/mnt/c/Users/lucas:/bin/bash
Next, press esc to exit insert mode, then type in the following:
:wq
The : tells vim you're inputting a command, w means write, and q means quit. If you've screwed up any of the above sections, you can also type in :q! to exit vim without saving the file. Just remember to exit insert mode by pressing esc before inputting commands, else you'll instead be writing to the file.
Great! If you now open up a new terminal and type in pwd, you should be in your Window's home folder! However, things seem to be lacking their usual color...

### 5. Importing your configuration files into the new home directory

Your home folder contains all your Ubuntu and bash configuration files. However, since we just changed the home folder to your Window's home folder, we've lost these configuration files. Let's bring them back! These configuration files are hidden inside /home/, and they all start with a . in front of the filename. So let's copy them over into your new home directory! Type in the following:
cp -r /home//* ~
cp stands for CoPy, -r stands for recursive (i.e. descend into directories), the * is a Kleene Star and means "grab everything that's here", and the ~ is a quick way of writing your home directory's filepath (which would be /mnt/c/Users/) without having to type all that in again. Once you've run this, all your configuration files should now be present in your new home directory. Configuration files like .bashrc, .profile, and .bash_profile essentially provides commands that are run whenever you open a new shell. So now, if you open a new shell, everything should be working normally. Amazing. We're done!

### 6. Tips & tricks

Here are two handy commands you can add to your .profile file. Run vim ~/.profile, then, type these in at the top of the .profile file, one per line, using the commands we discussed previously (i to enter insert mode, esc to exit insert mode, :wq to save and quit).
alias rm='rm -i' makes it so that the rm command will always ask for confirmation when you're deleting a file. rm, for ReMove, is like a Windows delete except literally permanent and you will lose that data for good, so it's nice to have this extra safeguard. You can type rm -f to bypass. Linux can be super powerful, but with great power comes great responsibility. NEVER NEVER NEVER type in rm -rf /, this is saying 'delete literally everything and don't ask for confirmation', your computer will die. You've been warned. Be careful.
export DISPLAY=:0 if you install XLaunch VcXsrv, this line allows you to open graphical interfaces through Ubuntu. The export sets the environment variable DISPLAY, and the :0 tells Ubuntu that it should use the localhost display.

## Appendix A: overview of top-level UNIX directories

tl;dr only mess with /mnt, /home, and maybe maybe /usr. Don't touch anything else.
• bin: binaries, contains Ubuntu binary (aka executable) files that are used in bash. Here you'll find the binaries that execute commands like ls and pwd. Similar to /usbin, but bin gets loaded earlier in the booting process so it contains the most important commands.
• boot: contains information for operating system booting. Empty in WSL, because WSL isn't an operating system.
• dev: devices, contains information for Ubuntu to communicate with I/O devices. One useful file here is /dev/null, which is basically an information black hole that automatically deletes any data you pass it.
• etc: no idea why it's called etc, but it contains system-wide configuration files
• home: equivalent to Window's C:/Users folder, contains home folders for the different users. In an Ubuntu system, under /home/ you'd find the Documents folder, Downloads folder, etc.
• lib: libraries used by the system
• lib64 64-bit libraries used by the system
• mnt: mount, where your drives are located
• opt: third-party applications that don't have any dependencies outside the scope of their own package
• proc: process information, contains details about your Linux system, kind of like Windows's C:/Windows folder
• run: directory for programs to store runtime information. Similarly to /bin vs /usbin, run has the same function as /varun, but gets loaded sooner in the boot process.
• srv: server folder, holds data to be served in protocols like ftp, www, cvs, and others
• sys: system, used by the Linux kernel to set or obtain information about the host system
• tmp: temporary, runtime files that are cleared out after every reboot. Kinda like RAM in that way.
• usr: contains additional UNIX commands, header files for compiling C programs, among other things. Most of everything you install using apt-get ends up here.
• var: variable, contains variable data such as logs, databases, e-mail etc, but that persist across different boots.

## glimpse into the future of Roblox

Our vision to bring the world together through play has never been more relevant than it is now. As our founder and CEO, David Baszucki (a.k.a. Builderman), mentioned in his keynote, more and more people are using Roblox to stay connected with their friends and loved ones. He hinted at a future where, with our automatic machine translation technology, Roblox will one day act as a universal translator, enabling people from different cultures and backgrounds to connect and learn from each other.
During his keynote, Builderman also elaborated upon our vision to build the Metaverse; the future of avatar creation on the platform (infinitely customizable avatars that allow any body, any clothing, and any animation to come together seamlessly); more personalized game discovery; and simulating large social gatherings (like concerts, graduations, conferences, etc.) with tens of thousands of participants all in one server. We’re still very early on in this journey, but if these past five months have shown us anything, it’s clear that there is a growing need for human co-experience platforms like Roblox that allow people to play, create, learn, work, and share experiences together in a safe, civil 3D immersive space.
Up next, our VP of Developer Relations, Matt Curtis (a.k.a. m4rrh3w), shared an update on all the things we’re doing to continue empowering developers to create innovative and exciting content through collaboration, support, and expertise. He also highlighted some of the impressive milestones our creator community has achieved since last year’s RDC. Here are a few key takeaways:
• Adopt Me! now has over 10 billion plays and surpassed 1.6 million concurrent users.
• Piggy, launched in January 2020, has close to 5 billion visits in just over six months.
• Developers are on track to earn over $250 million in 2020. • In June 2020, developers earned nearly$2 million from Premium Payouts, which rewards them based on the amount of engagement time Premium subscribers spend in their games.
• There are now 345,000 developers on the platform who are monetizing their games.
And lastly, our VP of Engineering, Technology, Adam Miller (a.k.a. rbadam), unveiled a myriad of cool and upcoming features developers will someday be able to sink their teeth into. We saw a glimpse of procedural skies, skinned meshes, more high-quality materials, new terrain types, more fonts in Studio, a new asset type for in-game videos, haptic feedback on mobile, real-time CSG operations, and many more awesome tools that will unlock the potential for even bigger, more immersive experiences on Roblox.

## Vibin’

Despite the virtual setting, RDC just wouldn’t have been the same without any fun party activities and networking opportunities. So, we invited special guests DJ Hyper Potions and cyber mentalist Colin Cloud for some truly awesome, truly mind-bending entertainment. Yoga instructor Erin Gilmore also swung by to inspire attendees to get out of their chair and get their body moving. And of course, we even had virtual rooms dedicated to karaoke and head-to-head social games, like trivia and Pictionary.
Over on the networking side, Team Adopt Me, Red Manta, StyLiS Studios, and Summit Studios hosted a virtual booth for attendees to ask questions, submit resumes, and more. We also had a networking session where three participants would be randomly grouped together to get to know each other.

## What does Roblox mean to you?

We all know how talented the Roblox community is from your creations. We’ve heard plenty of stories over the years about how Roblox has touched your lives, how you’ve made friendships, learned new skills, or simply found a place where you can be yourself. We wanted to hear more. So, we asked attendees: What does Roblox mean to you? How has Roblox connected you? How has Roblox changed your life? Then, over the course of RDC, we incorporated your responses into this awesome mural.
📷
Created by Alece Birnbach at Graphic Recording Studio

## Knowledge is power

This year’s breakout sessions included presentations from Roblox developers and staff members on the latest game development strategies, a deep dive into the Roblox engine, learning how to animate with Blender, tools for working together in teams, building performant game worlds, and the new Creator Dashboard. Dr. Michael Rich, Associate Professor at Harvard Medical School and Physician at Boston Children’s Hospital, also led attendees through a discussion on mental health and how to best take care of you and your friends’ emotional well-being, especially now during these challenging times.
📷
Making the Dream Work with Teamwork (presented by Roblox developer Myzta)
In addition to our traditional Q&A panel with top product and engineering leaders at Roblox, we also held a special session with Builderman himself to answer the community’s biggest questions.
📷
Roblox Product and Engineering Q&A Panel

## 2020 Game Jam

The Game Jam is always one of our favorite events of RDC. It’s a chance for folks to come together, flex their development skills, and come up with wildly inventive game ideas that really push the boundaries of what’s possible on Roblox. We had over 60 submissions this year—a new RDC record.
Once again, teams of up to six people from around the world had less than 24 hours to conceptualize, design, and publish a game based on the theme “2020 Vision,” all while working remotely no less! To achieve such a feat is nothing short of awe-inspiring, but as always, our dev community was more than up for the challenge. I’ve got to say, these were some of the finest creations we’ve seen.
WINNERS
Best in Show: Shapescape Created By: GhettoMilkMan, dayzeedog, maplestick, theloudscream, Brick_man, ilyannna You awaken in a strange laboratory, seemingly with no way out. Using a pair of special glasses, players must solve a series of anamorphic puzzles and optical illusions to make their escape.
Excellence in Visual Art: agn●sia Created By: boatbomber, thisfall, Elttob An obby experience unlike any other, this game is all about seeing the world through a different lens. Reveal platforms by switching between different colored lenses and make your way to the end.
Most Creative Gameplay: Visions of a perspective reality Created By: Noble_Draconian and Spathi Sometimes all it takes is a change in perspective to solve challenges. By switching between 2D and 3D perspectives, players can maneuver around obstacles or find new ways to reach the end of each level.
Outstanding Use of Tech: The Eyes of Providence Created By: Quenty, Arch_Mage, AlgyLacey, xJennyBeanx, Zomebody, Crykee This action/strategy game comes with a unique VR twist. While teams fight to construct the superior monument, two VR players can support their minions by collecting resources and manipulating the map.
Best Use of Theme: Sticker Situation Created By: dragonfrosting and Yozoh Set in a mysterious art gallery, players must solve puzzles by manipulating the environment using a magic camera and stickers. Snap a photograph, place down a sticker, and see how it changes the world.
OTHER TOP PICKS
HONORABLE MENTIONS
For the rest of the 2020 Game Jam submissions, check out the list below:
20-20 Vision | 20/20 Vision | 2020 Vision, A Crazy Perspective | 2020 Vision: Nyon | A Wild Trip! | Acuity | Best Year Ever | Better Half | Bloxlabs | Climb Stairs to 2021 | Double Vision (Team hey apple) | Eyebrawl | Eyeworm Exam | FIRE 2020 | HACKED | Hyperspective | Lucid Scream | Mystery Mansion | New Years at the Museum | New Year’s Bash | Poor Vision | Predict 2020 | RBC News | Retrovertigo | Second Wave | see no evil | Sight Fight | Sight Stealers | Spectacles Struggle | Specter Spectrum | Survive 2020 | The Lost Chicken Leg | The Outbreak | The Spyglass | Time Heist | Tunnel Vision | Virtual RDC – The Story | Vision (Team Freepunk) | Vision (Team VIP People ####) | Vision Developers Conference 2020 | Vision Is Key | Vision Perspective | Vision Racer | Visions | Zepto
And last but not least, we wanted to give a special shout out to Starboard Studios. Though they didn’t quite make it on time for our judges, we just had to include Dave’s Vision for good measure. 📷
Thanks to everyone who participated in the Game Jam, and congrats to all those who took home the dub in each of our categories this year. As the winners of Best in Show, the developers of Shapescape will have their names forever engraved on the RDC Game Jam trophy back at Roblox HQ. Great work!

## ‘Til next year

And that about wraps up our coverage of the first-ever digital RDC. Thanks to all who attended! Before we go, we wanted to share a special “behind the scenes” video from the 2020 RDC photoshoot.
Check it out:
It was absolutely bonkers. Getting 350 of us all in one server was so much fun and really brought back the feeling of being together with everyone again. That being said, we can’t wait to see you all—for real this time—at RDC next year. It’s going to be well worth the wait. ‘Til we meet again, my friends.

# Improving Simulation and Performance with an Advanced Physics Solver

## 05, 2020

by chefdeletat
PRODUCT & TECH
📷In mid-2015, Roblox unveiled a major upgrade to its physics engine: the Projected Gauss-Seidel (PGS) physics solver. For the first year, the new solver was optional and provided improved fidelity and greater performance compared to the previously used spring solver.
In 2016, we added support for a diverse set of new physics constraints, incentivizing developers to migrate to the new solver and extending the creative capabilities of the physics engine. Any new places used the PGS solver by default, with the option of reverting back to the classic solver.
We ironed out some stability issues associated with high mass differences and complex mechanisms by the introduction of the hybrid LDL-PGS solver in mid-2018. This made the old solver obsolete, and it was completely disabled in 2019, automatically migrating all places to the PGS.
In 2019, the performance was further improved using multi-threading that splits the simulation into jobs consisting of connected islands of simulating parts. We still had performance issues related to the LDL that we finally resolved in early 2020.
The physics engine is still being improved and optimized for performance, and we plan on adding new features for the foreseeable future.

## Implementing the Laws of Physics

📷
The main objective of a physics engine is to simulate the motion of bodies in a virtual environment. In our physics engine, we care about bodies that are rigid, that collide and have constraints with each other.
A physics engine is organized into two phases: collision detection and solving. Collision detection finds intersections between geometries associated with the rigid bodies, generating appropriate collision information such as collision points, normals and penetration depths. Then a solver updates the motion of rigid bodies under the influence of the collisions that were detected and constraints that were provided by the user.
📷
The motion is the result of the solver interpreting the laws of physics, such as conservation of energy and momentum. But doing this 100% accurately is prohibitively expensive, and the trick to simulating it in real-time is to approximate to increase performance, as long as the result is physically realistic. As long as the basic laws of motion are maintained within a reasonable tolerance, this tradeoff is completely acceptable for a computer game simulation.

## Taking Small Steps

The main idea of the physics engine is to discretize the motion using time-stepping. The equations of motion of constrained and unconstrained rigid bodies are very difficult to integrate directly and accurately. The discretization subdivides the motion into small time increments, where the equations are simplified and linearized making it possible to solve them approximately. This means that during each time step the motion of the relevant parts of rigid bodies that are involved in a constraint is linearly approximated.
📷📷
Although a linearized problem is easier to solve, it produces drift in a simulation containing non-linear behaviors, like rotational motion. Later we’ll see mitigation methods that help reduce the drift and make the simulation more plausible.

## Solving

📷
Having linearized the equations of motion for a time step, we end up needing to solve a linear system or linear complementarity problem (LCP). These systems can be arbitrarily large and can still be quite expensive to solve exactly. Again the trick is to find an approximate solution using a faster method. A modern method to approximately solve an LCP with good convergence properties is the Projected Gauss-Seidel (PGS). It is an iterative method, meaning that with each iteration the approximate solution is brought closer to the true solution, and its final accuracy depends on the number of iterations.
📷
This animation shows how a PGS solver changes the positions of the bodies at each step of the iteration process, the objective being to find the positions that respect the ball and socket constraints while preserving the center of mass at each step (this is a type of positional solver used by the IK dragger). Although this example has a simple analytical solution, it’s a good demonstration of the idea behind the PGS. At each step, the solver fixes one of the constraints and lets the other be violated. After a few iterations, the bodies are very close to their correct positions. A characteristic of this method is how some rigid bodies seem to vibrate around their final position, especially when coupling interactions with heavier bodies. If we don’t do enough iterations, the yellow part might be left in a visibly invalid state where one of its two constraints is dramatically violated. This is called the high mass ratio problem, and it has been the bane of physics engines as it causes instabilities and explosions. If we do too many iterations, the solver becomes too slow, if we don’t it becomes unstable. Balancing the two sides has been a painful and long process.

## Mitigation Strategies

📷A solver has two major sources of inaccuracies: time-stepping and iterative solving (there is also floating point drift but it’s minor compared to the first two). These inaccuracies introduce errors in the simulation causing it to drift from the correct path. Some of this drift is tolerable like slightly different velocities or energy loss, but some are not like instabilities, large energy gains or dislocated constraints.
Therefore a lot of the complexity in the solver comes from the implementation of methods to minimize the impact of computational inaccuracies. Our final implementation uses some traditional and some novel mitigation strategies:
1. Warm starting: starting with the solution from a previous time-step to increase the convergence rate of the iterative solver
2. Post-stabilization: reprojecting the system back to the constraint manifold to prevent constraint drift
3. Regularization: adding compliance to the constraints ensuring a solution exists and is unique
4. Pre-conditioning: using an exact solution to a linear subsystem, improving the stability of complex mechanisms
Strategies 1, 2 and 3 are pretty traditional, but 3 has been improved and perfected by us. Also, although 4 is not unheard of, we haven’t seen any practical implementation of it. We use an original factorization method for large sparse constraint matrices and a new efficient way of combining it with the PGS. The resulting implementation is only slightly slower compared to pure PGS but ensures that the linear system coming from equality constraints is solved exactly. Consequently, the equality constraints suffer only from drift coming from the time discretization. Details on our methods are contained in my GDC 2020 presentation. Currently, we are investigating direct methods applied to inequality constraints and collisions.

## Getting More Details

Traditionally there are two mathematical models for articulated mechanisms: there are reduced coordinate methods spearheaded by Featherstone, that parametrize the degrees of freedom at each joint, and there are full coordinate methods that use a Lagrangian formulation.
We use the second formulation as it is less restrictive and requires much simpler mathematics and implementation.
The Roblox engine uses analytical methods to compute the dynamic response of constraints, as opposed to penalty methods that were used before. Analytics methods were initially introduced in Baraff 1989, where they are used to treat both equality and non-equality constraints in a consistent manner. Baraff observed that the contact model can be formulated using quadratic programming, and he provided a heuristic solution method (which is not the method we use in our solver).
Instead of using force-based formulation, we use an impulse-based formulation in velocity space, originally introduced by Mirtich-Canny 1995 and further improved by Stewart-Trinkle 1996, which unifies the treatment of different contact types and guarantees the existence of a solution for contacts with friction. At each timestep, the constraints and collisions are maintained by applying instantaneous changes in velocities due to constraint impulses. An excellent explanation of why impulse-based simulation is superior is contained in the GDC presentation of Catto 2014.
The frictionless contacts are modeled using a linear complementarity problem (LCP) as described in Baraff 1994. Friction is added as a non-linear projection onto the friction cone, interleaved with the iterations of the Projected Gauss-Seidel.
The numerical drift that introduces positional errors in the constraints is resolved using a post-stabilization technique using pseudo-velocities introduced by Cline-Pai 2003. It involves solving a second LCP in the position space, which projects the system back to the constraint manifold.
The LCPs are solved using a PGS / Impulse Solver popularized by Catto 2005 (also see Catto 2009). This method is iterative and considers each individual constraints in sequence and resolves it independently. Over many iterations, and in ideal conditions, the system converges to a global solution.
Additionally, high mass ratio issues in equality constraints are ironed out by preconditioning the PGS using the sparse LDL decomposition of the constraint matrix of equality constraints. Dense submatrices of the constraint matrix are sparsified using a method we call Body Splitting. This is similar to the LDL decomposition used in Baraff 1996, but allows more general mechanical systems, and solves the system in constraint space. For more information, you can see my GDC 2020 presentation.
The architecture of our solver follows the idea of Guendelman-Bridson-Fedkiw, where the velocity and position stepping are separated by the constraint resolution. Our time sequencing is:
2. Constraint resolution in velocity space and position space
This scheme has the advantage of integrating only valid velocities, and limiting latency in external force application but allowing a small amount of perceived constraint violation due to numerical drift.
An excellent reference for rigid body simulation is the book Erleben 2005 that was recently made freely available. You can find online lectures about physics-based animation, a blog by Nilson Souto on building a physics engine, a very good GDC presentation by Erin Catto on modern solver methods, and forums like the Bullet Physics Forum and GameDev which are excellent places to ask questions.

## In Conclusion

The field of game physics simulation presents many interesting problems that are both exciting and challenging. There are opportunities to learn a substantial amount of cool mathematics and physics and to use modern optimizations techniques. It’s an area of game development that tightly marries mathematics, physics and software engineering.
Even if Roblox has a good rigid body physics engine, there are areas where it can be improved and optimized. Also, we are working on exciting new projects like fracturing, deformation, softbody, cloth, aerodynamics and water simulation.
Neither Roblox Corporation nor this blog endorses or supports any company or service. Also, no guarantees or promises are made regarding the accuracy, reliability or completeness of the information contained in this blog.
This blog post was originally published on the Roblox Tech Blog.

# Using Clang to Minimize Global Variable Use

## 23, 2020

by RandomTruffle
PRODUCT & TECH
Every non-trivial program has at least some amount of global state, but too much can be a bad thing. In C++ (which constitutes close to 100% of Roblox’s engine code) this global state is initialized before main() and destroyed after returning from main(), and this happens in a mostly non-deterministic order. In addition to leading to confusing startup and shutdown semantics that are difficult to reason about (or change), it can also lead to severe instability.
Roblox code also creates a lot of long-running detached threads (threads which are never joined and just run until they decide to stop, which might be never). These two things together have a very serious negative interaction on shutdown, because long-running threads continue accessing the global state that is being destroyed. This can lead to elevated crash rates, test suite flakiness, and just general instability.
The first step to digging yourself out of a mess like this is to understand the extent of the problem, so in this post I’m going to talk about one technique you can use to gain visibility into your global startup flow. I’m also going to discuss how we are using this to improve stability across the entire Roblox game engine platform by decreasing our use of global variables.

## Introducing -finstrument-functions

Nothing excites me more than learning about a new obscure compiler option that I’ve never had a use for before, so I was pretty happy when a colleague pointed me to this option in the Clang Command Line Reference. I’d never used it before, but it sounded very cool. The idea being that if we could get the compiler to tell us every time it entered and exited a function, we could filter this information through a symbolizer of some kind and generate a report of functions that a) occur before main(), and b) are the very first function in the call-stack (indicating it’s a global).
Unfortunately, the documentation basically just tells you that the option exists with no mention of how to use it or if it even actually does what it sounds like it does. There’s also two different options that sound similar to each other (-finstrument-functions and -finstrument-functions-after-inlining), and I still wasn’t entirely sure what the difference was. So I decided to throw up a quick sample on godbolt to see what happened, which you can see here. Note there are two assembly outputs for the same source listing. One uses the first option and the other uses the second option, and we can compare the assembly output to understand the differences. We can gather a few takeaways from this sample:
1. The compiler is injecting calls to __cyg_profile_func_enter and __cyg_profile_func_exit inside of every function, inline or not.
2. The only difference between the two options occurs at the call-site of an inline function.
3. With -finstrument-functions, the instrumentation for the inlined function is inserted at the call-site, whereas with -finstrument-functions-after-inlining we only have instrumentation for the outer function. This means that when using-finstrument-functions-after-inlining you won’t be able to determine which functions are inlined and where.
Of course, this sounds exactly like what the documentation said it did, but sometimes you just need to look under the hood to convince yourself.
To put all of this another way, if we want to know about calls to inline functions in this trace we need to use -finstrument-functions because otherwise their instrumentation is silently removed by the compiler. Sadly, I was never able to get -finstrument-functions to work on a real example. I would always end up with linker errors deep in the Standard C++ Library which I was unable to figure out. My best guess is that inlining is often a heuristic, and this can somehow lead to subtle ODR (one-definition rule) violations when the optimizer makes different inlining decisions from different translation units. Luckily global constructors (which is what we care about) cannot possibly be inlined anyway, so this wasn’t a problem.
I suppose I should also mention that I still got tons of linker errors with -finstrument-functions-after-inlining as well, but I did figure those out. As best as I can tell, this option seems to imply –whole-archive linker semantics. Discussion of –whole-archive is outside the scope of this blog post, but suffice it to say that I fixed it by using linker groups (e.g. -Wl,–start-group and -Wl,–end-group) on the compiler command line. I was a bit surprised that we didn’t get these same linker errors without this option and still don’t totally understand why. If you happen to know why this option would change linker semantics, please let me know in the comments!

## Implementing the Callback Hooks

If you’re astute, you may be wondering what in the world __cyg_profile_func_enter and __cyg_profile_func_exit are and why the program is even successfully linking in the first without giving undefined symbol reference errors, since the compiler is apparently trying to call some function we’ve never defined. Luckily, there are some options that allow us to see inside the linker’s algorithm so we can find out where it’s getting this symbol from to begin with. Specifically, -y should tell us how the linker is resolving . We’ll try it with a dummy program first and a symbol that we’ve defined ourselves, then we’ll try it with __cyg_profile_func_enter .
zturner@ubuntu:~/src/sandbox$cat instr.cpp int main() {} zturner@ubuntu:~/src/sandbox$ clang++-9 -fuse-ld=lld -Wl,-y -Wl,main instr.cpp /usbin/../lib/gcc/x86_64-linux-gnu/crt1.o: reference to main /tmp/instr-5b6c60.o: definition of main
No surprises here. The C Runtime Library references main(), and our object file defines it. Now let’s see what happens with __cyg_profile_func_enter and -finstrument-functions-after-inlining.
zturner@ubuntu:~/src/sandbox$clang++-9 -fuse-ld=lld -finstrument-functions-after-inlining -Wl,-y -Wl,__cyg_profile_func_enter instr.cpp /tmp/instr-8157b3.o: reference to __cyg_profile_func_enter /lib/x86_64-linux-gnu/libc.so.6: shared definition of __cyg_profile_func_enter Now, we see that libc provides the definition, and our object file references it. Linking works a bit differently on Unix-y platforms than it does on Windows, but basically this means that if we define this function ourselves in our cpp file, the linker will just automatically prefer it over the shared library version. Working godbolt link without runtime output is here. So now you can kind of see where this is going, however there are still a couple of problems left to solve. 1. We don’t want to do this for a full run of the program. We want to stop as soon as we reach main. 2. We need a way to symbolize this trace. The first problem is easy to solve. All we need to do is compare the address of the function being called to the address of main, and set a flag indicating we should stop tracing henceforth. (Note that taking the address of main is undefined behavior[1], but for our purposes it gets the job done, and we aren’t shipping this code, so ¯\_(ツ)_/¯). The second problem probably deserves a little more discussion though. ## Symbolizing the Traces In order to symbolize these traces, we need two things. First, we need to store the trace somewhere on persistent storage. We can’t expect to symbolize in real time with any kind of reasonable performance. You can write some C code to save the trace to some magic filename, or you can do what I did and just write it to stderr (this way you can pipe stderr to some file when you run it). Second, and perhaps more importantly, for every address we need to write out the full path to the module the address belongs to. Your program loads many shared libraries, and in order to translate an address into a symbol, we have to know which shared library or executable the address actually belongs to. In addition, we have to be careful to write out the address of the symbol in the file on disk. When your program is running, the operating system could have loaded it anywhere in memory. And if we’re going to symbolize it after the fact we need to make sure we can still reference it after the information about where it was loaded in memory is lost. The linux function dladdr() gives us both pieces of information we need. A working godbolt sample with the exact implementation of our instrumentation hooks as they appear in our codebase can be found here. ## Putting it All Together Now that we have a file in this format saved on disk, all we need to do is symbolize the addresses. addr2line is one option, but I went with llvm-symbolizer as I find it more robust. I wrote a Python script to parse the file and symbolize each address, then print it in the same “visual” hierarchical format that the original output file is in. There are various options for filtering the resulting symbol list so that you can clean up the output to include only things that are interesting for your case. For example, I filtered out any globals that have boost:: in their name, because I can’t exactly go rewrite boost to not use global variables. The script isn’t as simple as you would think, because simply crawling each line and symbolizing it would be unacceptably slow (when I tried this, it took over 2 hours before I finally killed the process). This is because the same address might appear thousands of times, and there’s no reason to run llvm-symbolizer against the same address multiple times. So there’s a lot of smarts in there to pre-process the address list and eliminate duplicates. I won’t discuss the implementation in more detail because it isn’t super interesting. But I’ll do even better and provide the source! So after all of this, we can run any one of our internal targets to get the call tree, run it through the script, and then get output like this (actual output from a Roblox process, source file information removed): excluded_symbols = [‘.\boost.*’]* excluded_modules = [‘/usr.\’]* /uslib/x86_64-linux-gnu/libLLVM-9.so.1: 140 unique addresses InterestingRobloxProcess: 38928 unique addresses /uslib/x86_64-linux-gnu/libstdc++.so.6: 1 unique addresses /uslib/x86_64-linux-gnu/libc++.so.1: 3 unique addresses Printing call tree with depth 2 for 29276 global variables. __cxx_global_var_init.5 (InterestingFile1.cpp:418:22) RBX::InterestingRobloxClass2::InterestingRobloxClass2() (InterestingFile2.cpp.:415:0) __cxx_global_var_init.19 (InterestingFile2.cpp:183:34) (anonymous namespace)::InterestingRobloxClass2::InterestingRobloxClass2() (InterestingFile2.cpp:171:0) __cxx_global_var_init.274 (InterestingFile3.cpp:2364:33) RBX::InterestingRobloxClass3::InterestingRobloxClass3() So there you have it: the first half of the battle is over. I can run this script on every platform, compare results to understand what order our globals are actually initialized in in practice, then slowly migrate this code out of global initializers and into main where it can be deterministic and explicit. ## Future Work It occurred to me sometime after implementing this that we could make a general purpose profiling hook that exposed some public symbols (dllexport’ed if you speak Windows), and allowed a plugin module to hook into this dynamically. This plugin module could filter addresses using whatever arbitrary logic that it was interested in. One interesting use case I came up for this is that it could look up the debug information, check if the current address maps to the constructor of a function local static, and write out the address if so. This effectively allows us to gain a deeper understanding of the order in which our lazy statics are initialized. The possibilities are endless here. ## Further Reading If you’re interested in this kind of thing, I’ve collected a couple of my favorite references for this kind of topic. 1. Various: The C++ Language Standard 2. Matt Godbolt: The Bits Between the Bits: How We Get to main() 3. Ryan O’Neill: Learning Linux Binary Analysis 4. Linkers and Loaders: John R. Levine 5. https://eel.is/c++draft/basic.exec#basic.start.main-3 Neither Roblox Corporation nor this blog endorses or supports any company or service. Also, no guarantees or promises are made regarding the accuracy, reliability or completeness of the information contained in this blog. submitted by jaydenweez to u/jaydenweez [link] [comments] ##### Ambrosia and Registration Now that Ambrosia is gone, new registrations are no longer possible, and due to their expiring codes, using legitimate license keys has become difficult. We may hope to see a few of their games revived in the future but at present, only the original releases are available. Perhaps this case study on Ambrosia's registration algorithms will be useful to some. ## The Old System In their earliest days, ASW didn't require registration, but they eventually began locking core features away behind codes. All of their classic titles use the original algorithm by Andrew Welch. Given a licensee name, number of copies, and game name, the code generator runs through two loops. The first loop iterates over each letter of the capitalized licensee name, adding the ASCII representation of that letter with the number of copies and then rotating the resulting bits. The second loop repeats that operation, only using the game's name instead of the license holder's name. Beginning with Mars Rising, later games added a step to these loops: XOR the current code with the common hex string$DEADBEEF. However, the rest of the algorithm remained essentially unchanged.
The resulting 32 bits are converted into a text registration code by adding the ASCII offset of $41 to each hex digit. This maps the 32-bit string into 8 characters, but due to the limit of a hex digit to only encode 16 values, codes only contain letters from the first 16 of the alphabet. The following chart shows an example using a well-known hacked code for Slithereens.  Iteration 1 ('A' in ANONYMOUS) Name: Anonymous Code =$0 + $41 Number: 100 (hex:$64) -> << 6 ... -> Code = $FD53 FFA0 Game: Slithereens +$64 ^ $DEAD BEEF >> 1 Add$41 to each digit: Registration -> $41 +$F = $50 = P -> Reverse string -> ------------$41 + $D =$4E = N | AKPPDFNP | ... ------------
Here is a Python implementation of the v1 system: aswreg_v1.py
Once you have the bitstring module installed via sudo pip install bitstring, you can test the output yourself with python aswreg_v1.py "Anonymous" 100 "Slithereens".

## The New System

As Ambrosia's Matt Slot explains, the old system continued to allow a lot of piracy, so in the early 2000's they decided to switch to a more challenging registration system. This new method was based on polynomial hashing and included a timestamp so that codes could be expired and renewed. Ambrosia now had better control over code distribution, but they assumed their renewal server would never be shut down...
They also took more aggressive steps to reduce key sharing. The registration app checks against a list of blacklisted codes, and if found to be using one, the number of licenses is internally perturbed so that subsequent calculations fail. To combat tampering, your own information can get locally blacklisted in a similar manner if too many failed attempts occur, at least until the license file is deleted. Furthermore, the app attempts to verify the system time via a remote time server to minimize registration by changing the computer's clock.
You can disable the internet connection, set the clock back, and enter codes. There's also a renewal bot for EV: Nova. But let us look at the algorithm more closely.

## 64-bit Codes

The first noticeable difference is that registration codes in v2 are now 12 digits, containing both letters and numbers. This is due to a move from a 32-bit internal code to a 64-bit one. Rather than add an ASCII offset to hex digits, every letter or number in a new registration code has a direct mapping to a chunk of 5 bits. Using 5 bits per digit supports up to 32 values, or almost all letters of the alphabet and digits up to 9 (O, I, 0, and 1 were excluded given their visual similarities).
The resulting 64 bits (really only 60 because the upper 4 are unused: 12 digits * 5 bits each = 60) are a combination of two other hashes XOR'd together. This is a notable change from v1 because it only used the registration code to verify against the hashing algorithm. Only the licensee name, number of copies, and game name were really used. In v2, the registration code is itself a hash which contains important information like a code's timestamp.

## Two Hashes

To extract such information from the registration code, we must reverse the XOR operation and split out the two hashes which were combined. Fortunately, XOR is reversible, and we can compute one of the hashes. The first hash, which I'll call the userkey, is actually quite similar to v1's algorithm. It loops through the licensee name, adding the ASCII value, number of copies, and shifting bits. This is repeated with the game name. An important change is including multiplication by a factor based on the string size.
The second hash, which I'll call the basekey, is the secret sauce of v2; it's what you pay Ambrosia to generate when registering a product. It is not computed by the registration app, but there are several properties by which it must be validated.
The chart below visualizes the relationships among the various hashes, using the well-known "Barbara Kloeppel" code for EV: Nova.
 TEXTCODE: ------------------ | L4B5-9HJ5-P3NB | ------------------ HASH1 (userkey): | calculated from licensee name, | copies, and game name BINCODE: ---------------------- 5 bits per character, /-> | 0x0902f8932acce305 | plus factors & rotation / ---------------------- ---------------------- / | 0x0008ecc1c2ee5e00 | <-- XOR ---------------------- \ \ ---------------------- \-> | 0x090a1452e822bd05 | ---------------------- HASH2 (basekey): generated by Ambrosia, extracted via XOR

## The Basekey

The basekey is where we must handle timestamps and several validation checks. Consider the binary representation of the sample 0x090a1452e822bd05:
binary basekey (above) and indices for reference (below): 0000 1001 0000 1010 0001 0100 0101 0010 1110 1000 0010 0010 1011 1101 0000 0101 b0 b3 b7 b11 b15 b19 b23 b27 b31 b35 b39 b43 b47 b51 b55 b59 b63

## Timestamps

Timestamp are encoded as a single byte comprised of bits indexed at b56,51,42,37,28,23,14,9 from the basekey. In this example, the timestamp is 01100010 or 0x62 or 98.
The timestamp represents the number of fortnights that have passed since Christmas Day, 2000 Eastern time, modulo 256 to fit in one byte. For example, 98 fortnights places the code at approximately October 2004.
Stored as a single byte, there are 256 unique timestamps. This is 512 weeks or about 10 years. Yes, this means that a code's validity rotates approximately once every decade.
After the code's timestamp is read, it is subtracted from the current timestamp (generated from the system clock or network time server if available). The difference must be less than 2, so codes are valid for 4 weeks or about a month at a time.
Of note, Pillars of Garendall has a bug in which the modulo is not taken correctly, so the timestamp corresponding to 0xFF is valid without expiry.

## Validity Check

The last three bits, b60-63, contain the sum of all other 3-bit chunks in the basekey, modulo 7. Without the correct number in these bits, the result will be considered invalid.
To this point, we have covered sufficient material to renew licenses. The timestamp can be changed, the last three bits updated, the result XOR'd with the userkey, and finally, the code converted from binary to text.

## Factors for Basekey Generation

I was next curious about code generation. For the purposes of this write-up, I have not fully reverse engineered the basekey, only duplicated the aspects which are used for validation. This yields functional keys, just not genuine ones. If the authors of the EV: Nova renewal bot have fully reversed the algorithm, perhaps they will one day share the steps to genuine basekey creation.
One aspect validated by the registration app is that the licensee name, number, and game name can be modified to yield a set of base factors. These are then multiplied by some number and written into the basekey. We do not need the whole algorithm; we simply must check that the corresponding regions in the basekey are multiples of the appropriate factors.
The regions of note in the basekey are f1 = b5-9,47-51,33-37,19-23, f2 = b43-47,29-33,15-19,57-61, and f3 = b24-28,10-14,52-56,38-42. The top 5 bits and f3 are never actually checked, so they can be ignored.
Considering f1 and f2, the values in the sample basekey are 0x25DA and 0x1500, respectively. The base factors are 0x26 and 0x1C, which are multiples by 0xFF and 0xC0, respectively.
Rather than analyze the code in detail, I wrote a small script to translate over the disassembled PPC to Python wholesale. It is sufficient for generating keys to EV: Nova, using the perfectly-valid multiple of 1x, but I have found it fails for other v2 products.

## Scripts

Here is a Python implementation for v2: aswreg_v2.py and aswreg_v2core.py
With bitstring installed, you can renew codes like python aswreg_v2.py renew "L4B5-9HJ5-P3NB" "Barbara Kloeppel" 1 "EV Nova" (just sample syntax, blacklisted codes will still fail in the app). There's also a function to check a code's timestamp with date or create a new license with generate.
As earlier cautioned, generating basekeys relies on code copied from disassembled PPC and will likely not work outside EV: Nova. In my tests with other v2 products, all essential parts of the algorithm remain the same, even the regions of the basekey which are checked as multiples of the factors. What differs is the actual calculation of base factors. Recall that these keys were created by Ambrosia outside the local registration system, so the only options are to copy the necessary chunks of code to make passable factors for each product or to fully reverse engineer the basekey algorithm. I've no doubt the factors are an easy computation once you know the algorithm, but code generation becomes less critical when renewal is an option for other games. I leave it to the authors of the Zeus renewal bot if they know how to find these factors more generally.
To renew codes for other games, keep in mind the name must be correct. For instance, Pillars of Garendall is called "Garendall" internally. You can find a game's name by typing a gibberish license in the registration app and seeing what file is created in Preferences. It should be of the form License.
Finally, a couple disclaimers: I have only tested with a handful of keys, so my interpretations and implementations may not be completely correct. YMMV. Furthermore, these code snippets are posted as an interesting case study about how a defunct company once chose to combat software piracy, not to promote piracy. Had Ambrosia remained operational, I'm sure we would have seen a v3 registration system or a move to online-based play as so many other games are doing today, but I hope this has been helpful for those who still wish to revisit their favorite Ambrosia classics.

# Boolean data type

In computer science, the Boolean data type is a data type that has one of two possible values (usually denoted true and false) which is intended to represent the two truth values of logic and Boolean algebra. It is named after George Boole, who first defined an algebraic system of logic in the mid 19th century. The Boolean data type is primarily associated with conditional) statements, which allow different actions by changing control flow depending on whether a programmer-specified Boolean condition evaluates to true or false. It is a special case of a more general logical data type (see probabilistic logic)—logic doesn't always need to be Boolean.

## Generalities

In programming languages with a built-in Boolean data type, such as Pascal) and Java), the comparison operators such as > and ≠ are usually defined to return a Boolean value. Conditional and iterative commands may be defined to test Boolean-valued expressions.
Languages with no explicit Boolean data type, like C90 and Lisp), may still represent truth values by some other data type. Common Lisp uses an empty list for false, and any other value for true. The C programming language uses an integer) type, where relational expressions like i > j and logical expressions connected by && and || are defined to have value 1 if true and 0 if false, whereas the test parts of if , while , for , etc., treat any non-zero value as true.[1][2] Indeed, a Boolean variable may be regarded (and implemented) as a numerical variable with one binary digit (bit), which can store only two values. The implementation of Booleans in computers are most likely represented as a full word), rather than a bit; this is usually due to the ways computers transfer blocks of information.
Most programming languages, even those with no explicit Boolean type, have support for Boolean algebraic operations such as conjunction (AND , & , * ), disjunction (OR , | , + ), equivalence (EQV , = , == ), exclusive or/non-equivalence (XOR , NEQV , ^ , != ), and negation (NOT , ~ , ! ).
In some languages, like Ruby), Smalltalk, and Alice) the true and false values belong to separate classes), i.e., True and False , respectively, so there is no one Boolean type.
In SQL, which uses a three-valued logic for explicit comparisons because of its special treatment of Nulls), the Boolean data type (introduced in SQL:1999) is also defined to include more than two truth values, so that SQL Booleans can store all logical values resulting from the evaluation of predicates in SQL. A column of Boolean type can also be restricted to just TRUE and FALSE though.

## ALGOL and the built-in boolean type

One of the earliest programming languages to provide an explicit boolean data type is ALGOL 60 (1960) with values true and false and logical operators denoted by symbols ' ∧ {\displaystyle \wedge } 📷' (and), ' ∨ {\displaystyle \vee } 📷' (or), ' ⊃ {\displaystyle \supset } 📷' (implies), ' ≡ {\displaystyle \equiv } 📷' (equivalence), and ' ¬ {\displaystyle \neg } 📷' (not). Due to input device and character set limits on many computers of the time, however, most compilers used alternative representations for many of the operators, such as AND or 'AND' .
This approach with boolean as a built-in (either primitive or otherwise predefined) data type was adopted by many later programming languages, such as Simula 67 (1967), ALGOL 68 (1970),[3] Pascal) (1970), Ada) (1980), Java) (1995), and C#) (2000), among others.

## Fortran

The first version of FORTRAN (1957) and its successor FORTRAN II (1958) have no logical values or operations; even the conditional IF statement takes an arithmetic expression and branches to one of three locations according to its sign; see arithmetic IF. FORTRAN IV (1962), however, follows the ALGOL 60 example by providing a Boolean data type (LOGICAL ), truth literals (.TRUE. and .FALSE. ), Boolean-valued numeric comparison operators (.EQ. , .GT. , etc.), and logical operators (.NOT. , .AND. , .OR. ). In FORMAT statements, a specific format descriptor ('L ') is provided for the parsing or formatting of logical values.[4]

## Lisp and Scheme

The language Lisp) (1958) never had a built-in Boolean data type. Instead, conditional constructs like cond assume that the logical value false is represented by the empty list () , which is defined to be the same as the special atom nil or NIL ; whereas any other s-expression is interpreted as true. For convenience, most modern dialects of Lisp predefine the atom t to have value t , so that t can be used as a mnemonic notation for true.
This approach (any value can be used as a Boolean value) was retained in most Lisp dialects (Common Lisp, Scheme), Emacs Lisp), and similar models were adopted by many scripting languages, even ones having a distinct Boolean type or Boolean values; although which values are interpreted as false and which are true vary from language to language. In Scheme, for example, the false value is an atom distinct from the empty list, so the latter is interpreted as true.

The language Pascal) (1970) introduced the concept of programmer-defined enumerated types. A built-in Boolean data type was then provided as a predefined enumerated type with values FALSE and TRUE . By definition, all comparisons, logical operations, and conditional statements applied to and/or yielded Boolean values. Otherwise, the Boolean type had all the facilities which were available for enumerated types in general, such as ordering and use as indices. In contrast, converting between Boolean s and integers (or any other types) still required explicit tests or function calls, as in ALGOL 60. This approach (Boolean is an enumerated type) was adopted by most later languages which had enumerated types, such as Modula, Ada), and Haskell).

## C, C++, Objective-C, AWK

Initial implementations of the language C) (1972) provided no Boolean type, and to this day Boolean values are commonly represented by integers (int s) in C programs. The comparison operators (> , == , etc.) are defined to return a signed integer (int ) result, either 0 (for false) or 1 (for true). Logical operators (&& , || , ! , etc.) and condition-testing statements (if , while ) assume that zero is false and all other values are true.
After enumerated types (enum s) were added to the American National Standards Institute version of C, ANSI C (1989), many C programmers got used to defining their own Boolean types as such, for readability reasons. However, enumerated types are equivalent to integers according to the language standards; so the effective identity between Booleans and integers is still valid for C programs.
Standard C) (since C99) provides a boolean type, called _Bool . By including the header stdbool.h , one can use the more intuitive name bool and the constants true and false . The language guarantees that any two true values will compare equal (which was impossible to achieve before the introduction of the type). Boolean values still behave as integers, can be stored in integer variables, and used anywhere integers would be valid, including in indexing, arithmetic, parsing, and formatting. This approach (Boolean values are just integers) has been retained in all later versions of C. Note, that this does not mean that any integer value can be stored in a boolean variable.
C++ has a separate Boolean data type bool , but with automatic conversions from scalar and pointer values that are very similar to those of C. This approach was adopted also by many later languages, especially by some scripting languages such as AWK.
Objective-C also has a separate Boolean data type BOOL , with possible values being YES or NO , equivalents of true and false respectively.[5] Also, in Objective-C compilers that support C99, C's _Bool type can be used, since Objective-C is a superset of C.

## Perl and Lua

Perl has no boolean data type. Instead, any value can behave as boolean in boolean context (condition of if or while statement, argument of && or || , etc.). The number 0 , the strings "0" and "" , the empty list () , and the special value undef evaluate to false.[6] All else evaluates to true.
Lua) has a boolean data type, but non-boolean values can also behave as booleans. The non-value nil evaluates to false, whereas every other data type always evaluates to true, regardless of value.

## Tcl

Tcl has no separate Boolean type. Like in C, the integers 0 (false) and 1 (true - in fact any nonzero integer) are used.[7]
Examples of coding:
set v 1 if { $v } { puts "V is 1 or true" } The above will show "V is 1 or true" since the expression evaluates to '1' set v "" if {$v } ....
The above will render an error as variable 'v' cannot be evaluated as '0' or '1'

## Python, Ruby, and JavaScript

Python), from version 2.3 forward, has a bool type which is a subclass) of int , the standard integer type.[8] It has two possible values: True and False , which are special versions of 1 and 0 respectively and behave as such in arithmetic contexts. Also, a numeric value of zero (integer or fractional), the null value (None ), the empty string), and empty containers (i.e. lists), sets), etc.) are considered Boolean false; all other values are considered Boolean true by default.[9] Classes can define how their instances are treated in a Boolean context through the special method __nonzero__ (Python 2) or __bool__ (Python 3). For containers, __len__ (the special method for determining the length of containers) is used if the explicit Boolean conversion method is not defined.
In Ruby), in contrast, only nil (Ruby's null value) and a special false object are false, all else (including the integer 0 and empty arrays) is true.
In JavaScript, the empty string ("" ), null , undefined , NaN , +0, −0 and false [10] are sometimes called falsy (of which the complement) is truthy) to distinguish between strictly type-checked and coerced Booleans.[11] As opposed to Python, empty containers (arrays , Maps, Sets) are considered truthy. Languages such as PHP also use this approach.

## Next Generation Shell

Next Generation Shell, has Bool type. It has two possible values: true and false . Bool is not interchangeable with Int and have to be converted explicitly if needed. When a Boolean value of an expression is needed (for example in if statement), Bool method is called. Bool method for built-in types is defined such that it returns false for a numeric value of zero, the null value, the empty string), empty containers (i.e. lists), sets), etc.), external processes that exited with non-zero exit code; for other values Bool returns true. Types for which Bool method is defined can be used in Boolean context. When evaluating an expression in Boolean context, If no appropriate Bool method is defined, an exception is thrown.

## SQL

Main article: Null (SQL) § Comparisons with NULL and the three-valued logic (3VL)#Comparisonswith_NULL_and_the_three-valued_logic(3VL))
Booleans appear in SQL when a condition is needed, such as WHERE clause, in form of predicate which is produced by using operators such as comparison operators, IN operator, IS (NOT) NULL etc. However, apart from TRUE and FALSE, these operators can also yield a third state, called UNKNOWN, when comparison with NULL is made.
The treatment of boolean values differs between SQL systems.
For example, in Microsoft SQL Server, boolean value is not supported at all, neither as a standalone data type nor representable as an integer. It shows an error message "An expression of non-boolean type specified in a context where a condition is expected" if a column is directly used in the WHERE clause, e.g. SELECT a FROM t WHERE a , while statement such as SELECT column IS NOT NULL FROM t yields a syntax error. The BIT data type, which can only store integers 0 and 1 apart from NULL, is commonly used as a workaround to store Boolean values, but workarounds need to be used such as UPDATE t SET flag = IIF(col IS NOT NULL, 1, 0) WHERE flag = 0 to convert between the integer and boolean expression.
In PostgreSQL, there is a distinct BOOLEAN type as in the standard[12] which allows predicates to be stored directly into a BOOLEAN column, and allows using a BOOLEAN column directly as a predicate in WHERE clause.
In MySQL, BOOLEAN is treated as an alias as TINYINT(1)[13], TRUE is the same as integer 1 and FALSE is the same is integer 0.[14], and treats any non-zero integer as true when evaluating conditions.
The SQL92 standard introduced IS (NOT) TRUE, IS (NOT) FALSE, IS (NOT) UNKNOWN operators which evaluate a predicate, which predated the introduction of boolean type in SQL:1999
The SQL:1999 standard introduced a BOOLEAN data type as an optional feature (T031). When restricted by a NOT NULL constraint, a SQL BOOLEAN behaves like Booleans in other languages, which can store only TRUE and FALSE values. However, if it is nullable, which is the default like all other SQL data types, it can have the special null) value also. Although the SQL standard defines three literals) for the BOOLEAN type – TRUE, FALSE, and UNKNOWN – it also says that the NULL BOOLEAN and UNKNOWN "may be used interchangeably to mean exactly the same thing".[15][16] This has caused some controversy because the identification subjects UNKNOWN to the equality comparison rules for NULL. More precisely UNKNOWN = UNKNOWN is not TRUE but UNKNOWN/NULL.[17] As of 2012 few major SQL systems implement the T031 feature.[18] Firebird and PostgreSQL are notable exceptions, although PostgreSQL implements no UNKNOWN literal; NULL can be used instead.[19]

Data typesUninterpreted
Numeric
Pointer)
Text
Composite
Other
Related topics

## References

1. "PostgreSQL: Documentation: 10: 8.6. Boolean Type". www.postgresql.org. Archived from the original on 9 March 2018. Retrieved 1 May 2018.
Categories:

• 📷
• 📷