CINXE.COM

<!doctype html><html lang="en" class="livevideo-html"><head><script>(function () { // Safari backcache fix window.onpageshow = function (event) { if (event.persisted) { window.location.reload() } } })()</script><script>var url = window.location.href if (url.indexOf("livevideo.manning.com") !== -1) { (function (w, d, s, l, i) { w[l] = w[l] || [] w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js", }) var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != "dataLayer" ? "&l=" + l : "" j.async = true j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl f.parentNode.insertBefore(j, f) })(window, document, "script", "dataLayer", "GTM-56F284H") } else if (url.indexOf("liveproject.manning.com") !== -1 || url.indexOf("liveproject-qa.manning.com") !== -1) { (function (w, d, s, l, i) { w[l] = w[l] || [] w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js", }) var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != "dataLayer" ? "&l=" + l : "" j.async = true j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl f.parentNode.insertBefore(j, f) })(window, document, "script", "dataLayer", "GTM-NPK4K85") }</script><script>var availableCourses = [] var currentCourse = null</script><link rel="shortcut icon" href="/src/resources/images/favicon.png" type="image/x-icon"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:100,100i,300,300i,400,700,i|Merriweather:300,700,i&display=swap"/><link rel="preload" as="style" href="https://fonts.googleapis.com/css?family=Lato:100,100i,300,300i,400,700,i|Merriweather:300,700,i&amp;display=swap"/><meta charset="utf-8"/><meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta http-equiv="cache-control" content="no-cache"/><meta http-equiv="x-ua-compatible" content="ie=edge"/><script>if ( url.indexOf("liveproject-qa.manning.com") !== -1 || url.indexOf("liveproject.manning.com") !== -1 || url.indexOf("pbc-qa.manning.com") !== -1 || url.indexOf("pbc.manning.com") !== -1 || url.indexOf("lp-test-ui") !== -1 || url.indexOf("dlc9nze5anfoi.cloudfront.net") !== -1 ) { document.title = "liveProject - premium training by Manning" } else { document.title = "liveVideo \u2022 premium video training by Manning" }</script><meta name="description" content="Online video courses from Manning courses with tests, exercises, and code tryouts alongside"/><meta name="keywords" content="online video courses, learn online, it video courses, Manning"/><script>var alertTimingInfo = false var debugShouldUpdate = false // This is important for avoiding Chrome pending state... var initialLoadCustomVideoControls = true var initialLoadCLTC = true var initialLoadCueContainer = true var initialLoadTIYTC = true var initialLoadMediaViewer = true var initialLoadModuleLoadTracker = true var initialLoadEXTC = true var initialLoadUnscrambledVideoFragment = true var initialLoadTocMenu = true var initialLoadCircularProgressBarModuleVersion = true var initialLoadCircularProgressBarUnitVersion = true var initialModuleMount = true var prevSrcCVC = null var prevSrcCLTC = null var prevSrcModuleCueContainer = null var prevSrcModuleTIYTC = null var prevSrcMediaViewer = null var prevSrcModuleLoadTracker = null //NE RADI var prevSrcEXTC = null var prevSrcModuleUnscrambledVideoFragment = null var prevSrcModuleTocMenu = null var prevSrcCircularProgressBar = null var globalSrcChangeDetectedForCircularProgressBar = false var globalSrcChangeDetectedForCircularProgressBarTempForModuleVersion = false var globalSrcChangeDetectedForCircularProgressBarTempForUnitVersion = false var editModuleLog = "" var is_chrome = navigator.userAgent.indexOf("Chrome") > -1 var is_explorer = navigator.userAgent.indexOf("MSIE") > -1 var is_firefox = navigator.userAgent.indexOf("Firefox") > -1 var is_safari = navigator.userAgent.indexOf("Safari") > -1 var is_opera = navigator.userAgent.toLowerCase().indexOf("op") > -1 if (is_chrome && is_safari) { is_safari = false } if (is_chrome && is_opera) { is_chrome = false } var win = window var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !win.MSStream //SSO stuff function getServerURL() { var url = window.location.href const toniDevIframe = "http://paneli.dynu.com:8080" const toniDevHTTPSIframe = "https://paneli.dynu.com:8443" const backendDevIframe = "https://livevideo-be-dev.manning.com" const backendProdIframe = "https://livevideo-be.manning.com" if ( url.indexOf("localhost") !== -1 || url.indexOf("192.168.0.") !== -1 || url.indexOf("livevideo-ui-dev") !== -1 || url.indexOf("livevideo-qa.manning.com") !== -1 || url.indexOf("pbc-qa.manning.com") !== -1 || url.indexOf("liveproject-qa.manning.com") !== -1 ) { return backendDevIframe } else if (url.indexOf("livevideo-ui-prod") !== -1 || url.indexOf("livevideo.manning.com") !== -1 || url.indexOf("pbc.manning.com") !== -1 || url.indexOf("liveproject.manning.com") !== -1) { return backendProdIframe } else if (url.indexOf("lv-test-ui") !== -1 || url.indexOf("d23vewbo0wjc8b.cloudfront.net") !== -1 || url.indexOf("lv-test-prod-ui") !== -1 || url.indexOf("lp-test-ui") !== -1 || url.indexOf("dlc9nze5anfoi.cloudfront.net") !== -1) { return toniDevIframe } } var check = false var myWin = window; (function (a) { if ( /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test( a ) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( a.substr(0, 4) ) ) check = true })(navigator.userAgent || navigator.vendor || myWin.opera) if (check) { var cssId = "myCss" // you could encode the css path itself to generate id.. if (!document.getElementById(cssId)) { var head = document.getElementsByTagName("head")[0] var link = document.createElement("link") link.id = cssId link.rel = "stylesheet" link.type = "text/css" link.href = "/src/styles/mobile.css?v=1.1.03" link.media = "all" head.appendChild(link) } } // check if localstorage // Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem // throw QuotaExceededError. We're going to detect this and just silently drop any calls to setItem // to avoid the entire page breaking, without having to do a check at each usage of Storage. if (typeof localStorage === "object") { try { localStorage.setItem("localStorage", 1) localStorage.removeItem("localStorage") } catch (e) { Storage.prototype._setItem = Storage.prototype.setItem Storage.prototype.setItem = function () {} var is_root = location.pathname == "/" if (is_root) { alert('Your web browser does not support storing settings locally. In Safari, the most common cause of this is using "Private Browsing Mode". Some settings may not save or some features may not work properly for you.') } } }</script><link rel="stylesheet" href="https://use.typekit.net/pwg6fmr.css"/></head><body> <noscript><img height="1" width="1" src="https://www.facebook.com/tr?id=1940497162877014&ev=PageView&noscript=1" /><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NPK4K85" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="root"></div><div id="full-screen-modal"></div><svg height="0" xmlns="http://www.w3.org/2000/svg" style="display: none"><filter id="drop-shadow"><feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="12" dy="12" result="offsetblur"/><feflood flood-color="rgb(0,0,0)" flood-opacity="0.5"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge></filter></svg><script>var url = document.location.href //Google analytics if (url.indexOf("livevideo.manning.com") !== -1) { /*Google analytics*/ //Turned off for liveVideo, using GTM instead // /* (function (i, s, o, g, r, a, m) { // i['GoogleAnalyticsObject'] = r; // i[r] = i[r] || function () { // (i[r].q = i[r].q || []).push(arguments) // }, i[r].l = 1 * new Date(); // a = s.createElement(o), // m = s.getElementsByTagName(o)[0]; // a.async = 1; // a.src = g; // m.parentNode.insertBefore(a, m) // })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga'); // ga('create', 'UA-96826557-1', 'auto'); // ga('send', 'pageview'); */ // Minified version found on net (https://mathiasbynens.be/notes/async-analytics-snippet) //Turned off for liveVideo, using GTM instead //(function (G, o, O, g, l) { G.GoogleAnalyticsObject = O; G[O] || (G[O] = function () { (G[O].q = G[O].q || []).push(arguments) }); G[O].l = +new Date; g = o.createElement('script'), l = o.scripts[0]; g.src = 'https://www.google-analytics.com/analytics.js'; l.parentNode.insertBefore(g, l) }(this, document, 'ga')); ga('create', 'UA-96826557-1'); // ga('send', 'pageview'); /* Hotjar Tracking Code for livevideo.manning.com */ // (function (h, o, t, j, a, r) { // h.hj = h.hj || function () { // (h.hj.q = h.hj.q || []).push(arguments) // }; // h._hjSettings = { // hjid: 717616, // hjsv: 6 // }; // a = o.getElementsByTagName('head')[0]; // r = o.createElement('script'); // r.async = 1; // r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv; // a.appendChild(r); // })(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv='); } else if (url.indexOf("liveproject.manning.com") !== -1) { // (function (G, o, O, g, l) { G.GoogleAnalyticsObject = O; G[O] || (G[O] = function () { (G[O].q = G[O].q || []).push(arguments) }); G[O].l = +new Date; g = o.createElement('script'), l = o.scripts[0]; g.src = 'https://www.google-analytics.com/analytics.js'; l.parentNode.insertBefore(g, l) }(this, document, 'ga')); ga('create', 'UA-96826557-2'); (function (h, o, t, j, a, r) { h.hj = h.hj || function () { (h.hj.q = h.hj.q || []).push(arguments) } h._hjSettings = { hjid: 2577599, hjsv: 6 } a = o.getElementsByTagName("head")[0] r = o.createElement("script") r.async = 1 r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv a.appendChild(r) })(window, document, "https://static.hotjar.com/c/hotjar-", ".js?sv=") } else if (url.indexOf("liveproject-qa.manning.com") !== -1) { (function(h,o,t,j,a,r){ h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; h._hjSettings={hjid:3127061,hjsv:6}; a=o.getElementsByTagName('head')[0]; r=o.createElement('script');r.async=1; r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; a.appendChild(r) })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); }</script><script>if (url.indexOf("liveproject.manning.com") !== -1) { !(function (f, b, e, v, n, t, s) { if (f.fbq) return n = f.fbq = function () { n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments) } if (!f._fbq) f._fbq = n n.push = n n.loaded = !0 n.version = "2.0" n.queue = [] t = b.createElement(e) t.async = !0 t.src = v s = b.getElementsByTagName(e)[0] s.parentNode.insertBefore(t, s) })(window, document, "script", "https://connect.facebook.net/en_US/fbevents.js") fbq("init", "1940497162877014") // fbq('track', 'PageView'); }</script><style>#playVideoImage:hover, #playVideoFragmentImage:hover { -webkit-filter: drop-shadow(12px 12px 25px rgba(0, 0, 0, 0.5)); filter: url(#drop-shadow); -ms-filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; cursor: pointer; transition: all 0.5s !important; } #rePlayVideoImage:hover, #rePlayVideoFragmentImage:hover { -webkit-filter: drop-shadow(12px 12px 25px rgba(0, 0, 0, 0.5)); filter: url(#drop-shadow); -ms-filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; cursor: pointer; transition: all 0.5s !important; } #rePlayVideoImageCentered:hover, #rePlayVideoFragmentImageCentered:hover { -webkit-filter: drop-shadow(12px 12px 25px rgba(0, 0, 0, 0.5)); filter: url(#drop-shadow); -ms-filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; cursor: pointer; transition: all 0.5s !important; } #nextVideoImage:hover, #nextVideoFragmentImage:hover { -webkit-filter: drop-shadow(12px 12px 25px rgba(0, 0, 0, 0.5)); filter: url(#drop-shadow); -ms-filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=12, OffY=12, Color='#444')"; cursor: pointer; transition: all 0.5s !important; }</style><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.0/katex.min.css" integrity="sha512-Yfxo7zXGaQYyzWNxz8r4s8axNfG4jS3dips8p2HA/wNWmuapakkQiki+/XA3o3Ol+i8WI03cRJVDDUElEtED6g==" crossorigin="anonymous" referrerpolicy="no-referrer"/><script defer="defer" src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.0/katex.min.js" integrity="sha512-M7/jkZoKEln1jaaY2roCK9Jt4t+j/iru0e2vInDkVO5LY0EBt3m66tjTT5XFsGH2LJG+VRRL2ueIR3U0frs/GQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script><script defer="defer" src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.0/contrib/auto-render.min.js" integrity="sha512-ZA/RPrAo88DlwRnnoNVqKINnQNcWERzRK03PDaA4GIJiVZvGFIWQbdWCsUebMZfkWohnfngsDjXzU6PokO4jGw==" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script><script defer="defer" src="https://www.youtube.com/iframe_api"></script><noscript><link rel="stylesheet" href="https://lv-resources.s3-us-west-2.amazonaws.com/fonts/fontawesome-pro-5.12.0-web/css/all.min.css"/><link rel="stylesheet" href="https://lv-resources.s3-us-west-2.amazonaws.com/fonts/fontawesome-pro-5.12.0-web/css/v4-shims.min.css"/></noscript><script>(function () { var font = document.createElement("link") font.type = "text/css" font.rel = "stylesheet" font.href = "https://lv-resources.s3-us-west-2.amazonaws.com/fonts/fontawesome-pro-5.12.0-web/css/all.min.css" var s = document.getElementsByTagName("link")[0] s.parentNode.insertBefore(font, s) })(); (function () { var font = document.createElement("link") font.type = "text/css" font.rel = "stylesheet" font.href = "https://lv-resources.s3-us-west-2.amazonaws.com/fonts/fontawesome-pro-5.12.0-web/css/v4-shims.min.css" var s = document.getElementsByTagName("link")[0] s.parentNode.insertBefore(font, s) })();</script><script defer="defer" src="/runtime.js?mnvffd7457e146d684c7c62e0dFFW"></script><script defer="defer" src="/npm.vbook-ui-components.js?mnvffd71335a597818152a7961FFW"></script><script defer="defer" src="/npm.css-loader.js?mnvffdda75c40095a983eb4919FFW"></script><script defer="defer" src="/npm.react.js?mnvffdeb04c9bc866cdc411195FFW"></script><script defer="defer" src="/npm.react-dom.js?mnvffdf203c5efc9bcbb7e2d9aFFW"></script><script defer="defer" src="/npm.core-js.js?mnvffd23c3092437e89ab06562FFW"></script><script defer="defer" src="/npm.sentry.js?mnvffd7a08e53f2f8d7b63c198FFW"></script><script defer="defer" src="/npm.react-redux.js?mnvffdb20a7c055aa8f52059fdFFW"></script><script defer="defer" src="/npm.uuid.js?mnvffd024f9835d89a1c42a187FFW"></script><script defer="defer" src="/npm.sidenotes.js?mnvffde5790f188cc3549f8bbeFFW"></script><script defer="defer" src="/npm.react-router.js?mnvffdab362a33effcc0b0f9fcFFW"></script><script defer="defer" src="/npm.style-loader.js?mnvffd66cf0360af60821fbdc7FFW"></script><script defer="defer" src="/npm.redux.js?mnvffdf29b762a54e3fa0135eeFFW"></script><script defer="defer" src="/npm.react-router-redux.js?mnvffd8fb91eac8f35cfe0c4aaFFW"></script><script defer="defer" src="/npm.react-router-dom.js?mnvffd702e65dc43999a53688aFFW"></script><script defer="defer" src="/npm.use-sync-external-store.js?mnvffd1d99b50ffbd233f985daFFW"></script><script defer="defer" src="/npm.prop-types.js?mnvffdaaa38a12ffe4aac220ecFFW"></script><script defer="defer" src="/npm.scheduler.js?mnvffdd1772d7fa008eb4e190cFFW"></script><script defer="defer" src="/npm.react-is.js?mnvffda0312271e59b1db9b00dFFW"></script><script defer="defer" src="/npm.history.js?mnvffde93b69a655b081147ea3FFW"></script><script defer="defer" src="/npm.tiny-invariant.js?mnvffdbbf65bce36b8677f4c84FFW"></script><script defer="defer" src="/npm.dateformat.js?mnvffd3e294d7e431c01bcc855FFW"></script><script defer="defer" src="/npm.value-equal.js?mnvffdb4056c0083270477b18dFFW"></script><script defer="defer" src="/npm.string-similarity.js?mnvffd671186a83130bc79b107FFW"></script><script defer="defer" src="/npm.resolve-pathname.js?mnvffd22364d96feefeae83977FFW"></script><script defer="defer" src="/npm.redux-thunk.js?mnvffded9a2fafd66224cd53c9FFW"></script><script defer="defer" src="/npm.redux-logger.js?mnvffd1719441f66b0c5f42ca3FFW"></script><script defer="defer" src="/npm.react-loadable.js?mnvffd963c888accc720a8745bFFW"></script><script defer="defer" src="/npm.object-assign.js?mnvffd781241998172b6160cf9FFW"></script><script defer="defer" src="/npm.jquery.js?mnvffd1b70db74ca7155a076e4FFW"></script><script defer="defer" src="/npm.immutable.js?mnvffd4d270ea1afe24a7749f4FFW"></script><script defer="defer" src="/npm.esprima.js?mnvffd1fbefdf692b5f19eae66FFW"></script><script defer="defer" src="/npm.es6-shim.js?mnvffdc6cf79f955de0ad08adcFFW"></script><script defer="defer" src="/npm.es6-promise.js?mnvffd04a8790b71365489ebd1FFW"></script><script defer="defer" src="/npm.es5-shim.js?mnvffd487e21f5aed1fc26ab15FFW"></script><script defer="defer" src="/npm.classnames.js?mnvffdf421583f983dbd8abae8FFW"></script><script defer="defer" src="/app.js?mnvffde52d9b1885bf6f3b260aFFW"></script></body></html>