CINXE.COM

Automate Reports

<!DOCTYPE html> <!--[if lt IE 7 ]> <html lang="en" class="no-js ie6 ie"> <![endif]--> <!--[if IE 7 ]> <html lang="en" class="no-js ie7 ie"> <![endif]--> <!--[if IE 8 ]> <html lang="en" class="no-js ie8 ie"> <![endif]--> <!--[if IE 9 ]> <html lang="en" class="no-js ie9 ie"> <![endif]--> <!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"><!--<![endif]--> <head> <meta name="theme-color" content="#333333"> <title>Automate Reports</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"> <meta name="application-name" content="Automate Reports"/> <meta name="apple-mobile-web-app-title" content="Automate Reports"/> <meta property="og:title" content="Automate Reports"/> <meta name="twitter:title" content="Automate Reports"/> <meta name="twitter:site" content="&#64;manningbooks"/> <meta name="twitter:card" content="summary_large_image"/> <meta property="og:type" content="website"/> <meta property="og:url" content="https://www.manning.com/liveproject/automate-reports"/> <meta property="og:site_name" content="Manning Publications"/> <meta property="og:locale" content="en_US"/> <meta property="og:description" content="Use Python, Kafka, and Postgres to enable your client’s system to provide a feedback loop in real time and enable external API access to status updates with no code changes."> <meta name="twitter:description" content="Use Python, Kafka, and Postgres to enable your client’s system to provide a feedback loop in real time and enable external API access to status updates with no code changes."> <meta name="keywords" content="Python, Faust, PostgreSQL, Apache Kafka, Draw.io"/> <meta property="og:image" content="https://images.manning.com/liveProject/0/24767f4-cd11-4902-8740-20582dc8e56d/"/> <meta property="og:image:alt" content="The cover for Automate Reports"/> <meta name="twitter:image" content="https://images.manning.com/liveProject/0/24767f4-cd11-4902-8740-20582dc8e56d/"/> <meta name="msapplication-TileColor" content="#343434"/> <meta name="msapplication-square70x70logo" content="https://images.manning.com/70/70/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <meta name="msapplication-square150x150logo" content="https://images.manning.com/150/150/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <meta name="msapplication-wide310x150logo" content="https://images.manning.com/310/150/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <meta name="msapplication-square310x310logo" content="https://images.manning.com/310/310/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" href="https://images.manning.com/152/152/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="57x57" href="https://images.manning.com/57/57/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="60x60" href="https://images.manning.com/60/60/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="72x72" href="https://images.manning.com/72/72/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="76x76" href="https://images.manning.com/76/76/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="114x114" href="https://images.manning.com/114/114/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="120x120" href="https://images.manning.com/120/120/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="144x144" href="https://images.manning.com/144/144/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <link rel="apple-touch-icon" sizes="152x152" href="https://images.manning.com/152/152/crop/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"/> <script type="text/javascript"> window.ManningExperimentation = window.ManningExperimentation || {} window.ManningExperimentation.getExperimentSeed = function(){ if(window.ManningExperimentation.experimentSeedPromise){ return window.ManningExperimentation.experimentSeedPromise; } function sumDigitsInString(str) { var sum = 0; for (let i = 0; i < str.length; i++) { if (!isNaN(str[i]) && str[i] !== ' ') { sum += Number(str[i]); } } return sum; } return window.ManningExperimentation.experimentSeedPromise = new Promise(function(resolve, reject){ fetch("\u002fanalytics\u002fgetIpAddress").then(function (response){ return response.json() }).then(function (response) { if(response && response.ipAddress){ resolve(sumDigitsInString(response.ipAddress)) } else { resolve(0) } }).catch(function(error){ resolve(0) }); }) } </script> <!-- Google tag (gtag.js) --> <script async src="https://www.googletagmanager.com/gtag/js?id=G-NMEV8ZBBN1"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-NMEV8ZBBN1'); </script> <script> /* SET YOUR EXPERIMENTS HERE */ var runningExperiments = [ {name: "ABC-MANNING_header_size", distribution: [50, 50], variants: ["ABC-MANNING_header_size-A" /* variant A */, "ABC-MANNING_header_size-B" /* variant B */]}, {name: "ABC-MANNING_add_to_cart_discount", distribution: [25, 25, 25, 25], variants: ["ABC-MANNING_add_to_cart_discount-Default", "ABC-MANNING_add_to_cart_discount-A", "ABC-MANNING_add_to_cart_discount-B", "ABC-MANNING_add_to_cart_discount-C"]}, {name: "ABC-MANNING_auth_delegate", distribution: [10, 90], variants: ["ABC-MANNING_auth_delegate-A", "ABC-MANNING_auth_delegate-B"]}, {name: "ABC-MANNING_faq", distribution: [50, 50], variants: ["ABC-MANNING_FAQ_test-A", "ABC-MANNING_FAQ_test-B"], targetPath: "/books/build-a-large-language-model-from-scratch"} ]; /* _________________________ */ </script> <script> runningExperiments.forEach(function(experiment) { var cookieName = experiment.name; var cookieValue = getCookie(cookieName); if (cookieValue === "") { var random = Math.random() * 100; var sum = 0; var variantIndex = experiment.distribution.findIndex(function(percentage) { sum += percentage; return random < sum; }); cookieValue = experiment.variants[variantIndex]; setCookie(cookieName, cookieValue, 90); // Set cookie to expire in 90 days } window.abcExperiments = window.abcExperiments || {}; window.abcExperiments[cookieName] = cookieValue; if (experiment.targetPath) { if (window.location.href.includes(experiment.targetPath)) { gtag('event', 'experience_impression', {exp_variant_string: cookieValue}); } } else { gtag('event', 'experience_impression', {exp_variant_string: cookieValue}); } }); function getCookie(cname) { var name = cname + "="; var decodedCookie = decodeURIComponent(document.cookie); var ca = decodedCookie.split(';'); for(var i = 0; i <ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ""; } function setCookie(cname, cvalue, exdays) { var d = new Date(); d.setTime(d.getTime() + (exdays*24*60*60*1000)); var expires = "expires="+ d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; } </script> <meta name="layout" content="application"/> <link rel="stylesheet" href="/assets/standalone/product-page-73fa4c2ca528481fac1a038a4e9a4962.css" /> <link rel="stylesheet" href="/assets/standalone/show-liveproject-648f308448702df007baf002bd7bd3e0.css" /> <link rel="stylesheet" href="/assets/standalone/subscription-tabber-2676579581c223671628c00eb7d5a0cf.css" /> <link rel="stylesheet" href="/assets/standalone/subscription-panels-b53a200babdb2105785fa12d60ed36a3.css" /> <style> .centered-lp-container { max-width: 700px; margin: 0 auto; } .show-liveproject .shipping-options-label { display: none; } </style> <script async>(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-59QHSR4');</script> <script data-ad-client="ca-pub-9702019192198904" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- Reddit Pixel --> <script> !function(w,d){if(!w.rdt){var p=w.rdt=function(){p.sendEvent?p.sendEvent.apply(p,arguments):p.callQueue.push(arguments)};p.callQueue=[];var t=d.createElement("script");t.src="https://www.redditstatic.com/ads/pixel.js",t.async=!0;var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}}(window,document);rdt('init','a2_dzgdobk0f71i', {"optOut":false,"useDecimalCurrencyValues":true,"aaid":"<AAID-HERE>","email":"<EMAIL-HERE>","externalId":"<EXTERNAL-ID-HERE>","idfa":"<IDFA-HERE>"});rdt('track', 'PageVisit'); </script> <!-- Page hiding snippet --> <style>.async-hide { opacity: 0 !important} </style> <script async>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date; h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')}; (a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c; })(window,document.documentElement,'async-hide','dataLayer',1000, {'GTM-59QHSR4':true});</script> <link rel="shortcut icon preload" as="image" href="/assets/favicon/favicon-06c8d32da14f50950f2c6422e9af1731.png" type="image/png"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="stylesheet" href="https://use.typekit.net/ogd3eap.css"> <link rel="stylesheet preload" as="style" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css" integrity="sha384-REHJTs1r2ErKBuJB0fCK99gCYsVjwxHrSU0N7I1zl9vZbggVJXRMsv/sLlOAGb4M" crossorigin="anonymous"> <link rel="stylesheet" href="/assets/application-162ddb0b8a4bb1b7439f92948adb776a.css" /> <script type="text/javascript"> var searchServerVars = { deploymentType: "production", polyfillsLocation: "\u002fassets\u002fsearch\u002fpolyfills-marketplace-05232e8143f92aac6c2589e26341a535.js", mainJsLocation: "\u002fassets\u002fsearch\u002fsearch-app-marketplace-496d6e0e921b747d15d5da1c355df61e.js", newJsLocation: "\u002fassets\u002fsearch\u002fnew-search-app-marketplace-dd750a152934d496b397c4a5c972baa7.js", coverImage: "\u002fassets\u002fcover-c0e554e9d065ae2e5b8b43d622fb8b95.png", livebookId: "", livebookManningId: "", videoId: "", videoManningId: "", optimizeTest: "3IFt_39gTxClytcLt-z57g", analyticsEndpoint: "\u002fanalytics\u002flogUserAction", feedbackEndpoint: "\u002ffeedback\u002fsendFeedback" } </script> <script type="text/javascript"> if(new URL(document.location.href).searchParams.get("cartIFrame") == "true"){ document.documentElement.classList.add("cart-iframe") } </script> <script type="text/javascript"> window.readingListsServerVars = { productId: 2282, externalId: "822", title: "Automate Reports", deploymentType: "production", libraryLocation: "\u002fassets\u002freadingLists\u002freading-lists-marketplace-58cbc56e981b09292f07bf5123745835.js", }; </script> </head> <body id="top" class="nav-show product-page product-2282 show-liveproject page-has-subscription-buttons show-monthly-subscription-options dismissible-deals side-social-view-count-only "> <script type="text/javascript" src="/assets/application-2ae854e15e50775f00816c73825e40fa.js" ></script> <script type="text/javascript" src="/assets/analytics/shopperApproved-5467a7e61287592fb79e0c22c00e7963.js" ></script> <!--Google Tag Manager (noscript) --> <noscript><iframe class="lazyload" data-src="https://www.googletagmanager.com/ns.html?id=GTM-59QHSR4" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><!--End Google Tag Manager (noscript) --> <header id="header"> <nav> <div id="top-nav" class=""> <a href="/" id="home-link" class="nav-home-button"> <img src="/assets/manningLogoBlack-4ce2f7a38da67c986590975d7769f389.svg" id="manning-m" loading="lazy"/> <img src="/assets/manningLettersBlack-0ebe3f78d807742e74e80ce85f130096.svg" id="manning-letters" loading="lazy"/> </a> <form id="search-form" onsubmit="return false"> <div class="header-input-group"> <div class='search-categories-selector-container'></div> <input name="q" type="search" autocomplete="off" spellcheck="false" class="form-control" placeholder="search"> <button class="btn btn-default" type="submit"> <span class="fa fa-search"></span> </button> <i class="fas fa-times clear-search-btn"></i> </div> <div class="nav-browse-button clickable visible-header-desktop"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 27.79 28"> <path fill="currentColor" d="M27.66,24.16l-7-18.73a2,2,0,0,0-2.57-1.18l-3.26,1.2a2,2,0,0,0-.87.64V2a2,2,0,0,0-2-2H8A2,2,0,0,0,6,2V7H2A2,2,0,0,0,0,9V26a2,2,0,0,0,2,2H6a1.87,1.87,0,0,0,1-.28A1.91,1.91,0,0,0,8,28h4a2,2,0,0,0,2-2V8.81l6.7,17.93a2,2,0,0,0,2.58,1.19l3.26-1.2A2,2,0,0,0,27.66,24.16ZM2,26V9H6V26Zm10,0H8V9s0-.06,0-.09V2h4Zm10.58.05-7-18.73,3.26-1.2,7,18.73Z"></path> </svg> <label for="browse-desktop">browse</label> </div> <a href="https://subscription.manning.com" target="_blank" class="nav-manning-online-button clickable"> <svg width="30" height="28" viewBox="0 0 36 38" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M18.5737 5.30664C18.2408 5.03125 17.7592 5.03125 17.4263 5.30664L6.42629 14.4066C6.21962 14.5776 6.09998 14.8319 6.09998 15.1001V29.4001C6.09998 30.3111 6.43968 31.195 7.06023 31.8551C7.68254 32.517 8.53887 32.9001 9.44442 32.9001H14C14.497 32.9001 14.9 32.4972 14.9 32.0001V19.9001H21.1V32.0001C21.1 32.4972 21.5029 32.9001 22 32.9001H26.5555C27.4611 32.9001 28.3174 32.517 28.9397 31.8551C29.5603 31.195 29.9 30.3111 29.9 29.4001V15.1001C29.9 14.8319 29.7803 14.5776 29.5737 14.4066L18.5737 5.30664ZM22.9 31.1001H26.5555C26.9466 31.1001 27.3338 30.9354 27.6283 30.6221C27.9246 30.3069 28.1 29.8683 28.1 29.4001V15.5236L18 7.16815L7.89998 15.5236V29.4001C7.89998 29.8683 8.07535 30.3069 8.37165 30.6221C8.66618 30.9354 9.05335 31.1001 9.44442 31.1001H13.1V19.0001C13.1 18.503 13.5029 18.1001 14 18.1001H22C22.497 18.1001 22.9 18.503 22.9 19.0001V31.1001Z" fill="currentColor"/> </svg> <label for="manning-online">home</label> </a> </form> <div id="controls"> <div class="nav-browse-button clickable hidden-header-desktop hidden-header-mobile"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 27.79 28"> <path fill="currentColor" d="M27.66,24.16l-7-18.73a2,2,0,0,0-2.57-1.18l-3.26,1.2a2,2,0,0,0-.87.64V2a2,2,0,0,0-2-2H8A2,2,0,0,0,6,2V7H2A2,2,0,0,0,0,9V26a2,2,0,0,0,2,2H6a1.87,1.87,0,0,0,1-.28A1.91,1.91,0,0,0,8,28h4a2,2,0,0,0,2-2V8.81l6.7,17.93a2,2,0,0,0,2.58,1.19l3.26-1.2A2,2,0,0,0,27.66,24.16ZM2,26V9H6V26Zm10,0H8V9s0-.06,0-.09V2h4Zm10.58.05-7-18.73,3.26-1.2,7,18.73Z"></path> </svg> <label for="browse-mobile">browse</label> </div> <a href="/cart" class="nav-cart-button visit-cart-link"> <svg viewBox="0 0 32 28" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0)"> <path fill-rule="evenodd" clip-rule="evenodd" d="M14.2555 25.7607C14.5331 23.963 13.0066 22.4429 11.2152 22.7141C10.0924 22.8844 9.1778 23.799 9.00749 24.9218C8.72995 26.7195 10.2564 28.246 12.0541 27.9684C13.1706 27.7981 14.0852 26.8772 14.2555 25.7607ZM12.8678 25.5399C12.9939 24.6947 12.2811 23.9819 11.4359 24.108C10.9061 24.1837 10.4771 24.6127 10.4014 25.1488C10.269 25.9941 10.9881 26.7131 11.8333 26.5807C12.3568 26.4987 12.7858 26.0634 12.8678 25.5399Z" fill="currentColor"></path> <path d="M10.0538 21.4841C8.72922 21.4841 8.65353 20.0396 8.65353 19.9766C8.63461 19.8189 6.89367 6.9385 6.81167 6.16896C6.71075 5.23541 5.6132 4.59203 5.56274 4.56679L1.21672 2.5294C0.144405 1.96801 -0.101597 1.18585 0.0308657 0.63708C0.125482 0.258617 0.396714 0 0.705792 0C0.787793 0 0.876101 0.0189232 0.964409 0.0567695C5.17166 2.0374 8.81753 3.75941 8.96891 4.69295C9.12661 5.68957 9.41676 8.13066 9.41676 8.14958L9.4483 8.42712H29.9926C30.5603 8.42712 30.945 8.57851 31.1469 8.86866C31.5569 9.46159 31.1721 10.5213 31.1658 10.5339L27.8921 20.2541C27.8732 20.3424 27.6398 21.4841 26.5422 21.4841H10.0538ZM10.7603 18.9863H26.1953L28.7121 10.4645H9.6943L10.7603 18.9863Z" fill="currentColor"></path> <path fill-rule="evenodd" clip-rule="evenodd" d="M25.849 25.7608C26.1266 23.9631 24.6001 22.4366 22.8024 22.7142C21.6859 22.8908 20.7713 23.7991 20.601 24.9156C20.3234 26.7069 21.8436 28.2334 23.6413 27.9622C24.7641 27.7919 25.6787 26.8773 25.849 25.7608ZM24.4614 25.5399C24.5875 24.6947 23.8748 23.9819 23.0295 24.108C22.506 24.1837 22.0708 24.6127 21.9951 25.1488C21.8626 25.9941 22.5817 26.7131 23.4269 26.5807C23.9505 26.4987 24.3794 26.0634 24.4614 25.5399Z" fill="currentColor"></path> </g> <defs> <clipPath id="clip0"> <rect width="31.3368" height="28" fill="white"></rect> </clipPath> </defs> </svg> <span id="header-cart-count"></span> <label for="cart">cart</label> </a> <div class="nav-dashboard-button clickable"> <svg class="avatar-icon" viewBox="0 0 22 30" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M12.0503 3.15739C8.57031 2.66025 5.71847 5.54102 6.14142 9.09382L6.14288 9.10608L6.14281 9.10609C6.38912 11.4051 8.29151 13.3237 10.7068 13.5736L10.7164 13.5746L10.7259 13.5757C14.1535 13.9937 17.068 11.1652 16.6576 7.65433C16.3178 5.31573 14.3858 3.40828 12.0869 3.16197L12.0686 3.16L12.0503 3.15739ZM12.3291 1.07592C7.4196 0.386074 3.48311 4.49739 4.05542 9.33598C4.41147 12.6311 7.10307 15.3074 10.4811 15.6614C15.2455 16.2365 19.3224 12.2742 18.7414 7.39382L18.74 7.38162L18.7382 7.36945C18.274 4.11966 15.6177 1.43722 12.3291 1.07592Z" fill="currentColor"></path> <path fill-rule="evenodd" clip-rule="evenodd" d="M15.3921 16.8559C16.4921 16.2344 17.7592 16.4075 18.6721 17.1683L18.6965 17.1886L18.7196 17.2103C20.6274 19.0059 21.75 21.4813 21.75 24.275C21.75 25.2619 21.2671 26.0629 20.5982 26.6639C19.9445 27.2511 19.0715 27.6915 18.1244 28.0225C16.2242 28.6863 13.7603 29 11.35 29C8.93957 29 6.47573 28.6863 4.57551 28.0225C3.62836 27.6915 2.7554 27.2511 2.10175 26.6639C1.43283 26.0629 0.949951 25.2619 0.949951 24.275C0.949951 21.487 2.06871 19.0079 4.08191 17.2084C4.95575 16.3588 6.35997 16.2646 7.40762 16.8558C8.54564 17.4662 9.9693 17.825 11.4 17.825C12.8305 17.825 14.2541 17.4662 15.3921 16.8559ZM17.3065 18.7643C17.0281 18.5441 16.7105 18.5211 16.4209 18.6866L16.4094 18.6932L16.3978 18.6995C14.9374 19.4858 13.1652 19.925 11.4 19.925C9.63474 19.925 7.86249 19.4858 6.40215 18.6995L6.39049 18.6932L6.379 18.6866C6.03783 18.4917 5.66684 18.593 5.54241 18.7174L5.5206 18.7392L5.49753 18.7597C3.92361 20.1588 3.04995 22.0723 3.04995 24.275C3.04995 24.513 3.15144 24.7839 3.50519 25.1017C3.87419 25.4332 4.46217 25.7584 5.26814 26.04C6.87417 26.6011 9.08533 26.9 11.35 26.9C13.6146 26.9 15.8257 26.6011 17.4318 26.04C18.2377 25.7584 18.8257 25.4332 19.1947 25.1017C19.5485 24.7839 19.65 24.513 19.65 24.275C19.65 22.0815 18.7828 20.1666 17.3065 18.7643Z" fill="currentColor"></path> </svg> <label for="sign-in">log in</label> </div> </div> </div> <ul id="browse-nav" class="list-unstyled"> <li class="nav-catalog-button"><a href="/catalog">catalog</a></li> <li class="nav-meaps-button"><a href="/meap-catalog">MEAP</a></li> <li class="nav-livebook-button"><a href="https://livebook.manning.com">liveBook</a></li> <li class="nav-livevideo-button"><a href="https://livevideo.manning.com">liveVideo</a></li> <li class="nav-liveproject-button"><a href="https://liveproject.manning.com">liveProject</a></li> <li class="nav-liveaudio-button"><a href="/liveaudio-landing">liveAudio</a></li> <li class="nav-free-content-button"><a href="http://freecontent.manning.com">free content</a></li> <li class="nav-register-button"><a href="/freebook">register pBook</a></li> <li class="nav-subscription-button"><a href="/subscription">subscription</a></li> </ul> <div id="top-nav-deals-wrapper"> <div id="top-nav-deals" class="top-nav-deals carousel slide noselect carousel-fade" data-ride="carousel" data-interval="7500"> <div class="carousel-inner" role="listbox"> <style> #banner-item-inner-1724 { background-color: #2F5380; } </style> <style> #banner-item-inner-1724:hover { background-color: #4271AD; } </style> <div class="item active" data-background-color="#2F5380"> <a class="banner-item-inner link-to-banner" id="banner-item-inner-1724" data-banner-id="1724" data-banner-name="Save 40 with emails" data-banner-position="0" target="_blank" href="https://deals.manning.com/sign-up-to-emails-and-save-40-digital/"> <div class="container banner-item-inner-container"> <img class="visible-xs img-responsive lazyload" loading="lazy" src="https://images.manning.com/banner/3/2b21b17-0114-425f-a1f4-8bce0dbd8663/save40signupmob.svg"/> <img class="hidden-xs img-responsive lazyload" loading="lazy" src="https://images.manning.com/banner/9/5a8e3fb-62ba-4e7a-8ea7-81fec08a1b3a/save40signupdesk.svg"/> </div> </a> </div> <style> #banner-item-inner-1734 { background-color: #000000; } </style> <style> #banner-item-inner-1734:hover { background-color: #454545; } </style> <div class="item " data-background-color="#000000"> <a class="banner-item-inner link-to-banner" id="banner-item-inner-1734" data-banner-id="1734" data-banner-name="DOTD Banner" data-banner-position="1" target="_blank" href="https://www.manning.com/dotd"> <div class="container banner-item-inner-container"> <div class="visible-xs"> <div class="dotd-with-text-container"> <img class="img-responsive lazyload" loading="lazy" src="https://images.manning.com/banner/dotd/dotd_mobile.svg"/> <span class="dotd-text-overlay"><em>Machine Learning for Tabular Data</em>—Save 45% TODAY ONLY!</span> </div> </div> <div class="hidden-xs"> <div class="dotd-with-text-container"> <img class="img-responsive lazyload" loading="lazy" src="https://images.manning.com/banner/dotd/dotd_desktop.svg"/> <span class="dotd-text-overlay"><em>Machine Learning for Tabular Data</em>—Save 45% TODAY ONLY!</span> </div> </div> </div> </a> </div> </div> <div class="carousel-controls"> <div class="left carousel-control"> <div id="left-side-prev-deal-button" href="#top-nav-deals" role="button" data-slide="prev"> <span class="fas fa-chevron-left" aria-hidden="true"></span> <span class="sr-only">Previous</span> </div> <div id="left-side-next-deal-button" href="#top-nav-deals" role="button" data-slide="next"> <span class="fas fa-chevron-right" aria-hidden="true"></span> <span class="sr-only">Next</span> </div> </div> <div class="right carousel-control" id="next-deal-button" href="#top-nav-deals" role="button" data-slide="next"> <span class="fas fa-chevron-right" aria-hidden="true"></span> <span class="sr-only">Next</span> </div> <div class="right carousel-control" id="dismiss-deals-button" role="button"> <span class="fas fa-chevron-up" aria-hidden="true"></span> <span class="sr-only">Dismiss</span> </div> </div> </div> </div> <div id="restore-deals-tab"> <span class="fas fa-chevron-down" aria-hidden="true"></span> </div> <script> if (typeof jQuery !== 'undefined') { (function ($) { const now = (new Date()).getTime(); const thirtyDays = 2592000000; var dealsDismissed = JSON.parse(localStorage.getItem("deals-dismissed")); var restoreDealsButton = $("#restore-deals-button, #restore-deals-tab"); if ((dealsDismissed + thirtyDays) < now) { dealsDismissed = null; localStorage.removeItem("deals-dismissed"); } if (localStorage.getItem("deals-dismissed")) { $("body").addClass("deals-dismissed"); } else { restoreDealsButton.attr('aria-hidden', true); } $("#dismiss-deals-button").click(function() { restoreDealsButton.removeAttr('aria-hidden'); $("body").addClass("deals-dismissing-right-now"); localStorage.setItem("deals-dismissed", now); }); restoreDealsButton.click(function() { $(this).attr('aria-hidden', true); $("body").removeClass("deals-dismissing-right-now").removeClass("deals-dismissed"); localStorage.removeItem("deals-dismissed"); }); var changeColorOfExpanderOnDealChange = function(target = null) { var bc = "#ccc"; if (target && target.data('background-color')) { bc = target.data('background-color'); } restoreDealsButton.css('color', bc); } $("#top-nav-deals").on('slide.bs.carousel', function(event) { changeColorOfExpanderOnDealChange($(event.relatedTarget)); }); // Set the initial color changeColorOfExpanderOnDealChange($("#top-nav-deals .item.active")); $("#top-nav-deals .link-to-banner").on("click", function(e){ var $target = $(e.currentTarget) $.ajax({ url: "/analytics/logUserAction", data: { type: "banner", additionalData: "click-" + $target.attr("href") } }); }); })(jQuery); } </script> <div id="account-sidebar"> <a href="/dashboard" class="account-block"> <div class="icon"> <i class="fas fa-tachometer-alt"></i> </div> <div class="caption"> view your dashboard </div> </a> <a href="/dashboard/details" class="account-block"> <div class="icon"> <i class="far fa-address-card"></i> </div> <div class="caption"> manage account details </div> </a> <a href="https://login.manning.com/logout?service=https://www.manning.com/logout" class="account-block signout-link"> <div class="btn btn-full-width btn-default"> sign out </div> </a> </div> </nav> </header> <script> if (typeof jQuery !== 'undefined') { (function ($) { var lookupTime = new Date().getTime(); var handleDynamicLoad = function(data, status, error) { $("#header-cart-count").text(data['cartCount']).trigger("cart-updated"); if(data['cartCount']){ $("#header-cart-count").addClass("show-cart-count"); $(document.body).addClass("has-items-in-cart"); } else { $(document.body).removeClass("has-items-in-cart"); } if (data['userLoggedIn'] && data['userLoggedIn'] === true) { $(".signout-link").show(); $("body").addClass("logged-in"); $("body").attr("data-user-id", data.userId); if (data['userId']) { $(document).trigger('user-gtm', { userId: data['userId'].toString(), ltke: data['ltke'], firstName: data['firstName']}); } if (data['firstName'] && data['firstName'].length <= 6) { $(".nav-dashboard-button label").text(data['firstName']); } else { $(".nav-dashboard-button label").text("account"); } $(".nav-dashboard-button").addClass("signed-in"); if (data['ltke']) { $(document).trigger('user-log-in-ltk', data['ltke']); localStorage.removeItem('dynamicloadcache'); } $(document).trigger("logged-in"); } else { $(".nav-dashboard-button").removeClass("signed-in"); $(".nav-dashboard-button label").text("sign in"); $(".signout-link").hide(); } if (status !== "cache") { data['timestamp'] = lookupTime; localStorage.setItem('dynamicloadcache', JSON.stringify(data)); } }; var localLoadCache = JSON.parse(localStorage.getItem('dynamicloadcache')); var uncacheablePages = /cart|checkout|dashboard/i; var areSubscriptionsEnabled = "true" == "true"; // 1200000 is a twenty minute cache length. if (localLoadCache === null || lookupTime > (localLoadCache['timestamp'] + 1200000) || document.location.href.match(uncacheablePages)) { // Check to ensure we have a place to put the data so it's not a waste of time if ($("#header-cart-count").length) { $.ajax({url: "/cart/currentCartCount.json", cache: false}) .done(handleDynamicLoad) .fail(handleDynamicLoad); } } else { handleDynamicLoad(JSON.parse(localStorage.getItem('dynamicloadcache')), "cache", null); } $(".nav-browse-button").click(function() { $("body").toggleClass("browse-nav-in"); }); $("#top-nav").on('click', '.nav-dashboard-button', function() { if ($(this).hasClass('signed-in')) { var $accountSidebar = $("#account-sidebar"); var oldHtml = $accountSidebar.html(); var isUserSubscriber = $(document.body).is(".subscription-expired-paused, .subscription-active"); var shouldLoadNewMenu = areSubscriptionsEnabled && isUserSubscriber && loadAndRenderNewMenu && !window.SettingsMenu if(shouldLoadNewMenu){ $accountSidebar.addClass("new"); $accountSidebar.html("<div class='loader-container'><i class='fa fa-circle-notch fa-spin'></i></div>"); } $accountSidebar.toggleClass("drawer-in"); if(isUserSubscriber){ if($accountSidebar.is(".drawer-in")){ $("body").addClass("manning-menu-shown"); } else { $("body").removeClass("manning-menu-shown"); } } if(shouldLoadNewMenu){ loadAndRenderNewMenu(oldHtml) } } else { window.location = '/dashboard/decide'; } }); $(".signout-link").click(function(e) { e.preventDefault(); localStorage.removeItem('dynamicloadcache'); location.href = $(this).attr('href'); }); })(jQuery); } $(document).ready(function() { $.ajax({ url: "/ajax/getSubscriptionStatus" }).done(function (data) { if (!jQuery.isEmptyObject(data) && data['status']) { let subscriptionStatusLoaded = new CustomEvent('subscription-status-loaded', { detail : data }); switch(data['subscriptionOfferingType']){ case "TEAM": case "PRO": $("body").addClass("team-pro-subscriber"); if(data.isSubscriptionOwner){ $("body").addClass("subscription-owner"); } break; } switch(data['status']) { case 'EXPIRED_PAUSED': $("body").addClass("subscription-expired-paused"); break; case 'ACTIVE': case 'PAUSED': case 'TRIAL': $("body").addClass("subscription-active"); $("body").addClass("deals-dismissed"); updateBrowseHeaderForSubscribers(); $(".hide-if-subscription-is-in-cart").remove(); break; case 'CANCELLED': if(data.endDate){ var now = new Date() var endDate = new Date(data.endDate); if(endDate > now){ $("body").addClass("subscription-active"); $("body").addClass("deals-dismissed"); updateBrowseHeaderForSubscribers(); $(".hide-if-subscription-is-in-cart").remove(); break; } } default: $("body").addClass("no-subscription"); } document.dispatchEvent(subscriptionStatusLoaded); } }); var dlc = JSON.parse(localStorage.getItem('dynamicloadcache')); if (dlc && dlc["cartHasSubscription"]) { $(".hide-if-subscription-is-in-cart").remove(); $(".click-if-subscription-is-in-cart").click(); } }); </script> <script> var isLoading = false var profileData = null function loadAndRenderNewMenu(oldHtml){ if(isLoading) { return } var isSourceLoaded = false, isProfileDataLoaded = false getSource().then(function(){ isLoading = false isSourceLoaded = true if(isSourceLoaded && isProfileDataLoaded){ clearTimeout(timer); renderSettingsMenu(); } }).catch(function() { $("#account-sidebar").html(oldHtml); }); getProfileData().then(function(data){ profileData = data isProfileDataLoaded = true if(isSourceLoaded && isProfileDataLoaded){ clearTimeout(timer); renderSettingsMenu(); } if(profileData != null){ $("body").toggleClass("browse-nav-in", (profileData.showBrowseHeader === null || profileData.showBrowseHeader)); } }); var timer = setTimeout(function(){ $("#account-sidebar").html(oldHtml); }, 4000); } function getInitialMenuState(){ return { name: profileData != null ? (profileData.firstName + " " + profileData.lastName) : "", showMenuBar: profileData != null ? (profileData.showBrowseHeader === null ? true : profileData.showBrowseHeader) : true, email: profileData != null ? profileData.email : "", avatarUrl: profileData != null ? profileData.avatarUrl : "" } } function getDeploymentType(){ switch("production"){ case "development": case "test": return SettingsMenu.DeploymentType.dev; case "qa": return SettingsMenu.DeploymentType.qa; case "production": return SettingsMenu.DeploymentType.prod; case "docker": return SettingsMenu.DeploymentType.docker; default: console.error("Unknown deployment environment, defaulting to production"); return SettingsMenu.DeploymentType.prod; } } function renderSettingsMenu(){ SettingsMenu.ReactDOM.render( SettingsMenu.React.createElement( SettingsMenu.ManningMenu, { sourceApp: SettingsMenu.SourceApp.marketplace, deploymentType: getDeploymentType(), avatarUrl: profileData != null ? profileData.avatarUrl : "", initialMenuState: getInitialMenuState(), isSubscriptionTeamOwner: $("body").is(".team-pro-subscriber.subscription-owner"), onMenuStateChange: function (oldState, newState) { if(oldState.showMenuBar != newState.showMenuBar){ $("body").toggleClass("browse-nav-in", newState.showMenuBar); syncShowMenuBar(newState.showMenuBar); } }, onProfile: function () { var profileLink = "/dashboard/details?template=profile" document.location.href = profileLink }, onViewDiscussions: function () { //alert("On discussions"); }, onLogOut: function () { var logoutLink = "https://login.manning.com/logout?service=https://www.manning.com/logout"; document.location.href = logoutLink } } ), $("#account-sidebar")[0] ) } var sourcePromise function getSource(){ if(sourcePromise != null) { return sourcePromise; } return sourcePromise = new Promise(function(resolve, reject){ $.getScript("/assets/settingsMenu/settings-menu-marketplace-a97275e061bfa2000492e182cf132f07.js") .done(resolve) .fail(reject) }) } var profileDataPromise; function getProfileData(){ if(profileDataPromise != null) { return profileDataPromise; } return profileDataPromise = new Promise(function(resolve, reject){ $.get("/userProfile/loadProfile") .done(function(profileData){ localStorage.setItem("showBrowseHeader", profileData.showBrowseHeader == null || profileData.showBrowseHeader); resolve(profileData) }).fail(function(e){ resolve({}) }); }); } function syncShowMenuBar(value){ localStorage.setItem("showBrowseHeader", value); $.post( "/userProfile/storeShowBrowserHeader", { value: value} ).fail(function(e){ console.log("Error when syncing show menu bar") }); } function updateBrowseHeaderForSubscribers(){ $("#browse-nav").html([ '<li><a href="https://subscription.manning.com?show-library">all</a></li>', '<li><a href="https://subscription.manning.com?show-books-library">books</a></li>', '<li><a href="https://subscription.manning.com?show-lv-library">video</a></li>', '<li><a href="https://subscription.manning.com?show-lp-library">projects</a></li>', '<li><a href="https://subscription.manning.com?show-audio" class="nav-liveaudio-button">audio books</a></li>' ].join("")); } (function(){ var showBrowseHeader = localStorage.getItem("showBrowseHeader"); if(showBrowseHeader == null || showBrowseHeader == "true"){ $("body").addClass("browse-nav-in"); } })(); </script> <div class="container content-body base-search-container" style="padding-top: 0; border-bottom: none !important;"> <div class="row"> <div class="col-xs-12"> <div class="row page-search-row"> <div class="col-xs-12 page-search-content-container" style="display:none;"></div> </div> </div> </div> </div> <div id="page-main-content-row" class="page-main-content-row"> <script> function setAnnualTab(){ document.body.classList.remove('show-monthly-subscription-options'); document.body.classList.add('show-annual-subscription-options'); $(".add-to-cart-form .annual-checkbox").each(function(index, element){ element.checked = true; }) } function setMonthlyTab(){ document.body.classList.add('show-monthly-subscription-options'); document.body.classList.remove('show-annual-subscription-options'); $(".add-to-cart-form .annual-checkbox").each(function(index, element){ element.checked = false; }) } document.addEventListener('click', function(event) { if (!event.target.matches('.tabber')) return; if (event.target.matches('.tabber-monthly')) { setMonthlyTab(); } else if (event.target.matches('.tabber-annual')) { setAnnualTab(); } }); if((document.location.search || "").indexOf("annual") >= 0){ setAnnualTab(); } </script> <div class="container-fluid"> <div class="row"> <div class="container"> <div class="row"> <div class="md-grid-container move-cart "> <div class="lx-cell hidden-xs hidden-sm"> <a class="product-cover-wrapper" href="https://liveproject.manning.com/course/822?findPromo=true&amp;origin=product-look-inside" target="_blank"> <div class="product-cover-inner"> <img class="product-cover lazyload" loading="lazy" src="https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" srcset=" https://images.manning.com/360/480/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 360w, https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 264w" sizes=" (min-width: 1170px) 263px, (min-width: 750px) 213px, 213px"/> <div class="click-label"> <div>click to<br />look inside</div> <span class="fas fa-eye"></span> </div> </div> <div class="btn btn-look-inside btn-default look-inside-btn product-look-inside"> <span class="fas fa-eye"></span> Look inside </div> </a> <div id="liveprojectTourLauncher" data-toggle="modal" data-target="#liveprojectTour"> <img src="/assets/tourALiveproject_thumbnail-df05161fcc1fe09cc16d9b66f16c17e2.svg" class="img-responsive"/> </div> <script type="text/javascript"> $(document).ready(function() { const lpTourVid = document.getElementById("liveprojectTourVideo"); $('#liveprojectTour').on('show.bs.modal', function() { lpTourVid.play(); }); $('#liveprojectTour').on('hide.bs.modal', function() { lpTourVid.pause(); }); }); </script> <!-- Modal --> <div class="modal fade fancy-modal" id="liveprojectTour" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-body"> <div class="container"> <video id="liveprojectTourVideo" class="tour-liveproject" controls playsinline preload="none" poster="/assets/liveProjectTour_thumbnail-542bc03898730e62e6f1a8bf80bdcdb3.png"> <source src="https://manning-content.s3.amazonaws.com/liveProject/static/tour-a-liveProject.mp4" type="video/mp4"> </video> </div> </div> </div> </div> </div> <div class="share-block"> <a href="https://twitter.com/intent/tweet?text=https%3A%2F%2Fwww.manning.com%2Fliveproject%2Fautomate-reports" target="_blank" class="twitter-share fab fa-twitter-square"></a> <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.manning.com%2Fliveproject%2Fautomate-reports" target="_blank" class="facebook-share fab fa-facebook-square"></a> <a href="https://reddit.com/submit?url=https%3A%2F%2Fwww.manning.com%2Fliveproject%2Fautomate-reports&amp;title=Automate+Reports" target="_blank" class="reddit-share fab fa-reddit-square"></a> <a href="https://www.linkedin.com/shareArticle?mini=true&amp;url=https%3A%2F%2Fwww.manning.com%2Fliveproject%2Fautomate-reports&amp;title=Automate+Reports" target="_blank" class="linkedin-share fab fa-linkedin"></a> </div> </div> <div class="title-and-meta-cell"> <h1 class="product-title"> Automate Reports <span class="wishlist-container"> <a href="/wishList/addItem/2282?productTitle=Automate+Reports&amp;slug=automate-reports" class="wishlist-toggle wishlist-login far fa-heart" data-product-id="2282" data-toggle="tooltip" title="Add this to your wish list"></a> <span class="wishlist-toggle wishlist-remove fa fa-heart" data-product-id="2282" data-toggle="tooltip" title="Remove this from your wish list"></span> <span class="wishlist-toggle wishlist-add far fa-heart" data-product-id="2282" data-toggle="tooltip" title="Add this to your wish list"></span> </span> <a href="/dashboard" class="ownership-indicator"> you own this product </a> <script> $(document).ready(function() { $.ajax({ url: "/ajax/getWishListDetails" }).done(function (data) { if (!jQuery.isEmptyObject(data) && data['wishlistProductIds']) { $(".wishlist-container").each(function() { if (data.wishlistProductIds.indexOf($(this).find('.wishlist-toggle').data('product-id')) > -1) { $(this).addClass("on-wishlist"); } }); } }); $.ajax({ url: "/ajax/getProductOwnershipDetails?productId=2282" }).done(function (data) { if (!jQuery.isEmptyObject(data)) { if (data['ownership']) { $(".wishlist-container").hide(); $(".ownership-indicator").addClass('owned'); $(document.body).addClass("user-owns-product"); } } }); }); </script> <span class="reading-list-icon-container"> <span class="reading-list-toggle fa" data-product-id="2282" data-toggle="tooltip" title="add to reading list"></span> </span> <script> document.addEventListener("subscription-status-loaded", function(e){ var status = e && e.detail && e.detail['status']; if(status != "ACTIVE" && status != "PAUSED"){ return; } if(window.readingListsServerVars != null){ $(document).ready(function() { var $readingListToggle = $(".reading-list-toggle"); $(document.body).append('<div class="modal fade" id="reading-lists-modal" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-body"></div></div></div></div>'); $(document.body).append('<div id="reading-list-toast"><i class="fa fa-circle-notch fa-spin"></i> loading reading lists ...</div>'); function adjustReadingListIcon(isInReadingList){ $readingListToggle.toggleClass("fa-plus", !isInReadingList); $readingListToggle.toggleClass("fa-check", isInReadingList); var tooltipMessage = isInReadingList ? "edit in reading lists" : "add to reading list"; $readingListToggle.attr("title", tooltipMessage); $readingListToggle.attr("data-original-title", tooltipMessage); } $.ajax({ url: "/readingList/isInReadingList", data: { productId: 2282 } }).done(function (data) { adjustReadingListIcon(data && data.hasProductInReadingList); }).catch(function(e){ console.log(e); adjustReadingListIcon(false); }); $readingListToggle.on("click", function(){ if(codePromise == null){ showToast() } loadCode().then(function(store){ store.requestReadingListSpecificationForProduct({ id: window.readingListsServerVars.externalId, manningId: window.readingListsServerVars.productId, title: window.readingListsServerVars.title }); ReadingLists.ReactDOM.render( ReadingLists.React.createElement(ReadingLists.ManningOnlineReadingListModal, { store: store, }), document.getElementById("reading-lists-modal") ); }).catch(function(e){ console.log("Error loading code reading list code"); }); }); var codePromise var readingListStore function loadCode(){ if(codePromise) { return codePromise } return codePromise = new Promise(function (resolve, reject){ $.getScript(window.readingListsServerVars.libraryLocation).done(function(){ hideToast() readingListStore = new ReadingLists.ReadingListStore( new ReadingLists.ReadingListProvider( new ReadingLists.ReadingListWebProvider( ReadingLists.SourceApp.marketplace, getDeploymentType() ) ) ); readingListStore.onReadingListChange(handleChange); readingListStore.onReadingListModalChange(handleChange); resolve(readingListStore); }).catch(function(){ hideToast(); console.log("Error downloading reading lists source"); $readingListToggle.css("display", "none"); reject(); }); }); } function handleChange(){ if(readingListStore != null) { adjustReadingListIcon(readingListStore.isInAtLeastOneReadingList({ id: window.readingListsServerVars.externalId, manningId: window.readingListsServerVars.productId })); } } var $readingListToast = $("#reading-list-toast"); function showToast(){ $readingListToast.css("display", "flex"); setTimeout(function(){ $readingListToast.addClass("shown"); }, 16); } function hideToast(){ $readingListToast.removeClass("shown"); setTimeout(function(){ $readingListToast.css("display", "none"); }, 150); } function getDeploymentType(){ switch(window.readingListsServerVars.deploymentType){ case "development": case "test": return ReadingLists.DeploymentType.dev; case "qa": return ReadingLists.DeploymentType.qa; case "production": return ReadingLists.DeploymentType.prod; case "docker": return ReadingLists.DeploymentType.docker; default: console.error("Unknown deployment environment, defaulting to production"); return ReadingLists.DeploymentType.prod; } } }); } }); </script> <img src="/assets/updated-246a1e15fb44f2071ff9bce079e5d3b7.svg" class="updated-badge lazyload" loading="lazy"/> </h1> <dl class="product-skills dl-horizontal"> <dt class="prerequisites-brief" data-toggle="tooltip" data-placement="top" title="All prerequisite knowledge is covered in the liveProject's resources.">prerequisites</dt> <dd>experience with grouping records in SQL • basics of generating files</dd> <dt>skills learned</dt> <dd>end-to-end pipeline • Kafka data into the database • web scraping • creating reports</dd> </dl> <div class="reviews-and-views"> <a class="star_container MNLP2021383" href="#reviews"></a> </div> <div class="row"> <div class="col-sm-8"> <div class="product-authors"> Robert Koch and Shane Smith-Sahnow </div> <div class="product-meta">1 week &middot 4-6 hours per week &middot <span class="difficulty" data-toggle="tooltip" data-placement="top" title="liveProject difficulty">BEGINNER</span></div> <div class="product-meta-subscription"><a href="/subscription?source=product-meta-link">Included with a Manning Online subscription</a></div> <div class="tag-block"> <ul class="list-unstyled"> <li><a href="/catalog/sort/sort-by-subject#section-50" class="tag-link"><span>Python</span></a></li> <li><a href="/catalog/sort/sort-by-subject#section-90" class="tag-link"><span>Operations &amp; Cloud</span></a></li> <li><a href="/catalog/sort/sort-by-subject#section-84" class="tag-link"><span>Development</span></a></li> </ul> </div> </div> <div class="col-sm-4"> <a id="subscriptionOpenProductNow" href="https://liveproject.manning.com/course/822?findPromo=true" class="btn btn-primary btn-block show-for-subscriber show-for-subscriber-block"><strong>try</strong> now</a> </div> </div> </div> <div class="content-cell"> <ul id="product-type-tabs" role="tablist"> <li> <button data-product-type="project" data-product-offering-id="3463" data-addon-offering-id="" class="_product-type-button selected "> <div class="_product-offering-tab-title">project</div> <div class="_product-offering-tab-subtitle"> for $19.99 </div> </button> </li> <li> <button data-product-type="with subscription" data-product-offering-id="4133" data-addon-offering-id="" class="_product-type-button _subscription-tab-button hide-for-subscriber "> <div class="_product-offering-tab-title">with subscription</div> <div class="_product-offering-tab-subtitle"> free </div> </button> </li> </ul> <div class="subscription-info-panel collapse" id="subscription-info-panel"> <div> <h3>pro $24.99 per month</h3> <ul> <li>access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!</li> <li>choose one free eBook per month to keep</li> <li>exclusive 50% discount on all purchases</li> </ul> <hr/> <h3>lite $19.99 per month</h3> <ul> <li>access to all Manning books, including MEAPs!</li> </ul> <hr/> <h3>team</h3> <p class="_last-p">5, 10 or 20 seats+ for your team - <a href="/subscription#add-to-cart-section--corporate-plans" target="_blank">learn more</a> </p> <hr/> </div> </div> <div class="hidden-md hidden-lg"> <div class="add-to-cart-box" data-product-offering-id="3463" data-addon-offering-id="" data-product-type="SOLO"> <div class="_heading"> <div class="_heading-item " data-product-offering-id="3463" data-product-type="project"> <div class="_title">project</div> <div class="_price" data-price-usd="19.99" data-list-price-usd="29.99"> <span id="list-price-3463" class="list-price price" data-list-price-usd="29.99"> $29.99 </span> <span class="_final-price" id="price-3463"> $19.99 </span> </div> <div class="_savings" data-savings-amount="10.00" data-savings-percentage="33"> you save $<span class="_savings-amount">10.00</span> (<span class="_savings-percent">33</span>%) </div> </div> <div class="_heading-item hidden " data-product-offering-id="4133" data-product-type="with subscription"> <div class="_title">with subscription</div> <div class="_price" data-price-usd="24.99" data-list-price-usd="24.99"> <span class="_final-price" id="price-4133"> $24.99 </span> </div> <div class="_savings" data-savings-amount="0.00" data-savings-percentage="0"> </div> <label class="activate-discount-container"> <input class="additional-discount-checkbox" data-product-type="ALL_ACCESS" type="checkbox" data-clickable-coupon-percent="20"/> <div class="additional-discount-message-container"> <div class="_emphasized">click to save <span class="_save-amount-label">$499.80</span> (<span class="_save-percent-label">20%</span>)</div> <div class="_deemphasized">check the box to apply</div> </div> </label> </div> </div> <div class="_content"> <button class="_add-to-cart-button">add to cart</button> <div class="hide-for-subscriber digital-buy-now" style="display: none;"> <button class="_buy-now-button" data-product-id="2282" data-po-id="3463">buy now</button> </div> <div class="_footer hidden"> <div class="_footer-combo hidden"> <div class="shipping-options-label"><a href="/shipping-and-returns#section-shipping-rates" target="_blank">shipping options</a></div> <div><a href="/shipping-and-returns#section-returns-policy" target="_blank">our return/exchange policy</a></div> </div> </div> <button class="_subscription-button hide-for-subscriber">free with subscription</button> </div> <div class="_subscription-content hidden _single-subscription-offering-container"> <button class="_buy-pro-subscription-button" data-product-offering-id="4133">buy pro subscription</button> </div> </div> </div> <script> function initializeForStackedDiscountExperiment(){ try { var $additionalDiscountCheckboxes = $(".add-to-cart-box .additional-discount-checkbox"); $additionalDiscountCheckboxes.on("change", function(){ $additionalDiscountCheckboxes.prop("checked", this.checked); this.checked ? applyAdditionalDiscountToPrices() : removeAdditionalDiscountFromPrices() }) var documentElement = document.documentElement; $additionalDiscountCheckboxes.each(function(index, additionalDiscountCheckbox) { var $additionalDiscountCheckbox = $(additionalDiscountCheckbox); var clickableCouponPercent = parseFloat($additionalDiscountCheckbox.attr("data-clickable-coupon-percent") || "0"); var $addToCartBox = $additionalDiscountCheckbox.closest(".add-to-cart-box"); $addToCartBox.find("._heading > ._heading-item").each(function (_, headingItem) { var $headingItem = $(headingItem); if($headingItem.attr("data-product-type") === "subscription") { return } var $price = $headingItem.find("._price"); var listPrice = parseFloat($price.attr("data-list-price-usd") || "0"); var extraDiscount = roundNumber(listPrice * clickableCouponPercent/100); $headingItem.find("._savings").html("&nbsp;"); if(extraDiscount > 0){ $headingItem.find(".additional-discount-message-container ._save-amount-label").text("$" + formatAsCurrency(roundNumber(extraDiscount))); $headingItem.find(".additional-discount-message-container ._save-percent-label").text(clickableCouponPercent + "%") } }); }); } catch(e){ console.log(e) } function applyAdditionalDiscountToPrices(){ $additionalDiscountCheckboxes.each(function(index, additionalDiscountCheckbox) { var $additionalDiscountCheckbox = $(additionalDiscountCheckbox); var clickableCouponPercent = parseFloat($additionalDiscountCheckbox.attr("data-clickable-coupon-percent") || "0"); var $addToCartBox = $additionalDiscountCheckbox.closest(".add-to-cart-box"); $addToCartBox.find("._heading > ._heading-item").each(function (_, headingItem) { var $headingItem = $(headingItem); if($headingItem.attr("data-product-type") == "subscription") { return } var $price = $headingItem.find("._price"); var listPrice = parseFloat($price.attr("data-list-price-usd") || "0"); var currentPrice = parseFloat($price.attr("data-price-usd") || "0"); var productOfferingId = $headingItem.attr("data-product-offering-id"); var $savings = $headingItem.find("._savings"); var initialSavingsAmount = parseFloat($savings.attr("data-savings-amount") || "0"); var initialSavingsPercentage = parseFloat($savings.attr("data-savings-percentage") || "0"); if(clickableCouponPercent > 0 && initialSavingsAmount <= 0 && initialSavingsPercentage <= 0){ var $listPriceContainer = $price.find(".list-price"); if($listPriceContainer.length === 0){ $listPriceContainer = $("<span class='list-price price'></span>"); $listPriceContainer.attr("id", "list-price-" + productOfferingId); $listPriceContainer.attr("data-list-price-usd", listPrice); $listPriceContainer.text("$" + listPrice); $price.prepend($listPriceContainer) var extraDiscount = formatAsCurrency(roundNumber(listPrice * clickableCouponPercent/100)); $savings.text("you save $" + extraDiscount + " (" + clickableCouponPercent + "%)"); $price.find("._final-price").text("$" + formatAsCurrency((roundNumber(listPrice - extraDiscount)))); } } else if(clickableCouponPercent > 0){ var extraDiscount = roundNumber(listPrice * clickableCouponPercent/100); if(extraDiscount > 0){ $price.find("._final-price").text(formatAsCurrency(roundNumber(currentPrice - extraDiscount))) $savings.find("._savings-amount").text(formatAsCurrency(roundNumber(initialSavingsAmount + extraDiscount))); $savings.find("._savings-percent").text(initialSavingsPercentage + clickableCouponPercent); } } }); }) } function removeAdditionalDiscountFromPrices(){ $additionalDiscountCheckboxes.each(function(index, additionalDiscountCheckbox) { var $additionalDiscountCheckbox = $(additionalDiscountCheckbox); var clickableCouponPercent = parseFloat($additionalDiscountCheckbox.attr("data-clickable-coupon-percent") || "0"); var $addToCartBox = $additionalDiscountCheckbox.closest(".add-to-cart-box"); $addToCartBox.find("._heading > ._heading-item").each(function (_, headingItem) { var $headingItem = $(headingItem); if($headingItem.attr("data-product-type") == "subscription") { return } var $price = $headingItem.find("._price"); var listPrice = parseFloat($price.attr("data-list-price-usd") || "0"); var currentPrice = parseFloat($price.attr("data-price-usd") || "0"); var $savings = $headingItem.find("._savings"); var initialSavingsAmount = parseFloat($savings.attr("data-savings-amount") || "0"); var initialSavingsPercentage = parseFloat($savings.attr("data-savings-percentage") || "0"); $savings.find("._savings-amount").text(formatAsCurrency(initialSavingsAmount)); $savings.find("._savings-percent").text(initialSavingsPercentage); $price.find("._final-price").text("$" + formatAsCurrency(currentPrice)); if(clickableCouponPercent > 0 && initialSavingsAmount <= 0 && initialSavingsPercentage <= 0){ $price.find(".list-price").remove(); $savings.html("&nbsp;"); } }); }); } function roundNumber(num){ return Math.round((num + Number.EPSILON) * 100) / 100 } function formatAsCurrency(num){ return (Math.round(num * 100) / 100).toFixed(2); } } $(document).ready(function(){ var $productTypeButtons = $("._product-type-button"); var $headingItems = $("._heading-item"); var $addToCartBoxStandardOfferingsContent = $(".add-to-cart-box ._content"); var $addToCartBoxSubscriptionOfferingsContent = $(".add-to-cart-box ._subscription-content"); var $footer = $(".add-to-cart-box ._footer, .add-to-cart-box ._footer-combo"); initializeForStackedDiscountExperiment(); $(".subscription-info-panel").collapse({toggle: false}) var $subscriptionButtons = $("._buy-pro-subscription-button, ._buy-lite-subscription-button"); $subscriptionButtons.on("click", function(e){ var $target = $(e.currentTarget); var productOfferingId = $target.attr("data-product-offering-id"); if(!productOfferingId){ return; } $subscriptionButtons.prop("disabled", true); var originalHtml = $target.html(); $target.html("adding to cart <i class='fa fa-circle-notch fa-spin'/>"); $.ajax({ url: "/analytics/logUserAction", data: { productId: "2282", type: "subscription", additionalData: "product-page-subscription-add-to-cart" } }); $.post( "/cart/addSubscriptionOfferingToCart", { productOfferingId: productOfferingId} ).done(function(data) { $subscriptionButtons.removeProp("disabled"); $target.html(originalHtml); document.location.href = "/cart"; }).fail(function(){ $subscriptionButtons.removeProp("disabled"); $target.html(originalHtml); alert("Error when adding subscription. Please try later"); }); }); $productTypeButtons.on("click", function(e) { var $target = $(e.currentTarget); $productTypeButtons.removeClass("selected"); $target.addClass("selected"); if ($target.is("._combo-tab-button")) { $footer.removeClass("hidden"); } else { $footer.addClass("hidden"); } if ($target.is("._subscription-tab-button")) { $(".subscription-info-panel").collapse("show"); $addToCartBoxStandardOfferingsContent.addClass("hidden"); $addToCartBoxSubscriptionOfferingsContent.removeClass("hidden"); if (document.documentElement.classList.contains("exp-stacked-discount-A")) { $(".add-to-cart-box ._footer").addClass("hidden"); } } else { $(".subscription-info-panel").collapse("hide"); $addToCartBoxStandardOfferingsContent.removeClass("hidden"); $addToCartBoxSubscriptionOfferingsContent.addClass("hidden"); if (document.documentElement.classList.contains("exp-stacked-discount-A")) { if ($target.is("._combo-tab-button")) { $(".add-to-cart-box ._footer").addClass("hidden"); } else { $(".add-to-cart-box ._footer").removeClass("hidden"); } } } var productOfferingId = $target.attr("data-product-offering-id"); var productType = $target.attr("data-product-type"); $headingItems.addClass("hidden"); $headingItems.filter("[data-product-offering-id=" + productOfferingId + "]").removeClass("hidden"); $(".add-to-cart-box").attr("data-product-offering-id", productOfferingId); $(".add-to-cart-box").attr("data-product-type", productType); $(".add-to-cart-box").attr("data-addon-offering-id", $target.attr("data-addon-offering-id")); $("._buy-now-button").attr("data-po-id", productOfferingId); if (productType == "print") { $(".add-to-cart-box ._subscription-button").text("save 50% with subscription"); } else { $(".add-to-cart-box ._subscription-button").text("free with subscription"); } }); $(".audio-offering-checkbox").on("change", function (e) { $(".audio-offering-checkbox").prop("checked", $(e.target).prop('checked')); }); $(".add-to-cart-box ._add-to-cart-button").on("click", function (e) { var $target = $(e.currentTarget); var $addToCartBox = $(".add-to-cart-box"); var productOfferingId = $addToCartBox.attr("data-product-offering-id"); if(!productOfferingId){ return } $target.prop("disabled", true); $target.html("adding to cart <i class='fa fa-circle-notch fa-spin'/>"); $(".audio-offering-checkbox").prop("disabled", true); addCurrentProductOfferingToCart( function() { $target.prop("disabled", false); $(".audio-offering-checkbox").prop("disabled", false); $target.text("add to cart") //When the product page is included as an iframe from the cart //send a message to the parent iframe document to update the cart try { if (document.documentElement.classList.contains("cart-iframe")) { window.parent.postMessage("iframe-cart-item-added", "*"); return; } } catch (e) { } document.location.href = "https://www.manning.com/cart" }, function () { $target.prop("disabled", false); $(".audio-offering-checkbox").prop("disabled", false); $target.text("add to cart") } ); }); function addCurrentProductOfferingToCart(successCallback, failureCallback) { var productOfferingId = $(".add-to-cart-box").attr("data-product-offering-id"); var addonOfferingId = $(".add-to-cart-box").attr("data-addon-offering-id"); if(!productOfferingId){ return } var data = { productOfferingId: productOfferingId, quantity: 1 } var $stackedDiscountCheckbox = $(".add-to-cart-box .additional-discount-checkbox"); if($stackedDiscountCheckbox.prop("checked")){ data.stackedDiscount = true; } var $audioOfferingCheckbox = $(".audio-offering-checkbox"); if(addonOfferingId){ data["addOn" + productOfferingId] = addonOfferingId } else if($audioOfferingCheckbox.prop("checked") && $audioOfferingCheckbox.attr("data-product-offering-id")){ data["addOn" + productOfferingId] = $audioOfferingCheckbox.attr("data-product-offering-id"); } $.post({ url: "/cart/addToCart", data: data }).done(successCallback) .fail(failureCallback); } $(".add-to-cart-box ._buy-now-button").on("click", function(e){ var buyNowBtn = $(this); $.getScript("https://js.stripe.com/v3/", function() { var buyNowModalElement = $("#buyNowModal"); buyNowModalElement.load("/ajax/getBuyNowModal?productId=" + buyNowBtn.data("product-id") + "&poId=" + buyNowBtn.data("po-id"), function () { buyNowModalElement.modal("show"); }); }); }); $(".add-to-cart-box ._subscription-button").on("click", function(e){ var $target = $(e.currentTarget); var productOfferingId = $(".add-to-cart-box").attr("data-product-offering-id"); if(!productOfferingId){ return } $('#subscribeNowInterstitial-' + productOfferingId).addClass('interstitial-in'); $('body').addClass('interstitial-active'); $(document.documentElement ).addClass('interstitial-active'); $("#dismiss-deals-button").click(); $(".audio-offering-checkbox").prop("checked", false); $.ajax({ url: "/analytics/logUserAction", data: { productId: "2282", type: "subscription", additionalData: "product-pageinterstitial-in" } }); }); $("body").on("click", ".interstitial-close", function() { $('body').removeClass('interstitial-active'); $(document.documentElement ).removeClass('interstitial-active'); $('.interstitial-in').removeClass('interstitial-in'); }); $(document.body).addClass("no-two-click-buy"); $.ajax({ url: "/ajax/getBuyNowDetails?productId=2282" }).done(function (data) { $(document.body).removeClass("no-two-click-buy"); if (!jQuery.isEmptyObject(data)) { if ((data['digitalBuyNow'] || data['physicalBuyNow'])) { $(document.body).addClass("has-two-click-buy"); $(".digital-buy-now").show(); } else { $(document.body).addClass("no-two-click-buy"); } userIsLoggedIn = data['userLoggedIn']; } else { $(document.body).addClass("no-two-click-buy"); } }).fail(function(){ $(document.body).addClass("no-two-click-buy"); }); }); </script> <div class="product-page-section"> <a class="product-cover-wrapper product-cover visible-xs visible-sm pull-right" href="https://liveproject.manning.com/course/822?findPromo=true&amp;origin=product-look-inside" target="_blank"> <div class="inset-wrapper"> <img class="actual-cover lazyload" loading="lazy" src="https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" srcset=" https://images.manning.com/360/480/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 360w, https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 264w"/> </div> <div class="btn btn-look-inside btn-default look-inside-btn product-look-inside"> <span class="fas fa-eye"></span> Look inside </div> </a> <div class="product-page-section"> <p>As a member of the development team at Piper Data Concepts, you’ll carry out the final steps of a workflow-improvement project: enabling your client’s staff to gather workflow process information in real-time. Several prototypes have been built, and the client’s workflow is more resilient than ever. You’ll write Python code that consumes messages from Kafka and prepares them for storing in the database, create Postgres queries to access the aggregated data, and build reports in CSV files to be read by visualization tools—and ultimately, your client’s staff. When you’re done, your client’s modern system will provide a feedback loop, enable external API access to status updates, and be ready for more specialized services to be plugged in later, with no code changes.</p> </div> <div class="product-page-section help-section"> This project is designed for learning purposes and is not a complete, production-ready application or solution. </div> </div> </div> <div class="rx-cell new-rx-cell" style="min-height: unset"> <div class="hidden-xs hidden-sm _add-to-cart-box-wrapper"> <div class="add-to-cart-box" data-product-offering-id="3463" data-addon-offering-id="" data-product-type="SOLO"> <div class="_heading"> <div class="_heading-item " data-product-offering-id="3463" data-product-type="project"> <div class="_title">project</div> <div class="_price" data-price-usd="19.99" data-list-price-usd="29.99"> <span id="list-price-3463" class="list-price price" data-list-price-usd="29.99"> $29.99 </span> <span class="_final-price" id="price-3463"> $19.99 </span> </div> <div class="_savings" data-savings-amount="10.00" data-savings-percentage="33"> you save $<span class="_savings-amount">10.00</span> (<span class="_savings-percent">33</span>%) </div> </div> <div class="_heading-item hidden " data-product-offering-id="4133" data-product-type="with subscription"> <div class="_title">with subscription</div> <div class="_price" data-price-usd="24.99" data-list-price-usd="24.99"> <span class="_final-price" id="price-4133"> $24.99 </span> </div> <div class="_savings" data-savings-amount="0.00" data-savings-percentage="0"> </div> <label class="activate-discount-container"> <input class="additional-discount-checkbox" data-product-type="ALL_ACCESS" type="checkbox" data-clickable-coupon-percent="20"/> <div class="additional-discount-message-container"> <div class="_emphasized">click to save <span class="_save-amount-label">$499.80</span> (<span class="_save-percent-label">20%</span>)</div> <div class="_deemphasized">check the box to apply</div> </div> </label> </div> </div> <div class="_content"> <button class="_add-to-cart-button">add to cart</button> <div class="hide-for-subscriber digital-buy-now" style="display: none;"> <button class="_buy-now-button" data-product-id="2282" data-po-id="3463">buy now</button> </div> <div class="_footer hidden"> <div class="_footer-combo hidden"> <div class="shipping-options-label"><a href="/shipping-and-returns#section-shipping-rates" target="_blank">shipping options</a></div> <div><a href="/shipping-and-returns#section-returns-policy" target="_blank">our return/exchange policy</a></div> </div> </div> <button class="_subscription-button hide-for-subscriber">free with subscription</button> </div> <div class="_subscription-content hidden _single-subscription-offering-container"> <button class="_buy-pro-subscription-button" data-product-offering-id="4133">buy pro subscription</button> </div> </div> </div> <script type="text/javascript" src="/assets/recommender/localStorageHelperRecommender-f55e39cc3f3131763b089d6064be0d35.js" ></script> <aside id="suggested-products-wrapper"> <div id="customers-also-bought-static" class="product-side-panel hidden-placeholder"> <div class="panel-heading">customers also bought</div> <div class="product-side-panel-link-container"> <div class="clink"> <a href="/liveproject/automate-reports" data-id="2282" data-position="0" data-name="Automate Reports" data-category="[com.manning.marketplace.product.Tag&#64;8f631cfc, com.manning.marketplace.product.Tag&#64;f8235187, com.manning.marketplace.product.Tag&#64;5603451b]" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 264w, https://images.manning.com/192/256/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 192w" > </a> </div> <div class="clink"> <a href="/liveproject/automate-reports" data-id="2282" data-position="1" data-name="Automate Reports" data-category="[com.manning.marketplace.product.Tag&#64;8f631cfc, com.manning.marketplace.product.Tag&#64;f8235187, com.manning.marketplace.product.Tag&#64;5603451b]" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 264w, https://images.manning.com/192/256/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 192w" > </a> </div> <div class="clink"> <a href="/liveproject/automate-reports" data-id="2282" data-position="2" data-name="Automate Reports" data-category="[com.manning.marketplace.product.Tag&#64;8f631cfc, com.manning.marketplace.product.Tag&#64;f8235187, com.manning.marketplace.product.Tag&#64;5603451b]" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 264w, https://images.manning.com/192/256/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 192w" > </a> </div> <div class="clink"> <a href="/liveproject/automate-reports" data-id="2282" data-position="3" data-name="Automate Reports" data-category="[com.manning.marketplace.product.Tag&#64;8f631cfc, com.manning.marketplace.product.Tag&#64;f8235187, com.manning.marketplace.product.Tag&#64;5603451b]" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 264w, https://images.manning.com/192/256/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg 192w" > </a> </div> </div> </div> <script> var currentProductId = 2282; $(document).ready(function() { getProductPageRecommendations(); }); function getProductPageRecommendations(variant) { $.post({ url: "/recommender/getRecommendedProductsOnProductPage", data: { productId: currentProductId, impressions: JSON.stringify(getImpressions()) } }).done(function (data) { $("#suggested-products-wrapper").html(data); setTimeout( function() {storeImpressions(impressions.map((it) => it.id));}, 1); }); } </script> </aside> </div> </div> </div> </div> </div> </div> <div class="back-stripe tier-description-section"> <div class="row"> <div class="container"> <div class="col-xs-12"> <div class="product-page-section"> <div class="centered-lp-container"> <h2>project authors</h2> <a name="projectAuthors" class="anchor"></a> <div class="product-author-bio product-author-bio-box-has-image"> <div class="product-author-bio-box"> <div class="product-author-name">Robert Koch</div> Rob Koch is a Principal Data Engineer at Slalom Build, and one of the community leaders of DeafintheCloud.com. He helps drive cloud-native architecture, blogs about migrating to the cloud and use of Lambdas, and has a passion for data- and event-driven systems. Having earned five AWS certifications (Cloud Practitioner, Big Data Specialty, DevOps Engineer Associate, SysOps Administrator Associate, and Solution Architect Associate), Robert is actively involved in the development community in Denver, often speaking at Denver Dev Day and the AWS Denver Meetup. Robert’s goal is to help the community understand the advantages of migrating to the cloud, being cloud-native, and having “serverless” applications and databases. </div> <img class="product-author-bio-img img-circle lazyload" loading="lazy" src="https://s3-us-west-2.amazonaws.com/lx-common-resources/avatars/869170/image_1648483496397.jpg"/> </div> <div class="product-author-bio product-author-bio-box-has-image"> <img class="product-author-bio-img img-circle lazyload" loading="lazy" src="https://s3-us-west-2.amazonaws.com/lx-common-resources/avatars/921674/image_1654629408490.jpg"/> <div class="product-author-bio-box"> <div class="product-author-name">Shane Smith-Sahnow</div> Shane Smith-Sahnow is a software engineer at Netlify. He has spent time at Github and New Relic working on large scale Kafka applications, developing analytical data pipelines, and shipping large scale features. </div> </div> </div> </div> </div> </div> </div> </div> <div class="container-fluid" style="margin-top:36px;"> <div class="row"> <div class="container"> <div class="row"> <div class="col-xs-12"> <div class="centered-lp-container"> <div class="product-page-section"> <h2>prerequisites</h2> <a name="prerequisites" class="anchor"></a> <p>This liveProject is for developers who understand the usefulness of event-driven architecture and want to learn to implement it. To begin these liveProjects you’ll need to be familiar with the following:</p> TOOLS <ul><li>Intermediate Python</li> <li>Apache Kafka</li> <li>Faust library</li> <li>Poetry</li> <li>PostgreSQL</li> <li>Visual Studio Code</li></ul> TECHNIQUES <ul><li>Python library management</li> <li>Use frameworks to make project-packaging easier</li> <li>Query databases</li> <li>Create data on the fly</li></ul> </div> </div> </div> </div> </div> </div> </div> <div class="back-stripe tier-description-section"> <div class="container"> <div class="row"> <div class="col-xs-12"> <div class="product-page-section"> <div class="centered-lp-container"> <a name="about-solo" class="anchor"></a> <h2><img src="/assets/liveproject-solo-b00e063f686e58ad25b4ea8afc940193.svg" class="about-icon lazyload" loading="lazy"/> features</h2> <dl> <dt>Self-paced</dt> <dd>You choose the schedule and decide how much time to invest as you build your project.</dd> <dt>Project roadmap</dt> <dd>Each project is divided into several achievable steps.</dd> <dt>Get Help</dt> <dd>While within the liveProject platform, get help from other participants and our expert mentors.</dd> <dt>Compare with others</dt> <dd>For each step, compare your deliverable to the solutions by the author and other participants.</dd> <dt>book resources</dt> <dd>Get full access to select books for 90 days. Permanent access to excerpts from Manning products are also included, as well as references to other resources.</dd> </dl> </div> </div> </div> </div> </div> </div> <div class="container-fluid" style="margin-top:36px;"> <div class="row"> <div class="container"> <div class="row"> <div class="col-xs-12"> <div class="centered-lp-container"> <div class="product-page-section table-of-contents standard-contents"> <div class="toc"> <div class="toc-loading-container"> <i class="fa fa-circle-notch fa-spin fa-2x"></i> <a name="toc" class="anchor"></a> </div> </div> </div> </div> </div> </div> </div> </div> </div> <div class="container-fluid"> <div class="row"> <div class="container"> <div class="row"> <div class="col-xs-12"> </div> </div> </div> </div> </div> <div class="container-fluid product-review-container"> <a name="reviews" class="anchor"></a> <div class="row"> <div class="container"> <div class="row" > <div class="col-xs-12"> <div id="shopper_review_page"> <div id="review_header"></div> <div id="product_page"></div> <div id="review_image"> <a href="https://www.shopperapproved.com/reviews/Manning.com/" onclick="var nonwin=navigator.appName!='Microsoft Internet Explorer'?'yes':'no'; var certheight=screen.availHeight-90; window.open(this.href,'shopperapproved','location='+nonwin+',scrollbars=yes,width=620,height='+certheight+',menubar=no,toolbar=no'); return false;" target="_blank" rel="nofollow"></a> </div> </div> </div> </div> </div> </div> </div> <div class="container-fluid space related-product-space show-controls"> <div class="row"> <div class="container"> <div class="row" > <div class="col-xs-12"> <h2 class="visible-xs header-space"> <div class="header-control-panel header-control-panel-left" href="#related-titles-carousel" role="button" data-slide="prev"></div> <div class="header-title">related titles</div> <div class="header-control-panel header-control-panel-right" href="#related-titles-carousel" role="button" data-slide="next"></div> </h2> <h2 class="hidden-xs">related titles</h2> </div> <div class="col-xs-12 carousel slide" id="related-titles-carousel" data-ride="carousel"> <!-- Wrapper for slides --> <div class="row carousel-control-and-inner-wrapper"> <div class="hidden-xs col-sm-1 col-sm-0-5 carousel-control-panel carousel-control-panel-left" href="#related-titles-carousel" role="button" data-slide="prev"> </div> <div class="col-xs-12 col-sm-11"> <div class="carousel-inner" role="listbox"> <div class="item active"> <div class="prod-row"> <div class="product-link book-product"> <a href="/books/the-well-grounded-data-analyst" class="link-to-product" data-id="3091" data-position="0" data-name="The Well-Grounded Data Analyst" data-category="" data-brand="book" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/book/e/ef39c9f-a0a4-41d2-b5bf-581089ca14d2/Asboth-HI.png" srcset=" https://images.manning.com/264/352/resize/book/e/ef39c9f-a0a4-41d2-b5bf-581089ca14d2/Asboth-HI.png 264w, https://images.manning.com/192/256/resize/book/e/ef39c9f-a0a4-41d2-b5bf-581089ca14d2/Asboth-HI.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link book-product"> <a href="/books/build-financial-software-with-generative-ai-from-scratch" class="link-to-product" data-id="3557" data-position="1" data-name="Build Financial Software with Generative AI (From Scratch)" data-category="" data-brand="book" data-edition="MEAP"> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/book/7/987a8d3-882f-484d-b327-6f2f3c8ca620/Kardell-MEAP-HI.png" srcset=" https://images.manning.com/264/352/resize/book/7/987a8d3-882f-484d-b327-6f2f3c8ca620/Kardell-MEAP-HI.png 264w, https://images.manning.com/192/256/resize/book/7/987a8d3-882f-484d-b327-6f2f3c8ca620/Kardell-MEAP-HI.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link book-product"> <a href="/books/learn-dbatools-in-a-month-of-lunches" class="link-to-product" data-id="1156" data-position="2" data-name="Learn dbatools in a Month of Lunches" data-category="" data-brand="book" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/book/0/998b76f-982a-4661-a020-5d94909f7ea5/LeMaire-HI.png" srcset=" https://images.manning.com/264/352/resize/book/0/998b76f-982a-4661-a020-5d94909f7ea5/LeMaire-HI.png 264w, https://images.manning.com/192/256/resize/book/0/998b76f-982a-4661-a020-5d94909f7ea5/LeMaire-HI.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link book-product"> <a href="/books/spark-in-action-second-edition" class="link-to-product" data-id="1007" data-position="3" data-name="Spark in Action, Second Edition" data-category="" data-brand="book" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/book/f/6e02a18-b021-4b98-b1c1-39613fefab98/Perrin-Spark-2ed-HI.png" srcset=" https://images.manning.com/264/352/resize/book/f/6e02a18-b021-4b98-b1c1-39613fefab98/Perrin-Spark-2ed-HI.png 264w, https://images.manning.com/192/256/resize/book/f/6e02a18-b021-4b98-b1c1-39613fefab98/Perrin-Spark-2ed-HI.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link book-product"> <a href="/books/data-wrangling-with-javascript" class="link-to-product" data-id="909" data-position="4" data-name="Data Wrangling with JavaScript" data-category="" data-brand="book" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/book/0/b9737af-dfee-46e5-8570-1ad400d39bf0/Davis-DWJS-HI.png" srcset=" https://images.manning.com/264/352/resize/book/0/b9737af-dfee-46e5-8570-1ad400d39bf0/Davis-DWJS-HI.png 264w, https://images.manning.com/192/256/resize/book/0/b9737af-dfee-46e5-8570-1ad400d39bf0/Davis-DWJS-HI.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> </div> </div> <div class="item "> <div class="prod-row"> <div class="product-link liveProject-product"> <a href="/liveproject/ensure-computational-governance" class="link-to-product" data-id="2206" data-position="0" data-name="Ensure Computational Governance" data-category="" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/c/297086d-bc0c-41ab-85b3-48c25fed66e0/DataMesh-EnsureComputationalGovernance.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/c/297086d-bc0c-41ab-85b3-48c25fed66e0/DataMesh-EnsureComputationalGovernance.jpg 264w, https://images.manning.com/192/256/resize/liveProject/c/297086d-bc0c-41ab-85b3-48c25fed66e0/DataMesh-EnsureComputationalGovernance.jpg 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveVideo-product"> <a href="/livevideo/elasticsearch-6-and-elastic-stack" class="link-to-product" data-id="1102" data-position="1" data-name="Elasticsearch 6 and Elastic Stack" data-category="" data-brand="liveVideo" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/video/8/c118441-d7a9-44b9-a21a-23e829d08115/livevideo-elasticsearch6-and-elastic-stack-in-depth-and-hands-on.png" srcset=" https://images.manning.com/264/352/resize/video/8/c118441-d7a9-44b9-a21a-23e829d08115/livevideo-elasticsearch6-and-elastic-stack-in-depth-and-hands-on.png 264w, https://images.manning.com/192/256/resize/video/8/c118441-d7a9-44b9-a21a-23e829d08115/livevideo-elasticsearch6-and-elastic-stack-in-depth-and-hands-on.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveProject-product"> <a href="/liveproject/publish-data-products" class="link-to-product" data-id="2204" data-position="2" data-name="Publish Data Products" data-category="" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/a/4e12eee-ea8a-4913-9a11-981e420ea6fa/DataMesh-PublishDataProducts.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/a/4e12eee-ea8a-4913-9a11-981e420ea6fa/DataMesh-PublishDataProducts.jpg 264w, https://images.manning.com/192/256/resize/liveProject/a/4e12eee-ea8a-4913-9a11-981e420ea6fa/DataMesh-PublishDataProducts.jpg 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveProject-product"> <a href="/liveproject/observability" class="link-to-product" data-id="2281" data-position="3" data-name="Observability" data-category="" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/7/e4ff6a8-15ea-48bf-b840-8119845714c5/UPDATED-DataPipeline-Observability.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/7/e4ff6a8-15ea-48bf-b840-8119845714c5/UPDATED-DataPipeline-Observability.jpg 264w, https://images.manning.com/192/256/resize/liveProject/7/e4ff6a8-15ea-48bf-b840-8119845714c5/UPDATED-DataPipeline-Observability.jpg 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveVideo-product"> <a href="/livevideo/ultimate-asp.net-core-web-api-development-guide" class="link-to-product" data-id="2872" data-position="4" data-name="Ultimate ASP.NET Core Web API Development Guide" data-category="" data-brand="liveVideo" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/video/5/3ae7ddc-7ef7-48f2-81d3-66eed68bc53c/UltimateASP.NETCoreWebAPIDevelopmentGuide_revB.png" srcset=" https://images.manning.com/264/352/resize/video/5/3ae7ddc-7ef7-48f2-81d3-66eed68bc53c/UltimateASP.NETCoreWebAPIDevelopmentGuide_revB.png 264w, https://images.manning.com/192/256/resize/video/5/3ae7ddc-7ef7-48f2-81d3-66eed68bc53c/UltimateASP.NETCoreWebAPIDevelopmentGuide_revB.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> </div> </div> <div class="item "> <div class="prod-row"> <div class="product-link liveVideo-product"> <a href="/livevideo/talk-python-building-data-driven-web-apps-with-flask-and-sqlalchemy" class="link-to-product" data-id="1376" data-position="0" data-name="Talk Python: Building Data-Driven Web Apps with Flask and SQLAlchemy" data-category="" data-brand="liveVideo" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/video/7/fb27f41-d57f-416b-b952-e32ab209b84c/Talk_Python_-_Building_Data-Driven_Web_Apps_with_Flask_and_SQLAlchemy.jpg" srcset=" https://images.manning.com/264/352/resize/video/7/fb27f41-d57f-416b-b952-e32ab209b84c/Talk_Python_-_Building_Data-Driven_Web_Apps_with_Flask_and_SQLAlchemy.jpg 264w, https://images.manning.com/192/256/resize/video/7/fb27f41-d57f-416b-b952-e32ab209b84c/Talk_Python_-_Building_Data-Driven_Web_Apps_with_Flask_and_SQLAlchemy.jpg 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveProject-product"> <a href="/liveproject/manage-data-products" class="link-to-product" data-id="2205" data-position="1" data-name="Manage Data Products" data-category="" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/b/092ebbb-458d-451f-8ab2-9eb1e900f0ad/DataMesh-ManageDataProducts.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/b/092ebbb-458d-451f-8ab2-9eb1e900f0ad/DataMesh-ManageDataProducts.jpg 264w, https://images.manning.com/192/256/resize/liveProject/b/092ebbb-458d-451f-8ab2-9eb1e900f0ad/DataMesh-ManageDataProducts.jpg 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveProject-product"> <a href="/liveproject/push-data-into-data-products" class="link-to-product" data-id="2203" data-position="2" data-name="Push Data into Data Products" data-category="" data-brand="liveProject" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/liveProject/1/d511d23-ff24-429b-8dc5-3692741406ee/DataMesh-PushDataintoDataProducts.jpg" srcset=" https://images.manning.com/264/352/resize/liveProject/1/d511d23-ff24-429b-8dc5-3692741406ee/DataMesh-PushDataintoDataProducts.jpg 264w, https://images.manning.com/192/256/resize/liveProject/1/d511d23-ff24-429b-8dc5-3692741406ee/DataMesh-PushDataintoDataProducts.jpg 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveVideo-product"> <a href="/livevideo/the-ultimate-introduction-to-big-data" class="link-to-product" data-id="1103" data-position="3" data-name="The Ultimate Introduction to Big Data" data-category="" data-brand="liveVideo" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/video/0/77ffcfb-a162-4742-8b1f-6a4cd809d25d/livevideo-the-ultimate-introduction-to-big-data.png" srcset=" https://images.manning.com/264/352/resize/video/0/77ffcfb-a162-4742-8b1f-6a4cd809d25d/livevideo-the-ultimate-introduction-to-big-data.png 264w, https://images.manning.com/192/256/resize/video/0/77ffcfb-a162-4742-8b1f-6a4cd809d25d/livevideo-the-ultimate-introduction-to-big-data.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> <div class="product-link liveVideo-product"> <a href="/livevideo/elasticsearch-7-and-elastic-stack" class="link-to-product" data-id="1213" data-position="4" data-name="Elasticsearch 7 and Elastic Stack" data-category="" data-brand="liveVideo" data-edition=""> <img class="lazyload" loading="lazy" data-src="https://images.manning.com/264/352/resize/video/c/2d1443b-1e00-4338-aa46-2dd3393dfd42/livevideo-elasticsearch-7-and-elastic-stack.png" srcset=" https://images.manning.com/264/352/resize/video/c/2d1443b-1e00-4338-aa46-2dd3393dfd42/livevideo-elasticsearch-7-and-elastic-stack.png 264w, https://images.manning.com/192/256/resize/video/c/2d1443b-1e00-4338-aa46-2dd3393dfd42/livevideo-elasticsearch-7-and-elastic-stack.png 192w" sizes="(min-width: 1170px) 264px, (min-width: 750px) 192px, 192px"> </a> </div> </div> </div> </div> </div> <div class="hidden-xs col-sm-1 col-sm-0-5 carousel-control-panel carousel-control-panel-right" href="#related-titles-carousel" role="button" data-slide="next"> </div> </div> </div> </div> </div> </div> </div> <script> var relatedProductsImpressionGtmPayload = {}; var relatedProductsImpressions = []; var position = 0; relatedProductsImpressions.push({ id: '3091', name: 'The Well-Grounded Data Analyst', edition: '', category: '', brand: 'book', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '3557', name: 'Build Financial Software with Generative AI (From Scratch)', edition: 'MEAP', category: '', brand: 'book', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '1156', name: 'Learn dbatools in a Month of Lunches', edition: '', category: '', brand: 'book', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '1007', name: 'Spark in Action, Second Edition', edition: '', category: '', brand: 'book', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '909', name: 'Data Wrangling with JavaScript', edition: '', category: '', brand: 'book', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '2206', name: 'Ensure Computational Governance', edition: '', category: '', brand: 'liveProject', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '1102', name: 'Elasticsearch 6 and Elastic Stack', edition: '', category: '', brand: 'liveVideo', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '2204', name: 'Publish Data Products', edition: '', category: '', brand: 'liveProject', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '2281', name: 'Observability', edition: '', category: '', brand: 'liveProject', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '2872', name: 'Ultimate ASP.NET Core Web API Development Guide', edition: '', category: '', brand: 'liveVideo', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '1376', name: 'Talk Python: Building Data-Driven Web Apps with Flask and SQLAlchemy', edition: '', category: '', brand: 'liveVideo', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '2205', name: 'Manage Data Products', edition: '', category: '', brand: 'liveProject', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '2203', name: 'Push Data into Data Products', edition: '', category: '', brand: 'liveProject', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '1103', name: 'The Ultimate Introduction to Big Data', edition: '', category: '', brand: 'liveVideo', list: 'related-products', position: position++ }); relatedProductsImpressions.push({ id: '1213', name: 'Elasticsearch 7 and Elastic Stack', edition: '', category: '', brand: 'liveVideo', list: 'related-products', position: position++ }); relatedProductsImpressionGtmPayload['impressions'] = relatedProductsImpressions; $(document).trigger('impression-gtm', relatedProductsImpressionGtmPayload); $(document).ready(function() { $(".link-to-related-product").on('click', function() { var $item = $(this); $(document).trigger('impression-click-gtm', { list: 'related-products', products: [{ id: $item.data('id').toString(), name: $item.data('name'), edition: $item.data('edition'), category: $item.data('category'), brand: $item.data('brand'), position: $item.data('position') }] }); }); }); </script> <div class="subscription-interstitial container" tabindex="-1" id="subscribeNowInterstitial-3463"> <div class="interstitial-close" aria-label="Close"> <i class="fas fa-times"></i> </div> <section class="farabq-big-subscription-buy-panel-container"> <div class="inner product-grid"> <h1>choose your plan</h1> <section> <div class="farabq-product-container farabq-flag-this farabq-flag-this-as-most-popular"> <div class="purchase-panel"> <div class="farabq-topper"> <h2>pro</h2> <div class="tabber-control"> <div class="tabber tabber-monthly"> monthly </div> <div class="tabber tabber-annual"> annual </div> </div> </div> <strong class="farabq-price tab-content"> <div class="show-monthly"> <div> $24.99 </div> </div> <div class="show-annual"> <div> $249.99 </div> <small>only $20.83 per month</small> </div> </strong> <ul> <li>access to <strong>all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!</strong></li> <li class="show-monthly">choose another <strong>free product</strong> every time you renew</li> <li class="show-annual">choose <strong>twelve free products</strong> per year</li> <li>exclusive <strong>50% discount</strong> on all purchases</li> <li class="farabq-product-image-wrapper"> <span class="fa fa-plus"></span> <img class="farabq-product-image img-responsive lazyload" loading="lazy" data-src="https://images.manning.com/360/480/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" /> <small><em>Automate Reports</em> project for <strong>free</strong></small> </li> </ul> <form action="/cart/subscribeNow" method="post" class="add-to-cart-form subscription-form" > <input type="hidden" name="contentPoId" value="3463" id="contentPoId" /> <input type="hidden" name="monthlyProductOfferingId" value="4133" id="monthlyProductOfferingId" /> <input type="hidden" name="annualProductOfferingId" value="4134" id="annualProductOfferingId" /> <input type="checkbox" class="hidden annual-checkbox" name="annual"/> <span class="button-wrap"> <input type="submit" name="submit" value="add to cart" class="add-to-cart btn-full-width btn-full-width-xs btn btn-primary farabq-btn" id="submit" /> </span> </form> </div> </div> <div class="farabq-product-container"> <div class="purchase-panel"> <div class="farabq-topper"> <h2>team</h2> <div class="tabber-control"> <div class="tabber tabber-monthly"> monthly </div> <div class="tabber tabber-annual"> annual </div> </div> </div> <strong class="farabq-price tab-content"> <div class="show-monthly"> <div>$49.99</div> </div> <div class="show-annual"> <div>$399.99</div> <small>only $33.33 per month</small> </div> </strong> <ul> <li><strong>five seats</strong> for your team</li> <li>access to <strong>all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!</strong></li> <li class="show-monthly">choose another <strong>free product</strong> every time you renew</li> <li class="show-annual">choose <strong>twelve free products</strong> per year</li> <li>exclusive <strong>50% discount</strong> on all purchases</li> <li class="farabq-product-image-wrapper"> <span class="fa fa-plus"></span> <img class="farabq-product-image img-responsive lazyload" loading="lazy" data-src="https://images.manning.com/360/480/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg" /> <small><em>Automate Reports</em> project for <strong>free</strong></small> </li> </ul> <form action="/cart/subscribeNow" method="post" class="add-to-cart-form subscription-form" > <input type="hidden" name="contentPoId" value="3463" id="contentPoId" /> <input type="hidden" name="monthlyProductOfferingId" value="4135" id="monthlyProductOfferingId" /> <input type="hidden" name="annualProductOfferingId" value="8135" id="annualProductOfferingId" /> <input type="checkbox" class="hidden annual-checkbox" name="annual"/> <span class="button-wrap"> <input type="submit" name="submit" value="add to cart" class="add-to-cart btn-full-width btn-full-width-xs btn btn-primary farabq-btn" id="submit" /> </span> </form> <div> <a href="/subscription?extra-seats-open#team-subscription-anchor" class="secondary-button btn btn-full-width more-seats-button" style="font-size: 1.15em; font-weight: bold;">more seats?</a> </div> </div> </div> </section> <script> document.addEventListener('DOMContentLoaded', function () { $(".add-to-cart-form.subscription-form").on("submit", function(e){ var $button = $(e.target).find("input[type='submit']"); var isButtonAlreadyDisabled = !!$button.attr("disabled"); var $buttons = $(".add-to-cart-form.subscription-form").find("input[type='submit']"); $buttons.addClass("disabled"); $buttons.attr("disabled", true); $button.val("adding to cart .."); var $form = $(e.currentTarget); if ($form.attr('action').includes('contentPoId') == false) { $form.attr('action', $form.attr('action') + '?' + $form.serialize()); } var submitDate = new Date(); if(!isButtonAlreadyDisabled){ $.ajax({ url: "/analytics/logUserAction", data: { productId: "2282", type: "subscription", additionalData: "product-page-subscription-add-to-cart" } }); $(document).on("click", function(e){ var clickDate = new Date(); var diffInSeconds = (clickDate.getTime() - submitDate.getTime()) / 1000; var $target = $(e.target); var elementKey = $target.prop('tagName') + ($target.attr("id") ? $target.attr("id") : "") + ($target.attr("class") ? "_" + $target.attr("class") : "") + ($target.attr("href") ? $target.attr("href").replace("https://", "").replace("http://", "") : ""); if(elementKey.length > 30){ elementKey = elementKey.substring(0, 30); } $.ajax({ url: "/analytics/logUserAction", data: { type: "subscription", additionalData: "after-click-" + diffInSeconds + "-" + elementKey }, }); }); } return true; }); $(".more-seats-button").on("click", function(){ if(window.isSendingMoreSeatsAction) { return; } window.isSendingMoreSeatsAction = true; $.ajax({ url: "/analytics/logUserAction", data: { type: "subscription", additionalData: "moreSeatsButtonClick" } }).done(function(){ window.isSendingMoreSeatsAction = false }); }); }); </script> </div> </section> </div> <script> var viewContentPayload = { contentIds: [ ], productCount: 5, dateFormat: 'F j, Y', productId: '2282', isbn: 'MNLP2021383' }; $(document).trigger("view-content", viewContentPayload); $("body").append($(".added-to-cart-interstitial")); $(document).ready(function() { $(document).trigger('show-product-gtm', { id: '2282', name: 'Automate Reports', edition: '', category: 'Development,Operations & Cloud,Python', brand: 'liveProject' }); $.ajax({ url: "/ajax/getWishListDetails" }).done(function (data) { if (!jQuery.isEmptyObject(data) && data['wishlistProductIds']) { $(".wishlist-container").each(function() { if (data.wishlistProductIds.indexOf($(this).find('.wishlist-toggle').data('product-id')) > -1) { $(this).addClass("on-wishlist"); } }); } }); $.ajax({ url: "/analytics/logUserAction", data: { productId: "2282", type: "view" } }) }); </script> <script> if (typeof jQuery !== 'undefined') { (function($) { $(".links-list").on('click', '.more-expander', function () { $(this).addClass("go-away").siblings().removeClass("collapsible"); }); $("body").on("click", ".openManuscriptReviews", function(e) { $(document).trigger('open-manuscript-reviews', { 'title': 'Automate Reports', 'event': 'manuscript-reviews-opened' }); }); var controllo = $("<a class='toc-controllo toc-expando'><span class='fa fa-caret-right expando' title='Expand'></span><span class='fa fa-caret-down retracto' title='Collapse'></span></a>"); (function(){ try { var titleHtml = ""; titleHtml = '<h2 class="header">project outline</h2> <a name="toc" class="anchor"></a>' var tocServerVars = { productId: 2282, getTocUrl: "/ajax/getTocHtml" } var tocStatusResolved = false; $(document).ready(loadTocIfVisible); function loadTocIfVisible(){ if(tocStatusResolved) { return; } if($('.toc-loading-container').isInViewport()){ window.removeEventListener("scroll", loadTocIfVisible); $(window).off("scroll", loadTocIfVisible); loadToc(); } } try { window.addEventListener("scroll", loadTocIfVisible, { passive: true}); } catch(e){ $(window).on("scroll", loadTocIfVisible); } function loadToc(){ tocStatusResolved = true; window.TocProvider.getToc(function (tocHtml) { var $tocLoadingContainer = $('.toc-loading-container'); $tocLoadingContainer.closest(".table-of-contents").prepend(titleHtml); $tocLoadingContainer.replaceWith(tocHtml); initializeToc(); }, function(){ $('.toc-loading-container').remove() }); } window.TocProvider = { toc: "", getToc: function(success, failure){ if(this.toc) { success && success(this.toc); return; } $.ajax({ url: tocServerVars.getTocUrl, data: { id: tocServerVars.productId } }).done(function(data){ if(data && data.tocHtml){ this.toc = data.tocHtml; success && success(this.toc); } else { failure && failure(); } }).fail(function(error){ failure && failure(); }); } }; } catch (e) {} })(); function initializeToc(){ // Append this only when children of their sectionbody siblings exist (appendices generally aren't expandable) $(".sectionbody *").children("*").parents(".sectionbody").siblings("h2").wrapInner("<span class='unit-link chap-link'>").append(controllo); $(".toc h2 > .chap-link, .toc h1, .toc h3, .toc h4").each(function() { $(this).html($(this).html().replace(/^(\b\w[0-9A-Z]{0,1}\b\.?)+\s/gi, "<span class='leading-number'>$&</span>")); }); $(".sectionbody").addClass("hidden-toc"); $("body").on("click", ".toc-expando", function(e) { e.stopPropagation(); $(this).removeClass("toc-expando").addClass("toc-retracto").closest(".sect1").find(".sectionbody").removeClass("hidden-toc").addClass("shown-toc"); }); $("body").on("click", ".toc-retracto", function(e) { e.stopPropagation(); $(this).removeClass("toc-retracto").addClass("toc-expando").closest(".sect1").find(".sectionbody").removeClass("shown-toc").addClass("hidden-toc"); }); $("body").on("click", ".available h2", function() { $(this).find(".toc-controllo").click(); }); $("body").on("click", "#show-hide", function() { if ($("#show-hide").hasClass("hide-full-toc")) { $(".table-of-contents .sect2, .table-of-contents .sect3").removeClass("shown-toc").addClass("hidden-toc"); $("#show-hide").removeClass("hide-full-toc").html("<i class=\"fas fa-toggle-off\"></i> detailed TOC"); $(".table-of-contents .body").removeClass("full-toc"); $(".toc-retracto").click(); } else { $(".table-of-contents .sect2, .table-of-contents .sect3").addClass("shown-toc").removeClass("hidden-toc"); $("#show-hide").addClass("hide-full-toc").html("<i class=\"fas fa-toggle-on\"></i> detailed TOC"); $(".table-of-contents .body").addClass("full-toc"); $(".toc-expando").click(); } }); $('[data-toggle="tooltip"]').tooltip(); } var addToWishlistUrl = "/wishList/addItemFromPage" + "?"; var removeFromWishlistUrl = "/wishList/removeItemFromPage" + "?"; $("body").on("click", ".wishlist-login", function() { localStorage.removeItem('dynamicloadcache'); }); $("body").on("click", ".wishlist-toggle.wishlist-add, .wishlist-toggle.wishlist-remove", function() { var productId = $(this).data("product-id"); var url = addToWishlistUrl; if ($(this).hasClass("wishlist-remove")) { url = removeFromWishlistUrl; $(".wishlist-container").removeClass("on-wishlist"); } else { $(".wishlist-container").addClass("on-wishlist"); } $.ajax({ type: "GET", url: url + "id=" + productId, timeout: 3000, dataType: "json", headers: { 'accept': "application/json" } }); }); $(document).trigger('activity-product-browse', {productId: '2282'}); })(jQuery); } </script> <script> $(function() { 'use strict'; const viewTime = (new Date()).getTime(); const product = { title : 'Automate Reports', slug : 'automate-reports', id : '2282', imageUrl : 'liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg', path : 'liveproject', edition : '', brand : 'liveProject', category : 'Development,Operations & Cloud,Python', viewTime : viewTime, lastUpdated : viewTime }; let recentlyViewed = JSON.parse(localStorage.getItem('recently-viewed')); if (!recentlyViewed || !Array.isArray(recentlyViewed)) { recentlyViewed = []; } // Composite key of id and path const found = recentlyViewed.find(element => element.id === product.id && element.path === product.path ); if (found) { // Remove it const idx = recentlyViewed.indexOf(found); recentlyViewed.splice(idx, 1); } // Add this page to the front, guaranteeing that the first item is ALWAYS from the current page recentlyViewed.unshift(product); // Remove everything past the ninth element recentlyViewed = recentlyViewed.slice(0, 9); localStorage.setItem("recently-viewed", JSON.stringify(recentlyViewed)); // Add a class to the body so our CSS knows that the first item is THIS item and shouldn't be shown. document.body.classList.add('recently-viewed-collector-collected'); }); </script> <script> document.addEventListener('subscription-status-loaded', function(e) { function setPriceTo50Percent($element){ try { var priceString = $element.find("[data-list-price-usd]").attr("data-list-price-usd"); if(!priceString){ priceString = $element.find("._final-price").first().text().trim().replace("$", ""); } if(priceString){ var priceValue = parseFloat(priceString) if(!Number.isNaN(priceValue)){ $element.find("._final-price").text("$" + (priceValue/2).toFixed(2)); } } } catch(e){ console.log(e); } } switch(e.detail['status']) { case 'EXPIRED_PAUSED': case 'ACTIVE': case 'PAUSED': if(e.detail.isSubscriptionOwner) { var $addToCartDigital = $(".add-to-cart-box ._heading-item[data-product-type=eBook], .add-to-cart-box ._heading-item[data-product-type=video], .add-to-cart-box ._heading-item[data-product-type=project], .add-to-cart-box ._heading-item[data-product-type='whole series']"); if(e.detail.quantityCreditBalance > 0){ $addToCartDigital.find("._savings").text("FREE with subscription credits"); $addToCartDigital.find("._final-price").text("$0.00"); } if(e.detail.subscriptionOfferingType == "PRO" || e.detail.subscriptionOfferingType == "TEAM"){ if(e.detail.quantityCreditBalance === 0){ $addToCartDigital.find("._savings").text("50% discount with subscription"); setPriceTo50Percent($addToCartDigital); } var $addToCartPrintItem = $(".add-to-cart-box ._heading-item[data-product-type=print]"); if($addToCartPrintItem.length > 0){ $addToCartPrintItem.find("._savings").text("50% discount with subscription"); setPriceTo50Percent($addToCartPrintItem); } } } if($("#product-type-tabs ._product-type-button:visible").length <= 1){ $("#product-type-tabs").hide(); } break; default: } }); </script> <div class="scroll-to-cart-button-container"> <button class="btn btn-primary"> <i class="fas fa-cart-plus"></i> </button> </div> <script> $(document).ready(function(){ var $mainContentAddToCartBox = $(".content-cell .add-to-cart-box, .lpseries-tabs-wrapper .add-to-cart-box"); var scrollTimerId = -1 var $window = $(window); var $header = $("#header") document.addEventListener("scroll", function() { clearTimeout(scrollTimerId); scrollTimerId = setTimeout(function(){ var viewportTop = $window.scrollTop() + ($header.height() || 0); var offset = $mainContentAddToCartBox.offset(); if(offset == null) { return; } var mainContentAddToCartBoxBottom = offset.top + $mainContentAddToCartBox.height(); if(viewportTop > mainContentAddToCartBoxBottom){ $scrollToCartContainer.addClass("visible"); } else { $scrollToCartContainer.removeClass("visible"); } }, 200); }); var $scrollToCartContainer = $(".scroll-to-cart-button-container"); $scrollToCartContainer.on("click", function(){ var offset = 0; try { if($(".content-cell").length > 0){ offset = $(".content-cell").offset().top } else if($(".lpseries-center-meta-and-buy-wrapper").length > 0){ offset = $(".lpseries-center-meta-and-buy-wrapper").offset().top } else if($(".product-title").length > 0){ offset = $(".product-title").offset().top } else if($("#product-type-tabs").length > 0) { offset = $("#product-type-tabs").offset().top } offset -= $("#header").height() + ($("#top-nav-deals-wrapper").height() || 0); offset = Math.max(offset, 0); } catch(e){ console.log(e); } window.scrollTo(0, offset); $scrollToCartContainer.removeClass("visible"); }); }); </script> <div id="new-user-modal" class="fancy-modal modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <div class="modal-body"> <script> var primaryFocus = { "Software Engineering": ["Backend Software Engineer", "Software Developer / Engineer", "Software Architect", "Engineering Project Manager / Engineering Manager", "Engineering Lead / Team Lead", "Principal Software Engineer", "Senior Software Engineer", "Other"], "Data / Data Science": ["Analytics Director", "Data Scientist", "Machine Learning Engineer", "Big Data Engineer / Architect", "BI Developer / Analyst", "Web Analyst", "Insight Director, Research Analyist", "Other"], "Operations": ["Network Engineer", "Cloud Architect / Engineer", "DevOps Engineer", "Operations Lead", "Security Compliance", "SRE", "Systems Engineer", "Other"], "Business Management": ["CIO / CTO", "CISO", "IT Manager", "IT Director", "VP / Director of Technology", "Business Development Manager", "Other"] } var titles = [ "Backend Software Engineer", "Software Developer / Engineer", "Software Architect", "Engineering Project Manager / Engineering Manager", "Engineering Lead / Team Lead", "Principal Software Engineer", "Senior Software Engineer", "Analytics Director", "Data Scientist", "Machine Learning Engineer", "Big Data Engineer / Architect", "BI Developer / Analyst", "Web Analyst", "Insight Director, Research Analyist", "Network Engineer", "Cloud Architect / Engineer", "DevOps Engineer", "Operations Lead", "Security Compliance", "SRE", "Systems Engineer", "CIO / CTO", "CISO", "IT Manager", "IT Director", "VP / Director of Technology", "Business Development Manager", "Other" ] window.onload = function() { var titleSelect = document.getElementById("title"); if(titleSelect != null) { titleSelect.length = 1; for (var i = 0; i < titles.length; i++) { titleSelect.options[titleSelect.options.length] = new Option(titles[i], titles[i]); } } } </script> <form action="/bundles/register?id=registration-form" method="post" class="row" name="registration-form" onsubmit="document.getElementById(&#39;registration-submit&#39;).disabled=true; return true;" id="registration-form" > <div class="container"> <div class="row flex-row"> <div class="col-xs-12 form-side"> <strong class="fancy-title">Please complete the fields below to get your FREE access to Automate Reports.</strong> <input type="hidden" name="_emailSubscription" /> <div class="form-group"> <label for="new-user-fullname">Name</label> <input id="new-user-fullname" name="fullName" class="form-control" required="required" placeholder="First Name Last Name" maxlength="100"> </div> <div class="form-group"> <label for="new-user-email">Email address</label> <input id="new-user-email" type="email" name="email" class="form-control" required="required" placeholder="you@example.com" maxlength="100"> </div> <div class="fancy-fine-print"> You'll receive a link in your inbox to access your project. By submitting your email, you agree to receive email from Manning Publications about Manning products. You can unsubscribe at any time. <br> <a href="/privacy">Read our privacy policy.</a> </div> <div class="button-row"> <button type="submit" class="btn btn-primary btn-special" id="registration-submit"> request live Project </button> </div> <div> </div> </div> <div class="hidden-xs image-side is-cover"> <img class="img-responsive lazyload" loading="lazy" src="https://images.manning.com/360/480/resize/liveProject/a/815680b-20e8-4ace-ab4a-3e1a427ef02b/UPDATED-DataPipeline-AutomateReports.jpg"> </div> </div> </div> </form> <script type="text/javascript"> $("form[name='registration-form']").on("submit", function(e){ $.post("\u002fbundles\u002fregister", $(this).serialize()) .done(function(data) { var $registrationSuccessModal = $("#registration-success-modal"); if($registrationSuccessModal.length > 0){ $registrationSuccessModal.modal("show"); } else { document.location.href = "\u002fdashboard\u002findex" } }).fail(function (data) { alert("Error getting free product. Try again or contact support@manning.com"); }); e && e.preventDefault && e.preventDefault(); return false }); </script> </div> </div> </div> </div> <div id="registration-success-modal" class="fancy-modal modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <div class="modal-body"> <div class="_title" style="font-size: 1.25em;"> Check your email for instructions on downloading Automate Reports. </div> </div> </div> </div> </div> <script type="text/javascript"> $(document).ready(function(){ var productOfferingId = "3463" if($("#registrationProductOfferingId").length == 0){ $('#registration-form').append('<input type="hidden" name="registrationProductOfferingId" id="registrationProductOfferingId" />'); } $('#registrationProductOfferingId').val(productOfferingId); var $button = $(".show-registration-form"); $button.on("click", function(){ if($("body").is(".logged-in")){ $button.prop("disabled", true); $button.find(".button-label").html("getting <strong>FREE</strong> product <i class='fa fa-circle-notch fa-spin fa-fw'></i>"); $.post({ url: "\u002fcart\u002fgetFreeProduct", data: {"productOfferingId": productOfferingId } }).done(function(data){ document.location.href = "\u002fdashboard\u002findex" }).fail(function(){ $button.prop("disabled", false); $button.find(".button-label").html("get now for <strong>FREE</strong>"); alert("Error getting free product. Try again or contact support@manning.com"); }); } else { $("#new-user-modal").modal("show"); } }) $("#new-user-modal").on("shown.bs.modal", function() { $(document).off("focusin.modal"); }); }) </script> </div> <div role="contentinfo" id="footer"> <div id="minimize-footer-button" role="button" title="minimize footer"> <span class="fas fa-chevron-down" aria-hidden="true"></span> <span class="sr-only">minimize</span> </div> <div class="container"> <div class="row"> <div class="col-md-12"> <div class="row"> <div class="col-md-3 col-sm-12"> <dl> <dt>about</dt> <dd><a href="/manning">Manning</a></dd> <dd><a href="/meap-program">MEAP</a></dd> <dd><a href="/livebook-program">liveBook</a></dd> <dd><a href="/livevideo-program">liveVideo</a></dd> <dd><a href="https://liveproject.manning.com">liveProject</a></dd> <dd><a href="/liveaudio-landing">liveAudio</a></dd> <dd><a href="/ebooks">eBooks</a></dd> <dd><a href="/subscription">subscriptions</a></dd> <dd><a href="/tokens">tokens</a></dd> <dd><a href="/covers">our covers</a></dd> </dl> </div> <div class="col-md-3 col-sm-12"> <dl> <dt>info & inquiries</dt> <dd><a href="/reviews">site reviews<span class="site-review-count"></span></a></dd> <dd><a href="/user-group">user group program</a></dd> <dd><a href="/write-a-book">write a book</a></dd> <dd><a href="/create-a-liveproject">create a liveProject</a></dd> <dd><a href="/academic">academic</a></dd> <dd><a href="/distributors">distributors</a></dd> <dd><a href="/careers">careers</a></dd> <dd><a href="/manuscript-reviews">manuscript reviews</a></dd> <dd><a href="/affiliate-program">affiliate program</a></dd> <dd><a href="/news">news</a></dd> </dl> </div> <div class="col-md-3 col-sm-12"> <dl> <dt>help</dt> <dd><a href="/freebook">register pBook</a></dd> <dd><a href="/placing-an-order">placing an order</a></dd> <dd><a href="/shipping-and-returns">shipping & returns</a></dd> <dd><a href="/why-buy-from-manning">why buy from Manning?</a></dd> <dd><a href="/faq">faq</a></dd> <dd><a href="/contact">contact</a></dd> <dd><a href="/support">support</a></dd> </dl> </div> <div class="col-md-3 col-sm-12"> <dl> <dt>legal</dt> <dd><a href="/privacy">privacy</a></dd> <dd><a href="/terms-of-use">terms of use</a></dd> <dd><a href="/ebook-license">eBook license</a></dd> <dd><a href="/source-code">source code</a></dd> <dd><a href="/translations">translations</a></dd> </dl> </div> </div> </div> <div class="col-md-12"> <div class="row"> <div class="col-md-6 col-md-push-6 text-right-md"> <ul class="list-inline social-media-links"> <li><a href="/mail-preferences" tabindex="-1" data-toggle="tooltip" title="Subscribe to our Newsletter"><span class="far fa-newspaper"></span><span aria-hidden="true" class="hidden">Subscribe to our Newsletter</span></a> </li> <li><a href="https://www.linkedin.com/company/manning-publications-co/" tabindex="-1" data-toggle="tooltip" title="Manning on LinkedIn" rel="noopener" target="_blank"><span class="fab fa-linkedin-in"></span><span aria-hidden="true" class="hidden">Manning on LinkedIn</span></a> </li> <li><a href="https://www.instagram.com/manning_publications/" tabindex="-1" data-toggle="tooltip" title="Manning on Instagram" rel="noopener" target="_blank"><span class="fab fa-instagram"></span><span aria-hidden="true" class="hidden">Manning on Instagram</span></a> </li> <li><a href="https://www.facebook.com/ManningBooks?ref=nf" tabindex="-1" data-toggle="tooltip" title="Manning on Facebook" rel="noopener" target="_blank"><span class="fab fa-facebook-f"></span><span aria-hidden="true" class="hidden">Manning on Facebook</span></a> </li> <li><a href="https://twitter.com/manningbooks" tabindex="-1" data-toggle="tooltip" title="Manning on Twitter" rel="noopener" target="_blank"><span class="fab fa-twitter"></span><span aria-hidden="true" class="hidden">Manning on Twitter</span></a> </li> <li><a href="https://www.youtube.com/channel/UCDia_lkNYKLJVLRLQl_-pFw" tabindex="-1" data-toggle="tooltip" title="Manning on YouTube" rel="noopener" target="_blank"><span class="fab fa-youtube"></span><span aria-hidden="true" class="hidden">Manning on YouTube</span></a> </li> <li><a href="https://www.twitch.tv/manningpublications" tabindex="-1" data-toggle="tooltip" title="Manning on Twitch" rel="noopener" target="_blank"><span class="fab fa-twitch"></span><span aria-hidden="true" class="hidden">Manning on Twitch</span></a> </li> <li><a href="https://techhub.social/&#64;ManningPublications" tabindex="-1" data-toggle="tooltip" title="Manning on Mastodon" rel="noopener" target="_blank"><span class="fab fa-mastodon"></span><span aria-hidden="true" class="hidden">Manning on Mastodon</span></a> </li> </ul> </div> <div class="col-md-6 col-md-pull-6 text-left-md"> <div id="copyright"> &copy; 2025&nbsp;&nbsp;Manning Publications Co.&nbsp;&nbsp;<span class="hidden-xs">All rights reserved.</span> </div> </div> </div> <div class="row"> <div class="col-md-12 text-center dmca-footer"> <a href="https://www.dmcaforce.com" title="This copyright holder prohibits the use and distribution of their content from unauthorized sources. Support them by purchasing or accessing from authorized sources only. www.dmcaforce.com is the authorized DMCA Agent for this copyright holder." target="_blank" style="display: inline-block; vertical-align: middle;"><img src="https://www.dmcaforce.com/wp-content/uploads/2013/07/dmca-icon-enforced.png" alt="DMCA Enforced" width="200" height="50"/></a> </div> </div> </div> </div> </div> <script src="/assets/footer-6f2f4c0a1d29b9c2bd0d814422836837.js" /> </div> <!-- google tag manager code for promotional banner in header.gsp --> <script> var bannerPromotionGtmPayload = {}; var bannerPromotions = []; var p = 0; bannerPromotions.push({ id: '1724', name: 'Save 40 with emails', creative: 'banner', position: p++ }); bannerPromotions.push({ id: '1734', name: 'DOTD Banner', creative: 'banner', position: p++ }); bannerPromotionGtmPayload['promotions'] = bannerPromotions; $(document).trigger('promotion-gtm', bannerPromotionGtmPayload); $(document).ready(function () { $(".link-to-banner").on('click', function () { var $item = $(this); $(document).trigger('promotion-click-gtm', { promotions: [{ id: $item.data('banner-id').toString(), name: $item.data('banner-name'), position: $item.data('banner-position'), creative: 'banner' }] }); }); }); </script> <!-- Twitter universal website tag code --> <script type="text/javascript" async> $(document).trigger('twitter-init-tag'); </script> <!-- End Twitter universal website tag code --> <!-- Shopper approved review-count code --> <script async> $(document).trigger('sa-review-count'); </script> <!-- End shopper approved review-count code --> <!-- Facebook pixel --> <script async> $(document).trigger('page-view'); </script> <noscript> <img class="lazyload" loading="lazy" height="1" width="1" src="https://www.facebook.com/tr?id=1940497162877014&ev=PageView&noscript=1"/> </noscript> <!-- End Facebook Pixel Code --> <noscript> <img class="lazyload" loading="lazy" height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=1420473&fmt=gif" /> </noscript> <script type="text/javascript"> $.getScript("\u002fassets\u002fanalytics\u002fhotjar-b02672c9dafc632ff02836d97454dee2.js"); </script> <script> $(document).one("mousemove click keydown touchstart", function(){ $.getScript("/assets/analytics/bing-6ada15fe5fae6589ca2927a32d3d40e7.js", function(){ (function(w,d,t,r,u){var f,n,i;w[u]=w[u]||[],f=function(){var o={ti:"26032741"};o.q=w[u],w[u]=new UET(o),w[u].push("pageLoad")},n=d.createElement(t),n.src=r,n.async=1,n.onload=n.onreadystatechange=function(){var s=this.readyState;s&&s!=="loaded"&&s!=="complete"||(f(),n.onload=n.onreadystatechange=null)},i=d.getElementsByTagName(t)[0],i.parentNode.insertBefore(n,i)})(window,document,"script","//bat.bing.com/bat.js","uetq"); }); $.getScript("/assets/analytics/twitter-9cae03c447d02181487106a5c757d662.js"); $.getScript("/assets/analytics/reddit-3950eab301a1ef9d9bd25d1e27047643.js"); setTimeout(function(){ _linkedin_partner_id = "1420473"; window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || []; window._linkedin_data_partner_ids.push(_linkedin_partner_id); (function(){var s = document.getElementsByTagName("script")[0]; var b = document.createElement("script"); b.type = "text/javascript";b.async = true; b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js"; s.parentNode.insertBefore(b, s);})(); var postAffProScript = document.createElement("script") postAffProScript.addEventListener("load", function(){ PostAffTracker.setAccountId('default1'); try { PostAffTracker.track(); } catch (err) { } }); postAffProScript.id = "pap_x2s6df8d"; postAffProScript.src = "https://manning.postaffiliatepro.com/scripts/trackjs.js"; document.body.appendChild(postAffProScript); }, 100); }); </script> <div id="recently-viewed-drawer"> <div id="recently-viewed-toggler">RECENTLY VIEWED</div> <div id="recently-viewed-closer"> <svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path fill="#666" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"></path></svg> </div> <div id="recently-viewed-list"> </div> </div> <script> $(function() { 'use strict'; var gtmPayload = {}; let recentlyViewed = JSON.parse(localStorage.getItem('recently-viewed')); function getRelativeTimeFrom(sourceDate){ if(window.Intl && window.Intl.RelativeTimeFormat){ var now = new Date() var dayDiff = -Math.abs(now.getDate() - sourceDate.getDate()); var formatter = new Intl.RelativeTimeFormat(); if (dayDiff === 0) { var hourDiff = -Math.abs(now.getHours() - sourceDate.getHours()); if (hourDiff === 0) { return 'within the hour'; } else { return formatter.format(hourDiff, 'hour'); } } else { return formatter.format(dayDiff, 'day'); } } else if(window.dayjs){ return dayjs(sourceDate).fromNow(); } else { return ""; } } function loadRecentlyViewed(){ if (Array.isArray(recentlyViewed)) { fillInRecentlyViewed() } } function fillInRecentlyViewed(){ if (Array.isArray(recentlyViewed)) { if (recentlyViewed.length <= 1) { document.getElementById('recently-viewed-drawer').remove(); } else { let position = 0; var impressions = []; recentlyViewed.forEach(function (product) { let item = document.createElement('a'); item.className = 'recently-viewed-product'; item.href = 'https://www.manning.com/' + product.path + '/' + product.slug; item.setAttribute('data-id', product.id); item.setAttribute('data-name', product.title); item.setAttribute('data-edition', product.edition); item.setAttribute('data-category', product.category); item.setAttribute('data-brand', product.brand); item.setAttribute('data-position', position); let img = document.createElement('img'); img.width = "100" img.height = "132" img.src = 'https://images.manning.com/100/132/resize/' + product.imageUrl; img.className = 'cover lazyload'; let title = document.createElement('div'); title.className = 'title'; title.innerHTML = product.title; if (product.viewTime) { let relativeTime = document.createElement('div'); relativeTime.className = 'relative-time'; relativeTime.innerHTML = getRelativeTimeFrom(new Date(product.viewTime)) item.appendChild(relativeTime); } item.appendChild(img); item.appendChild(title); document.getElementById('recently-viewed-list').appendChild(item); impressions.push({ id: product.id, name: product.title, edition: product.edition, category: product.category, brand: product.brand, list: 'recently-viewed-product', position: position++ }); }); gtmPayload['impressions'] = impressions; } } } if(window.Intl && window.Intl.RelativeTimeFormat){ loadRecentlyViewed(); } else { $.getScript("/assets/dayjs/dayjs-4b3b84d9ad069b307917ffc925be36c6.js", function(){ dayjs.extend(window.dayjs_plugin_relativeTime); loadRecentlyViewed(); }); } $(".recently-viewed-product").on('click', function () { var $item = $(this); $(document).trigger('impression-click-gtm', { list: 'recently-viewed-product', products: [{ id: $item.data('id').toString(), name: $item.data('name'), edition: $item.data('edition'), category: $item.data('category'), brand: $item.data('brand'), position: $item.data('position') }] }); }); $("#recently-viewed-toggler, #recently-viewed-closer").on('click', function () { document.getElementById('recently-viewed-drawer').classList.toggle('drawer-in'); }); $("#recently-viewed-toggler").one('click', function () { $(document).trigger('impression-gtm', gtmPayload); }); }); </script> <!-- Hide it behind a feature toggle --> </body> <!-- end of linkedin retargetting ads script --> </html>

Pages: 1 2 3 4 5 6 7 8 9 10