logo

NJP

GlideAjax in ServiceNow | Learn ServiceNow APIs

Import · Jan 02, 2021 · video

[Music] please subscribe to my channel and click on the bell icon to get the regular updates of my channel and do not forget to like comment and share hello everyone welcome to sas with servicenow in this video you will learn about glide ajax in servicenow servicenow provides different client-side javascript apis which allow you to control the elements on the form and functions within the web browser these apis are classes and methods which can be used to control the end user experience much easier glide ajax is one of the api provided by servicenow and used to call server-side code from client glide ajax class enables a client script to call server-side code mentioned in a script include overall if you get a requirement in which you have to fetch some details on the form from a racket in a table and use it on the client then glide ajax is the effective way to use let's see what all different classes and methods we have in glide ajax with their parameters starting with glide ajax class which needs a parameter as name of the class in string glide ajax is a constructor of glide ajax class in java in order to use glide ajax you need to initialize it and by providing parameter as the name of the class or script include this script include will have a function to execute the server side code if you have to use glide ajax for any functionality then you have to start with initializing glide ajax next is add param method which is used to provide function which needs to be called and parameters which needs to be passed to server side code you can pass two parameters to add param method one is name of the sys parameter and second is value offices parameter now this value is passed to server side code written in script include you can call these add param methods multiple times with different parameters and values there is one default syspem parameter called as sperm underscore name whose value is the name of the function which needs to be called mentioned in the script include next is get answer get answer method is used to retrieve the results from a server side method called from the client via get xml weight method however get xml weight is synchronous call which means it waits for the response from server and then user can perform further action on the form or client which gives bad user experience so get xml weight is not recommended by servicenow it you might get some situations as well in which you might need to use get xml weight however if i talk about a general situation you should always ignore to use get xml weight overall that get answer method as well next we have is get xml method now getxml method sends request to server to execute the method and parameters which are associated with glide ajax object now this request is processed asynchronously and response is returned when it is ready via callback function this is the best and recommended approach for glide ajax we will see live example practical examples of how you can use these methods then we have get xml weight get xml weight method also sends requests to the server to execute the method and parameters which are associated with glide ajax object however request is processed synchronously which wait for the response from the server and this is not the recommended approach for glide ajax from servicenow so overall these are all different methods which you can use with glide ajax as per the requirement of the script or as per the requirement you get from the customers and you have to create that script by using glide ajax there is a procedure to use glide ajax in service now which has some steps to follow so you start with creating a client callable script include first in this script include you create a function which process server side code as per the values provided by parameters you can also use existing script include and create a new function in the same script include and in this function you mentioned the code which you want to execute for server side data and return the data in response once you are done with this script include creation you can create client script and in this client script you create a glide ajax class object and pass the name of the script include as parameter so whatever script include you have created you have to pass that particular name as the parameter for this glide ajax instance the object which you have created then you call add param method and that first method will be called for default one that is the default sperm parameter that is syspum underscore name and the value will be the function the name of the function which you have mentioned in your script include and then you can also call some additional add param methods as well to send other parameters from client side to server side as well now after adding all the parameters all after mentioning all the add pattern methods then you can use then you can call get xml method to send the request to execute server side code with callback function then you can invoke that function which you have provided in the parameter of this get xml method that means you can invoke it which will basically process the results whatever response we will get from the server side code you can process it and use it in your client-side code as well let's see the syntax of glide ajax so you create a client callable script include with some name which becomes the class and also extends another class for ajax so this code which you can see on the screen will be populated automatically once name is mentioned in the script include and name of the script include becomes the name of the class then you have to create a function and mention your server side code which should return some results you can use this dot get parameter method with name of the parameter mentioned in the client script which basically holds the value of a data from the client when you pass the same parameter that same value can be fetched in this particular server code as well and if you want to send user id of the user let's say you have to add another parameter in that case and you have to send a user id from client to the server that means to this script include in that case you can store that in a different parameter like for example you can use like this dot get parameter and that is sperm underscore user id so that's one of the example so if you have to send any other data you can use that relevant name like syspem underscore society maybe ci anything it's it's just up to you how you exactly provide the name but says it has to be cis perm underscore then any name you want to give that parameter if you will provide that parameter in your client script and in your server side script as well basically you get that parameter that value will be fetched automatically from the client to your server side code and then you can use this value in your server side query so maybe you are if you're getting that particular value and with that value you have to do some query on a particular table then you can use that particular value and do the query once you are done with the script include and function then you create a client script and in this client script you start with initializing glide ajax by passing the name of the script include so you create a glide ajax object so which you can see like we will start with var keyword and then you provide any variable and then you do equal to and then you use new keyword and then you put that glide ajax class we have and you have to provide the parameter the name of the script include the script include which you have created to run server side code and then you call add param method by passing syspem underscore name and value as a function which is created in same script include so the value would be the name of the function which you have mentioned in your script include and then you can call same add para method again to send any value from client to server side code like in this case i'm sending user id it's just an example now the syntax is like says perm underscore then you put you can put any name and then the second parameter as its value which can be fetched from the client so any name in any value maybe you want to fetch some value from the form as well like general score from uh dot get value that is also possible so you can just get that value put it into the parameter that means add that parameter and that that particular value will be sent to the server side code as well and then after uh after putting all these methods after calling all these methods then you can call getxml method in which you will pass callback function as a parameter now this callback function is used to process the response which is returned from the server and then you can invoke same callback function and in this function you can create a variable which is basically used to store the response retrieved from the server side code now how exactly you can store that particular response so in that case you have to use response so you put that variable you create that variable a var answer or any variable in this case i have used answer but you can use any variable you want and then we will do equal to and then i put response dot response xml dot document element dot get attribute and then here in brackets you put that particular element that is answer and this way you get the value and answer element of the response and which you can use basically whatever response we are getting from that server side code whatever value that will be returned to this particular variable so that means this particular variable where answer will store that particular value and then you can use that same value on the client side maybe you want to populate in an alert maybe you want to use that for any different purpose on the client maybe in your client side code you want to use that value that's how you can use it so in this case in in this whole scripting part you are basically creating two things script include and uh client script so you are basically sending the request from client script to your server which is basically processing your server side query or any kind of server-side code giving you the response that means giving you the results the data which you are expecting from that server-side code and then once you will receive that response you can process it on the client and that's how this glide ajax works now let's understand glide ajax and its methods with live example in my personal developer instance so this is my personal developer instance now let's say you have to populate number of incidents incident rackets associated with the problem and show it on the top of the form of a problem racket so this is something maybe you you got the requirement from your customer now how can you fulfill this requirement now in order to fetch the number of brackets you have to do a query on incident table which is a server-side execution so we will use glide ajax for this because that data is not available on the client so how can i do that i have to count the number of rackets associated with problem so in that case i have to do i have to query a table so what exactly i will do i will go to problem racket first maybe just to show you what kind of message we are looking for and what kind of data we are looking for so if i show you this list of problem now first of all the data which we are talking about related incidents to a problem that data is already available so we already have a field if you can see here we have related incidents this this data is already available in in this table in problem table but as of now in order to show you this demo i'm just ignoring this particular field let's say because you have to use the logic because the only thing is you have to understand how exactly we can execute server side code from a client so in this case i'm just ignoring the data we have in this particular field and i just want to make sure that if a user is opening the problem form that user should be able to see all the incidents the number of rackets number of incident brackets associated with that particular problem racket which user has opened so if i open let's say this particular problem and if user is opening this he should see a message on the top over here that hey this particular problem has 10 records associated with it so you can just see that message how can i show that because it's a client side now the method which i'm talking about i can show this message um with server side code as well but as i told you i want to show you show you the demo that how exactly you can run a server side code from client that's the reason i'm just doing everything on client first so i want to see this message on this client whenever i open i load this form i should be able to see the number of incident rackets associated with that existing problem record in that in that case what i will do i will quickly create a client script just to show you the type of message i want to see so i will go to client script and here i will click on new to create a new client script i will provide a name maybe demo dot glide ajax and that's it and i will make it all and maybe i will do on load we will do it on load and the message would be now in order to show you the message on the top of the form we always use on client i'm talking about generous go form add info message and the message would be this problem is associated with 10 incidents now this count is incorrect right now because i'm just showing you the example that what kind of message i want to populate for the user so i will just save this so this client script will be created and i will just try to open any existing problem bracket let's say this one and if i will open this will show a message here over here you can see it says this problem is associated with 10 incidents now overall this count is incorrect right now because if i go at the bottom i just have one incident associated with these problems overrides incorrect so what i have to do now i have to query incident rackets the incident table to check if this how many how many rackets how many incident rackets are associated have relationship with that particular problem bracket which user is watching which user is basically has opened so that particular problem i have to check in this particular list that is incident table because an incident table we already have a relationship that means we already have a field which shows the problem number as well so if i open this incident record and i can show you that particular field which shows the relationship so if i go to related bracket you can see here we have this problem field now with the help of this field i can get the count of rackets which are associated for that particular problem bracket so whatever incident records are related to that particular problem i can just find it with the help of this particular id so whatever user is watching whatever user is opening that particular form i will take that number maybe society and then try to filter out all the rackets and i will count the numbers so that case overall i have to do a server side i have to do a server side execution so what i will do i will quickly go over here here i have demo dot glide ajax now what i will do i will start with creating script include first as we learned that for for glide ajax you you can start creating script and glued first now there is no hard and fast rule you can also change the sequence you can definitely create the create the client script first but overall you have to provide parameters and to provide those parameters you have to have script includes a script include available as well because you have to provide the name and function so it's better to start with script include so what i will do i will just quickly mention script include here and i will okay i will open a new tab i will click on new button and i will do let's say demo demo glide ajax now i'm just giving it a name demo glide ajax and if i press tab if you remember i already mentioned that this will automatically create the class with the same name i have for a script include now if because in this case i'm i'm going to use it for glide agax for ajax so in that case i have to make it client callable that is mandatory because this particular script will be called by client script so i will make it client callable as soon as i will check this box you will see that it will extend another class that is abstract ajax processor now what i will do i will start with creating a function so this is the syntax so i will keep on talking about the syntax as well so maybe i will make it full screen like this and if i come over here so this is the syntax now this code will be populated automatically you don't have to write anything once you will provide the name it will show that name with the same class and then all the code all the lines of code you can see it will be as is so that means it will be populated automatically now in this line of code like after this curly bracket and bit like overall between these curly brackets you have to provide your function and i will start with invoking the function so that would be function and i think i have to start with the name first so i will be starting with let's say because we have to count the numbers so it'll be count inc that's a function i'm taking and then i would do function that's it all the curly brackets and i will do comma so this is how you create a function in in this particular script include now in this function we have to write our server side code now what i will do i have to get the value that's that's this id that's how i can filter the records so in that case because let's say i have this incident right what i can do i will do incident dot list and if i open the list of incident record and if i maybe i will just look for a problem bracket so i will do problem and here i will provide same problem because i want to show you that how exactly this would work so i will select this problem i will run this now i am able to see one incidence overall one incident is associated with that particular problem but for that i am using this problem id that's how i can do the search so as of now user is opening the form on the client and i have to send that id to server side code so in that case what i will do i will start with here and i will do it i will give it a variable so i will create a variable to store that problem id which i will get it from client so i'll be pro prb underscore id and here i can do this dot i can do get parameter and here i can give it a name says perm underscore prb id that's the name i have given i have to use same name in our client script as well now once i will get the id now this will be the society now i have to query the table so in that case i will do where where gri equal to new glide record because i have to query the incident table and i will do incident incident and then i will do gri dot add query and here i will provide the name of the field that is problem underscore id and here i can just put this because this will accept the society and that's it and then i will do gr i dot query semicolon and i will do while now one thing i think i'm just doing a mistake what mistake i have to do a query but at the same time i don't have to get any data data from this incident table i just have to return the count now for count it's always recommended in service now not to use glide racket you should always use glide aggregate so i will just quickly change this and i will make it aggregate and i will do gri dot add aggregate and here i will do count because we have to do count of number of rackets i have add aggregate i'm doing the query and here i can do gri dot next and here i can provide let's say i will do var maybe i can just do where it will have where um count con count of inc it's just a variable i'm just creating over here it's a var count of inc and i can provide gr i dot get aggregate now in this get aggregate i have to just do count that's it and it will give me the count and here i can give return i can i think i can just quickly mention this one that's it so in this function i'm just returning this return count off incident that what so this will store the count of rackets i'm getting with this problem id which i'm getting from the client so here i think it's mixed spaces that's fine let me check this so i think your script is good so this is how you create the script include you create the function you write the server side code and i think you're done you're just returning the response this is definitely important the reason behind it when your client-side code will call this script we'll call this script include and the function this will basically return the response and that response is count of rackets count of incident records so i will save this so my script include will be saved so demo glide ajax this is saved now what i will do i will go to my client script so i will go to my client script now so as you know as part of the procedure of creating uh using glide ajax you have to create a script include then you have to create client script now we already created this client script but what i will do i will just do some changes in the same client script so i will start with where ga equal to new glide ajax now here i will provide the name of the script include you have to make sure it's a string so you have to use these codes as well and i will come over here here i will just copy the name i will go to the client script put it into this as a parameter and then i will do semicolon then i will start with the first add pattern method so i will call that and the first parameter would be cis perm underscore name and that name is the name of the function you have in your script include and that script include function is count inc i will come here i will provide the name and then i will now you have to send the value of that problem id which user is opening how we will get that value so for that what i can do maybe i can just put it over here and maybe i will do where prb id equal to and then i can do g underscore form dot get value let's say we will we will get the value of the problem number not society we will get the number so in that case i will do g underscore form dot get value and we have field as number and then so this will basically store the number value so this prb id or maybe i can do it prb num this will basically store the number the whatever value we have in number field for that particular font form which user is opening so i will just copy this and i will maybe mention ga dot add pattern and here i can do genesis perm underscore now one thing i have to remember i have if i will change the name here i have to use the same name same parameter name in script include as well so maybe i will give prb num and here uh syspum underscore num is fine and then i will do comma and here is the variable that's it so we are basically storing uh the value this number field in this particular variable which i'm putting over here and which i'm sending with this parameter to script include now i will do ga dot get xml and here i will provide the callback function and that callback function can be maybe demo call back that's it and then i can maybe let me just change this i think that is that is better so i will go to my script include and here i will change this to cisperm num one more thing now here i am using this problem id now what i will do if i will go to the list of rackets i have let me go to the list here i will just copy this so i will do copy query and if i i think this will always i think if i'm not wrong this will definitely uh check for the society and i think i don't want to use uh society because if i come over here this is definitely using the society so i don't want to use uh society so what i can do maybe i can use let me do that problem and or maybe i will do show related fields and then i will do problem fields and here i can do number uh problem or maybe number i have number is and then i put maybe maybe that number the problem bracket which we have and that is this one so i will just quickly put that and run this if i will run this you can see we again got same thing and i will just copy query this time this time you can see the query got changed so i will go to my script over here uh basically to script include here i will add gr dot add encoded query and here i will put the encoded query that's it but the thing is you have to do it till here do plus and i will put this prb id that's it this way this will put this query and filter the rackets and return the count count of incidents i have so i think you are done with this we can quickly save it again and then i can go to the client script here we have callback function demo callback and i can just give function demo call back and i can give the parameter as response that's it and here i can provide any variable maybe it's a equal to i can do response dot response xml dot document element dot get attribute and here i can put that element that is answer semicolon and now i have to populate that message so i will quickly do like this gs.info message uh not gs g g underscore form dot add info message and i can just put like this plus and i can put whatever response i will get it will be populated here so i will get the right answer so this will basically uh it is it is basically sending the request to run the server side code i'm getting the response with this callback function and i'm using that response whatever response i'm getting i'm storing that in this particular variable that is a and then i am using that response whatever data i'm getting i'm using that in my client script that is this particular code and i'm populating that count here so in that case i can just quickly save this so once it is saved and if i go to my incidents let's say i will just try to open some incidents we have where we have multiple uh like we will open problems not incidents so i will open problem brackets so i will go to the problem list i will go to problem and i will try to open i will i will open those problems basically where we have a lot of existing incidents associated with them but i don't think we have more problems but let's find i can just open this one for now if i open this one let's see what kind of message i will get and it is working okay you can see it says this problem is associated with one incident that means i'm able to get the right count how can i verify this let me go at the bottom if i go at the bottom you can see i have one incident let's say i will associate any other incident to this particular problem racket let's do that so i have clicked on add and i will try to associate maybe let me i will just add baby this one this one this one and i will do add selected it is trying to add you can see it added three more and now we will see whether this count will change or not if i will reload it you will see the magic you can see now this time it is showing four incidents that means on the client side it is doing a server-side query it is it is running it is doing a server side code it is running the server side code and then it is returning the response with that part account and populating it with the help of client script code so this is how you can call server side code from client side and service now now let's let's see another example as well so that you can understand better because as of now we were just counting the rackets now let's say you have to populate some data on the form let's say maybe on incident form on incident form you are selecting a configuration item and when you open the form it shows you some details of that configuration item and if i talk about incident table you don't have much details about configuration at item apart from that reference field where you select the ci but let's say you want to show some other details of a configuration item racket as well maybe support group or maybe expiry data or whatever different information we will see that what all information we can populate so in that case because that's again a server side because you only have ci racket that is a society of that particular ci record on the client but you don't have other information available on the client and you have to show that information on an alert that means you have to populate an alert which should show all those information like maybe ci support group or maybe some other field data which we have on configuration items so how you can do that now this is again you have to do a server side query you have to run a server side code so that you can fetch those details and then show it on the form on the client so in that case again client script and script include will come into the picture so what i will do now i will uh quickly first disable my maybe client script so the client script which we created this one we can just disable this so that it does not interrupt our other work so i'm just going to disable this and maybe we'll continue to use this particular script include because if you remember i mentioned to you that you can use same script include or existing script include however you just need to create different functions in order to you know to get different types of functionalities so what i will do i will create another function in the same script include and i will call it and you can also maybe we can also comment this particular function and create another function as well so maybe i will comment this one so that we don't have any issues overall this won't disturb this won't impact anything because s script include will only work once you call it so if you have a script include even it's available in the system that won't impact the performance not even any kind of execution until any script call that particular script include so in this case i will just maybe comment this one so this is commented and now i will create a new function but before that the requirement is let me go to the incident so i will go to the incident list and i will open any record existing record so if i open this record let's see if i have any configuration item so we have this file server floor 2. now the requirement is when i open this racket that means user opens this racket i should be able to see some details maybe maybe ci support group or if i open this cmdb racket let's see what all other details we have on the cmdb racket so we have um i think we can maybe show uh os version or maybe we can show asset tag yeah let's let's show as a tag that's i think that will be better we can show asset tag and we can also show maybe uh manufacturer so these two details we want to show on client when user loads the form basically when form is loaded and when user is opening the form then you show those information so let's start with the script include first so we'll go to our script include and i will create a new function so i will make it full screen and i will do like this now here i will create our function and that function so i will start with maybe uh here i have to populate uh details so i will do cm db details this is my this is my function which i'm creating so i will do function and then i will do like this now here we will write our code so i will start with fetching the parameter value which will store uh the value of that cmdb ci this the configuration item value because i have to search basically that ci and then i have to fetch those details and how exactly i will get the ci i will get it from the client so in that case i will start with where cmdb id equal to i will do this dot get parameter and here i will provide the name that will assist perm underscore cmdb maybe id and i will just do semicolon and what i will do i will do where gr c equal to new because i have to query cmdb table so i will do glide record and here i will do cmdb underscore ci cmdb underscore ci semicolon i will do g r c dot add query and here i will just do society because we will get the society from our client how we will get the society i will show you so i will just get the society and here i will put this variable because we will store that society we will get that society stored in this particular variable then i will do semicolon then i can do grc dot i can do grc dot query semicolon and then i will do i don't have to do while because we don't have to run loop we have to just check details of one bracket so i will do if and i will do grc dot next and here i will basically do maybe where um where cmdb details um where cm db d that's fine this is a variable i'm just creating and then i can do maybe in this string and here i can do um the menu factor is the manufacturer is grc dot now i can directly see so let me go here manufacturer's manufacturer so that's the name of the field so i can go to my script include and here i can do menu manufacturer manufacturer grc.manufacturer now let me i think it's a straight i think you can see it's a reference field now you will again get an issue the reason behind it because it's a reference field so we will get cis id printed so in that case i can fix it it's not a big deal i just need to do get get display value that's it so if you will do get display value and then the manufacturer is this and i can do and i said tag is here i can just put grc dot and that is a set underscore tag so i will come over here i will do asset underscore tag that's it so this will have that response basically so we will get these values printed here and now i will return this response this basically variable so i will do return same variable which we are creating over here that's it and i will do semicolon and i think it is totally good so it will query the racket called the table first with the same society which will get it from the client it will query the racket it will run it check uh look for the next record yes if it will find uh then it will store that value the whole value in this particular variable and then i'm just returning this response back to the client so in that case i will save this but you have to remember i think script include will still be the same but the function is definitely changed this time so i will maybe cmdb details so i will go to the incident form now and i will go to client script not form right now i will go to client script first because we have to create the client script so i will click on new glide dot demo dot ajax 2 and then i can provide maybe onload and desktop or maybe i will give it all that's totally fine and i will here is start with client script make it full screen now here i will start with initialization of glideagex objects i will create the guide ajax object so that will be ver ga equal to new glide ajax and here i will provide the class name and that class name is this one that's it semicolon i will ga dot add pattern here i will provide cis perm underscore name and then i will provide the name of the function now this time the name of the function is different that is cmdb details so i will provide the name of the function semicolon ga dot now i have to provide another parameter the reason behind it because i have to send that the configuration item society which is selected on the form so in that case i will select same parameter name which i have this one so i will copy this i will come over here i will put the same one and then i will do g underscore form dot get value now here i will provide the name the name of the field that is cmdb cm db underscore ci then i will do semicolon and then i will do ga dot get xml here i will do callback functions so cm db call back that's it semicolon and here i will do function cmdb i will just copy it syntax is same as i told you but all but just the names will be different definitely and here i will do response and then i will do like this curly brackets and here i can do maybe where b this time or maybe i will do where you can maybe give answer that's okay you can give anything you want here and then you can do response dot response xml xml dot document element dot get attribute and then here you can put that answer element so we have answer and then i can maybe do alert and i can just put answer so that means whatever value we got from from the server side code which is stored in answer that will be populated in alert that means whenever i will load the form i will open the form i will see that value so in that case i will click on save because our script seems to be okay i don't find any issues and i'm sure this would work without any issue i don't see any kind of syntax error all seems to be okay and then let me go to incident form and i think here i don't have any uh any value selected so what i will do i will open that type of that incident racket where we have configuration item selected so let's open this one and if i come over here yes manufacturer is dell inc and asset tag is this one not even a single error which is pd script we were able to get this value on the client that means we were able to call server side code from client and we were able to get the response now one thing is very important maybe i would like to show you that uh synchronous synchronous call which we do from client side with this glide ajax because you can do that but that is not recommendable but overall as of now we are done with both the use cases but just to show you the example overall it is not recommendable but i still want to show you maybe we will see let's see if if we get any kind of maybe latency in the response or we will see that or how what exactly happens uh when you use that get xml weight so let's see that so in that case what i will do i will go to my client script so you don't have to touch your script include the only difference you will make synchronous and asynchronous call with the client script so here you can see we have ga dot get xml what i will do i will make this comment and i will make it full screen i'll make it as a comment and here i will do like this here i will do ga dot get xml and if i do that i have to just add weight so we are going to use get xml weight which is basically synchronous call so i will do semicolon and then i will do alert and i will provide ga dot and i can do get answer that's it if i will do this now as i mentioned again this is not recommendable from servicenow that's how you can see that if i will do ga dot get get xml you can't you can't get that get xml wait because servicenow is not recommending but in any case you might need to use it i think you might get some situation as of now i don't remember in what situation you might need to use get xml weight but overall it is totally not recommended but i'm sure you will get the similar output well let's see do we get any kind of maybe uh delay what exactly we will get what kind of response we will see on the client let's see that so ga dot get example weight alert ga dot get answer and if i will save this if i will save this so this is saved and i will go to my same incident racket and i will reload it if i will reload it it is processing it and yep we are getting the same response but the only problem as i mentioned user will be able to do something because this client will always wait for the response and when you do server so query it might happen that you are acquiring multiple rackets and it might take maybe more than one second or two three seconds in that case user will not be able to do anything and that is not the best way that is not the best approach so you should always use get xml only not get xml weight so this is how you can use glide ajax and its different methods in servicenow to fulfill the different functionalities you get from your customers and clients overall whenever you need to call a server-side code or anything which is not available on the form and you have to fetch some data from the server side from a table you have to query some tables in that case the best approach is glide ajax there are some other ways as well like get reference you also have scratch pad but the best approach is glide ajax which is basically i would say which will not impact the performance of the system so that's how you can use glide ajax for different requirements of your customers and clients so thank you and have a great day

View original source

https://www.youtube.com/watch?v=uEL3xyqvuUM