Azure Virtual Machine Primary Interface

Here’s a very quick way of finding out the primary interface of your Virtual Machine in Azure, if you got multiple Network Interface Cards. This will only function for your current subscription.

#1. Simple Powershell Azure command get all the primary network interface card for your current subscription.
Get-AzureRmNetworkInterface | ?{$_.Primary -eq $true}

I had a situation where i knew which is my primary network interface card, however i wanted to be sure double sure by verifying the result through powershell.

Happy Learning

Hardeep

 

Azure-Windows2016-Native-Docker-And-Sitecore8-Setup

In this blog we will setup Sitecore 8 on a Windows Server 2016 Docker container, some basic understanding of Sitecore, Windows server and Docker is required and will be of certain advantage, but if you do not know much about them it’s ok, you are here to learn. so let’s dive in and get started.

  1. Identify the images and download from Docker HUB.

We need to pull/download the images from Docker hub/registry to begin, an image is an inert, immutable, file that’s essentially a snapshot of a container. Images are created with the build command, and they’ll produce a container when started with run.

I have identified following two images for our Sitecore on Docker.

  1. Microsoft/mssql-server-windows-express
  2. Microsoft/iis

If you are aren’t sure about which image you are looking for then either from command line you can go and search for the image, however https://hub.docker.com/explore/ is the best place to start with.

Since I already know the name of the image, I’ll go and pull it from registry.

Registry: A service responsible for hosting and distributing images. The default registry is the Docker Hub. Repository. A collection of related images (usually providing different versions of the same application or service)

If you would like to search on Docker command line, then you can use the following command and it should provide you with Microsoft images listed on Docker hub.

#docker search Microsoft

           

We will select Microsoft/IIS and proceed to pull the image from Docker registry.

  1. Pull/Download image from Docker Hub/Registry.

 

To build the container we will have to download the image or multiple images in our case, because we will have one IIS web server and a backend SQL server.

For Docker images certain mannerism is followed, so I suggest you visit http://docs.docker.com

Let’s back to downloading image from Docker.

  1. Download IIS Webserver

Note: I had already downloaded that image previously hence it says already exists.

  1. Download Microsoft/mssql-server-windows-express

If you are downloading it for first time, here’s what you’ll see on your screen. The time it takes to download it completely dependent on your bandwidth, if you are running your host machine on any cloud platform then it shouldn’t be a problem in downloading and should not take more than few mins.

Here’s the confirmation on images download.

#docker images

So you can see that we have two images being pulled from Docker Hub a. microsoft/mssql-server-windows-express b. microsoft/iis

We will first work with microsoft/iis, make some required changes and then deploy Sitecore.

Let’s build the container from the image and get going.

  1. Build Container from image (IIS Server)

I’ll show you how to build the container from image shortly, however for better understanding of Docker I’d encourage you spend sometime with Docker help before you go ahead.

#Docker –help (two dashes)

Back to building container.

We will be using following command in Docker to build the container from image.

# docker run –rm –d –p 81:80 microsoft/iis

Options explained:

Run: tells Docker to run a command in new Docker container, so it creates a new container to execute all of the following commands on:

–rm: automatically removes the container after existing it and this is actually very important, otherwise it gets cached (Docker keeps it), it will lock up the name and consequently, you’re filling up the hard drive partition of your host

-d: run container in background and print container ID for information.

-p port:port: bind host port 81 to container port 80 so that we can access container outside container/host as well.

For example: if your host machine is having live IP 1.2.3.4 and you associate your host port 81 to container port 80, then using the following url you can access the site from anywhere on internet.

http://1.2.3.4:81

If your command ran successfully then you should be able to see output something similar to above screenshot, the long alpha numeric character are the container ID. You might need part of it in future use.

Secondly, you can also try to access the site outside your host machine if you wish to using the method explained above (http://1.2.3.4:81). Make sure you have allowed port 81 in your host machine firewall, otherwise it won’t work.

Alright, let’s get back to working with our new container, let’s get couple of windows feature enabled.

  1. Enable Windows Feature for ASP.net

So far we have only downloaded and build our container from image, now we have to go and enable some of the windows feature so as to work with IIS/Asp.net

So as to enable some of the windows feature within Container we will be using PowerShell, here’s the Docker command to get PowerShell extension on container.

Just before that make a note of your container ID, because using the container ID you will be able to run the PowerShell.

#docker ps

Now we will run the Docker command to get Powershell prompt for given container.

# docker exec –it 37a6 PowerShell

Before you start enabling windows feature it’s a good practice to see what’s already enabled and what needs to be, I like doing that, so that I can be sure that my commands are working fine and as per expectation.

#Get-Windowsfeature

Make a note of second column with heading as “Name”, there are two feature down the list (not visible in screenshot) which we will have to enable.

  1. NET-Framework-45-ASPNET
  2. Web-ASP-Net45

With PowerShell it’s quite easy to do so and here’s how it’s done.

#Install-windowsfeature net-framework-45-aspnet

Once started here’s what you will see as your first screen and the last screen shot shows you the confirmation.

Collecting data info.

Starting Installation.

Installation done.

Let’s quickly enable the other feature as well.

#Install-windowsfeature Web-Asp-Net45

In our case it’s already enabled so here’s what we get.

  1. Build Container from image (SQL Server)

So let’s quickly go and run the SQL Container in background, since we have already downloaded the image it should be pretty quick and easy, as we already know how to run the container from image.

# docker run –rm –d –p 1433:1433 –e sa_password=P@ssw0rd1234 –e ACCEPT_EULA=Y microsoft/mssql-server-windows-express

Few changes in this Docker command.

  1. We are exporting port 1433 of SQL Server for both host and container
  2. We are specifying sa password for sql
  3. We are accepting SQL end user license agreement, this is important without which SQL won’t start.

Here’s the interesting part:

To restore the Sitecore databases I do not use the command line, it’s much easier to connect your Sql Server Management Studio to container and easily restore the DB’s.

  1. Connecting SSMS to SQL Container

There are couple of ways you can restore your Sitecore DB’s to SQL container however for the learning purpose or maybe in production too, I find it easier to use SQL Server Management Studio connected to container or host machine.

There are two scenarios that I’ll show you to connect your SQL server management studio to either your container or your host machine.

Scenario 1:

  1. Your host machine is already having SSMS installed and you need to connect to your container from host.
  2. In this case find out the IP address of your container
  3. Ping back and forth between host machine and container
  4. If they are able to talk to each other than point your SSMS to container IP and use SA user/password details to login.
  5. To test connectivity login to container PowerShell and ping.

  1. Server name: IP address of your SQL container, you can find out couple of ways
    1. Connect to your SQL Server using Powershell (Refer to section 4) and run following command and it should let you know the local IP address of your container

# ipconfig

  1. Other method to find out the IP address is using following command

# docker inspect containerID

This command will show you the local IP address of container at the end of the output.

  1. If you are like me and would like to test SQL connectivity from different perspective then you can connect from your host machine IP address.

You can run your SSMS outside your host and point it to your live IP, make sure your firewall is allowing it go through, not a very secure way, nonetheless you can define security methods once you are logged in.

For the purpose of this demonstration, connecting to your Container from host machine is good enough.

Now as such you are connected let’s quickly attach your DB’s so that we are done with our SQL part and can move back to Sitecore setup in IIS Container.

Note: through SSMS server you are connecting to your SQL container which means using SSMS GUI when you try to restore the DB the SSMS will try to restore from SQL Container, it will look for those DBS MDF/LDF there in container, so make you copy db on to that SQL Server.

How to copy the DBs to SQL container ?

Let’s look at step 7 quickly.

  1. Copying DBs to SQL Container

You have to using Docker command to copy DBs from your local host machine to SQL Container so as to attach/restore those DBs.

#docker cp Databases grave_perlman:/c:\

Let’s understand this.

cp: simple copy parameter to pass on

Database: Name of the local folder on host machine which contains all the DBs.

grave:Perlman:/c:\ à grave:Perlman is the name of the container and later part is the path location where you want to copy your database folder.

Now you can go ahead use SSMS and restore the DBs, I am not going to show that part here. Once you have restore the DBs then you can move to step 8:

  1. Cleanup IIS Container.

Before you start copying the Sitecore application, I like getting rid of any default IIS setting/website.

So I’ll quickly run

# remove-website –Name “Default web site”

  1. Deploying Sitecore App to IIS Container.

Alright, so the Sitecore App fun begins here. Let’s copy the application folder to IIS container, create new website and define the permissions in coming few steps. There are other config changes that we will have to make to get the Sitecore up and running.

Let’s go step by step.

  1. Copy Sitecore app folder to inetpub path, not that you have to use this but that’s the default path.

Alright, so let’s understand what’s happening here:

  • My current location is c:\docker\sitecore 8.2\wwwroot
  • I am trying to copy everything wwwroot in current location to IIS container under c:\inetpub\wwwroot\
  • Hence the command #docker cp . jolly_stallman:/c:\inetpub\wwwroot\ will copy everything from my current location to remote location in IIS container.

Now let’s deploy new website in IIS using PowerShell

 #New-Website –Name “Sitecore” –Port 80 –PhyscialPath “C:\inetput\wwwroot” –ApplicationPool “.Net v4.5”

Great, so our application is deployed and if you have done your license file and network path setting correctly in Sitecore.config and Connectionstring.config then you should be able to see Sitecore default page.

#docker run –d –p 81:80 microsoft/iis

  1. There’s all possibility that you might be able to see the default page, might also be able to login to admin but when you try to open the control panel, you’ll come across this error.

In such situation we have to go and check the permission of folder where we have copied our Sitecore application.

So let’s first check, then set the policy and recheck the page for final confirmation.

  1. Go to location where you have deployed your application and run following command

#get-acl

 

  1. Set the permission for Network Service as follows and hopefully it should work for you, if doesn’t then it’s definitely to do with permission only.

$acl = Get-Acl c:\inetpub

$permission = “NETWORK SERVICE”,”FullControl”,”Allow”

$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission

$acl.SetAccessRule($accessRule)

$acl | Set-Acl c:\inetpub

 

 

 

 

Office365 Equipment-Conference Room Mailbox Setting-PowerShell Studio

So there’s been few instances that i have come across on Office365 specifically to Equipment and Conference room Mailbox, if you just create the Conference room in office 365 and don’t change the settings that Outlook user will not be able to see who’s occupying the room and the conference room in Outlook Calendar will only say as “Busy”, not an ideal situation.

Now the Office portal doesn’t give you that ability to change the Mailbox properties, you have to do it through PowerShell, however the information isn’t just readily available with PowerShell too, you have to dig in a little bit and then make the changes.

so i have managed to get it done with PowerShell few times and i thought it would be cool so put that all as a tool and put it online so that anybody can use it, doesn’t really matter if you got PowerShell knowledge or not, so what better way that using PowerShell Studio to get it done.

so using PowerShell Studio i have combined the script in to a very specific small tool and putting it here so that you all can use it.

Download Instruction PDF from here:

https://dl.dropboxusercontent.com/u/69201487/Office365Mailbox/Office365Mailbox.pdf

Download Tool from here:

https://dl.dropboxusercontent.com/u/69201487/Office365Mailbox/OfficeMailboxUpdate.zip

 

Happy Learning

Hardeep

Azure Operating System Disk Resize

Recently one of my colleague ask me how to increase the size of Azure VM data disk, which is pretty straight forward however while working on it, i thought it would be nice to have a tool that can increase the size of Operating system disk, because that’s where’s users are usually little skeptical. Hence DiskMan came in to existence, i have made this tool using Powershell Studio, which is amazing and not only helps me in coding but such tools is a great way of learning too.

DiskMan was created to ease the process of increasing operating system disk drive on Azure Virtual Machines.

There are couple of ways you can increase the size of the operating disk, however most of them need some sort of familiarity with Azure portal or Powershell cmdlets, with DiskMan you don’t need to know either of them and you still will be able to increase the operating system disk size.

Here’s the exe link

https://dl.dropboxusercontent.com/u/69201487/DiskMan/DiskMan.zip

 

Here’s the instruction PDF.

https://dl.dropboxusercontent.com/u/69201487/DiskMan/DiskMan.pdf

 

Thanks

Hardeep

PowerAdmin (A Powershell GUI Tool Made Using Powershell STudio 2015)

For quite some time i have been working on Powershell and i always wanted to have a GUI available for the powershell scripts that i have prepared, there are different ways you can do it, however i find Powershell Studio 2015 as the best way to have a GUI for Powershell.

So here’s the first version of PowerAdmin (beta), the documentation will take some time, but a small description is as below:

1. Local Computer Tab, all the button available on Local Computer tab will execute on local machine, for eg: If you click the Service button you will get only local services.

2. Remote Computer Tab, as the name says, you can fetch information from remote computer, however to do so, you will have to first establish a remote session with the computer.

3. Azure cloud, with limited feature available on PowerAdmin about Azure, you can login to Azure and create VM, get VM info, Delete VM, Get Images, you can even have session with individual computer and find out their process. ( I intend to add more to this as time permits).

4. Security, you can fetch all local LAN info from security tab, for eg: if you click Sweep LAN button, it will go and sweep Lan for IP addresses and find out which service is active on which port.

5. RDP, as the name says, you can create RDP session here.

DOWNLOAD PowerAdmin. https://dl.dropboxusercontent.com/u/69201487/PowerAdmin(beta)/PowerAdmin.zip

Try out, its not completely ready yet, it’s in beta version, but worth trying.

Happy Powershelling.

Hardeep

Create Azure VM from PowerShell with IIS Web Server auto installed

I saw someone asking on a forum about how to create Azure VM with Windows feature pre-installed, i thought it would be nice weekend exercise to see if i can get a Azure virtual machine created from PowerShell with IIS Web Server auto installed.

Now, by no means, i am saying that the PowerShell script given below is the best way to do it, there could be better, easier and correct way of doing it, but hey … this got my job done, so it should help you as well.

So in below PowerShell script the only thing that you have to change is, replace wherever you see XXXXXX with your cloud service name (the name that appears in Azure cloud service section), i know i can add a variable and make it easier for you, perhaps in next version of script.

so let’s see the script.


#Let's select the VMImage first that we want to use to build Server
$getvmimage = "a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201412.01-en.us-127GB.vhd"

# keep some variable handy which we will reuse many times
$user = "webadmin"
$pass = "P@ssw0rd"
$name = "Web60" #####This will be the name of your VM, you can changet if you wish to########

# Create new AzureVMconfig for Web60 and provide it as input to Azureprovisioningconfig and eventually to New-AzureVM
$newvm = New-AzureVMConfig -Name $name -InstanceSize Medium -ImageName $getvmimage | Add-AzureProvisioningConfig -Windows -AdminUsername $user -Password $pass
New-AzureVM -ServiceName XXXXXXXXXXX -VMs $newvm -WaitForBoot -Verbose

#Some Port & Session Variables
$port = Get-AzureEndpoint -Name PowerShell -VM (Get-AzureVM -ServiceName XXXXXXXXXXX -Name $name) | Select -ExpandProperty Port

Write-Host "$port"   ####No real importance, writing it on console only for testing##############

$credential = Get-Credential -Credential $user -Verbose
$sessionoption = New-PSSessionOption -SkipCACheck
$session =  New-PSSession -ComputerName XXXXXXXXX.cloudapp.net -Credential $credential -Port $port -UseSSL -SessionOption $sessionoption -Verbose

$getstatus = Get-AzureVM -ServiceName XXXXXXXXXX -name $name | select InstanceStatus, PowerState -Verbose
if ($getstatus -match "ReadyRole" -and "Started") {Write-Host "Server is Ready, Connecting Now"; Enter-PSSession -Session $session}
else {Write-Host "Unable to Connect, Something Wrong, Try Again"; $getstatus }

#Once PSSession  starts then it should install Webserver Role in remote server
#Install-WindowsFeature -Name Web-Server -IncludeAllSubFeature -IncludeManagementTools -Verbose

Invoke-Command -Session $session  -ScriptBlock {Install-WindowsFeature -Name Web-Server -IncludeAllSubFeature -IncludeManagementTools -Verbose} -Verbose

There are many more stuff that you can do it from this script by making some easy changes, like instead of Web-server you can deploy any other Windows Feature by just making some changes, or you can leave the windows feature about completely and just use the PowerShell remoting to login to remote server and do whatever you want to.

If you come across any bug, or if you know about a better way of doing it, just share in comment.

Till then happy learning.

Hardeep

Create New Storage Account with PowerShell

Creating New Storage Account in Azure.
It’s pretty easy when you want to create an Azure storage account using management portal, however let’s see how to create one using PowerShell, gradually you’ll see all this smaller tutorials adding up to one complete how to tutorial for Azure VM creation.

1. Let’s first see if you have any storage account available in Azure subscription

You can query your subscription with “Get-AzureSubscription” and under “CurrentStorageAccountName” property you will see the name of storage account, if the property is blank than that means either no storage account is created or the storage account is not yet set in subscription.

08-Get-AzureSubscription

As you can see we do not have any account available as of now under “CurrentStorageAccountName”.

2. So let’s now create a storage account in Azure using PowerShell cmdlets and later on we will set the account in subscription

#New-AzureStorageAccount –Location “East US 2” –StorageAccountName “hi1” –Label “HI1”

11-New-AzureStorageAccount

We have successfully created the storage account, you should be able to verify it in your management portal as well, for me it took about a min for information to appear on management portal.

3. Now let’s verify in your PowerShell and see if PowerShell can detect the new storage account automatically.

#Get-AzureSubscription

08-Get-AzureSubscription

AS you can see “CurrentStorageAccountName” property doesn’t have any value set, so let’s update the properties of a Microsoft Azure Storage account in current subscription.

4. Let’s set the newly created storage account in Azure Subscription.

The “Set-Azuresubscription” cmdlet establishes and changes the properties of an Azure Subscription. You can use this cmdlet to create a new subscription or change the properties of an existing subscription.

Required parameter are: -CurrentStorageAccountName
: -SubscriptionName

# Set-AzureSubscription -SubscriptionName -CurrentStroageAccountName “write the name of your account here.”

Now if you do not come across any error, let’s verify and check the properties of “CurrentStorageAccount” whether it’s update or not with new value.

15-Blur-AzureSub

Keeping learning, Keep Sharing

Thanks

Hardeep

Connecting Powershell To Azure Account

Hi,

Apart from managing your Azure setup from management portal you can do it through your PowerShell console as well, additionally it helps in automating your task too, so let’s see how to connect your PowerShell to Azure account.

1. How to list cmdlet modules in PowerShell
Windows PowerShell module exist in two states, either they are loaded or are available within your setup but aren’t loaded yet, first we will see how to list down modules which are loaded in your PowerShell, then we will see how to list down all the cmdlet available in your system but not loaded yet.

2. How to list loaded module in PowerShell
You can use the “Get-Module” cmdlet without any parameters to list down loaded module in Powershell

01-Get-Module-All

3. How to list all modules in PowerShell
To obtain list of all modules available in system but might not be loaded in Windows PowerShell console, you can use the same cmdlet “Get-Module” but with additional parameters

02-Get-Module-List-Available

4. If you do not see Azure cmdlets in your system, than you’ll have to install them, let’s see how to do that.

5. The easiest way is to do it from Microsoft Web Platform installer, the web platform installer will not only install the cmdlet, but it will also resolve all the dependencies and install them as well, so that makes it very easier for you.

So open your preferred browser and go to Microsoft Azure Downloads

Once you are in download section of command line tools you can click on install and that should download the web platform installer, rest of the installation of cmdlet then should be done from web platform installer.

03-Webinstaller-from-microsoft

6. Once you have downloaded the web installer and started the deployment the first screen would look like something as below, from there on rest of is just clicking Next button.

04-Web-installer

 

7. Once you have installed the module you can search in PowerShell for Azure module.

05-Get-command-Azure

8. Let’s connect your powershell to Azure
There are couple of ways you can add the Azure account to Windows PowerShell. You can use the “Add-AzureAccount” cmdlet, which uses Azure Active Directory authentication access tokens, or you can do it through “Import-AzurePublishSettingsFile”, which uses a management certificate, which you have to download first.

8.1
The “Add-AzureAccount” cmdlet makes your Azure Account and its subscriptions available in Windows PowerShell. It’s like logging in to your Azure account in Windows PowerShell.
When you run Add-AzureAccount, it displays an interactive windows that prompts you to sign into your Azure account. This sign-in is valid until the access token expires. When it expires, cmdlet that require access to your account prompt you to run Add-AzureAccount again.
I guess the access token TTL is one hour, but that’s just my guess.

06-Add-Azureaccount

As you can see above, you can simply write “Add-AzureAccount” cmdlet in PowerShell console without any option and it will prompt you for your username and then password.

8.2 Verify your Azure Account
Once you have successfully logged in, it would be good to verify your account and ensure you have logged in to correct account, you might have multiple accounts.

To verify your account, you can run following command.

“Get-AzureSubscription”

08-Get-AzureSubscription

8.3 Connect your Powershell to Azure using “Get-AzurePublishingsettingsFile” and “Import-AzurePublishSettingsFile”

With “Get-AzurePublishingSettingsFile” you have to download the publishing profile from Azure management portal and store it as some secure path.

Once you have downloaded the profile you have to than import in PowerShell with “Import-AzurePublishSettingsFile”, the import command would like something as below.

PS C:\Windows\system32> Import-AzurePublishSettingsFile “Path to your file you downloaded from portal”

Note: Ensure to mention your path in double quotes

8.4 Once you have managed to connect PS to Azure, then let’s verify it for last time.

08-Get-AzureSubscription

9. For some reason if you want to remove this subscription from your PowerShell then you can use the following cmdlet to remove.

#Remove-AzureSubscription

The Remove-AzureSubscription cmdlet deletes an Azure subscription from your subscription data file so Windows PowerShell can’t find it. This cmdlet does not delete the subscription from Microsoft Azure, or change the actual subscription in any way.

Required parameter is -SubscriptionName

so the final cmdlet would be

#Remove-AzureSubscription -SubscriptionName “whatever is your subscription name”

If you have any query/question write to hardeepbhamra@gmail.com

Thanks

Hardeep

Comparison SaaS, IaaS and PaaS

SaaS-IaaS-PaaS-1 SaaS-IaaS-PaaS

SaaS: Software as a Service

Cloud application services or “Software as a Service”(SaaS) are probably the most popular form of cloud computing and are easy to use. SaaS uses the Web to deliver applications that are managed by a third-party vendor and whose interface is accessed on the clients’ side. Most SaaS applications can be run directly from a Web browser, without any downloads or installations required. SaaS eliminates the need to install and run applications on individual computers. With SaaS, it’s easy for enterprises to streamline their maintenance and support, because everything can be managed by vendors: applications, runtime, data, middleware, O/S, virtualization, servers, storage, and networking. Gmail is one famous example of a SaaS mail provider.

For further reading you can visit wiki’s SaaS explanation here

PaaS: Platform as a Service

The most complex of the three, cloud platform services or “Platform as a Service” (PaaS) deliver computational resources through a platform. What developers gain with PaaS is a framework they can build upon to develop or customize applications. PaaS makes the development, testing, and deployment of applications quick, simple, and cost-effective, eliminating the need to buy the underlying layers of hardware and software. One comparison between SaaS vs. PaaS has to do with what aspects must be managed by users, rather than providers: With PaaS, vendors still manage runtime, middleware, O/S, virtualization, servers, storage, and networking, but users manage applications and data. PaaS provides the computing infrastructure, the hardware, and the platforms that are installed on top of the hardware. Similar to the way that you might create macros in Excel, PaaS allows you to create applications using software components that are controlled by a third-party vendor. PaaS is highly scalable , and users don’t have to worry about platform upgrades or having their site go down during maintenance. Users who benefit most from PaaS include companies who want to increase the effectiveness and interactivity of a large staff. For the needs of larger companies and independent software vendors, Apprenda is one provider of a private cloud PaaS for .NET and Java business-application development and deployment.

Some examples of PaaS include Google App Engine [17], Microsoft Azure Services [18], and the Force.com [19] platform.

For further reading you can visit wiki’s PaaS explanation here

 

IaaS: Infrastructure as a Service

Cloud infrastructure services, known as “Infrastructure as a Service” (IaaS), deliver computer infrastructure (such as a platform virtualization environment), storage, and networking. Instead of having to purchase software, servers, or network equipment, users can buy these as a fully outsourced service that is usually billed according to the amount of resources consumed. Basically, in exchange for a rental fee, a third party allows you to install a virtual server on their IT infrastructure. Compared to SaaS and PaaS, IaaS users are responsible for managing more: applications, data, runtime, middleware, and O/S. Vendors still manage virtualization, servers, hard drives, storage, and networking. What users gain with IaaS is infrastructure on top of which they can install any required platforms. Users are responsible for updating these if new versions are released.

For further reading you can visit wiki’s IaaS explanation here