Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-manipulation-dom-objects-using-firebug
Packt
16 Apr 2010
3 min read
Save for later

Manipulation of DOM Objects using Firebug

Packt
16 Apr 2010
3 min read
Inspecting DOM The DOM inspector allows for full, in-place editing of our document structure, not just text nodes. In the DOM inspector, Firebug auto completes property value when we press the Tab key. The following are the steps to inspect an element under the DOM tab: Press Ctrl+Shift+C—the shortcut key to open Firebug in inspect mode. Let's move the mouse pointer over the HTML element that we want to inspect and click on that element. The HTML script of that element will be shown in Firebug's HTML tab. Right-clicking on the selected DOM element will open a context menu. Let's select the Inspect in DOM Tab option from the context menu. As soon as we do that, Firebug will take us to its DOM tab. Filtering properties, functions, and constants Many times we want to analyze whether a function written by us is associated with an HTML element. Firebug provides us an easy way to figure out whether an event, listener, function, property, or constants are associated with a particular element. The DOM tab is not only a tab but also a drop-down menu. When we click on the down arrow icon on the DOM tab, Firebug will show a drop-down list from which one can select the filtering options and inspect the element thoroughly. The following are the options provided by this menu: Show User-defined Properties Show User-defined Functions Show DOM Properties Show DOM Functions Show DOM Constants Refresh There are two kinds of objects and functions: Part of the standard DOM Part of our own JavaScript code Firebug can notify the difference, and shows us our own script-created objects and functions in bold at the top of the list. The text that is bold and green is a user-defined function. The text that is bold and black is a user-defined property. The text whose size is normal and is green in color is a DOM-defined function. The text whose size is normal and is black in color is a DOM-defined property. The upper case letters (capital letters) are the DOM constants. We can see the actual colored depiction in Firebug's DOM tab. In the following code, the onkeyup() event is a user-defined function for <input/> and calculatefactorial() is a user-defined function for the current window. To test this code, let's type the code in an HTML file, open it with Firefox, and enable Firebug by pressing the F12 key. Inspect the input element in the DOM. <html><head><script>function calculateFactorial(num,event){if(event.keyCode!=13){return;}var fact=1;for(i=1;i<=num;i++){fact*=i;}alert ("The Factorial of "+ num + " is: " +fact)}</script><title>code_6_1.html.html</title></head><body><font face="monospace">Enter a number to calculate its factorial<input type = "text" name="searchBox" onkeyup="calculateFactorial(this.value,event)"/></font></body></html> Intuitive DOM element summariesThere are many different kinds of DOM and JavaScript objects, and Firebug does its best to visually distinguish each, while providing as much information as possible. When appropriate, objects include brief summaries of their contents so that we can see what's there without having to click. Objects are color coded so that HTML elements, numbers, strings, functions, arrays, objects, and nulls are all easy to distinguish.
Read more
  • 0
  • 0
  • 3508

article-image-basic-routing-expressjs
Antonio Cucciniello
08 Feb 2017
6 min read
Save for later

Basic Routing with Express.js

Antonio Cucciniello
08 Feb 2017
6 min read
Want an easy way to have a few routes in your Node.js web application? If you answered yes, you willunderstand how to do exactly that by the end of this post. But first, what is routing? In simple terms, it is how an application is told to respond to a client on a specific endpoint. An endpoint is basically a path or URI and one of the HTTP request methods (GET, POST, and so on). Express is a Node.js framework that allows you to help organize your web applications on the server side. It is one of the most popular node packages and many of the other popular packages on NPM are built using Express. So, today we are going to learn how to use this in our web app! This tutorial assumes that you have Node installed; if you do not, visit this link. Install and Setup The first step is to setup your environment. Make sure that you create a new project directory for this sample app using the following: $ mkdir basic-routing-example I will be using basic-routing-example, but you can use whatever name you would like. Enter that directory using this: $ cd basic-routing-example Now that you are in that directory, create a file called server.jsfor our code. This is the entry point of our application. Now, you need to install the Express.js package with the following command: $ npm install express --save Then, if you are familiar with Node.js development, we need to create a package.json file using this command: $ npm init Now that you are all setup to use Express, it's time to start coding! Code Open the server.js file we created earlier and start editing it by adding this to the top of your file: const express = require('express') const app = express() var port = 3000 The first line allows us to use the Express.js package in our code. The second line creates a variable called app that is an instance of Express. This is how we will access the functionalities of Express. We then create a variable called port to store the port the server will listen on when it is started. Then below our variables, add this: app.get('/', function (req, res) { res.send('This is our home page!') }) app.listen(port, function () { console.log('We are listening on port ' + port) }) The first bit here is our first example of handling a route. It says that we would like to handle a HTTP GET request method on the route /, which in this case is the homepage of our web application. If there is a GET request to the route /, then it will handle it by calling the callback function specified. So upon receiving a GET request, it will send a response to the page with the text This is our home page!. In order to get this to show, we need to have our server listen on a port. We do that with the second bit of code: app.listen(). To test that you have handled this request properly, save the file, and in the command line enter,$ node server.js. The command line should outputWe are listening on port 3000. Then, go to your web browser and go tothe pagelocalhost:3000. Here is a sample image of what you should see on that page:   GET_reqImage Now, let's test this with a second web page for your web application. Suppose you had an About page as part of your site. The route you would want for this page would be /about. Let's see how we would handle a GET Request to that page: app.get('/about', function (req, res) { res.send('This is a basic app with routing in express') }) This is similar to how we handled the GET request for the home page route of /. Here, we change the route to /about to specify the About page of our application and we change how we would like to handle it by changing the message being sent in with res.send(). Now, let's test to see if this works by saving our file, running it with: $ node server.js, and then opening up a web browser and going to the URLlocalhost:3000/about. This image is what your webpage should look like:   GET_aboutImage Let's say you wanted to handle another request such as a POST request. We would add the following code to our application: app.post('/', function (req, res) { res.send('we got a POST req from the client') }) This handles a POST request on the route /. To make this fully functional, we would have to go out of the scope of this tutorial, but this is simply an example of how you would handle a different type of HTTP request for a route. Now, what if you had multiple types of HTTP request methods that need to be handled for one route? We could use app.route(). Remove the code for app.get('/') and app.post('/') handlers and add this following code snippet: app.route('/') .get(function (req, res) { res.send('This is our home page!') }) .post(function (req, res) { res.send('we got a POST req from the client') }) This allows us to handle multiple types of HTTP requests for one specific route. In this case, the route is /, and it has a handler for a GET and POST request. Conclusion You made it! You now have a simple web app that can handle different HTTP request methods on different routes. Here is a high-level overview of what we did here: We installed Express.js. Created an instance of Express called appin our code. Used that instance to handle multiple routes. Used that instance to handle different types of HTTP requests. Learned how to use app.route() to simplify handling of HTTP requests for one route. If you enjoyed this post, share it on twitter. Check out the code for this tutorial on GitHub. About the Author Antonio Cucciniello is a software engineer with a background in C, C++, and Javascript (Node.Js) from New Jersey. His most recent project called Edit Docs is an Amazon Echo skill that allows users to edit Google Drive files using theirvoice. He loves building cool things with software and reading books on self-help and improvement, finance, and entrepreneurship. You can find Antonio on Twitter @antocucciniello and on GitHub.
Read more
  • 0
  • 0
  • 3507

article-image-text-search-your-database-or-solr
Packt
30 Nov 2009
6 min read
Save for later

Text Search, your Database or Solr

Packt
30 Nov 2009
6 min read
Text Search Features If you think that text search is just a basic thing and nothing more than returning results that matched words in a user query, then think again! There are many technical details that a good search implementation will give you control over to affect how well this fundamental capability works, like text analysis and relevancy ranking. But there are also a variety of ancillary features to look for that make a big difference such as result highlighting and faceting. Text analysis: This is the processing of the original text into indexed terms, and there's a lot to it. Being able to configure the tokenization of words could mean that searching for “Mac” will be found if the word “MacBook” is in the text. And then there's synonym processing so that users can search for similar words. You might want both a common language dictionary and also hand-picked ones for your data. There's the ability to smartly handle desired languages instead of the pervasive English. And then there's stemming which normalizes word variations so that for example “working” and “work” can be indexed the same. Yet another variation of text analysis is phonetic indexing to find words that sound-like the search query. Relevancy ranking: This is the logic behind ranking the search results that closest match the query. In Lucene/Solr, there are a variety of factors in an overall equation with the opportunity to adjust factors based on matching certain fields, certain documents, or using field values in a configurable equation. By comparison, the commercial Endeca platform allows configuration of a variety of matching rules that behaves more like a strict sort. Query features & syntax: From boolean logic to grouping to phrases to fuzzy-searches, to score boosting... there are a variety of queries that you might perform and combine. Many apps would prefer to hide this from users but some may wish to expose it for “advanced” searches. Result highlighting: Displaying a text snippet of a matched document containing the matched word in context is clearly very useful. We have all seen this in Google. Query spell correction (i.e. “did you mean”): Instead of unhelpfully returning no results (or very few), the search implementation should be able to try and suggest variation(s) of the search that will yield more results. This feature is customarily based on the actual indexed words and not a language dictionary. The variations might be based on the so-called edit-distance which is basically the number of alterations needed, or it might be based on phonetic matching. Faceted navigation: This is a must-have feature which enables search results to include aggregated values for designated fields that users can subsequently choose to filter the results on. It is commonly used on e-commerce sites to the left of the results to navigate products by various attributes like price ranges, vendors, etc. Term-suggest (AKA search auto-complete): As seen on Google, as you start typing a word in the search box, it suggests possible completions of the word. These are relevancy sorted and filtered to those that are also found with any words prior to the word you are typing. Sub-string indexing: In some cases, it is needed to match arbitrary sub-strings of words instead of being limited to complete words. Unlike what happens with an SQL like clause, the data is indexed in such a way for this to be quick. Geo-location search: Given the coordinates to a location on the globe with records containing such coordinates, you should be able to search for matching records from a user-specified coordinate. An extension to Solr allows a radial based search with appropriate ranking, but it is also straight-forward to box the search based on a latitude & longitude. Field/facet suggestions: The Endeca search platform can determine that your search query matches some field values used for faceting and then offer a convenient filter for them. For example, given a data set of employees, the search box could have a pop-up suggestion that the word in the search box matches a department code and then offer the choice of navigating to those matching records. This can be easier and faster than choosing facets to filter on, especially if there are a great number of facet-able fields. Solr doesn't have this feature but it would not be a stretch to implement it based on its existing foundation. Clustering: This is another aid to navigating search results besides faceting. Search result clustering will dynamically divide the results into multiple groups called clusters, based on statistical correlation of terms in common. It is a bit of an exotic feature, but is useful with lots of results with lots of text information and after any faceted navigation is done if applicable. So that's quite a list and there are other features you may find too. This should give you a list of features to look for in whatever you choose. Some features are obviously more important to you than others. How NOT to implement text search: the SQL “like” clause Perhaps “back in the day” you implemented search by simply adding like “%searchword%” in the where clause of your SQL (the author is guilty as charged!) But of course, this has serious problems such as: It is very slow, especially given a data set of decent size and any amount of load on the server. A database does a simple brute-force search. There is no concept of relevancy (e.g. a match score). A record simply matched or not. You are forced to sort on one of your columns. It is too literal. Even if the search is case insensitive, any extra punctuation can screw it up, or it may match parts of words when you only wanted to match whole words. So the bottom line is don't do it! There are smarter approaches to this problem. Probably, the only situation you would do this is if you had a particular database column holding a limited number of short values and you have it indexed. Searches should go quickly and it's very easy to implement this approach.
Read more
  • 0
  • 0
  • 3506

article-image-how-use-jquery-mobile-grid-and-columns-layout
Packt
18 Jul 2011
6 min read
Save for later

How to Use jQuery Mobile Grid and Columns Layout

Packt
18 Jul 2011
6 min read
  jQuery Mobile First Look Discover the endless possibilities offered by jQuery Mobile for rapid Mobile Web Development Trying to communicate and provide information in an effective way can be a little trickier when we are targeting mobile devices; their screens are relatively small (ridiculously small if we think about our 24 inch iMac resting on our office desk), and we have already understood that we cannot display content in the way we used to, back in the days when desktop computers were the only way to access data on the Internet. With the advent of mobile browsing, new solutions had to be found. The jQuery Mobile framework provides a number of tools, widgets, and components which are extremely helpful in formatting our content and make it look elegant and put-together even on our beloved smaller-screen devices – well, especially for them! In fact, the difficulty in designing, formatting, and correctly showing a page on a mobile device is going to become a no-brainer using the set of elements jQuery Mobile provides in order to allow for an easy styling of our web application content. How content is displayed Yes, there is nothing wrong in just writing down what our website or web application is about in the HTML file. It's always worked and always will. The actual point here is taking advantage of the tools jQuery Mobile offers us to format our information, specifically for mobile devices. For example, there are occasions in which the need for multiple columns may arise: we can use a layout grid, which is nothing more than some CSS-based columns. Or, on a completely different note, we might just need to hide/show a block of content: collapsible blocks have been designed for this, and can be easily implemented in our site layout. But before we begin analyzing any of the methods in which we are able to format our content according to our liking, we should take a look at how content is displayed in its basic HTML formatting. Based upon the "light hand approach" (as they call it), jQuery Mobile lets the browser rendering take precedence over any other third-party styling, with exceptions made for the following little tweaks the framework applies to any page by default: Adding a bit of padding for a better readability Using the theming system to apply fonts and colors This particular approach to styling by default should make the designers really happy, as they often find themselves fighting with preset colors schemes, default fonts, weird margin, and padding values and usually end up resetting everything and starting again from scratch. Thankfully, the default padding value looks quite right and, as far as theming goes, we are able to easily customize (and create new) themes through CSS files and a theming framework which is extremely versatile and flexible. Default HTML markup styling So, what happens if we just write some HTML markup and want some text to be bold, emphasized, or hyper-linked? jQuery Mobile applies some basic styling to the elements and makes their look consistent with the simple and clean layout we have already seen in action. The following screenshot represents how headings and standard paragraphs are displayed and generated by the following code: <!DOCTYPE html> <html> <head> <title>Default HTML markup styling</title> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a2/ jquery.mobile-1.0a2.min.css" /> <script src="http://code.jquery.com/jquery-1.4.3.min.js"></script> <script src="http://code.jquery.com/mobile/1.0a2/jquery.mobile- 1.0a2.min.js"></script> </head> <body> <div data-role="page" id="home"> <div data-role="content"> <h1>H1 Heading</h1> <h2>H2 Heading</h2> <h3>H3 Heading</h3> <h4>H4 Heading</h4> <h5>H5 Heading</h5> <h6>H6 Heading</h6> <p>This is a paragraph. <strong>Lorem (bold)</strong> <em>ipsum (emphasized)</em> <a href="#">dolor (link)</a> sit amet, consectetur adipiscing elit.</p> <blockquote>Blockquote containing a <cite>cite</cite></ blockquote> <p>This is a paragraph. <strong>Lorem (bold)</strong> <em>ipsum (emphasized)</em> <a href="#">dolor (link)</a> sit amet, consectetur adipiscing elit.</p> </div> </div> </body> </html> The result is shown in the following screenshot: Similarly, the following code produces a preview of what lists and tables look like: <!DOCTYPE html> <html> <head> <title>Default HTML markup styling</title> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a2/ jquery.mobile-1.0a2.min.css" /> <script src="http://code.jquery.com/jquery-1.4.3.min.js"></script> <script src="http://code.jquery.com/mobile/1.0a2/jquery.mobile- 1.0a2.min.js"></script> </head> <body> <div data-role="page" id="home"> <div data-role="content"> <ul> <li>Unordered list item 1</li> <li>Unordered list item 2</li> <li>Unordered list item 3</li> </ul> <ol> <li>Ordered list item 1</li> <li>Ordered list item 2</li> <li>Ordered list item 3</li> </ol> <table> <caption>Table caption</caption> <thead> <tr> <th scope="col">Name</th> <th scope="col">City</th> <th scope="col">Phone</th> </tr> </thead> <tfoot> <tr> <td colspan="5">Table foot</td> </tr> </tfoot> <tbody> <tr> <th scope="row">David Green</th> <td>New York City, NY</td> <td>555-0123</td> </tr> <tr> <th scope="row">Martha White</th> <td>Los Angels, CA</td> <td>555-0188</td> </tr> <tr> <th scope="row">Bobby Brown</th> <td>Washington, D.C.</td> <td>555-0110</td> </tr> </tbody> </table> </div> </div> </body> </html>
Read more
  • 0
  • 0
  • 3506

article-image-qmail-quickstarter-virtualization
Packt
22 Oct 2009
6 min read
Save for later

Qmail Quickstarter: Virtualization

Packt
22 Oct 2009
6 min read
Generic Virtualization Framework The most straightforward mail handling in qmail is used for what are known as the local domains: those listed in the file. The users for these domains are all the same, and are typically the users defined in control/locals/etc/passwd, though they can be defined in users/assign as well (discussed in the Non-Virtual Non-System Users section). Qmail, however, has another sense in which an email can be local, which is to assign a domain to a user (or, more accurately, to a prefix). This feature is configured with the control/virtualdomains file. Power of the virtualdomains File The virtualdomains file is one of the most powerful, useful, and stunningly simple mechanisms for configuring qmail. Virtual domains and even virtual users can be created, independently of one another, and assigned to controlling users. Virtual domains are fully independent, and as they are assigned to users (or, more accurately, prefixes) they can be in different UNIX protection domains if desired. This file can also define virtual users and similarly assign them to controlling users. This file thus makes it both possible and easy to intercept specific addresses and do something special with them. Perhaps surprisingly for the power this file wields, the control/virtualdomains file is only slightly more complicated than similar control files, such as control/locals. Rather than a list of domains, the virtualdomains file is a list of patterns and their associated prefixes. The entries are of the form: matching-pattern: prefix Only one prefix is associated with each pattern. The matching pattern can be one of the following three things: a domain (that follows the same wildcarding semantics used in the control/rcpthosts file), an email address, or an empty string. The empty string is considered to match anything. An email address matches any message addressed to that email address, and a domain matches any message addressed to a user in that domain. If there are multiple possible matches, the longest match is used. Emails that match patterns listed in the control/virtualdomains file are considered to be local emails, similar to those addressed to domains in the control/locals file. Messages that match patterns in the virtualdomains file must first undergo a simple modification before delivery. While messages are prepared for delivery, if they have an envelope destination address that matches a pattern in the virtualdomains file, that destination address is prepended with the matching pattern's associated prefix. This turns the original local part of the address into an extension of the prepended user. In this way, a domain can be mapped to a user, giving that user full control over the mailboxes (or users) within that domain. The virtualdomains file can also be used to define exceptions to the matching rules, if the prefix is blank. It is important to note that the control/virtualdomains file is considered after the control/locals file, which means that if an email is addressed to a domain listed in locals, the virtualdomains file will not apply. Also, virtualdomains rewriting occurs before the mail is given to qmail-lspawn for delivery. This sounds complex, but is easy to understand with an example. Basic Virtual Domains An example virtualdomains file that demonstrates most of the file's features is as follows: example.com:foo.example.com:foo-bartwo.example.com:bazwaldo@domain.com:quxdomain.com::garply Presuming that the users mentioned i.e. foo, baz, qux, and garply are the only local users on this system; these lines cause the following results:      The first line matches any address ending in @example.com, such as user@example.com. Such a destination address will be rewritten as foo-user@example.com, ensuring that the email's delivery will be controlled by the local user named foo.      Messages addressed to user@something.example.com do not match the first line but do match the second line, and so will be delivered as if they had been addressed to foo-bar-user@something.example.com.      Because the virtualdomains file is used in a longest match wins manner, the third line (not the second) will match messages addressed to user@two.example.com. This destination will be rewritten asbaz-user@two.example.com and baz will control the delivery of such messages.      The fourth line specifies that email addressed to waldo@domain.com will be instead delivered as if it had been addressed to qux-waldo@domain.com. The qux user will control that delivery.      The fifth line specifies that any domain.com email—other than waldo@domain.com—should be treated as if had been listed in the domain.comcontrol/locals file.      Finally, the sixth line specifies that all other email will be rewritten and delivered to the local garply user. For example, email addressed to someone@somewhere.org will be rewritten as garply-someone@somewhere.org and delivery will be attempted locally. In this example, the foo user is essentially in charge of the entirety of the example.com domains. Users that are specific to example.com are defined by creating appropriately named .qmail files in foo's home directory. For example, to establish the standard postmaster@example.com address, foo would create a file named .qmail-postmaster in its home directory, containing the instructions for delivering postmaster's email. The foo user could also establish a address by creating a file named foo@example.com.qmail-foo in his or her home directory. In this way, once the example.com mapping has been established, the foo user can set up and maintain the users in the example.com domain without ever requiring further permission from or contact with the system administrator. It is worth pointing out that precisely who controls what can get more complex if real usernames have extension separator characters (a hyphen, by default) in them. For example, if the address postmaster@example.com is rewritten to be foo-postmaster@example.com, it is typically delivered according to the instructions in ~foo/.qmail-postmaster or, if that file does not exist, ~foo/.qmail-default. However, if there is a user named foo-postmaster, that user will receive email addressed to postmaster@example.com. If a .qmail file (such as ~foo/.qmail-postmaster) cannot be located for a given extension address (such as foo-postmaster@example.com), the alias user's directory is checked for .qmail files. Specifically, .qmail-foo-postmaster, .qmail-foo-default, and .qmail-default. If none of these files exist, the message is considered undeliverable and is bounced. Note that during delivery of such an email, the standard environment variables are defined per the rewritten destination rather than per the original address. For example, if a message addressed to postmaster@example.com is delivered using the example configuration, the affected environment variables will be defined as follows (assuming foo's home directory is /home/foo):   Environment Variable Content for Virtual Domain Delivery Content for Normal Delivery RECIPIENT foo-postmaster@example.com postmaster@example.com USER foo-postmaster postmaster LOCAL foo postmaster HOME /home/foo /home/postmaster HOST example.com example.com HOST2 example example HOST3 example example HOST4 example example EXT postmaster      
Read more
  • 0
  • 0
  • 3505

article-image-advanced-less-coding
Packt
09 Feb 2015
40 min read
Save for later

Advanced Less Coding

Packt
09 Feb 2015
40 min read
In this article by Bass Jobsen, author of the book Less Web Development Cookbook, you will learn: Giving your rules importance with the !important statement Using mixins with multiple parameters Using duplicate mixin names Building a switch leveraging argument matching Avoiding individual parameters to leverage the @arguments variable Using the @rest... variable to use mixins with a variable number of arguments Using mixins as functions Passing rulesets to mixins Using mixin guards (as an alternative for the if…else statements) Building loops leveraging mixin guards Applying guards to the CSS selectors Creating color contrasts with Less Changing the background color dynamically Aggregating values under a single property (For more resources related to this topic, see here.) Giving your rules importance with the !important statement The !important statement in CSS can be used to get some style rules always applied no matter where that rules appears in the CSS code. In Less, the !important statement can be applied with mixins and variable declarations too. Getting ready You can write the Less code for this recipe with your favorite editor. After that, you can use the command-line lessc compiler to compile the Less code. Finally, you can inspect the compiled CSS code to see where the !important statements appear. To see the real effect of the !important statements, you should compile the Less code client side, with the client-side compiler less.js and watch the effect in your web browser. How to do it… Create an important.less file that contains the code like the following snippet: .mixin() { color: red; font-size: 2em; } p { &.important {    .mixin() !important; } &.unimportant {    .mixin(); } } After compiling the preceding Less code with the command-line lessc compiler, you will find the following code output produced in the console: p.important { color: red !important; font-size: 2em !important; } p.unimportant { color: red; font-size: 2em; } You can, for instance, use the following snippet of the HTML code to see the effect of the !important statements in your browser: <p class="important"   style="color:green;font-size:4em;">important</p> <p class="unimportant"   style="color:green;font-size:4em;">unimportant</p> Your HTML document should also include the important.less and less.js files, as follows: <link rel="stylesheet/less" type="text/css"   href="important.less"> <script src="less.js" type="text/javascript"></script> Finally, the result will look like that shown in the following screenshot:  How it works… In Less, you can use the !important statement not only for properties, but also with mixins. When !important is set for a certain mixin, all properties of this mixin will be declared with the !important statement. You can easily see this effect when inspecting the properties of the p.important selector, both the color and size property got the !important statement after compiling the code. There's more… You should use the !important statements with care as the only way to overrule an !important statement is to use another !important statement. The !important statement overrules the normal CSS cascading, specificity rules, and even the inline styles. Any incorrect or unnecessary use of the !important statements in your Less (or CCS) code will make your code messy and difficult to maintain. In most cases where you try to overrule a style rule, you should give preference to selectors with a higher specificity and not use the !important statements at all. With Less V2, you can also use the !important statement when declaring your variables. A declaration with the !important statement can look like the following code: @main-color: darkblue !important; Using mixins with multiple parameters In this section, you will learn how to use mixins with more than one parameter. Getting ready For this recipe, you will have to create a Less file, for instance, mixins.less. You can compile this mixins.less file with the command-line lessc compiler. How to do it… Create the mixins.less file and write down the following Less code into it: .mixin(@color; @background: black;) { background-color: @background; color: @color; } div { .mixin(red; white;); } Compile the mixins.less file by running the command shown in the console, as follows: lessc mixins.less Inspect the CSS code output on the console, and you will find that it looks like that shown, as follows: div { background-color: #ffffff; color: #ff0000; } How it works… In Less, parameters are either semicolon-separated or comma-separated. Using a semicolon as a separator will be preferred because the usage of the comma will be ambiguous. The comma separator is not used only to separate parameters, but is also used to define a csv list, which can be an argument itself. The mixin in this recipe accepts two arguments. The first parameter sets the @color variable, while the second parameter sets the @background variable and has a default value that has been set to black. In the argument list, the default values are defined by writing a colon behind the variable's name, followed by the value. Parameters with a default value are optional when calling the mixins. So the .color mixin in this recipe can also be called with the following line of code: .mixin(red); Because the second argument has a default value set to black, the .mixin(red); call also matches the .mixin(@color; @background:black){} mixin, as described in the Building a switch leveraging argument matching recipe. Only variables set as parameter of a mixin are set inside the scope of the mixin. You can see this when compiling the following Less code: .mixin(@color:blue){ color2: @color; } @color: red; div { color1: @color; .mixin; } The preceding Less code compiles into the following CSS code: div { color1: #ff0000; color2: #0000ff; } As you can see in the preceding example, setting @color inside the mixin to its default value does not influence the value of @color assigned in the main scope. So lazy loading is applied on only variables inside the same scope; nevertheless, you will have to note that variables assigned in a mixin will leak into the caller. The leaking of variables can be used to use mixins as functions, as described in the Using mixins as functions recipe. There's more… Consider the mixin definition in the following Less code: .mixin(@font-family: "Helvetica Neue", Helvetica, Arial,   sans-serif;) { font-family: @font-family; } The semicolon added at the end of the list prevents the fonts after the "Helvetica Neue" font name in the csv list from being read as arguments for this mixin. If the argument list contains any semicolon, the Less compiler will use semicolons as a separator. In the CSS3 specification, among others, the border and background shorthand properties accepts csv. Also, note that the Less compiler allows you to use the named parameters when calling mixins. This can be seen in the following Less code that uses the @color variable as a named parameter: .mixin(@width:50px; @color: yellow) { width: @width; color: @color; } span { .mixin(@color: green); } The preceding Less code will compile into the following CSS code: span { width: 50px; color: #008000; } Note that in the preceding code, #008000 is the hexadecimal representation for the green color. When using the named parameters, their order does not matter. Using duplicate mixin names When your Less code contains one or more mixins with the same name, the Less compiler compiles them all into the CSS code. If the mixin has parameters (see the Building a switch leveraging argument matching recipe) the number of parameters will also match. Getting ready Use your favorite text editor to create and edit the Less files used in this recipe. How to do it… Create a file called mixins.less that contains the following Less code: .mixin(){ height:50px; } .mixin(@color) { color: @color; }   .mixin(@width) { color: green; width: @width; }   .mixin(@color; @width) { color: @color; width: @width; }   .selector-1 { .mixin(red); } .selector-2 { .mixin(red; 500px); } Compile the Less code from step 1 by running the following command in the console: lessc mixins.less After running the command from the previous step, you will find the following Less code output on the console: .selector-1 { color: #ff0000; color: green; width: #ff0000; } .selector-2 { color: #ff0000; width: 500px; } How it works… The .selector-1 selector contains the .mixin(red); call. The .mixin(red); call does not match the .mixin(){}; mixin as the number of arguments does not match. On the other hand, both .mixin(@color){}; and .mixin(@width){}; match the color. For this reason, these mixins will compile into the CSS code. The .mixin(red; 500px); call inside the .selector-2 selector will match only the .mixin(@color; @width){}; mixin, so all other mixins with the same .mixin name will be ignored by the compiler when building the .selector-2 selector. The compiled CSS code for the .selector-1 selector also contains the width: #ff0000; property value as the .mixin(@width){}; mixin matches the call too. Setting the width property to a color value makes no sense in CSS as the Less compiler does not check for this kind of errors. In this recipe, you can also rewrite the .mixin(@width){}; mixin, as follows: .mixin(@width) when (ispixel(@width)){};. There's more… Maybe you have noted that the .selector-1 selector contains two color properties. The Less compiler does not remove duplicate properties unless the value also is the same. The CSS code sometimes should contain duplicate properties in order to provide a fallback for older browsers. Building a switch leveraging argument matching The Less mixin will compile into the final CSS code only when the number of arguments of the caller and the mixins match. This feature of Less can be used to build switches. Switches enable you to change the behavior of a mixin conditionally. In this recipe, you will create a mixin, or better yet, three mixins with the same name. Getting ready Use the command-line lessc compiler to evaluate the effect of this mixin. The compiler will output the final CSS to the console. You can use your favorite text editor to edit the Less code. This recipe makes use of browser-vendor prefixes, such as the -ms-transform prefix. CSS3 introduced vendor-specific rules, which offer you the possibility to write some additional CSS, applicable for only one browser. These rules allow browsers to implement proprietary CSS properties that would otherwise have no working standard (and might never actually become the standard). To find out which prefixes should be used for a certain property, you can consult the Can I use database (available at http://caniuse.com/). How to do it… Create a switch.less Less file, and write down the following Less code into it: @browserversion: ie9; .mixin(ie9; @degrees){ transform:rotate(@degrees); -ms-transform:rotate(@degrees); -webkit-transform:rotate(@degrees); } .mixin(ie10; @degrees){ transform:rotate(@degrees); -webkit-transform:rotate(@degrees); } .mixin(@_; @degrees){ transform:rotate(@degrees); } div { .mixin(@browserversion; 70deg); } Compile the Less code from step 1 by running the following command in the console: lessc switch.less Inspect the compiled CSS code that has been output to the console, and you will find that it looks like the following code: div { -ms-transform: rotate(70deg); -webkit-transform: rotate(70deg); transform: rotate(70deg); } Finally, run the following command and you will find that the compiled CSS wll indeed differ from that of step 2: lessc --modify-var="browserversion=ie10" switch.less Now the compiled CSS code will look like the following code snippet: div { -webkit-transform: rotate(70deg); transform: rotate(70deg); } How it works… The switch in this recipe is the @browserversion variable that can easily be changed just before compiling your code. Instead of changing your code, you can also set the --modify-var option of the compiler. Depending on the value of the @browserversion variable, the mixins that match will be compiled, and the other mixins will be ignored by the compiler. The .mixin(ie10; @degrees){} mixin matches the .mixin(@browserversion; 70deg); call only when the value of the @browserversion variable is equal to ie10. Note that the first ie10 argument of the mixin will be used only for matching (argument = ie10) and does not assign any value. You will note that the .mixin(@_; @degrees){} mixin will match each call no matter what the value of the @browserversion variable is. The .mixin(ie9,70deg); call also compiles the .mixin(@_; @degrees){} mixin. Although this should result in the transform: rotate(70deg); property output twice, you will find only one. Since the property got exactly the same value twice, the compiler outputs the property only once. There's more… Not only switches, but also mixin guards, as described in the Using mixin guards (as an alternative for the if…else statements) recipe, can be used to set some properties conditionally. Current versions of Less also support JavaScript evaluating; JavaScript code put between back quotes will be evaluated by the compiler, as can be seen in the following Less code example: @string: "example in lower case"; p { &:after { content: "`@{string}.toUpperCase()`"; } } The preceding code will be compiled into CSS, as follows: p:after { content: "EXAMPLE IN LOWER CASE"; } When using client-side compiling, JavaScript evaluating can also be used to get some information from the browser environment, such as the screen width (screen.width), but as mentioned already, you should not use client-side compiling for production environments. Because you can't be sure that future versions of Less still support JavaScript evaluating, and alternative compilers not written in JavaScript cannot evaluate the JavaScript code, you should always try to write your Less code without JavaScript. Avoiding individual parameters to leverage the @arguments variable In the Less code, the @arguments variable has a special meaning inside mixins. The @arguments variable contains all arguments passed to the mixin. In this recipe, you will use the @arguments variable together with the the CSS url() function to set a background image for a selector. Getting ready You can inspect the compiled CSS code in this recipe after compiling the Less code with the command-line lessc compiler. Alternatively, you can inspect the results in your browser using the client-side less.js compiler. When inspecting the result in your browser, you will also need an example image that can be used as a background image. Use your favorite text editor to create and edit the Less files used in this recipe. How to do it… Create a background.less file that contains the following Less code: .background(@color; @image; @repeat: no-repeat; @position:   top right;) { background: @arguments; }   div { .background(#000; url("./images/bg.png")); width:300px; height:300px; } Finally, inspect the compiled CSS code, and you will find that it will look like the following code snippet: div { background: #000000 url("./images/bg.png") no-repeat top     right; width: 300px; height: 300px; } How it works… The four parameters of the .background() mixin are assigned as a space-separated list to the @arguments variable. After that, the @arguments variable can be used to set the background property. Also, other CSS properties accept space-separated lists, for example, the margin and padding properties. Note that the @arguments variable does not contain only the parameters that have been set explicit by the caller, but also the parameters set by their default value. You can easily see this when inspecting the compiled CSS code of this recipe. The .background(#000; url("./images/bg.png")); caller doesn't set the @repeat or @position argument, but you will find their values in the compiled CSS code. Using the @rest... variable to use mixins with a variable number of arguments As you can also see in the Using mixins with multiple parameters and Using duplicate mixin names recipes, only matching mixins are compiled into the final CSS code. In some situations, you don't know the number of parameters or want to use mixins for some style rules no matter the number of parameters. In these situations, you can use the special ... syntax or the @rest... variable to create mixins that match independent of the number of parameters. Getting ready You will have to create a file called rest.less, and this file can be compiled with the command-line lessc compiler. You can edit the Less code with your favorite editor. How to do it… Create a file called rest.less that contains the following Less code: .mixin(@a...) { .set(@a) when (iscolor(@a)) {    color: @a; } .set(@a) when (length(@a) = 2) {    margin: @a; } .set(@a); } p{ .mixin(red); } p { .mixin(2px;4px); } Compile the rest.less file from step 1 using the following command in the console: lessc rest.less Inspect the CSS code output to the console that will look like the following code: p { color: #ff0000; } p { margin: 2px 4px; } How it works… The special ... syntax (three dots) can be used as an argument for a mixin. Mixins with the ... syntax in their argument list match any number of arguments. When you put a variable name starting with an @ in front of the ... syntax, all parameters are assigned to that variable. You will find a list of examples of mixins that use the special ... syntax as follows: .mixin(@a; ...){}: This mixin matches 1-N arguments .mixin(...){}: This mixin matches 0-N arguments; note that mixin() without any argument matches only 0 arguments .mixin(@a: 1; @rest...){}: This mixin matches 0-N arguments; note that the first argument is assigned to the @a variable, and all other arguments are assigned as a space-separated list to @rest Because the @rest... variable contains a space-separated list, you can use the Less built-in list function. Using mixins as functions People who are used to functional programming expect a mixin to change or return a value. In this recipe, you will learn to use mixins as a function that returns a value. In this recipe, the value of the width property inside the div.small and div.big selectors will be set to the length of the longest side of a right-angled triangle based on the length of the two shortest sides of this triangle using the Pythagoras theorem. Getting ready The best and easiest way to inspect the results of this recipe will be compiling the Less code with the command-line lessc compiler. You can edit the Less code with your favorite editor. How to do it… Create a file called pythagoras.less that contains the following Less code: .longestSide(@a,@b) { @length: sqrt(pow(@a,2) + pow(@b,2)); } div { &.small {    .longestSide(3,4);    width: @length; } &.big {    .longestSide(6,7);    width: @length; } } Compile the pythagoras.less file from step 1 using the following command in the console: lessc pyhagoras.less Inspect the CSS code output on the console after compilation and you will see that it looks like the following code snippet: div.small { width: 5; } div.big { width: 9.21954446; } How it works… Variables set inside a mixin become available inside the scope of the caller. This specific behavior of the Less compiler was used in this recipe to set the @length variable and to make it available in the scope of the div.small and div.big selectors and the caller. As you can see, you can use the mixin in this recipe more than once. With every call, a new scope is created and both selectors get their own value of @length. Also, note that variables set inside the mixin do not overwrite variables with the same name that are set in the caller itself. Take, for instance, the following code: .mixin() { @variable: 1; } .selector { @variable: 2; .mixin; property: @variable; } The preceding code will compile into the CSS code, as follows: .selector { property: 2; } There's more… Note that variables won't leak from the mixins to the caller in the following two situations: Inside the scope of the caller, a variable with the same name already has been defined (lazy loading will be applied) The variable has been previously defined by another mixin call (lazy loading will not be applied) Passing rulesets to mixins Since Version 1.7, Less allows you to pass complete rulesets as an argument for mixins. Rulesets, including the Less code, can be assigned to variables and passed into mixins, which also allow you to wrap blocks of the CSS code defined inside mixins. In this recipe, you will learn how to do this. Getting ready For this recipe, you will have to create a Less file called keyframes.less, for instance. You can compile this mixins.less file with the command-line lessc compiler. Finally, inspect the Less code output to the console. How to do it… Create the keyframes.less file, and write down the following Less code into it: // Keyframes .keyframe(@name; @roules) { @-webkit-keyframes @name {    @roules(); } @-o-keyframes @name {    @roules(); } @keyframes @name {    @roules(); } } .keyframe(progress-bar-stripes; { from { background-position: 40px 0; } to   { background-position: 0 0; } }); Compile the keyframes.less file by running the following command shown in the console: lessc keyframes.less Inspect the CSS code output on the console and you will find that it looks like the following code: @-webkit-keyframes progress-bar-stripes { from {    background-position: 40px 0; } to {    background-position: 0 0; } } @-o-keyframes progress-bar-stripes { from {    background-position: 40px 0; } to {    background-position: 0 0; } } @keyframes progress-bar-stripes { from {    background-position: 40px 0; } to {    background-position: 0 0; } } How it works… Rulesets wrapped between curly brackets are passed as an argument to the mixin. A mixin's arguments are assigned to a (local) variable. When you assign the ruleset to the @ruleset variable, you are enabled to call @ruleset(); to "mixin" the ruleset. Note that the passed rulesets can contain the Less code, such as built-in functions too. You can see this by compiling the following Less code: .mixin(@color; @rules) { @othercolor: green; @media (print) {    @rules(); } }   p { .mixin(red; {color: lighten(@othercolor,20%);     background-color:darken(@color,20%);}) } The preceding Less code will compile into the following CSS code: @media (print) { p {    color: #00e600;    background-color: #990000; } } A group of CSS properties, nested rulesets, or media declarations stored in a variable is called a detached ruleset. Less offers support for the detached rulesets since Version 1.7. There's more… As you could see in the last example in the previous section, rulesets passed as an argument can be wrapped in the @media declarations too. This enables you to create mixins that, for instance, wrap any passed ruleset into a @media declaration or class. Consider the example Less code shown here: .smallscreens-and-olderbrowsers(@rules) { .lt-ie9 & {    @rules(); } @media (min-width:768px) {    @rules(); } } nav { float: left; width: 20%; .smallscreens-and-olderbrowsers({    float: none;    width:100%; }); } The preceding Less code will compile into the CSS code, as follows: nav { float: left; width: 20%; } .lt-ie9 nav { float: none; width: 100%; } @media (min-width: 768px) { nav {    float: none;    width: 100%; } } The style rules wrapped in the .lt-ie9 class can, for instance, be used with Paul Irish's <html> conditional classes technique or Modernizr. Now you can call the .smallscreens-and-olderbrowsers(){} mixin anywhere in your code and pass any ruleset to it. All passed rulesets get wrapped in the .lt-ie9 class or the @media (min-width: 768px) declaration now. When your requirements change, you possibly have to change only these wrappers once. Using mixin guards (as an alternative for the if…else statements) Most programmers are used to and familiar with the if…else statements in their code. Less does not have these if…else statements. Less tries to follow the declarative nature of CSS when possible and for that reason uses guards for matching expressions. In Less, conditional execution has been implemented with guarded mixins. Guarded mixins use the same logical and comparison operators as the @media feature in CSS does. Getting ready You can compile the Less code in this recipe with the command-line lessc compiler. Also, check the compiler options; you can find them by running the lessc command in the console without any argument. In this recipe, you will have to use the –modify-var option. How to do it… Create a Less file named guards.less, which contains the following Less code: @color: white; .mixin(@color) when (luma(@color) >= 50%) { color: black; } .mixin(@color) when (luma(@color) < 50%) { color: white; }   p { .mixin(@color); } Compile the Less code in the guards.less using the command-line lessc compiler with the following command entered in the console: lessc guards.less Inspect the output written on the console, which will look like the following code: p { color: black; } Compile the Less code with different values set for the @color variable and see how to output change. You can use the command as follows: lessc --modify-var="color=green" guards.less The preceding command will produce the following CSS code: p {   color: white;   } Now, refer to the following command: lessc --modify-var="color=lightgreen" guards.less With the color set to light green, it will again produce the following CSS code: p {   color: black;   }   How it works… The use of guards to build an if…else construct can easily be compared with the switch expression, which can be found in the programming languages, such as PHP, C#, and pretty much any other object-oriented programming language. Guards are written with the when keyword followed by one or more conditions. When the condition(s) evaluates true, the code will be mixed in. Also note that the arguments should match, as described in the Building a switch leveraging argument matching recipe, before the mixin gets compiled. The syntax and logic of guards is the same as that of the CSS @media feature. A condition can contain the following comparison operators: >, >=, =, =<, and < Additionally, the keyword true is the only value that evaluates as true. Two or more conditionals can be combined with the and keyword, which is equivalent to the logical and operator or, on the other hand, with a comma as the logical or operator. The following code will show you an example of the combined conditionals: .mixin(@a; @color) when (@a<10) and (luma(@color) >= 50%) { } The following code contains the not keyword that can be used to negate conditions: .mixin(@a; @color) when not (luma(@color) >= 50%) { } There's more… Inside the guard conditions, (global) variables can also be compared. The following Less code example shows you how to use variables inside guards: @a: 10; .mixin() when (@a >= 10) {} The preceding code will also enable you to compile the different CSS versions with the same code base when using the modify-var option of the compiler. The effect of the guarded mixin described in the preceding code will be very similar with the mixins built in the Building a switch leveraging argument matching recipe. Note that in the preceding example, variables in the mixin's scope overwrite variables from the global scope, as can be seen when compiling the following code: @a: 10; .mixin(@a) when (@a < 10) {property: @a;} selector { .mixin(5); } The preceding Less code will compile into the following CSS code: selector { property: 5; } When you compare guarded mixins with the if…else constructs or switch expressions in other programming languages, you will also need a manner to create a conditional for the default situations. The built-in Less default() function can be used to create such a default conditional that is functionally equal to the else statement in the if…else constructs or the default statement in the switch expressions. The default() function returns true when no other mixins match (matching also takes the guards into account) and can be evaluated as the guard condition. Building loops leveraging mixin guards Mixin guards, as described besides others in the Using mixin guards (as an alternative for the if…else statements) recipe, can also be used to dynamically build a set of CSS classes. In this recipe, you will learn how to do this. Getting ready You can use your favorite editor to create the Less code in this recipe. How to do it… Create a shadesofblue.less Less file, and write down the following Less code into it: .shadesofblue(@number; @blue:100%) when (@number > 0) {   .shadesofblue(@number - 1, @blue - 10%);   @classname: e(%(".color-%a",@number)); @{classname} {    background-color: rgb(0, 0, @blue);    height:30px; } } .shadesofblue(10); You can, for instance, use the following snippet of the HTML code to see the effect of the compiled Less code from the preceding step: <div class="color-1"></div> <div class="color-2"></div> <div class="color-3"></div> <div class="color-4"></div> <div class="color-5"></div> <div class="color-6"></div> <div class="color-7"></div> <div class="color-8"></div> <div class="color-9"></div> <div class="color-10"></div> Your HTML document should also include the shadesofblue.less and less.js files, as follows: <link rel="stylesheet/less" type="text/css"   href="shadesofblue.less"> <script src="less.js" type="text/javascript"></script> Finally, the result will look like that shown in this screenshot: How it works… The CSS classes in this recipe are built with recursion. The recursion here has been done by the .shadesofblue(){} mixin calling itself with different parameters. The loop starts with the .shadesofblue(10); call. When the compiler reaches the .shadesofblue(@number - 1, @blue – 10%); line of code, it stops the current code and starts compiling the .shadesofblue(){} mixin again with @number decreased by one and @blue decreased by 10 percent. The process will be repeated till @number < 1. Finally, when the @number variable becomes equal to 0, the compiler tries to call the .shadesofblue(0,0); mixin, which does not match the when (@number > 0) guard. When no matching mixin is found, the compiler stops, compiles the rest of the code, and writes the first class into the CSS code, as follows: .color-1 { background-color: #00001a; height: 30px; } Then, the compiler starts again where it stopped before, at the .shadesofblue(2,20); call, and writes the next class into the CSS code, as follows: .color-2 { background-color: #000033; height: 30px; } The preceding code will be repeated until the tenth class. There's more… When inspecting the compiled CSS code, you will find that the height property has been repeated ten times, too. This kind of code repeating can be prevented using the :extend Less pseudo class. The following code will show you an example of the usage of the :extend Less pseudo class: .baseheight { height: 30px; } .mixin(@i: 2) when(@i > 0) { .mixin(@i - 1); .class@{i} {    width: 10*@i;    &:extend(.baseheight); } } .mixin(); Alternatively, in this situation, you can create a more generic selector, which sets the height property as follows: div[class^="color"-] { height: 30px; } Recursive loops are also useful when iterating over a list of values. Max Mikhailov, one of the members of the Less core team, wrote a wrapper mixin for recursive Less loops, which can be found at https://github.com/seven-phases-max. This wrapper contains the .for and .-each mixins that can be used to build loops. The following code will show you how to write a nested loop: @import "for"; #nested-loops { .for(3, 1); .-each(@i) {    .for(0, 2); .-each(@j) {      x: (10 * @i + @j);    } } } The preceding Less code will produce the following CSS code: #nested-loops { x: 30; x: 31; x: 32; x: 20; x: 21; x: 22; x: 10; x: 11; x: 12; } Finally, you can use a list of mixins as your data provider in some situations. The following Less code gives an example about using mixins to avoid recursion: .data() { .-("dark"; black); .-("light"; white); .-("accent"; pink); }   div { .data(); .-(@class-name; @color){    @class: e(@class-name);    &.@{class} {      color: @color;    } } } The preceding Less code will compile into the CSS code, as follows: div.dark { color: black; } div.light { color: white; }   div.accent { color: pink; } Applying guards to the CSS selectors Since Version 1.5 of Less, guards can be applied not only on mixins, but also on the CSS selectors. This recipe will show you how to apply guards on the CSS selectors directly to create conditional rulesets for these selectors. Getting ready The easiest way to inspect the effect of the guarded selector in this recipe will be using the command-line lessc compiler. How to do it… Create a Less file named darkbutton.less that contains the following code: @dark: true; button when (@dark){ background-color: black; color: white; } Compile the darkbutton.less file with the command-line lessc compiler by entering the following command into the console: lessc darkbutton.less Inspect the CSS code output on the console, which will look like the following code: button { background-color: black; color: white; } Now try the following command and you will find that the button selector is not compiled into the CSS code: lessc --modify-var="dark=false" darkbutton.less How it works… The guarded CSS selectors are ignored by the compiler and so not compiled into the CSS code when the guard evaluates false. Guards for the CSS selectors and mixins leverage the same comparison and logical operators. You can read in more detail how to create guards with these operators in Using mixin guards (as an alternative for the if…else statements) recipe. There's more… Note that the true keyword will be the only value that evaluates true. So the following command, which sets @dark equal to 1, will not generate the button selector as the guard evaluates false: lessc --modify-var="dark=1" darkbutton.less The following Less code will give you another example of applying a guard on a selector: @width: 700px; div when (@width >= 600px ){ border: 1px solid black; } The preceding code will output the following CSS code: div {   border: 1px solid black;   } On the other hand, nothing will be output when setting @width to a value smaller than 600 pixels. You can also rewrite the preceding code with the & feature referencing the selector, as follows: @width: 700px; div { & when (@width >= 600px ){    border: 1px solid black; } } Although the CSS code produced of the latest code does not differ from the first, it will enable you to add more properties without the need to repeat the selector. You can also add the code in a mixin, as follows: .conditional-border(@width: 700px) {    & when (@width >= 600px ){    border: 1px solid black; } width: @width; } Creating color contrasts with Less Color contrasts play an important role in the first impression of your website or web application. Color contrasts are also important for web accessibility. Using high contrasts between background and text will help the visually disabled, color blind, and even people with dyslexia to read your content more easily. The contrast() function returns a light (white by default) or dark (black by default) color depending on the input color. The contrast function can help you to write a dynamical Less code that always outputs the CSS styles that create enough contrast between the background and text colors. Setting your text color to white or black depending on the background color enables you to meet the highest accessibility guidelines for every color. A sample can be found at http://www.msfw.com/accessibility/tools/contrastratiocalculator.aspx, which shows you that either black or white always gives enough color contrast. When you use Less to create a set of buttons, for instance, you don't want some buttons with white text while others have black text. In this recipe, you solve this situation by adding a stroke to the button text (text shadow) when the contrast ratio between the button background and button text color is too low to meet your requirements. Getting ready You can inspect the results of this recipe in your browser using the client-side less.js compiler. You will have to create some HTML and Less code, and you can use your favorite editor to do this. You will have to create the following file structure: How to do it… Create a Less file named contraststrokes.less, and write down the following Less code into it: @safe: green; @danger: red; @warning: orange; @buttonTextColor: white; @ContrastRatio: 7; //AAA, small texts   .setcontrast(@backgroundcolor) when (luma(@backgroundcolor)   =< luma(@buttonTextColor)) and     (((luma(@buttonTextColor)+5)/     (luma(@backgroundcolor)+5)) < @ContrastRatio) { color:@buttonTextColor; text-shadow: 0 0 2px black; } .setcontrast(@backgroundcolor) when (luma(@backgroundcolor)   =< luma(@buttonTextColor)) and     (((luma(@buttonTextColor)+5)/     (luma(@backgroundcolor)+5)) >= @ContrastRatio) { color:@buttonTextColor; }   .setcontrast(@backgroundcolor) when (luma(@backgroundcolor)   >= luma(@buttonTextColor)) and     (((luma(@backgroundcolor)+5)/     (luma(@buttonTextColor)+5)) < @ContrastRatio) { color:@buttonTextColor; text-shadow: 0 0 2px white; } .setcontrast(@backgroundcolor) when (luma(@backgroundcolor)   >= luma(@buttonTextColor)) and     (((luma(@backgroundcolor)+5)/     (luma(@buttonTextColor)+5)) >= @ContrastRatio) { color:@buttonTextColor; }   button { padding:10px; border-radius:10px; color: @buttonTextColor; width:200px; }   .safe { .setcontrast(@safe); background-color: @safe; }   .danger { .setcontrast(@danger); background-color: @danger; }   .warning { .setcontrast(@warning); background-color: @warning; } Create an HTML file, and save this file as index.html. Write down the following HTML code into this index.html file: <!DOCTYPE html> <html> <head>    <meta charset="utf-8">    <title>High contrast buttons</title>    <link rel="stylesheet/less" type="text/css"       href="contraststrokes.less">    <script src="less.min.js"       type="text/javascript"></script> </head> <body>    <button style="background-color:green;">safe</button>    <button class="safe">safe</button><br>    <button style="background-color:red;">danger</button>    <button class="danger">danger</button><br>    <button style="background-color:orange;">     warning</button>    <button class="warning">warning</button> </body> </html> Now load the index.html file from step 2 in your browser. When all has gone well, you will see something like what's shown in the following screenshot: On the left-hand side of the preceding screenshot, you will see the original colored buttons, and on the right-hand side, you will find the high-contrast buttons. How it works… The main purpose of this recipe is to show you how to write dynamical code based on the color contrast ratio. Web Content Accessibility Guidelines (WCAG) 2.0 covers a wide range of recommendations to make web content more accessible. They have defined the following three conformance levels: Conformance Level A: In this level, all Level A success criteria are satisfied Conformance Level AA: In this level, all Level A and AA success criteria are satisfied Conformance Level AAA: In this level, all Level A, AA, and AAA success criteria are satisfied If you focus only on the color contrast aspect, you will find the following paragraphs in the WCAG 2.0 guidelines. 1.4.1 Use of Color: Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. (Level A) 1.4.3 Contrast (Minimum): The visual presentation of text and images of text has a contrast ratio of at least 4.5:1 (Level AA) 1.4.6 Contrast (Enhanced): The visual presentation of text and images of text has a contrast ratio of at least 7:1 (Level AAA) The contrast ratio can be calculated with a formula that can be found at http://www.w3.org/TR/WCAG20/#contrast-ratiodef: (L1 + 0.05) / (L2 + 0.05) In the preceding formula, L1 is the relative luminance of the lighter of the colors, and L2 is the relative luminance of the darker of the colors. In Less, the relative luminance of a color can be found with the built-in luma() function. In the Less code of this recipe are the four guarded .setcontrast(){} mixins. The guard conditions, such as (luma(@backgroundcolor) =< luma(@buttonTextColor)) are used to find which of the @backgroundcolor and @buttonTextColor colors is the lighter one. Then the (((luma({the lighter color})+5)/(luma({the darker color})+5)) < @ContrastRatio) condition can, according to the preceding formula, be used to determine whether the contrast ratio between these colors meets the requirement (@ContrastRatio) or not. When the value of the calculated contrast ratio is lower than the value set by the @ContrastRatio, the text-shadow: 0 0 2px {color}; ruleset will be mixed in, where {color} will be white or black depending on the relative luminance of the color set by the @buttonTextColor variable. There's more… In this recipe, you added a stroke to the web text to improve the accessibility. First, you will have to bear in mind that improving the accessibility by adding a stroke to your text is not a proven method. Also, automatic testing of the accessibility (by calculating the color contrast ratios) cannot be done. Other options to solve this issue are to increase the font size or change the background color itself. You can read how to change the background color dynamically based on color contrast ratios in the Changing the background color dynamically recipe. When you read the exceptions of the 1.4.6 Contrast (Enhanced) paragraph of the WCAG 2.0 guidelines, you will find that large-scale text requires a color contrast ratio of 4.5 instead of 7.0 to meet the requirements of the AAA Level. Large-scaled text is defined as at least 18 point or 14 point bold or font size that would yield the equivalent size for Chinese, Japanese, and Korean (CJK) fonts. To try this, you could replace the text-shadow properties in the Less code of step 1 of this recipe with the font-size, 14pt, and font-weight, bold; declarations. After this, you can inspect the results in your browser again. Depending on, among others, the values you have chosen for the @buttonTextColor and @ContrastRatio variables, you will find something like the following screenshot: On the left-hand side of the preceding screenshot, you will see the original colored buttons, and on the right-hand side, you will find the high-contrast buttons. Note that when you set the @ContrastRatio variable to 7.0, the code does not check whether the larger font indeed meets the 4.5 contrast ratio requirement. Changing the background color dynamically When you define some basic colors to generate, for instance, a set of button elements, you can use the built-in contrast() function to set the font color. The built-in contrast() function provides the highest possible contrast, but does not guarantee that the contrast ratio is also high enough to meet your accessibility requirements. In this recipe, you will learn how to change your basic color automatically to meet the required contrast ratio. Getting ready You can inspect the results of this recipe in your browser using the client-side less.js compiler. Use your favorite editor to create the HTML and Less code in this recipe. You will have to create the following file structure: How to do it… Create a Less file named backgroundcolors.less, and write down the following Less code into it: @safe: green; @danger: red; @warning: orange; @ContrastRatio: 7.0; //AAA @precision: 1%; @buttonTextColor: black; @threshold: 43;   .setcontrastcolor(@startcolor) when (luma(@buttonTextColor)   < @threshold) { .contrastcolor(@startcolor) when (luma(@startcolor) < 100     ) and (((luma(@startcolor)+5)/     (luma(@buttonTextColor)+5)) < @ContrastRatio) {    .contrastcolor(lighten(@startcolor,@precision)); } .contrastcolor(@startcolor) when (@startcolor =     color("white")),(((luma(@startcolor)+5)/     (luma(@buttonTextColor)+5)) >= @ContrastRatio) {    @contrastcolor: @startcolor; } .contrastcolor(@startcolor); }   .setcontrastcolor(@startcolor) when (default()) { .contrastcolor(@startcolor) when (luma(@startcolor) < 100     ) and (((luma(@buttonTextColor)+5)/     (luma(@startcolor)+5)) < @ContrastRatio) {    .contrastcolor(darken(@startcolor,@precision)); } .contrastcolor(@startcolor) when (luma(@startcolor) = 100     ),(((luma(@buttonTextColor)+5)/(luma(@startcolor)+5))       >= @ContrastRatio) {    @contrastcolor: @startcolor; } .contrastcolor(@startcolor); }   button { padding:10px; border-radius:10px; color:@buttonTextColor; width:200px; }   .safe { .setcontrastcolor(@safe); background-color: @contrastcolor; }   .danger { .setcontrastcolor(@danger); background-color: @contrastcolor; }   .warning { .setcontrastcolor(@warning); background-color: @contrastcolor; } Create an HTML file and save this file as index.html. Write down the following HTML code into this index.html file: <!DOCTYPE html> <html> <head>    <meta charset="utf-8">    <title>High contrast buttons</title>      <link rel="stylesheet/less" type="text/css"       href="backgroundcolors.less">    <script src="less.min.js"       type="text/javascript"></script> </head> <body>    <button style="background-color:green;">safe</button>    <button class="safe">safe</button><br>    <button style="background-color:red;">danger</button>    <button class="danger">danger</button><br>    <button style="background-color:orange;">warning     </button>    <button class="warning">warning</button> </body> </html> Now load the index.html file from step 2 in your browser. When all has gone well, you will see something like the following screenshot: On the left-hand side of the preceding figure, you will see the original colored buttons, and on the right-hand side, you will find the high contrast buttons. How it works… The guarded .setcontrastcolor(){} mixins are used to determine the color set depending upon whether the @buttonTextColor variable is a dark color or not. When the color set by @buttonTextColor is a dark color, with a relative luminance below the threshold value set by the @threshold variable, the background colors should be made lighter. For light colors, the background colors should be made darker. Inside each .setcontrastcolor(){} mixin, a second set of mixins has been defined. These guarded .contrastcolor(){} mixins construct a recursive loop, as described in the Building loops leveraging mixin guards recipe. In each step of the recursion, the guards test whether the contrast ratio that is set by the @ContrastRatio variable has been reached or not. When the contrast ratio does not meet the requirements, the @startcolor variable will darken or lighten by the number of percent set by the @precision variable with the built-in darken() and lighten() functions. When the required contrast ratio has been reached or the color defining the @startcolor variable has become white or black, the modified color value of @startcolor will be assigned to the @contrastcolor variable. The guarded .contrastcolor(){} mixins are used as functions, as described in the Using mixins as functions recipe to assign the @contrastcolor variable that will be used to set the background-color property of the button selectors. There's more… A small value of the @precision variable will increase the number of recursions (possible) needed to find the required colors as there will be more and smaller steps needed. With the number of recursions also, the compilation time will increase. When you choose a bigger value for @precision, the contrast color found might differ from the start color more than needed to meet the contrast ratio requirement. When you choose, for instance, a dark button text color, which is not black, all or some base background colors will be set to white. The chances of finding the highest contrast for white increase for high values of the @ContrastRatio variable. The recursions will stop when white (or black) has been reached as you cannot make the white color lighter. When the recursion stops on reaching white or black, the colors set by the mixins in this recipe don't meet the required color contrast ratios. Aggregating values under a single property The merge feature of Less enables you to merge property values into a list under a single property. Each list can be either space-separated or comma-separated. The merge feature can be useful to define a property that accepts a list as a value. For instance, the background accepts a comma-separated list of backgrounds. Getting ready For this recipe, you will need a text editor and a Less compiler. How to do it… Create a file called defaultfonts.less that contains the following Less code: .default-fonts() { font-family+: Helvetica, Arial, sans-serif; } p { font-family+: "Helvetica Neue"; .default-fonts(); } Compile the defaultfonts.less file from step 1 using the following command in the console: lessc defaultfonts.less Inspect the CSS code output on the console after compilation and you will see that it looks like the following code: p { font-family: "Helvetica Neue", Helvetica, Arial, sans-   serif; } How it works… When the compiler finds the plus sign (+) before the assignment sign (:), it will merge the values into a CSV list and will not create a new property into the CSS code. There's more… Since Version 1.7 of Less, you can also merge the property's values separated by a space instead of a comma. For space-separated values, you should use the +_ sign instead of a + sign, as can be seen in the following code: .text-overflow(@text-overflow: ellipsis) { text-overflow+_ : @text-overflow; } p, .text-overflow { .text-overflow(); text-overflow+_ : ellipsis; } The preceding Less code will compile into the CSS code, as follows: p, .text-overflow { text-overlow: ellipsis ellipsis; } Note that the text-overflow property doesn't force an overflow to occur; you will have to explicitly set, for instance, the overflow property to hidden for the element. Summary This article walks you through the process of parameterized mixins and shows you how to use guards. A guard can be used with as if-else statements and make it possible to construct interactive loops in Less. Resources for Article: Further resources on this subject: Web Application Testing [article] LESS CSS Preprocessor [article] Bootstrap 3 and other applications [article]
Read more
  • 0
  • 0
  • 3502
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-probabilistic-graphical-models
Packt
17 Feb 2016
6 min read
Save for later

Probabilistic Graphical Models

Packt
17 Feb 2016
6 min read
Probabilistic graphical models, or simply graphical models as we will refer to them in this article, are models that use the representation of a graph to describe the conditional independence relationships between a series of random variables. This topic has received an increasing amount of attention in recent years and probabilistic graphical models have been successfully applied to tasks ranging from medical diagnosis to image segmentation. In this article, we'll present some of the necessary background that will pave the way to understanding the most basic graphical model, the Naïve Bayes classifier. We will then look at a slightly more complicated graphical model, known as the Hidden Markov Model, or HMM for short. To get started in this field, we must first learn about graphs. (For more resources related to this topic, see here.) A Little Graph Theory Graph theory is a branch of mathematics that deals with mathematical objects known as graphs. Here, a graph does not have the everyday meaning that we are more used to talking about, in the sense of a diagram or plot with an x and y axis. In graph theory, a graph consists of two sets. The first is a set of vertices, which are also referred to as nodes. We typically use integers to label and enumerate the vertices. The second set consists of edges between these vertices. Thus, a graph is nothing more than a description of some points and the connections between them. The connections can have a direction so that an edge goes from the source or tail vertex to the target or head vertex. In this case, we have a directed graph. Alternatively, the edges can have no direction, so that the graph is undirected. A common way to describe a graph is via the adjacency matrix. If we have V vertices in the graph, an adjacency matrix is a V×V matrix whose entries are 0 if the vertex represented by the row number is not connected to the vertex represented by the column number. If there is a connection, the entry is 1. With undirected graphs, both nodes at each edge are connected to each other so the adjacency matrix is symmetric. For directed graphs, a vertex vi is connected to a vertex vj via an edge (vi,vj); that is, an edge where vi is the tail and vj is the head. Here is an example adjacency matrix for a graph with seven nodes: > adjacency_m 1 2 3 4 5 6 7 1 0 0 0 0 0 1 0 2 1 0 0 0 0 0 0 3 0 0 0 0 0 0 1 4 0 0 1 0 1 0 1 5 0 0 0 0 0 0 0 6 0 0 0 1 1 0 1 7 0 0 0 0 1 0 0 This matrix is not symmetric, so we know that we are dealing with a directed graph. The first 1 value in the first row of the matrix denotes the fact that there is an edge starting from vertex 1 and ending on vertex 6. When the number of nodes is small, it is easy to visualize a graph. We simply draw circles to represent the vertices and lines between them to represent the edges. For directed graphs, we use arrows on the lines to denote the directions of the edges. It is important to note that we can draw the same graph in an infinite number of different ways on the page. This is because the graph tells us nothing about the positioning of the nodes in space; we only care about how they are connected to each other. Here are two different but equally valid ways to draw the graph described by the adjacency matrix we just saw: Two vertices are said to be connected with each other if there is an edge between them (taking note of the order when talking about directed graphs). If we can move from vertex vi to vertex vj by starting at the first vertex and finishing at the second vertex, by moving on the graph along the edges and passing through an arbitrary number of graph vertices, then these intermediate edges form a path between these two vertices. Note that this definition requires that all the vertices and edges along the path are distinct from each other (with the possible exception of the first and last vertex). For example, in our graph, vertex 6 can be reached from vertex 2 by a path leading through vertex 1. Sometimes, there can be many such possible paths through the graph, and we are often interested in the shortest path, which moves through the fewest number of intermediary vertices. We can define the distance between two nodes in the graph as the length of the shortest path between them. A path that begins and ends at the same vertex is known as a cycle. A graph that does not have any cycles in it is known as an acyclic graph. If an acyclic graph has directed edges, it is known as a directed acyclic graph, which is often abbreviated as a DAG. There are many excellent references on graph theory available. One such reference which is available online, is Graph Theory, Reinhard Diestel, Springer. This landmark reference is now in its 4th edition and can be found at http://diestel-graph-theory.com/. It might not seem obvious at first, but it turns out that a large number of real world situations can be conveniently described using graphs. For example, the network of friendships on social media sites, such as Facebook, or followers on Twitter, can be represented as graphs. On Facebook, the friendship relation is reciprocal, and so the graph is undirected. On Twitter, the follower relation is not, and so the graph is directed. Another graph is the network of websites on the Web, where links from one web page to the next form directed edges. Transport networks, communication networks, and electricity grids can be represented as graphs. For the predictive modeler, it turns out that a special class of models known as probabilistic graphical models, or graphical models for short, are models that involve a graph structure. In a graphical model, the nodes represent random variables and the edges in between represent the dependencies between them. Before we can go into further detail, we'll need to take a short detour in order to visit Bayes' Theorem, a classic theorem in statistics that despite its simplicity has implications both profound and practical when it comes to statistical inference and prediction. Summary In this article, we learned that graphs are consist of nodes and edges. We also learned the way of describing a graph is via the adjacency matrix. For more information on graphical models, you can refer to the books published by Packt (https://www.packtpub.com/): Mastering Predictive Analytics with Python (https://www.packtpub.com/big-data-and-business-intelligence/mastering-predictive-analytics-python) R Graphs Cookbook Second Edition (https://www.packtpub.com/big-data-and-business-intelligence/r-graph-cookbook-%E2%80%93-second-edition) Resources for Article: Further resources on this subject: Data Analytics[article] Big Data Analytics[article] Learning Data Analytics with R and Hadoop[article]
Read more
  • 0
  • 0
  • 3502

article-image-how-microsoft-dynamics-nav-fits-consultancy-company
Packt
16 Jun 2010
15 min read
Save for later

How Microsoft Dynamics NAV fits a consultancy company

Packt
16 Jun 2010
15 min read
(Further on Microsoft Dynamics NAV:here.) The process The two main processes for Microsoft Dynamics NAV partners are implementing new projects and providing services such as support and upgrades to existing customers. A third process is selling infrastructure and assembling computer systems but this is an extra service, not the core business. To support the projects (jobs) the company needs people, software licenses and hardware. The people (resources) need to be carefully planned on the projects as they are the least flexible part of the company. Hardware (items) and software licenses (G/L accounts) will be purchased from vendors such as Microsoft. The projects can be divided into large and small projects. The larger projects are new implementations and upgrades. Smaller projects include implementing small features and helping users with regular support issues. Invoicing can be done in various ways. New implementations and small projects can be invoiced per billable hour while upgrades are sold fixed price. For hardware we will use items. Licenses are invoiced directly to the General Ledger. Large projects also have budgets and a plan that need to be maintained. If the budget is fully used and the planning milestones have not been reached there should be a new budget created in order to complete the project. To support this process we will use the Jobs functionality with some customizations. Projects are called Jobs in Microsoft Dynamics NAV so we will use that term from now on. The Jobs module has been completely redesigned by Microsoft for version 5. In this article we will use a lot of the new functionality where we would have done customizations in the older versions of Microsoft Dynamics NAV. Fits The registration of the Jobs can be done using the standard functionality of Microsoft Dynamics NAV as well as the budgeting and planning. The standard software also allows us to invoice Jobs both fixed price and on time and materials. We can also purchase items for our Jobs. Gaps The Jobs module in Microsoft Dynamics NAV is often referenced as a framework that almost always needs some changes. Fortunately, it is designed to be easily changed and we will do so to support our processes. Resource groups Although many companies work this way; budgeting on Resource Groups is not possible. We will create a solution for that. We will also make it possible to see the total number of planned, used and invoiced hours. Time registration The standard software allows us to register hours but it does not have a real-time sheet application. We will create one. Item calculation We will create a solution calculating the system assembling. As hardware specifications are changing rapidly we do not want to create a new item for each system when we may only sell that particular configuration once or twice. Issue registration Our support team needs a single point for registration of all support issues for all customers and follow up their workflow. For this we will also create the functionality to register and follow up issues. Getting started Before we start creating any new jobs, we should have a look at the data and posting model of the Microsoft Dynamics NAV Jobs module. The starting point is the Job table, which has Job Tasks and Job Planning Lines we can use for budgeting and planning. Each job can have its own prices. The Job Planning Lines get invoiced through the standard Microsoft Dynamics NAV Sales functionality which then creates Job Ledger Entries. How many jobs The first step is setting up a new job. There can be different angles on setting up jobs.This depends on how we want to work with the system. The minimum requirement is to have at least one job per Bill-to Customer. This enables us to do the invoicing.Some companies use jobs this way to use it as a pre-invoice engine. Another angle can be to set up new jobs nicely for each project we do for the customer. In our case this starts with the basic Dynamics NAV implementation.When this is finished we close the job. If the customer has any new requirements we will need to start a new job. This way we can keep better track of what issues we have outstanding with each customer. The downside of this methodology is that it requires some work to set up a new job every time. Most companies end up with a solution in the middle. It is common to set up a new job for larger jobs and to have a job for support issues. This also allows us to set up different invoicing strategies for each job. We will use this strategy. Job card Let's have a look at the Job Card and the important fields there. Let's see these fields in more detail: No.: This is the unique number of a job. We can use different number series strategies for this, from simple sequential numbering to linked number series for different job types or manual numbering. Description: This should be a logical description of the job for internal use. Most people will search on this field so make sure to have certain rules for naming. This will make searching for old jobs easier in the future. Bill-to Customer No.: Each job has one Bill-to Customer. If we want to invoice multiple customers for one job we will need to customize the application. Search Description: By default this will be populated with the value of the description field but can be changed to another value if required. Person Responsible: This is an informative field indicating who is responsible for this job. Blocked: If this field is checked, it is not possible to make new entries for this job. Use this for closed jobs. Job Posting Group: This refers to the G/L Accounts that are used for the Work In Progress postings (WIP). There can be different G/L Accounts for different types of jobs or WIP methods. WIP Method: Each job can have one Work in Progress method. We wild discuss this briefly later in this article. Status: The jobs have a limited set of status fields. The only available status values are Planning, Quote, Order, and Completed. Most companies want to have more sub statuses for the order phase.The best approach for this is to add a new status field that maps with the standard status field. This requires minimum changes to the application while creating new workflow possibilities. Allow Schedule/Contract Lines: If this field is not checked it is not possible to create planning lines, which have both schedule and contract options. When planning lines are created they will be split into a schedule and a contract line. Starting and Ending Date: These are informative fields that are only used to calculate the currency exchange rates for the job. Foreign Trade: In the jobs module it is possible to send calculate and create invoices in a currency other than the local currency. This will increase the complexity of the implementation and should be used carefully. Job task and planning lines When the Job is created, the next step is to create Job Tasks and Planning Lines.These can be used in different ways. Using job task lines we can cut the job into smaller pieces, which we can then schedule and invoice. The more detailed the job tasks are, the better we can measure the progress of the job, but the more work they require to maintain. Balance is the key to success here. The Job Tasks can be created with the same structure as the Chart of Accounts, meaning the actual Task Lines can be grouped using Begin and End Total lines. Each level can be indented for better readability. The Job Planning Lines are the detail lines of each job task. This defines what we will do and how this will be invoiced. A job planning line can be linked to the master data types Resource, Item, G/L Account, or Text. Job Tasks and Job Planning Lines can be copied very easily from other jobs. This allows us to reuse them and even create template jobs for frequently used combinations. The line type in the job planning line defines how it will be invoiced. There are three types: Schedule: The amounts on this line will only be used in for budgeting purposes. When invoicing we need to post one or more job journal lines that will be invoiced or we can create another job planning line with the invoice amount. Schedule lines should be used when billing on time and materials. Contract: This line will be invoiced with the exact amounts. However the amounts do not show up in the budget. This can be used when invoicing fixed price jobs in a schedule, for example: 50% when signing the contract and 50% on job completion. Both Schedule and Contract: This line will be invoiced exactly the same way as the contract lines but the amount will also show up in the budget. Job journal When the job tasks and job planning lines are set up we can start the job. During the job we will consume resources and items from our company. This should be registered using the Job Journal. When creating a job journal line a few fields are particularly important for the process: Line Type: This has the same options as the job planning line, Schedule,Contract, and Both Schedule and Contract. When the job journal line should be invoiced, the type should be Contract. When the job journal line is part of a fixed price the line type should be left blank. When the line type is Schedule, the system will create additional Job Planning Lines of this type which may corrupt our budget for the customer asthey are already created. Unit Cost and Unit Price: These fields will determine the cost of the job and the price that will be invoiced to the customer if the line type is Contract.This information is also used in the calculation of the Work in Progress.   Job examples Let's go through some different job scenarios to see how we can use this functionality. Chapter objects The chapter objects contain both the changes we discuss in this article and as the example jobs we will use. After importing chapter 8.job, run page 123.456.700 Jobs Add-on Setup and then run Initialise Application. When this completes, restart the Role Tailored Client. You should now see the Project Manager Role Center. 1 | The new implementation Implementing Microsoft Dynamics NAV 2009 is not an easy task and many things need to be taken care of before we can use the product. We will implement Microsoft Dynamics NAV for Packt Publishing. The job for this example is EXAMPLE1. For the implementation we will create various job task groups. Each part of the implementation gets a code. Because the sorting is done on this field we will create codes using numbers and a logical name. For example, 0200. SETUP and 0210. FIN. Leave enough space in the numbers to add additional lines if required. This will avoid renaming which is an expensive task for the database engine and users will have to wait until it is completed.. Our consultants will help the customer to install the system, help with the setup and convert the data from the old system. When this is done we will help them with testing and train them for using Microsoft Dynamics NAV. The consultants will be set up in the system as Resources, which are in turn entered into the job planning lines. When everything is working as expected we can schedule a go-live weekend and help them in the first period using the system. Invoicing a job like this is done using a budget. We will make a pre calculation of the number of hours we think are necessary and start with that. During the job we need to measure the used budget and compare it with the progress. Budgeting The budget is created using the Job Planning Lines. During this phase of the job we do not yet know which resource will be used for the job tasks and it might even be done by more than one resource. This is why we want to use Resource Groups in our budget. This is not possible in the standard application so we have created a modification which we will discuss at the end of this article. The Line Type of these job planning lines is Schedule. This means that these lines are just for budgeting and schedule purposes. The system will invoice the actual consumption posted in the Job Journal. 2 | The infrastructure To use Microsoft Dynamics NAV 2009 Packt Publishing needs new infrastructure.Their current systems do not meet the requirements for Microsoft Dynamics NAV 2009. For this job we could create new Job Task Lines in the implementation job, but for a clearer overview we will create a new job, EXAMPLE2. Our company builds and sells its own computer systems. We can build both servers and desktop systems. Because none of the systems are exactly the same and available components switch regularly we do not want to create an item and a bill of materials for each system. Instead we use a Calculation system that allows us to determine a price for a system. For other products like switches, routers, printers, and laptops we use items which we purchase from vendors. The Job Tasks and Job Planning Lines for this job look like this: The installation costs in this job are Resource Groups with line type Schedule,just as in the previous job, so we invoice actual hours spent on the job. The other lines are of type Both Schedule and Contract. This means we will invoice exactly what is in the budget. The job journal lines for these tasks should be posted with a blank line type. 3 | The upgrade Our customer requests an upgrade from Navision version 3.70 to Microsoft Dynamics NAV 2009. We can do this for a fixed price but we require a fee for analyzing the system. For this job, EXAMPLE3, we can start with a limited number of Job Task Lines, just for the quote. When the customer agrees to do the upgrade we can add new job task lines. Both the Quote and the Upgrade are fixed price and posted directly to the general ledger. This does not mean we cannot have our resources to register the actual hours using the job journal but the line type should be blank. Another part of the upgrade is not done fixed price. The systems needs some redesign, a conversion to SQL Server 2008, and the customer wants additional training and support. The fixed price part of the upgrade is invoiced in three phases. When the job starts we invoice 50%, when we deliver the test system we invoice 40% and 10% is invoiced three months after go-live. This is done using lines of Both Schedule and Contract line type. 4 | The support team For the support team, our policy is to create one job per fiscal year per Customer.We will use this job, EXAMPLE4, for invoicing the maintenance of the license and all support issues. The support issues can be both little questions customers call us for, such as changing a report or a page, or implementing new features that requires only a few days work. Each issue and new feature will be created as a job task line. The new features will be created by the account manager who sells the feature. We can then decide if the invoicing is done fixed price, using contract lines, or on time and materials using schedule lines. Our support team also needs to use the job system, but we do not want them to manually create a new job task line for each support call, and we also want them to view all outstanding issues for all customers easily. For this we have created a new issue registration system which we discuss at the end of this article. Each issue in the system is linked to a job task. When Support Engineers create a new issue, the job task line is automatically generated for them and they can use it in our time and billing system.   Time sheets For all the jobs in our examples it is critical to have a solid registration of resource hours. In the standard Microsoft Dynamics NAV job application resources need to post a job journal for each combination of Job, Job Task, and Posting Date. This is not the way most people want to register their hours; therefore we have created a Time Sheet application. Data and transaction model The Time Sheet application is layered above the job journal line and is created using resources and job tasks. There is an approval process for the person responsible for the job allowing them to make corrections. The time sheet is designed to be created for each week. The system automatically generates the week starting date and creates the description. After that the resource can create time sheet lines for each job task line, and populate the number of hours each day of the week. If we look at this time sheet we can see, after it is updated, that Wednesday is missing two hours.
Read more
  • 0
  • 0
  • 3499

article-image-users-and-permissions-cms-made-simple-16-part-1
Packt
29 Mar 2010
6 min read
Save for later

Users and Permissions with CMS Made Simple 1.6: Part 1

Packt
29 Mar 2010
6 min read
Understanding users and their roles A role is a collection of permissions grouped by general tasks that the user has to be able to perform on the website. An editor may be responsible for creating, reorganizing, and editing pages. A designer does not need to have any permission for page operations, but for creating and editing templates (including module templates). An administrator is a person who has all permissions in the admin console and has unrestricted access to the entire admin console. In CMS Made Simple, three roles are suggested by default—editor, designer, and administrator. The first user created during installation of CMS Made Simple gets the administrator role by default. This user cannot be deleted, deactivated, or removed from the administrator group, as it would mean that there is no administrator for the website at all. You should choose the name of this user and pay attention to the password strength. Members of the administrator group automatically get all the permissions. Let's see how you can create a new user and learn about the minimum features that every user has, independent of his/her role. Time for action – creating a new user In the admin console, click on Users & Groups | Users. Click on Add New User, and fill in the fields, as shown in the following screenshot: Click on Submit. Log out (CMS | Logout) and log in as Peter. The admin console should now look as shown in the following screenshot: What just happened? You have created a new user without assigning him to any group. This user can log in to the admin console. There are only two main menu items that the user can access—CMS and My Preferences. The user can change his name, password, and e-mail address in the MyAccount section. He can define his personal preferences such as language, admin template, set default start page for the admin console, and more. He is also able to manage his personal shortcuts. It is important to define an e-mail address for every user, as this e-mail is used to recover the password, in case the user forgets it. On the login screen of the admin console of CMS Made Simple (when you are not logged in), you will find the link Forgot your password. Click it, enter Peter in the Username field, and click on Submit. An e-mail will be sent to the e-mail address associated with this user. If no e-mail address has been set for this user, then automatic password recovery is not possible. In this case, only the administrator of the website can reset the user's password. The administrator of the website can set any user as inactive by clicking the icon with a green tick in the column Active (Users & Groups | Users). The user account is not deleted, but the user is not able to log in to the admin console until his account has been activated again. If you delete the user, all permissions and personal user preferences will be irrevocably removed. If the user is not assigned to any group, then he is not allowed to do anything other than changing his personal settings. Let's assign the user Peter to the editor group to see what tasks he will be allowed to perform as an editor. Time for action – assigning a user to a group In the admin console, click on Users & Groups | Users. Select the user Peter for edit by clicking on his username. Select the Editor checkbox at the bottom of the screen, as shown in the following screenshot: Click on Submit. Log out (CMS | Logout) and log in as Peter. The admin console should look as shown in the following screenshot: What just happened? You have given the user additional permissions. Now, he can access a new menu item called Content. There are no content pages, but only News that Peter can submit. Let's see what permissions Peter has now. In the admin console, click on Users & Groups | Group Permissions. In the first column, all available permissions are listed. To the right of the permission, there are three columns, one for each group—Admin, Editor, and Designer. You can limit the view to only one group by selecting the group at the top of the table from the drop-down list. Find all selected checkboxes in the Editor column to see what permissions the user assigned to this group gets. You can see that only the Modify News permission is checked for the group. This means that the user can create news articles and edit existing news. When the user creates a new item, the news is automatically saved as a draft, so that only the administrator of the page or a user who has the Approve News For Frontend Display permission can publish the article on the website. Peter is not allowed to delete news articles (permission Delete News Articles) and has no access to the content pages (permission Modify Any Page or Manage All Content). Content permissions As the target goal of CMS Made Simple is content management, the permissions on editing content are the most flexible. You can create and manage as many editors for the website as you like. Moreover, you can create editors with different access levels thus thoroughly separating who is allowed to do what on your website. For example, the permission Manage All Content will give the group full access to all the features that are available with the administrator account in Content | Pages. A user assigned to this group can: Create new pages Reorder and move them through the hierarchy Make pages inactive or prevent them from showing in the navigation Change the default page of the website Delete pages Edit pages including all the information placed in the Options tab To restrict the features mentioned above, you can grant the permission Modify Any Page. This permission allows us to edit the content only. The Options tab is not shown for the users with this permission, so that any information placed in the Options tab cannot be changed. In addition to the last permission, you can allow some fields from the Options tab, so that the editor is able to change the template or mark the page as inactive.
Read more
  • 0
  • 0
  • 3498

article-image-sage-act-2011-working-act-dashboards
Packt
18 Feb 2011
6 min read
Save for later

Sage ACT! 2011: Working with the ACT! Dashboards

Packt
18 Feb 2011
6 min read
In ACT! CRM, dashboards allow you to access key information in the form of a graphical interface. You can filter a Dashboard so that it contains just the information you need, or you can tweak the various elements of a Dashboard to give it a different look. Administrators and Managers of your ACT! database can create brand new Dashboards if they're required. If you want more details about the information you see in a Dashboard, you can drill-down into the Dashboard with a simple double-click to access all the juicy details. At that point, you can edit or add to your information and the Dashboard will update automatically. You can even print out a hard copy of a Dashboard to preserve the contents for posterity. Because many of the Dashboards consist of pie charts and graphs, you might even want to copy one of them and paste it into other applications such as Word, Excel, or PowerPoint. Getting familiar with the Dashboard layouts Quite simply, a Dashboard is a graphical interface that gives you a visual snapshot of a part of your business. ACT! Dashboards let you view and work with the various information contained in your database in one easy-to-access location. Dashboards can take the form of charts, graphs, or even lists. Dashboards are associated with a database and not a user; therefore all users share the same Dashboards. However, you can select your own Dashboard view in much the same way that you can select a layout. You can also filter the information that is shown in your Dashboard. A Dashboard consists of two parts: The Dashboard layout: The Dashboard layout determines which Dashboard components you see and how the filters are set. ACT! comes with six Dashboard layouts. However, Managers and Administrators can create additional Dashboard layouts using the Dashboard Designer or make permanent changes to the existing ones. Dashboard components: Each Dashboard layout consists of one or more components. A component displays different types of data from the ACT! database. For example, a Dashboard layout might include a component that lists a user's top 10 current sales opportunities, another component that graphs the activities of a specific user, and a component that displays a pie chart of the company's current pipeline. A layout can have a maximum of six components. Getting ready In order to really take advantage of the ACT! Dashboard, you'll need to make sure that your database contains a variety of information. Specifically you'll need to make sure that your database contains a few Contacts, Activities, and Opportunities if you're going to view any of those Dashboards. How to do it... Click the Dashboard icon on ACT!'s navigation bar. The following screenshot shows you an example of the default Dashboard page: Choose the Dashboard layout you want from the Dashboard drop-down list, at the top-left side of the Dashboard. How it works... Many of the layouts consist of the exact same components. However, the components in each of the layouts are filtered differently, giving the layouts a bit of variety. There's more... Out of the box there are five Dashboard layouts: ACT! Activities Dashboard: Shows the activities of the user currently signed into ACT!, like the one you see in the following screenshot: ACT! Administration Dashboard: Lists the database users and shows when they've logged in and out of the database. Also lists any remote sync users, the date of their list sync, and how many days they have before their remote database expires if they don't synchronize. ACT! Contact Dashboard: Gives you a list of recently created contacts, recently edited contacts, and the number of fields that have changed. ACT! Default Dashboard: Includes three activity and three opportunity components. ACT! Opportunities Dashboard: Provides you with four different opportunity components including sales analysis by stage, value, and product. Each Dashboard layout is actually a file ending with the .dsh extension. You'll find them safely filed in the Dashboards sub-folder of the database files folder associated with your database. Accessing information from Dashboards Once you've become familiar with the various Dashboard layouts your next step is to start exploring the components found in each layout to see what data they contain. The components are generally arranged in a grid of two columns of three rows for a total of six components per Dashboard layout. The basic components include: My Schedule At-A-Glance: Found on the Default and Activities Dashboards, this component lists your activities of the current user for the current day. Activities by User: Found on the Default and Activities Dashboards, this component displays the activities for the current user for the current month, sorted by type, in a bar chart. The total numbers of activities are shown in the following screenshot. In addition you can hover your mouse over a bar section to see the number of activities for that activity type. Activity List: Found on the Activities Dashboard, this component is identical to the My Schedule At-A-Glance components, except that it lists all the activities for the current month. Opportunity Pipeline by Stage: Found on the Opportunities and Default Dashboards, this component displays your open opportunities in the ACT! Sales Cycle process for the current month sorted by stage, in a pie chart and includes a recap on the side like the one you see in the following screenshot: Contact History Count by User Type: Found on the Contacts Dashboard this component displays history items created by database users within a specified number of days similar to what's shown in the following screenshot: Opportunities - Open by Product: Found on the Opportunities Dashboard, the component displays a pie chart of the open opportunities by product and by user. Top 10 Opportunities: Found on the Opportunities and Default Dashboards, this component displays a list, by company and opportunity name, of the top ten open opportunities in the ACT! Sales Cycle process for the current month. Closed Sales to Date: Found on the Opportunities and Default Dashboards, this component displays the weighted and total value of opportunities in the ACT! Sales Cycle process, you closed and won in the form of a chart. Optionally you can customize the component to indicate a sales goal like the one shown in the following screenshot:
Read more
  • 0
  • 0
  • 3498
article-image-blender-engine-characters
Packt
09 Nov 2012
4 min read
Save for later

Blender Engine : Characters

Packt
09 Nov 2012
4 min read
(For more resources related to this topic, see here.) An example — save the whale! The game can augment its levels of difficulty as we develop our world using different environments. We can always increase the capability of your character with new keyboard functions. Obviously, this is an example. Feel free to change the game, remake it, create another completely different character, and provide a gameplay of another gaming genre. There are thousands of possibilities, and it's fine if you deviate from our idea. It is important that you clear your design before you start your game library. That's all. How to create a library If we start working with the Blender Game Engine (BGE), we must have a library of all of the objects we use in our game. For example, the basic character, or even the smallest details, such as the appearance of health levels of our enemies. On the Internet, we can find plenty of 3D objects, which can be useful for our game. Let's make sure we use free models and read the instructions to run the model. Do not forget to mention the authorship of each object that you download. Time for action — downloading models from the Internet Let's go to one of the repositories for Blender, which can be found at http://www.opengameart.org/ and let's try to search for what is closest to our character. Write sea in the Search box, and choose 3D Art for Art Type, as shown in the following screenshot: We have some interesting options. We see a shark, seaweed, and some icebergs to select from. Choose and click on the thumbnail with the name ICEBERGS IN 3D: At the bottom of the page, you will find the file.blend downloadable. Click on it to start the download. Remember to click on RMB before the download begins. Now, let's try web pages, which have libraries that offer 3D models in other formats. An example of a very extensive library is http://sketchup.google.com/3dwarehouse/. Write trawler in the Search box, and choose the one that you like. In our case, we decided to go for the Google 3D model with the title Trawler boat, 28': Click on the Download model button: Save the file on your hard disk, in a folder of your game. What just happened? We have searched the Internet for 3D models, which will allow us to start a library for our game objects in Blender. Whether they are .blend files (original blender format) or of a 3D-model format, you can import them and work with them. Don't download models that you will not use. The libraries on the Internet grow every day, and we don't need to save all of the models that we like. Remember that before downloading the model and using it, we need to check if it has a free license. If you are releasing your project under some other free and/or open source license, then there could be licensing conflicts depending on what license the art is released under. It is your responsibility to verify the compatibility of the art license with the license you are using. Importing other files into Blender Before the imported mesh can be used, some scene and mesh prepping in Blender is usually required. It basically cleans up the model imported in Blender. Google SketchUp is another free, 3D software option. You can build models from scratch, and you can upload or download what you need, as you have seen. People all over the world share what they've made on the Google 3D Warehouse. It's our time to do the same. Download the program from http://sketchup.comand install it. You can uninstall it later. Open the boat file in SketchUp, click on Save as, and export the 3D model using the COLLADA format. The *.dae Collada format is a common, cross-platf orm file, which can be imported directly into Blender.
Read more
  • 0
  • 0
  • 3497

article-image-getting-started-scratch-14-part-1
Packt
16 Oct 2009
6 min read
Save for later

Getting Started with Scratch 1.4 (Part 1)

Packt
16 Oct 2009
6 min read
Before we create any code, let's make sure we speak the same language. The interface at a glance When we encounter software that's unfamiliar to us, we often wonder, "Where do I begin?" Together, we'll answer that question and click through some important sections of the Scratch interface so that we can quickly start creating our own projects. Now, open Scratch and let's begin. Time for action – first step When we open Scratch, we notice that the development environment roughly divides into three distinct sections, as seen in the following screenshot. Moving from left to right, we have the following sections in sequential order: Blocks palette Script editor Stage Let's see if we can get our cat moving: In the blocks palette, click on the Looks button. Drag the switch to costume block onto the scripts area. Now, in the blocks palette, click on the Control button. Drag the when flag clicked block to the scripts area and snap it on top of the switch to costume block, as illustrated in the following screenshot. How to snap two blocks together?As you drag a block onto another block, a white line displays to indicate that the block you are dragging can be added to the script. When you see the white line, release your mouse to snap the block in place. In the scripts area, click on the Costumes tab to display the sprite's costumes. Click on costume2 to change the sprite on the stage. Now, click back on costume1 to change how the sprite displays on the stage. Directly beneath the stage is a sprites list. The current list displays Sprite1 and Stage. Click on the sprite named Stage and notice that the scripts area changes. Click back on Sprite1 in the sprites list and again note the change to the scripts area. Click on the flag above the stage to set our first Scratch program in motion. Watch closely, or you might miss it. What just happened? Congratulations! You created your first Scratch project. Let's take a closer look at what we did just now. As we clicked through the blocks palette, we saw that the available blocks changed depending on whether we chose Motion, Looks, or Control. Each set of blocks is color-coded to help us easily identify them in our scripts. The first block we added to the script instructed the sprite to display costume2. The second block provided a way to control our script by clicking on the flag. Blocks with a smooth top are called hats in Scratch terminology because they can be placed only at the top of a stack of blocks. Did you look closely at the blocks as you snapped the control block into the looks block? The bottom of the when flag clicked block had a protrusion like a puzzle piece that fits the indent on the top of the switch to costume block. As children, most of us probably have played a game where we needed to put the round peg into the round hole. Building a Scratch program is just that simple. We see instantly how one block may or may not fit into another block. Stack blocks have indents on top and bumps on the bottom that allow blocks to lock together to form a sequence of actions that we call a script. A block depicting its indent and bump can be seen in the following screenshot: When we clicked on the Costumes tab, we learned that our cat had two costumes or appearances. Clicking on the costume caused the cat on the stage to change its appearance. As we clicked around the sprites list, we discovered our project had two sprites: a cat and a stage. And the script we created for the cat didn't transfer to the stage. We finished the exercise by clicking on the flag. The change was subtle, but our cat appeared to take its first step when it switched to costume2. Basics of a Scratch project Inside every Scratch project, we find the following ingredients: sprites, costumes, blocks, scripts, and a stage. It's how we mix the ingredients with our imagination that creates captivating stories, animations, and games. Sprites bring our program to life, and every project has at least one. Throughout the book, we'll learn how to add and customize sprites. A sprite wears a costume. Change the costume and you change the way the sprite looks. If the sprite happens to be the stage, the costume is known as a background. Blocks are just categories of instructions that include motion, looks, sound, pen, control, sensing, operators, and variables. Scripts define a set of blocks that tell a sprite exactly what to do. Each block represents an instruction or piece of information that affects the sprite in some way. We're all actors on Scratch's stage Think of each sprite in a Scratch program as an actor. Each actor walks onto the stage and recites a set of lines from the script. How each actor interacts with another actor depends on the words the director chooses. On Scratch's stage, every object, even the stone in the corner, is a sprite capable of contributing to the story. As directors, we have full creative control. Time for action – save your work It's a good practice to get in the habit of saving your work. Save your work early, and save it often: To save your new project, click the disk icon at the top of the Scratch window or click File | Save As. A Save Project dialog box opens and asks you for a location and a New Filename. Enter some descriptive information for your project by supplying the Project author and notes About this project in the fields provided. Set the cat in motion Even though our script contains only two blocks, we have a problem. When we click on the flag, the sprite switches to a different costume and stops. If we try to click on the flag again, nothing appears to happen, and we can't get back to the first costume unless we go to the Costumes tab and select costume1. That's not fun. In our next exercise, we're going to switch between both costumes and create a lively animation.
Read more
  • 0
  • 0
  • 3497

article-image-tree-test-and-surveys
Packt
21 Feb 2018
13 min read
Save for later

Tree Test and Surveys

Packt
21 Feb 2018
13 min read
In this article by Pablo Perea and  Pau Giner, authors of the book UX Design for Mobile, we will cover how to use different techniques that can be applied according to the needs of the project and the how to obtain the information that we want. (For more resources related to this topic, see here.) Tree Test This is also called reverse card sorting. This is a method where the participants try to find elements in a given structure. The objective of this method is to discover findability problems and improve the organization and labeling system. The organization structure used should represent a realistic navigation for the application or web page you are evaluating. If you don’t have one by the time the experiment is taking place, try to create a real scenario, as using a fake organization will not lead to really valuable results. There are some platforms available to perform this type of experiment with a computer. One example is https://www.optimalworkshop.com. This can have several advantages: the experiment can be carried out without requiring a physical displacement by the participant, and you can also study the participant steps and not just analyze whether the participant succeeded or not. It can be that the participants found the objectives but had to make many attempts to achieve them. The method steps Create the structure: Type or create the navigation structure with all the different levels you want to evaluate. Create a set of findability tasks: Think about different items that the participant should find or give a location in the given structure. Test with participants: The participant will receive a set of tasks to do. The following are some examples of possible tasks: Find some different products to buy Contact the customer support Get the shipping rates The results: At the end, we should have a success rate for each of the tasks. Tasks such as finding products in a store must be done several times with products located in different sections. This will help us classify our assortment and show us how to organize the first levels of the structure better. How to improve the organization Once we find the main weak points and workarounds we have in our structure, we can create alternative structures to retest and try to find better results. We can repeat this process several times until we get the desired results. The Information Architecture is the science field of organizing and labeling content in a web page to support usability and findability. There's a growing community of Information architecture specialists that supports the Information architecture Institute--https://en.wikipedia.org/wiki/Information_architecture. There are some general lines of work in which we have to invest time in order to improve our Information architecture. Content organization The content can be ordered by following different schemes, in the same way that a supermarket orders products according to different criteria. We should try to find the one that better fits our user needs. We can order the content, dividing it into groups according to nature, goals, audience, chronological entry, and so on. Each of these approaches will lead to different results and each will work better with different kinds of users. In the case of mobile applications, it is common to have certain sections where they mix contents of a different nature, for instance, integrating messages for the user in the contents of the activity view. However, an abuse of these types of techniques can lead to turning the section into a confusing area for the user. Areas naming There are words that have a completely different meaning for one person to another, especially if those people are thinking in different fields when they use our solution. Understanding our user needs, and how the think and speak, will help us provide clear names for sections and subsections. For example, the word pool will represent a different set of products for a person looking for summer products than for a person looking for games. In the case of applications, we will have to find a balance between simplicity and clarity. If space permits, adding a label along with the icon will clarify and reduce the possible ambiguities that may be encountered in recognizing the meaning of these graphic representations. In the case of mobiles, where space is really small, we can find some universal icons, but we must test with users to ensure that they interpret them properly. In the following examples, you can find two different approaches. In the Gmail app, attachment and send are known icons and can work without a label. We find a very different scenario in the Samsung Clock app, where it would be really difficult to differentiate between the Alarm, the Stopwatch, and the Timer without labels:      Samsung system and Google Gmail App screenshots (source: Screenshot from Google Gmail App, source: Screenshot from Gmail App) The working memory limit The way the information is displayed to the user can drastically change the ease with which it is understood. When we talk about mobiles, where space is very limited, limiting the number of options and providing a navigation adapted to small spaces can help our user have a more satisfactory experience. As you probably know, the human working memory is not limitless, and it is commonly supposed to be limited to remembering a maximum of seven elements (https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two). Some authors such as Nelson Cowan suggested that the number of elements an adult can remember while performing a task is even lower, and gives the number of reference as four (https://en.wikipedia.org/wiki/Working_memory). This means that your users will understand the information you give them better if you block it into groups according to their limitations. Once we create a new structure, we can evaluate the efficiency of this new structure versus the last version. With small improvements, we will be able to increase the user engagement. Another way to learn about how the user understands the organization of our app or web is by testing a competitor product. This is one of the cheapest ways to have a quick prototype. Evaluate as many versions as you can; in each review, you will find new ideas to organize and show the content of your application or web app better. Surveys Surveys allow us to gather information from lots of participants without too much effort. Sometimes, we need information from a big group of people, and interviewing them one by one will not be affordable. Instead of that, surveys can quickly provide answers from lots of participants and analyze the results with bulk methods. It is not the purpose of this book to deal in depth with the field of questionnaires since there are books devoted entirely to this subject. Nevertheless, we will give some brushstrokes on the subject since they are commonly used to gather information in both web pages and mobile applications. Creating proper questions is a key part of the process that will reduce the noise and help the participants provide useful answers. Some questions will require more effort to analyze, but they will give us answers with deeper level of detail. Questions with pre-established answers are usually easier to automatize, and we can get results in less time. What we want to discover? The first thing to do is to define the objective for which we are making a survey. Working with a clear objective will help the process be focused and will get better results. Plan carefully and determine the information that you really need at that moment. We should avoid surveys with lots of questions that do not have a clear purpose. They will produce poor outcome and result in meaningless exercises for the participants. On the contrary, if we have a general leitmotiv for the questionnaire, it will also help the participants understand how the effort of completing the survey will help the company, and therefore it will give clear value to the time expended. You can plan your survey according to different planning approaches, your questions can be focussed on short and long term goals: Long-term planning: Understanding your users expectations and their view about your product in the long term will help plan the evolution of your application and help create new features that match their needs. For example, imagine that you are designing a music application, and you are unsure about focusing on mass majority music or maybe giving more visibility to amateur groups. Creating a long-term survey can help you understand what your users want to find in your platform and plan changes that match the conclusions extracted from the survey analysis. Short-term planning: This is usually related to operational actions. The objective with these kind of surveys is to gather information for taking actions later with a defined mission. These kind of surveys are useful when we need to choose between two options, that is, whether we are deciding to make a change in our platform or not. For example, it can help to decide what type of information is most important for the user when choosing between one group and another, so we can make that information more visible. We will take better decisions by understanding the main aspects our users will expect to find in our platform. Find the participants Depending on the goal of the survey, we can use a wider range of participants or reduce their number, filtering by their demographics, experience, or the relationship with our brand or products. If the goal is to expand our number of users, it may be interesting to expand the search range to participants outside our current set of users. Looking for new niches and interesting features for our potential users can make new users try out our application. If, on the contrary, our objective is to keep our current users loyal, it can be a great source of improvement to consult them about their preferences and their opinions about the things that work properly in our application. This data, along with the data of use and navigation, will let us see areas for improvement, and we will be able to solve problems of navigation and usability. Determining the questions We can ask different types of questions; depending on the type, we will get more or less detailed answers. If we choose the right type, we can save analysis effort, or we can reduce the number of participants when we require a deep analysis of each response. It is common to include questions at the beginning of the questionnaires in order to classify the results. They are usually called filtering or screening questions, and they will allow us to analyze the answers based on data such as age, gender, or technical skills. These questions have the objective of knowing the person answering the survey. If we know the person solving the questionnaire, we will be able to determine whether the answers given by this user are useful for our goals or not. We can add questions about the experience the participant has with general technology, or with our app, and about the relation with the brand. We can create two kinds of questions based on the type of answers the participant can provide; each of them, therefore, will lead to different results. Open-answer questions The objective of this type of questions is to know more about the participant without guiding the answers. We will try to ask objectively for a subject without providing possible answers. The participant will answer these type of questions with open-ended answers, so it will be easier to know more about how that participant thinks and which aspects are proving more or less satisfactory. While the advantage of this kind of questions is that you will gain a lot of insights and new ideas, the con is the cost of managing big amounts of data. So, these type of questions will be more useful when the number of participants is reduced. Here are some examples of open-answer questions: How often have you been using our customer service? How was your last purchase experience on our platform? Questions with pre-established answers These type of questions facilitate the analysis when the number of participants is high. We will create questions with a clear objective and give different options to respond. Participants will be able to choose one of the options in response. The analysis of these types of questions can be automated and therefore is faster, but it will not give us as detailed information as an open question, in which the participant can expose all his ideas about the matter in the question. The following is an example of a question with pre-established answers: Questions: How many times have you used our application in the last week? Answers: 1) More than five times 2) Two to Five 3) Once 4) None Another great advantage is the facility to answer these types of questions when the participant does not have much time or interest to respond. In environments such as mobile phones, typing long answers can be costly and frustrating. With these types of questions, we can offer answers that the user can select with a single click. This can help increase the number of participants completing the form. It is common to mix both the types of questions. Open-answer questions where the user can respond in more detail can be included as optional questions. The participants willing to share more information can use these fields to introduce more detailed answers. This way, we can make a quicker analysis on the questions with pre-established answers and analyze the questions that require more precise revision later. Humanize the forms When we create a form, we must think about the person who will answer it. Almost no one likes to fill in questionnaires, especially if they are long and complex. To make our participants feel comfortable filling out all the answers on our form, we have to try to treat the process as a human relationship: The first thing we should do is to explain the reason of our form. If our participants understand how their answers will be used in the project, and how they can help us achieve the goal, they will feel more encouraged to answer the questions and take their role seriously. Ask only what is strictly necessary for the purpose you have set for it. We must prevent different departments from introducing questions without a common goal. If the form will answer concerns of different departments, all of them should have the same goal. This way, the form will have more cohesion. The tone used on the form should be friendly and clear. We should not go beyond the limits of indiscretion with our questions, or the participant may feel overwhelmed, especially if the participants of our study are not users of our application or our services, we must treat them as unknown. Being respectful and kind is a key point in getting high participation. Summary In the article we saw how to apply Tree Test and how to conduct surveys to gain information that you want. Resources for Article:   Further resources on this subject: Trends UX Design [article] Building Mobile Apps [article] Auditing Mobile Applications [article]
Read more
  • 0
  • 0
  • 3495
article-image-hive-security
Packt
17 Feb 2016
13 min read
Save for later

Hive Security

Packt
17 Feb 2016
13 min read
In this article by Hanish Bansal, Saurabh Chauhan, and Shrey Mehrotra, the authors of the book, Apache Hive Cookbook, we will cover the following recipes: Securing Hadoop Authorizing Hive Security is a major concern in all the big data frameworks. It is little complex to implement security in distributed systems because the components of different machines need to communicate with each other. It is very important to enable security on the data. (For more resources related to this topic, see here.) Securing Hadoop In today's era of big data, most organizations are concentrating to use Hadoop as a centralized data store. Data size is growing day by day, and organizations want to derive some insights and make decisions using the important information. While everyone is focusing on collecting the data, but having all the data at a centralized place increases the risk of data security. Securing the data access of Hadoop Distributed File System (HDFS) is very important. Hadoop security means restricting the access of data to only authorized users and groups. Further, when we talk about security, there are two major things—Authentication and Authorization. The HDFS supports a permission model for files and directories that is much equivalent to standard POSIX model. Similar to UNIX permissions, each file and directory in HDFS are associated with an owner, a group, and other users. There are three types of permissions in HDFS: read, write, and execute. In contrast to the UNIX permission model, there is no concept of executable files. So in case of files, read (r) permission is required to read a file, and write (w) permission is required to write or append to a file. In case of directories, read (r) permission is required to list the contents of directory, write (w) permission is required to create or delete the files or subdirectories, and execute (x) permission is required to access the child objects (files/subdirectories) of that directory. The following screenshot shows the level of access to each individual entity, namely OWNER, GROUP, and OTHER: The Default HDFS Permission Model As illustrated in the previous screenshot, by default, the permission set for the owner of files or directories is rwx (7), which means the owner of the file or directory is having full permission to read, write, and execute. For the members of group, the permission set is r-x, which means group members can only read and execute the files or directories and they cannot write or update anything in the files or directories. For other members, a permission set is same as a group, that is, other members can only read and execute the files or directories and they cannot write or update anything in files or directories. Although this basic permission model is sufficient to handle a large number of security requirements at the block level, but using this model, you cannot define finer level security to specifically named users or groups. HDFS also has a feature to configure Access Control List (ACL), which can be used to define fine-grained permissions at file level as well as directory level for specifically named users or groups. For example, you want to give read access to users John, Mike, and Kate; then, HDFS ACLs can be used to define such kind of permissions. HDFS ACLs are designed on the base concept of POSIX ACLs of UNIX systems. How to do it… First of all, you will need to enable ACLs in Hadoop. To enable ACL permissions, configure the following property in Hadoop-configure file named hdfs-site.xml located at <HADOOP_HOME>/etc/hadoop/hdfs-site.xml: <property> <name>dfs.namenode.acls.enabled</name> <value>true</value> </property> There are two main commands that are used to configure ACLs: setfacl and getfacl. The command setfacl is used to set Finer Access Control Lists (FACL) for files or directories, and getfacl is used to retrieve Finer Access Control Lists (FACL) for files or directories. Let's see how to use these commands: hdfs dfs -setfacl [-R] [-b |-k -m |-x <acl_specification> <path>] |[--set <acl_specification> <path>] The same command can be run using hadoop fs also, as follows: hadoop fs -setfacl [-R] [-b |-k -m |-x <acl_specification> <path>] |[--set <acl_specification> <path>] This command contains the following elements: -R is used to apply operation recursively for all files and subdirectories under a directory. -b is used to remove all ACLs except the base ACLs. -k is used to remove the default ACLs. -m is used to modify ACLs. Using this option, new entries are added to the existing set of ACLs. -x is used to remove specific ACLs. acl_specification is a comma-separated list of ACLs. path is the path of a file or directory for which ACL has to be applied. --set is used to set new ACLs. It removes all existing ACLs and set the new ACLs only. Now, let's see another command that is used to retrieve the ACLs: hdfs dfs -getfacl [-R] <path> This command can also be run using hadoop fs as follows: hadoop fs -getfacl [-R] <path> This command contains the following elements: -R is used to retrieve ACLs recursively for all files and subdirectories under a directory path is a path of a file or directory of which ACL is to be retrieve The command getfacl will list all default ACLs as well as new ACLs defined for specified files or directories. How it works… If ACLs are defined for a file or directory, then while accessing that file/directory, access is validated as given in the following algorithm: If the username is the same as the owner name of the file, then owner permissions are enforced If username matches with one of named user ACL entry, then those permissions are enforced If a user's group name matches with one of the named group ACL entry, then those permissions are enforced In case multiple ACLs entries found for a user, then the union of all those permissions is enforced If no ACL entry found for a user, then other permissions are enforced Let's assume that we have a file named stock-data containing stock market data. To retrieve all ACLs of this file, run the following command after which the output is shown in the screenshot given later: $ hadoop fs -getfacl /stock-data Because we have not defined any custom ACL for this file, as shown in the previous screenshot, command will return default ACL for this file. You can check the permissions of a file or directory using the ls command also. As shown in the previous screenshot, the permission set for stock-data file is -rw-r--r--, which means read and write access for owner as well as read access for group members and others. In the following command, we give read and write access to user named mike, and the result is shown in the following screenshot: $ hadoop fs -setfacl -m user:mike:rw- /stock-data As shown in the previous screenshot, first, we defined the ACLs for the user mike using setfacl command; then, we retrieved the ACLs using the getfacl command. The output of the getfacl command will list out all default permissions as well as all ACLs. We defined ACLs for the user mike, so in the output, there is an extra row user:mike:rw-. There is an extra row in the output mask::rw-, which defines special mask ACLs entry. Mask is a special type of ACLs that filters out the access for all named users, named groups, and unnamed groups. If you have not defined mask ACL, then its value is calculated using the union of all permissions. In addition to this, the output of the ls command is also changed after defining ACLs. There is an extra plus (+) sign in permissions list that indicates that there are additional ACLs defined for this file or directory. Revoking access of user mike. To remove a specific ACL -x option is used with the setfacl command: $ hadoop fs -setfacl -x user:mike /stock-data In the previous screenshot, after revoking access of user mike, ACLs are updated, and there is no entry for the user mike now. See also You can read more about the permission model in Hadoop at https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsPermissionsGuide.html. Authorizing Hive Hive authorization is to verifying that a user is authorized to perform particular action. Authentication is about verifying the identity of a user, which is different from the authorization concept. Hive can be used in the following different ways: Using HCatalog API: Hive's Hcatalog API is used to access Hive by many other frameworks such as Apache Pig, MapReduce, Facebook Presto, Spark SQL, and Cloudera Impala. Using the HCatalog API, users have direct access to HDFS data and hive metadata. Hive metadata is directly accessible using metastore server API. Using Hive CLI: Using Hive CLI also, users have direct access to HDFS data and Hive metadata. Hive CLI directly interacts with a Hive metastore server. Currently Hive CLI don't support rich authorization. In next versions of hive, Hive CLI's implementation will be changed to provide better security, and also Hive CLI will interact with HiveServer2 rather than directly interacting with the metastore server. Using ODBC/JDBC and other HiveServer2 clients such as Beeline: These clients don't have direct access to HDFS data and metadata but through HiveServer2. For security purpose, this is the best way to access Hive. How to do it… The following are the various ways of authorization in Hive: Default authorization: the legacy mode: The legacy authorization mode was available in earlier versions of Hive. This authorization scheme prevents the users from doing some unwanted actions. This scheme doesn't prevent malicious users from doing activities. It manages the access control using grant and revoke statements. This mode supports Hive Command Line Interface (Hive CLI). In case of Hive CLI, users have direct access to HDFS files and directories, so they can easily break the security checks. Also in this model for granting privileges, the permissions needed for a user are not defined, which means that any user can grant the access to themselves, so it is not secure to use this model. Storage-based Authorization: As storage perspective, both HDFS data as well as Hive metadata must be accessed only to authorized users. If users use the HCatalog API or Hive CLI, then they have direct access to data. To protect the data, HDFS ACLs are being enabled. In this mode, HDFS permissions work as a single source of truth for protecting data.Generally in Hive metastore, database credentials are configured in Hive configuration file hive-site.xml. Malicious users can easily read the metastore credentials and then cause serious damage to data as well as metadata, so Hive metastore server can also be secured. In this authorization, you can also enable security at metastore level. After enabling metastore security, it will restrict the access on metadata objects by verifying that users have respective system permissions corresponding to different files and directories of metadata objects. To configure the storage-based authorization, set the following properties in the hive-site.xml file: Property Value hive.metastore.pre.event.listeners org.apache.hadoop.hive.ql.security.authorization.AuthorizationPreEventListener hive.security.metastore.authorization.manager org.apache.hadoop.hive.ql.security.authorization.StorageBasedAuthorizationProvider hive.security.metastore.authenticator.manager org.apache.hadoop.hive.ql.security.HadoopDefaultMetastoreAuthenticator hive.security.metastore.authorization.auth.reads true After setting all these configurations, Hive configuration file hive-site.xml will look as follows: <configuration> <property> <name>hive.metastore.pre.event.listeners</name> <value>org.apache.hadoop.hive.ql.security.authorization.AuthorizationPreEventListener</value> </property> <property> <name>hive.security.metastore.authorization.manager</name> <value>org.apache.hadoop.hive.ql.security.authorization.StorageBasedAuthorizationProvider</value> </property> <property> <name>hive.security.metastore.authenticator.manager</name> <value>org.apache.hadoop.hive.ql.security.HadoopDefaultMetastoreAuthenticator</value> </property> <property> <name>hive.security.metastore.authorization.auth.reads</name> <value>true</value> </property> </configuration> hive.metastore.pre.event.listeners: This property is used to define pre-event listener class, which is loaded on the metastore side. APIs of this class are executed before occurring of any event such as creating a database, table, or partition; altering a database, table, or partition; or dropping a database, table, or partition. Configuring this property turns on security at a metastore level. Set value of this property to org.apache.hadoop.hive.ql.security.authorization.AuthorizationPreEventListener. hive.security.metastore.authorization.manager: This property is used to define the authorization provider class for metastore security. The default value of this property is DefaultHiveMetastoreAuthorizationProvider, which provides default legacy authorization described in the previous bullet. To enable storage-based authorization based on Hadoop ACLs, set value of this property to org.apache.hadoop.hive.ql.security.authorization.StorageBasedAuthorizationProvider. You can also write your own custom class to manage authorization and configure this property to enable custom authorization manager. The custom authorization manager class must implement an interface org.apache.hadoop.hive.ql.security.authorization.HiveMetastoreAuthorizationProvider. hive.security.metastore.authenticator.manager: This property is used to define an authentication manager class. Set value of this property to org.apache.hadoop.hive.ql.security.HadoopDefaultMetastoreAuthenticator. You can also write your custom class to manage authentication and configure to this property. The custom authentication manager class must implement an interface org.apache.hadoop.hive.ql.security.HiveAuthenticationProvider. hive.security.metastore.authorization.auth.reads: This property is used to define whether metastore authorization should check for read access or not. The default value of this property is true. SQL Standard-based Authorization: SQL standard-based authorization is the third way of authorizing Hive. Although the previous methodology storage-based authorization also provides access control at level of partitions, tables, and databases, that methodology does not provide access control at more granular level such as columns and rows. This is because storage-based authorization depends on access control provided by HDFS using ACL that controls the access on the level of files and directories. SQL Standard-based authorization can be used to enforce fine-grained security. It is recommended to use as it is fully SQL compliant in its authorization model. There's more Many things can be done with SQL standard-based authorization. Use SQL standard-based authorization for more details. Summary In this article, we learned two different recipes Securing Hadoop and Authorizing Hive. You also learned different terminology of access permissions and their types. You went through various steps to secure Hadoop and learned different ways to perform authorization in Hive. Resources for Article: Further resources on this subject: Hive in Hadoop[article] Processing Tweets with Apache Hive[article] Using Hive non-interactively (Simple)[article]
Read more
  • 0
  • 0
  • 3495

article-image-introducing-test-driven-machine-learning
Packt
14 Oct 2015
19 min read
Save for later

Introducing Test-driven Machine Learning

Packt
14 Oct 2015
19 min read
In this article by Justin Bozonier, the author of the book Test Driven Machine Learning, we will see how to develop complex software (sometimes rooted in randomness) in small, controlled steps also it will guide you on how to begin developing solutions to machine learning problems using test-driven development (from here, this will be written as TDD). Mastering TDD is not something the book will achieve. Instead, the book will help you begin your journey and expose you to guiding principles, which you can use to creatively solve challenges as you encounter them. We will answer the following three questions in this article: What are TDD and behavior-driven development (BDD)? How do we apply these concepts to machine learning, and making inferences and predictions? How does this work in practice? (For more resources related to this topic, see here.) After having answers to these questions, we will be ready to move onto tackling real problems. The book is about applying these concepts to solve machine learning problems. This article is the largest theoretical explanation that we will have with the remainder of the theory being described by example. Due to the focus on application, you will learn much more than what you can learn about the theory of TDD and BDD. To read more about the theory and ideals, search the internet for articles written by the following: Kent Beck—The father of TDD Dan North—The father of BDD Martin Fowler—The father of refactoring, he has also created a large knowledge base, on these topics James Shore—one of the author of The Art of Agile Development, has a deep theoretical understanding of TDD, and explains the practical value of it quite well These concepts are incredibly simple and yet can take a lifetime to master. When applied to machine learning, we must find new ways to control and/or measure the random processes inherent in the algorithm. This will come up in this article as well as others. In the next section, we will develop a foundation for TDD and begin to explore its application. Test-driven development Kent Beck wrote in his seminal book on the topic that TDD consists of only two specific rules, which are as follows: Don't write a line of new code unless you first have a failing automated test Eliminate duplication This as he noted fairly quickly leads us to a mantra, really the mantra of TDD: Red, Green, Refactor. If this is a bit abstract, let me restate it that TDD is a software development process that enables a programmer to write code that specifies the intended behavior before writing any software to actually implement the behavior. The key value of TDD is that at each step of the way, you have working software as well as an itemized set of specifications. TDD is a software development process that requires the following: Writing code to detect the intended behavioral change. Rapid iteration cycle that produces working software after each iteration. It clearly defines what a bug is. If a test is not failing but a bug is found, it is not a bug. It is a new feature. Another point that Kent makes is that ultimately, this technique is meant to reduce fear in the development process. Each test is a checkpoint along the way to your goal. If you stray too far from the path and wind up in trouble, you can simply delete any tests that shouldn't apply, and then work your code back to a state where the rest of your tests pass. There's a lot of trial and error inherent in TDD, but the same matter applies to machine learning. The software that you design using TDD will also be modular enough to be able to have different components swapped in and out of your pipeline. You might be thinking that just thinking through test cases is equivalent to TDD. If you are like the most people, what you write is different from what you might verbally say, and very different from what you think. By writing the intent of our code before we write our code, it applies a pressure to our software design that prevents you from writing "just in case" code. By this I mean the code that we write just because we aren't sure if there will be a problem. Using TDD, we think of a test case, prove that it isn't supported currently, and then fix it. If we can't think of a test case, we don't add code. TDD can and does operate at many different levels of the software under development. Tests can be written against functions and methods, entire classes, programs, web services, neural networks, random forests, and whole machine learning pipelines. At each level, the tests are written from the perspective of the prospective client. How does this relate to machine learning? Lets take a step back and reframe what I just said. In the context of machine learning, tests can be written against functions, methods, classes, mathematical implementations, and the entire machine learning algorithms. TDD can even be used to explore technique and methods in a very directed and focused manner, much like you might use a REPL (an interactive shell where you can try out snippets of code) or the interactive (I)Python session. The TDD cycle The TDD cycle consists of writing a small function in the code that attempts to do something that we haven't programmed yet. These small test methods will have three main sections; the first section is where we set up our objects or test data; another section is where we invoke the code that we're testing; and the last section is where we validate that what happened is what we thought would happen. You will write all sorts of lazy code to get your tests to pass. If you are doing it right, then someone who is watching you should be appalled at your laziness and tiny steps. After the test goes green, you have an opportunity to refactor your code to your heart's content. In this context, refactor refers to changing how your code is written, but not changing how it behaves. Lets examine more deeply the three steps of TDD: Red, Green, and Refactor. Red First, create a failing test. Of course, this implies that you know what failure looks like in order to write the test. At the highest level in machine learning, this might be a baseline test where baseline is a better than random test. It might even be predicts random things, or even simpler always predicts the same thing. Is this terrible? Perhaps, it is to some who are enamored with the elegance and artistic beauty of his/her code. Is it a good place to start, though? Absolutely. A common issue that I have seen in machine learning is spending so much time up front, implementing the one true algorithm that hardly anything ever gets done. Getting to outperform pure randomness, though, is a useful change that can start making your business money as soon as it's deployed. Green After you have established a failing test, you can start working to get it green. If you start with a very high-level test, you may find that it helps to conceptually break that test up into multiple failing tests that are the lower-level concerns. I'll dive deeper into this later on in this article but for now, just know that you want to get your test passing as soon as possible; lie, cheat, and steal to get there. I promise that cheating actually makes your software's test suite that much stronger. Resist the urge to write the software in an ideal fashion. Just slap something together. You will be able to fix the issues in the next step. Refactor You got your test to pass through all the manners of hackery. Now, you get to refactor your code. Note that it is not to be interpreted loosely. Refactor specifically means to change your software without affecting its behavior. If you add the if clauses, or any other special handling, you are no longer refactoring. Then you write the software without tests. One way where you will know for sure that you are no longer refactoring is that you've broken previously passing tests. If this happens, we back up our changes until our tests pass again. It may not be obvious but this isn't all that it takes for you to know that you haven't changed behavior. Read Refactoring: Improving the Design of Existing Code, Martin Fowler for you to understand how much you should really care for refactoring. By the way of his illustration in this book, refactoring code becomes a set of forms and movements not unlike karate katas. This is a lot of general theory, but what does a test actually look like? How does this process flow in a real problem? Behavior-driven development BDD is the addition of business concerns to the technical concerns more typical of TDD. This came about as people became more experienced with TDD. They started noticing some patterns in the challenges that they were facing. One especially influential person, Dan North, proposed some specific language and structure to ease some of these issues. Some issues he noticed were the following: People had a hard time understanding what they should test next. Deciding what to name a test could be difficult. How much to test in a single test always seemed arbitrary. Now that we have some context, we can define what exactly BDD is. Simply put, it's about writing our tests in such a way that they will tell us the kind of behavior change they affect. A good litmus test might be asking oneself if the test you are writing would be worth explaining to a business stakeholder. How this solves the previous may not be completely obvious, but it may help to illustrate what this looks like in practice. It follows a structure of given, when, then. Committing to this style completely can require specific frameworks or a lot of testing ceremony. As a result, I loosely follow this in my tests as you will see soon. Here's a concrete example of a test description written in this style Given an empty dataset when the classifier is trained, it should throw an invalid operation exception. This sentence probably seems like a small enough unit of work to tackle, but notice that it's also a piece of work that any business user, who is familiar with the domain that you're working in, would understand and have an opinion on. You can read more about Dan North's point of view in this article on his website at dannorth.net/introducing-bdd/. The BDD adherents tend to use specialized tools to make the language and test result reports be as accessible to business stakeholders as possible. In my experience and from my discussions with others, this extra elegance is typically used so little that it doesn't seem worthwhile. The approach you will learn in the book will take a simplicity first approach to make it as easy as possible for someone with zero background to get up to speed. With this in mind, lets work through an example. Our first test Let's start with an example of what a test looks like in Python. The main reason for using this is that while it is a bit of a pain to install a library, this library, in particular, will make everything that we do much simpler. The default unit test solution in Python requires a heavier set up. On top of this, by using nose, we can always mix in tests that use the built-in solution where we find that we need the extra features. First, install it like this: pip install nose If you have never used pip before, then it is time for you to know that it is a very simple way to install new Python libraries. Now, as a hello world style example, lets pretend that we're building a class that will guess a number using the previous guesses to inform it. This is the first simplest example to get us writing some code. We will use the TDD cycle that we discussed previously, and write our first test in painstaking detail. After we get through our first test and have something concrete to discuss, we will talk about the anatomy of the test that we wrote. First, we must write a failing test. The simplest failing test that I can think of is the following: def given_no_information_when_asked_to_guess_test(): number_guesser = NumberGuesser() result = number_guesser.guess() assert result is None, "Then it should provide no result." The context for assert is in the test name. Reading the test name and then the assert name should do a pretty good job of describing what is being tested. Notice that in my test, I instantiate a NumberGuesser object. You're not missing any steps; this class doesn't exist yet. This seems roughly like how I'd want to use it. So, it's a great place to start with. Since it doesn't exist, wouldn't you expect this test to fail? Lets test this hypothesis. To run the test, first make sure your test file is saved so that it ends in _tests.py. From the directory with the previous code, just run the following: nosetests When I do this, I get the following result: Here's a lot going on here, but the most informative part is near the end. The message is saying that NumberGuesser does not exist yet, which is exactly what I expected since we haven't actually written the code yet. Throughout the book, we'll reduce the detail of the stack traces that we show. For now, we'll keep things detailed to make sure that we're on the same page. At this point, we're in a red state in the TDD cycle. Use the following steps to create our first successful test: Now, create the following class in a file named NumberGuesser.py: class NumberGuesser: """Guesses numbers based on the history of your input"" Import the new class at the top of my test file with a simple import NumberGuesser statement. I rerun nosetests, and get the following: TypeError: 'module' object is not callable Oh whoops! I guess that's not the right way to import the class. This is another very tiny step, but what is important is that we are making forward progress through constant communication with our tests. We are going through extreme detail because I can't stress this point enough; bear with me for the time being. Change the import statement to the following: from NumberGuesser import NumberGuesser Rerun nosetests and you will see the following: AttributeError: NumberGuesser instance has no attribute 'guess' The error message has changed, and is leading to the next thing that needs to be changed. From here, just implement what we think we need for the test to pass: class NumberGuesser: """Guesses numbers based on the history of your input""" def guess(self): return None On rerunning the nosetests, we'll get the following result: That's it! Our first successful test! Some of these steps seem so tiny so as to not being worthwhile. Indeed, overtime, you may decide that you prefer to work on a different level of detail. For the sake of argument, we'll be keeping our steps pretty small if only to illustrate just how much TDD keeps us on track and guides us on what to do next. We all know how to write the code in very large, uncontrolled steps. Learning to code surgically requires intentional practice, and is worth doing explicitly. Lets take a step back and look at what this first round of testing took. Anatomy of a test Starting from a higher level, notice how I had a dialog with Python. I just wrote the test and Python complained that the class that I was testing didn't exist. Next, I created the class, but then Python complained that I didn't import it correctly. So then, I imported it correctly, and Python complained that my guess method didn't exist. In response, I implemented the way that my test expected, and Python stopped complaining. This is the spirit of TDD. You have a conversation between you and your system. You can work in steps as little or as large as you're comfortable with. What I did previously could've been entirely skipped over, and the Python class could have been written and imported correctly the first time. The longer you go without talking to the system, the more likely you are to stray from the path to getting things working as simply as possible. Lets zoom in a little deeper and dissect this simple test to see what makes it tick. Here is the same test, but I've commented it, and broken it into sections that you will see recurring in every test that you write: def given_no_information_when_asked_to_guess_test(): # given number_guesser = NumberGuesser() # when guessed_number = number_guesser.guess() # then assert guessed_number is None, 'there should be no guess.' Given This section sets up the context for the test. In the previous test, you acquired that I didn't provide any prior information to the object. In many of our machine learning tests, this will be the most complex portion of our test. We will be importing certain sets of data, sometimes making a few specific issues in the data and testing our software to handle the details that we would expect. When you think about this section of your tests, try to frame it as Given this scenario… In our test, we might say Given no prior information for NumberGuesser… When This should be one of the simplest aspects of our test. Once you've set up the context, there should be a simple action that triggers the behavior that you want to test. When you think about this section of your tests, try to frame it as When this happens… In our test we might say When NumberGuesser guesses a number… Then This section of our test will check on the state of our variables and any return result if applicable. Again, this section should also be fairly straight-forward, as there should be only a single action that causes a change into your object under the test. The reason for this is that if it takes two actions to form a test, then it is very likely that we will just want to combine the two into a single action that we can describe in terms that are meaningful in our domain. A key example maybe loading the training data from a file and training a classifier. If we find ourselves doing this a lot, then why not just create a method that loads data from a file for us? In the book, you will find examples where we'll have the helper functions help us determine whether our results have changed in certain ways. Typically, we should view these helper functions as code smells. Remember that our tests are the first applications of our software. Anything that we have to build in addition to our code, to understand the results, is something that we should probably (there are exceptions to every rule) just include in the code we are testing. Given, When, Then is not a strong requirement of TDD, because our previous definition of TDD only consisted of two things (all that the code requires is a failing test first and an eliminate duplication). It's a small thing to be passionate about and if it doesn't speak to you, just translate this back into Arrange, act, assert in your head. At the very least, consider it as well as why these specific, very deliberate words are used. Applied to machine learning At this point, you maybe wondering how TDD will be used in machine learning, and whether we use it on regression or classification problems. In every machine learning algorithm, there exists a way to quantify the quality of what you're doing. In the linear regression; it's your adjusted R2 value; in classification problems, it's an ROC curve (and the area beneath it) or a confusion matrix, and more. All of these are testable quantities. Of course, none of these quantities have a built-in way of saying that the algorithm is good enough. We can get around this by starting our work on every problem by first building up a completely naïve and ignorant algorithm. The scores that we get for this will basically represent a plain, old, and random chance. Once we have built an algorithm that can beat our random chance scores, we just start iterating, attempting to beat the next highest score that we achieve. Benchmarking algorithms are an entire field onto their own right that can be delved in more deeply. In the book, we will implement a naïve algorithm to get a random chance score, and we will build up a small test suite that we can then use to pit this model against another. This will allow us to have a conversation with our machine learning models in the same manner as we had with Python earlier. For a professional machine learning developer, it's quite likely that an ideal metric to test is a profitability model that compares risk (monetary exposure) to expected value (profit). This can help us keep a balanced view of how much error and what kind of error we can tolerate. In machine learning, we will never have a perfect model, and we can search for the rest of our lives for the best model. By finding a way to work your financial assumptions into the model, we will have an improved ability to decide between the competing models. Summary In this article, you were introduced to TDD as well as BDD. With these concepts introduced, you have a basic foundation with which to approach machine learning. We saw that the specifying behavior in the form of sentences makes for an easier to ready a set of specifications for your software. Building off of that foundation, we started to delve into testing at a higher level. We did this by establishing concepts that we can use to quantify classifiers: the ROC curve and AUC metric. Now, we've seen that different models can be quantified; it follows that they can be compared. Putting all of this together, we have everything we need to explore machine learning with a test-driven methodology. Resources for Article: Further resources on this subject: Optimization in Python[article] How to do Machine Learning with Python[article] Modeling complex functions with artificial neural networks [article]
Read more
  • 0
  • 0
  • 3494
Modal Close icon
Modal Close icon