Slide 1

Slide 1 text

Training @BradBroulik BradBroulik.blogspot.com BradBroulik@gmail.com Express Slides: bit.ly/training-jqm

Slide 2

Slide 2 text

No hoax, two days of live jQuery Mobile training with real problems and real solutions! http://www.flickr.com/photos/42757699@N04/5215096404/

Slide 3

Slide 3 text

•Name •Company •Background •Why are you learning jQuery Mobile? Introductions

Slide 4

Slide 4 text

Agenda Day 1 Day 2 •The jQuery Mobile advantage •Getting Started with jQuery Mobile •Grab the code •Getting up and running •Single-page template •Multi-page template •Ajax navigation •Transitions •Buttons •Header buttons •Exercise #1: Creating a Disney mobile site ! ! •Segmented control •Toolbars •Tab bars •Popups •Lists •Basic list •Inset list •List dividers •List with thumbnails •List with icons •List with split buttons •List badges (count bubbles) •List filtering •Fixed lists •Dynamic lists •Exercise #2: Creating a list of Disney Parks •Forms •Select menu •Radio buttons •Checkboxes •Flipswitch •Switch •Grids •Basic grids •Multi-row grids •Uneven grids Collapsible content blocks Collapsible content sets •Themes •List example •Themeroller •Theme defaults and inheritance •Exercise #3: Creating a custom theme ! •Configuring jQuery Mobile •jQuery Mobile methods •jQuery Mobile events diagram •What’s new in jQuery Mobile 1.3 •Exercise #4: Sliding drawer & responsive grid •Responsive Patterns •Performance tips •Debugging •Maps integration •Client-side Twitter integration •Backbone and Require.JS •PhoneGap •Bar and Pie Charts

Slide 5

Slide 5 text

“A UI framework for building cross-platform Mobile Web applications” “With a single jQuery Mobile codebase we can create a unified user experience for nearly all mobile devices” jQ uery M obile 1.3 5

Slide 6

Slide 6 text

Simplify the journey http://i132.photobucket.com/albums/q24/BluSky07/MOBILE%20GAMES%202/OregonTrailv321.png 6

Slide 7

Slide 7 text

One codebase... CSS3 7

Slide 8

Slide 8 text

no device customer left behind iOS Android Blackberry Windows WebOS Meego Kindle Nook Desktop Bada 8

Slide 9

Slide 9 text

Simplified Markup-Driven Development !

Page Header

!

Hello jQuery Mobile!

!

Page Footer

9

Slide 10

Slide 10 text

Unified User Interface 10

Slide 11

Slide 11 text

A-Grade experience C-Grade experience Progressive Enhancement 11

Slide 12

Slide 12 text

Responsive Design 12

Slide 13

Slide 13 text

Portrait Landscape Responsive Forms 13

Slide 14

Slide 14 text

Default Theme Alternate Theme Themable Styling 14

Slide 15

Slide 15 text

Accessible 15

Slide 16

Slide 16 text

16

Slide 17

Slide 17 text

http://www.flickr.com/photos/wongdood/3379046643/sizes/z/in/photostream/ Getting Started in 60 seconds 17

Slide 18

Slide 18 text

Build a page #1 !

Movies

! 18

Slide 19

Slide 19 text

Add jQuery Mobile #2 ! Step Two - Add jQuery Mobile CDN repository or download via jquerymobile.com/download 19

Slide 20

Slide 20 text

Enhance: data- attributes #3 !

Movies

! 20

Slide 21

Slide 21 text

More enhancements... 21 !

Slide 22

Slide 22 text

Add theming and branding !

Movies

! 22

Slide 23

Slide 23 text

Learning jQuery Mobile step-by-step 23 1) Learn the jQuery Mobile data-attributes and CSS 2) Learn to configure jQuery Mobile 3) Learn the jQuery Mobile events

Slide 24

Slide 24 text

Download code: http://bit.ly/training-jqm-code Grab the code 24 Download and run local Run anywhere: http://bit.ly/training-jqm-run Run anywhere

Slide 25

Slide 25 text

Getting up and Running 25 Example: ch2/template.html Book: p13 IMPORTANT: The sequence of the CSS and JavaScript files must appear in the order as listed in template.html. The order is necessary to properly initialize the dependencies before they are referenced by jQuery Mobile.

Slide 26

Slide 26 text

Single-page template 26 Book: p190

Page Header

!

Hello jQuery Mobile!

!

Page Footer

Slide 27

Slide 27 text

Multi-page template 27 !

Multi-Page

! Contact Us
!

Contact Us

!
Contact information...
! Example: ch2/multi-page.html Book: p18

Slide 28

Slide 28 text

28 Example: ch2/prefetch.html Book: p20 Single-page + prefetch TIP: We can asynchronously load pages into the DOM by adding the data-prefetch=”true” attribute on any link. The prefetched links will get loaded in the background after the active page is shown. !

Prefetch

! Contact Us !

Slide 29

Slide 29 text

Single-page versus Multi-page 29 TIP: In most cases it is recommended to leverage the single-page model and dynamically append popular pages to the DOM in the background. We can achieve this behavior by adding the data-prefetch attribute to any link we want to dynamically load: ! ! This hybrid approach allows us to selectively choose which links we want to load and cache. Again, this pattern is only recommended for pages that are accessed very frequently because this behavior will trigger an additional HTTP request to load the page dynamically Book: p20

Slide 30

Slide 30 text

Ajax navigation 30 Example: ch2/hijax.html Book: p21 TIP: By default, all pages are loaded via Ajax. This behavior can be disabled: $.mobile.ajaxEnabled = false; NOTE: The “from” and “to” page will both be cached in the DOM to enable transitions.

Slide 31

Slide 31 text

Step 1, tap the button to navigate to another page Ajaxified Navigation 31

Slide 32

Slide 32 text

Step 2, framework loads the next page side-by-side Ajaxified Navigation 32

Slide 33

Slide 33 text

Ajaxified Navigation Step 3, framework transitions to next page 33

Slide 34

Slide 34 text

Ajaxified Navigation Step 4, transition complete 34

Slide 35

Slide 35 text

External links are loaded without Ajax 35 IMPORTANT: Ajax navigation will not be used for situations where you load an external link: 
 HomeHome Under these conditions, normal HTTP request processing will occur. Furthermore, CSS transitions will not be applied. As mentioned earlier, the framework is able to achieve smooth transitions by dynamically loading the "from" and "to" pages into the same DOM and then applying a smooth CSS transition. Without Ajax navigation the transition will not appear as smooth and the default loading message will not be shown during the transition.

Slide 36

Slide 36 text

A multi-page can’t be loaded via Ajax 36 IMPORTANT: When linking to a page that contains multiple pages, you must add rel="external" to its link. Home Home This will perform a full-page refresh. It is required because jQuery Mobile cannot load a multi-page document into the DOM of an active page. It would cause a namespace collision with how jQuery Mobile leverages the URL hash (#). jQuery Mobile leverages the hash value to identify internal pages within a multi-page document. However, there is a plugin available to make this possible: https://github.com/ToddThomson/jQuery-Mobile-Subpage-Widget

Slide 37

Slide 37 text

Transitions 37 Examples: •ch2/transitions.html •bonus/config/transitions/ios.html Book: p25 TIP: You can set a “backward” transition by adding data-direction=”reverse” to your links. For instance, a reverse transition is applied by default when transitioning back in history. However, if you have a “home” link on your header you will need to apply the data-direction=”reverse” attribute otherwise the default “forward” effect would occur: ! slide

Slide 38

Slide 38 text

Buttons 38 Examples: • ch4/link-buttons.html • ch4/form-buttons.html • ch4/image-buttons.html • ch4/icon-buttons-standard.html • ch4/icon-only-buttons.html • ch4/icon-positioning.html • ch4/icon-buttons-custom.html • ch4/dynamic-buttons.html (optional) Book: p64 TIP: If you want buttons to sit side-by-side and consume the entire width of the screen, us a 2-column grid. We will explore flexible grid layouts in more detail tomorrow. TIP: The image src for the custom button icon was loaded with the data URI scheme. This can be a performant alternative to loading small images externally because we eliminate an HTTP request: background: url(data:image/png;base64,iVBORw0KG...);

Slide 39

Slide 39 text

Header buttons 39 Example: ch3/header-buttons.html Book: p42 TIP: If you want to disable the automatic initialization of buttons or any other control, you may add the data-role=”none” attribute to the element and jQuery Mobile will not enhance the control:
 Button element TIP: To fix a truncated header see ch3/truncation-fixed.html

Slide 40

Slide 40 text

1) Create the Disney site as shown in the wireframes above. 2) Link the “Disney Parks” button to the “Disney parks coming soon...” page on the right using a “slide” transition. 3) Add a home icon in the header that links (reverse transition) back to the home page. 4)The solution for the exercise can be found at bonus/exercises/ex1/index.html. Exercise #1 - Disney mobile site 40

Slide 41

Slide 41 text

Segmented control 41 Example: ch3/header-segmented-control.html Book: p45 NOTE: This example uses a multi-page template. What page is shown first in a multi-page template?

Slide 42

Slide 42 text

Toolbars 42 Examples: •ch3/toolbar-icons-standard.html •ch3/toolbar-segmented-control.html Book: p53 TIP: For custom icons see http:/ /glyphish.com/. The next slide shows an example of how to attach custom icons to a toolbar or tab bar button.

Slide 43

Slide 43 text

Tab bars 43 Examples: •ch3/tabbar-icons-standard.html •ch3/tabbar-icons-custom.html Book: p56 CAUTION: jQuery Mobile is an excellent framework for building applications that display responsively across mobile, tablet, and desktop browsers. While the header and footer components provide a "native" feel on mobile devices they translate poorly when viewed on the desktop. If your jQuery Mobile application is targeted for a diverse set of browser sizes you may prefer to omit the header and footer components. As an alternative, you may find it more beneficial to add custom header or footer markup directly within the content section.

Slide 44

Slide 44 text

Popups 44 Examples: •ch2/alert.html •ch2/dialog.html •bonus/popups/popup1.html •bonus/popups/popup2.html Usecases: •alerts •dialogs •tooltips •menus •forms •anything...

Slide 45

Slide 45 text

Basic List 45 Example: ch5/list-basic.html Book: p107

Slide 46

Slide 46 text

Inset List 46 Example: ch5/list-inset.html Book: p108

Slide 47

Slide 47 text

List dividers 47 Example: ch5/list-dividers.html Book: p109 TIP: Auto dividers (data-autodividers=”true”) is a new feature in JQM 1.2.

Slide 48

Slide 48 text

List with thumbnails 48 Example: ch5/list-thumbnails.html Book: p111

Slide 49

Slide 49 text

List with icons 49 Example: ch5/list-icons.html Book: p112
  • Go See It!

  • .ui-li-icon { max-width:16px; max-height:16px; }

    Slide 50

    Slide 50 text

    List with split buttons 50 Example: ch5/list-split-buttons.html Book: p113

    Slide 51

    Slide 51 text

    • Thanks for the review.

      1 day
    List badges 51 Example: ch5/list-badges.html Book: p117

    Slide 52

    Slide 52 text

    List filtering 52 Example: ch5/list-filter.html Book: p118

    Slide 53

    Slide 53 text

    Fixed lists 53 Example: bonus/lists/fixed-list.html

    Slide 54

    Slide 54 text

    Dynamic lists 54 Examples: •ch5/dynamic-lists.html •bonus/maps/map.html (show more button) Book: p121

    Slide 55

    Slide 55 text

    1)Create a listing of Disney Parks as shown above. The image icons are available in bonus/ exercises/ex2/images. 2)The solution for the exercise can be found at bonus/exercises/ex2/index.html. Exercise #2 - Disney Parks List 55

    Slide 56

    Slide 56 text

    Keyboard sensitive input types 56 Examples: •ch4/text-input.html •ch4/dates.html Book: p79

    Slide 57

    Slide 57 text

    Forms 57 Examples: •ch4/form-request.html •ch4/native.html Book: p77 TIP: Prefer to disable Ajax on all form submissions (data-ajax=”false”) because Ajax does not play well with the POST/Redirect/GET (double-submit) pattern.

    Slide 58

    Slide 58 text

    Calendar 58 Example: •bonus/plugins/datebox/calbox.html NOTE: The DateBox API and documentation can be found at http:/ /dev.jtsage.com/jQM-DateBox2/ // blackout days > 365 TIP: The original size of the day buttons were 30 X 36 px. I increased them to 40 X 40 px to make them more touch friendly.

    Slide 59

    Slide 59 text

    Select menu 59 Examples: •ch4/select-menu-native.html •ch4/select-menu-custom.html •ch4/dynamic-select-menu.html Book: p83 TIP: Prefer native select menus for best performance. TIP: Prefer custom select menus when you want your users to select multiple otptions (select-menu-custom.html).

    Slide 60

    Slide 60 text

    Radio buttons 60 Examples: •ch4/radio-buttons.html •ch4/dynamic-radio-buttons.html Book: p90 Caution: Horizontal radio buttons or checkboxes will wrap if their container is not wide enough to display them on a single row. You may reduce their font size if wrapping is an issue: .ui-controlgroup-horizontal .ui-radio label {font-size: 13px !important;}

    Slide 61

    Slide 61 text

    Checkboxes 61 Examples: •ch4/checkboxes.html •ch4/dynamic-checkboxes.html Book: p94 TIP: To hide labels in an accessible way attach the ui-hidden-accessible style to the element. For instance, we applied this technique to the search field. This will gracefully hide the label while preserving 508 compliance: ! Search

    Slide 62

    Slide 62 text

    Flipswitch 62 Examples: •ch4/slider.html •ch4/dynamic-slider.html Book: p96

    Slide 63

    Slide 63 text

    Switch 63 Examples: •ch4/switch-control.html •ch4/dynamic-switch-control.html Book: p99 TIP: When building forms it is recommended to semantically associate each form field with its corresponding label. The label's for attribute and the input's id attribute establish this relationship: First name: This association creates 508-compliant applications that are accessible to assistive technologies. Accessibility is often required by government or state agencies. You can test your mobile application for compliance with the WAVE3 tool (see http:/ /wave.webaim.org/).

    Slide 64

    Slide 64 text

    Basic grids 64 Examples: •ch6/grid-2col.html •ch6/grid-3col.html •ch6/grid-4col.html •ch6/grid-5col.html Book: p125
    Block A
    Block B
    Grid Template:

    Slide 65

    Slide 65 text

    Multi-row grids 65 Example: ch6/grid-multi-row.html Book: p132 NOTE: Emoji icons are a performant alternative to images because they consume zero HTTP requests and their payload is only a few characters of text. Unfortunately, Emoji icons are currently only supported in iOS. Data URIs are a platform neutral alternative.

    Slide 66

    Slide 66 text

    Uneven grids 66 Example: ch6/grid-uneven.html Book: p133

    Slide 67

    Slide 67 text

    Collapsible content blocks 67 Example: ch6/collapsible-block.html Book: p136 TIP: Collapsible content blocks have several advantages when compared to an inline page structure. First, we can collapse content into segmented groups to make them all visible within a single view. And secondly, our users will be more efficient because we have eliminated scrolling from the user experience.

    Slide 68

    Slide 68 text

    Collapsible content sets 68 Example: ch6/collapsible-set.html Book: p140 NOTE: A collapsible block allows you to have many blocks expanded or collapsed at once. Collapsible sets only allow one segment open at a time.

    Slide 69

    Slide 69 text

    Themes 69 Examples: •ch7/theme-list1.html •ch7/theme-list2.html Book: p147 TIP: If you plan to style your entire jQuery Mobile application with custom themes it is recommended to use the structure-only CSS file from jQuery Mobile’s download site (http:/ /jquerymobile.com/download). This is a lightweight alternative for applications that do not need the default themes and it simplifies the management of the custom themes.

    Slide 70

    Slide 70 text

    Themeroller 70 Example: jquerymobile.com/themeroller.html Book: p164

    Slide 71

    Slide 71 text

    Theme defaults & inheritance 71 Examples: •ch7/theme-defaults.html •ch7/theme-inheritance.html Book: p153 NOTE: All components will inherit the theme of the page container. The page defaults to the “ a” theme.

    Slide 72

    Slide 72 text

    Themes and min-height 72 Example: ch7/min-height.html Book: p158 TIP: By default, the minimum height of the content container will only stretch the height of the components inside. This is an issue when the theme of the content is different than the theme of its page container. We can remedy this issue with CSS. For instance, we can set the minimum height of our content container to the height of the screen (see min-height.html): .ui-content { min-height:inherit; }

    Slide 73

    Slide 73 text

    Open bonus/exercises/ex3/index.html. Create a custom “red” theme for dangerous actions (delete buttons). When complete, the solution should appear as shown above. In Themeroller, complete the following tasks: 1) Import the existing custom-theme.css file. 2) Create a new red color for the “c” swatch. 3) Export the new theme, import it into your exercise and set the new red swatch for all dangerous buttons. 4) The CSS solution for the exercise can be found at bonus/exercises/ex3/css/custom-theme- solution.css Exercise #3 - Creating a custom theme 73

    Slide 74

    Slide 74 text

    Configuring jQuery Mobile 74 Example: ch8/config.html Book: p171 Online: http://api.jquerymobile.com/global-config/ $(document).on("mobileinit", function(){ $.mobile.ajaxEnabled = false; // Disable ajax $.mobile.defaultPageTransition = "slide"; $.mobile.loader.prototype.options.text = "Loading..."; }); TIP: To load scripts dynamically by page see bonus/config/js/load-scripts-dynamically.js TIP: To manually remove cached pages from the DOM see bonus/config/js/backbone.js

    Slide 75

    Slide 75 text

    $.mobile API 75 ! ! ! $( "#changePage" ).on( "click", function() { // Create page markup var newPage = $("<div data-role=header><h1>Hi</h1></div>Hello Again!"); // Add page to page container newPage.appendTo( $.mobile.pageContainer ); // Enhance and open new page $( “body”).pagecontainer( “change”, newPage ); });

    Slide 76

    Slide 76 text

    jQuery Mobile methods 76 Examples: ch8/changePage-dynamic.html Book: p176 Online: http://api.jquerymobile.com/category/methods/ .pagecontainer( “change” #page);! .pagecontainer( “load” “page.html”);! $.mobile.loading( “show” );! $.mobile.path.parseUrl();! .pagecontainer( “getActivePage” );

    Slide 77

    Slide 77 text

    pagebeforechange pagecontainerbeforeload pagebeforecreate Load page Page enhancements pagecreate DOM “Ready” pagecontainerload pagecontainerbeforeshow Page transition pagecontainershow pagechange Triggered on document Triggered on page Triggered on page container mobileinit pagecontainertransition pagecontainerbeforetransition No Page transition pagebeforecreate Page enhancements pagecreate DOM “Ready” pagebeforechange pagebeforechange pagecontainerbeforetransition pagecontainerbeforehide pagecontainerbeforeshow pagechange pagecontainertransition pagecontainerhide pagecontainershow Complete Yes Setup config settings Complete Change Page Is cached ! page? Change Page Events diagram

    Slide 78

    Slide 78 text

    Panels (sliding drawer) 78 jQ uery M obile 1.3 Example: bonus/1.3/panel.html

    Slide 79

    Slide 79 text

    Responsive tables 79 jQ uery M obile 1.3 Examples: bonus/1.3/responsive-reflow-custom.html bonus/1.3/responsive-reflow-default.html

    Slide 80

    Slide 80 text

    Responsive tables 80 jQ uery M obile 1.3 Examples: bonus/1.3/responsive-column-custom.html bonus/1.3/responsive-column-default.html

    Slide 81

    Slide 81 text

    Responsive grids 81 jQ uery M obile 1.3 Examples: bonus/1.3/responsive-grid-custom.html bonus/1.3/responsive-grid-default.html

    Slide 82

    Slide 82 text

    jQ uery M obile 1.3 Auto dividers Example: bonus/1.3/auto-dividers.html 82

    Slide 83

    Slide 83 text

    Listview auto-complete jQ uery M obile 1.3
      Examples: •bonus/1.3/listview-autocomplete-local.html •bonus/1.3/listview-autocomplete-remote.html 83

    Slide 84

    Slide 84 text

    File input support jQ uery M obile 1.3 Example: •bonus/1.3/file-input.html 84

    Slide 85

    Slide 85 text

    More new features... jQ uery M obile 1.3 Dual range slider data-clear-btn=”true” New icons •New demo & API sites •jQuery 1.9.1 (and 2.0.0) support 85

    Slide 86

    Slide 86 text

    1)Add a sliding drawer to your existing Disney home page. The drawer will contain the navigational menu for the site. 2)Add a two-column responsive grid to your existing Disney home page. These two blocks will contain promotional text with an optional image. 3)The solution for the exercise can be found at bonus/exercises/ex4/index.html. Ex #4 - Sliding drawer & responsive grid 86

    Slide 87

    Slide 87 text

    Responsive Patterns Nested doll Bento box Ajax-include Append around Picturefill 87

    Slide 88

    Slide 88 text

    Responsive images (Picturefill) Scott Jehl: https://github.com/scottjehl/picturefill 88

    Slide 89

    Slide 89 text

    Responsive nested doll pattern 89

    Slide 90

    Slide 90 text

    Responsive bento box pattern 90

    Slide 91

    Slide 91 text

    Ajax include pattern http://filamentgroup.com/lab/ajax_includes_modular_content/ NOTE: Technology articles are only loaded when min-width: 30em NOTE: Entertainment articles are lazy loaded after page load 91

    Slide 92

    Slide 92 text

    http://www.flickr.com/photos/oddne/3838032598/sizes/l/in/photostream/ How can we gain a performance advantage?

    Slide 93

    Slide 93 text

    Prefer Native jQuery Mobile Widgets Custom message box adds overhead Native inset list uses 80% less CSS! Compatible across all browsers! Simplifies maintenance! 93

    Slide 94

    Slide 94 text

    Remove Unused Themes ! Custom Theme jQuery Mobile’s structure file without default theme 94

    Slide 95

    Slide 95 text

    Remove Unused Plugins Download Builder •grid •navbar •select •slider •textinput •transitions •checkboxradio •collapsible •collapsibleset •controlgroup •fieldContain •fixedToolbar http://jquerymobile.com/download-builder/ 95

    Slide 96

    Slide 96 text

    Cache highly accessed read-only pages

    Popular Page

    !
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur hendrerit nisl et tortor tincidunt mattis.
    96

    Slide 97

    Slide 97 text

    Prefer the CDN-hosted resources CDN Hosted minified and gzipped jQuery Mobile files Example: bonus/config/https/https-template.html 97

    Slide 98

    Slide 98 text

    Performance Analysis Tools http://developer.yahoo.com/yslow/mobile http://blaze.io/mobile 98

    Slide 99

    Slide 99 text

    Performance tuning 99 Chrome developer tools Safari Web Inspector

    Slide 100

    Slide 100 text

    Debugging 100 Chrome Remote Debugging Safari Remote Web Inspector

    Slide 101

    Slide 101 text

    Maps integration 101 Examples: •ch9/maps.html (Google) •bonus/maps/map.html (Google) •bonus/maps/bing/maps.html (Bing) Book: p222 NOTE: Nearly 75% of Web developers use Geolocation, making it the most popular HTML5 API.

    Slide 102

    Slide 102 text

    Client-side Twitter integration 102 Example: ch9/reviews.html Book: p202 TIP: To view all the data elements that are available from Twitter's search API, launch this string in your browser: “http:/ /search.twitter.com/ search.json?q=xmen”. This is the basic search API where the value of the “q” parameter is our searchable keyword(s). In this case, we are searching Twitter for any tweets with the keyword “xmen” in them.

    Slide 103

    Slide 103 text

    Client-side RSS integration 103 Example: bonus/rss/rss.html NOTE: Most social media sites have a public API for accessing their data: Twitter: http:/ /dev.twitter.com LinkedIn: http:/ /developer.linkedin.com/rest Facebook: http:/ /developers.facebook.com

    Slide 104

    Slide 104 text

    In this demo we show you how to: • Use backbone and require.js for client-side MVC integration. • How to use the multi-page template to load all pages in a single request. • How to load data from Twitter's Restful API. • How to cache the Twitter resultset in localStorage. Backbone and Require.JS 104

    Slide 105

    Slide 105 text

    105 + =

    Slide 106

    Slide 106 text

    Bar and pie charts 106 Examples: •bonus/charts/bar.html •bonus/charts/pie-chart.html (Google) •bonus/charts/visualize/pie.html •bonus/charts/server/pie.html

    Slide 107

    Slide 107 text

    Inspiration 107 jqmgallery.com

    Slide 108

    Slide 108 text

    Resources 108 • @jquerymobile • #jquerymobile

    Slide 109

    Slide 109 text

    You have safely arrived at your destination http://i132.photobucket.com/albums/q24/BluSky07/MOBILE%20GAMES%202/OregonTrailv321.png

    Slide 110

    Slide 110 text

    Thank You! @BradBroulik BradBroulik.blogspot.com Slides: bit.ly/training-jqm