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-recommender-systems
Packt
16 Sep 2015
6 min read
Save for later

Recommender Systems

Packt
16 Sep 2015
6 min read
In this article by Suresh K Gorakala and Michele Usuelli, authors of the book Building a Recommendation System with R, we will learn how to prepare relevant data by covering the following topics: Selecting the most relevant data Exploring the most relevant data Normalizing the data Binarizing the data (For more resources related to this topic, see here.) Data preparation Here, we show how to prepare the data to be used in recommender models. These are the steps: Select the relevant data. Normalize the data. Selecting the most relevant data On exploring the data, you will notice that the table contains: Movies that have been viewed only a few times; their rating might be biased because of lack of data Users that rated only a few movies; their rating might be biased We need to determine the minimum number of users per movie and vice versa. The correct solution comes from an iteration of the entire process of preparing the data, building a recommendation model, and validating it. Since we are implementing the model for the first time, we can use a rule of thumb. After having built the models, we can come back and modify the data preparation. We define ratings_movies containing the matrix that we will use. It takes the following into account: Users who have rated at least 50 movies Movies that have been watched at least 100 times The following code shows this: ratings_movies <- MovieLense[rowCounts(MovieLense) > 50, colCounts(MovieLense) > 100] ratings_movies ## 560 x 332 rating matrix of class 'realRatingMatrix' with 55298 ratings. ratings_movies contains about half the number of users and a fifth of the number of movies that MovieLense has. Exploring the most relevant data Let's visualize the top 2 percent of users and movies of the new matrix: # visualize the top matrix min_movies <- quantile(rowCounts(ratings_movies), 0.98) min_users <- quantile(colCounts(ratings_movies), 0.98) Let's build the heat-map: image(ratings_movies[rowCounts(ratings_movies) > min_movies, colCounts(ratings_movies) > min_users], main = ""Heatmap of the top users and movies"") As you have already noticed, some rows are darker than the others. This might mean that some users give higher ratings to all the movies. However, we have visualized the top movies only. In order to have an overview of all the users, let's take a look at the distribution of the average rating by users: average_ratings_per_user <- rowMeans(ratings_movies) Let's visualize the distribution: qplot(average_ratings_per_user) + stat_bin(binwidth = 0.1) + ggtitle(""Distribution of the average rating per user"") As suspected, the average rating varies a lot across different users. Normalizing the data Users that give high (or low) ratings to all their movies might bias the results. We can remove this effect by normalizing the data in such a way that the average rating of each user is 0. The prebuilt normalize function does it automatically: ratings_movies_norm <- normalize(ratings_movies) Let's take a look at the average rating by user. sum(rowMeans(ratings_movies_norm) > 0.00001) ## [1] 0 As expected, the mean rating of each user is 0 (apart from the approximation error). We can visualize the new matrix using an image. Let's build the heat-map: # visualize the normalised matrix image(ratings_movies_norm[rowCounts(ratings_movies_norm) > min_movies,colCounts(ratings_movies_norm) > min_users],main = ""Heatmap of the top users and movies"") The first difference that we can notice are the colors, and it's because the data is continuous. Previously, the rating was an integer number between 1 and 5. After normalization, the rating can be any number between -5 and 5. There are still some lines that are more blue and some that are more red. The reason is that we are visualizing only the top movies. We already checked that the average rating is 0 for each user. Binarizing the data A few recommendation models work on binary data, so we might want to binarize our data, that is, define a table containing only 0s and 1s. The 0s will be treated as either missing values or bad ratings. In our case, we can do either of the following: Define a matrix that has 1 if the user rated the movie and 0 otherwise. In this case, we are losing the information about the rating. Define a matrix that has 1 if the rating is more than or equal to a definite threshold (for example 3) and 0 otherwise. In this case, giving a bad rating to a movie is equivalent to not rating it. Depending on the context, one choice is more appropriate than the other. The function to binarize the data is binarize. Let's apply it to our data. First, let's define a matrix equal to 1 if the movie has been watched, that is, if its rating is at least 1. ratings_movies_watched <- binarize(ratings_movies, minRating = 1) Let's take a look at the results. In this case, we will have black-and-white charts, so we can visualize a bigger portion of users and movies, for example, 5 percent. Similar to what we did earlier, let's select the 5 percent using quantile. The row and column counts are the same as the original matrix, so we can still apply rowCounts and colCounts on ratings_movies: min_movies_binary <- quantile(rowCounts(ratings_movies), 0.95) min_users_binary <- quantile(colCounts(ratings_movies), 0.95) Let's build the heat-map: image(ratings_movies_watched[rowCounts(ratings_movies) > min_movies_binary, colCounts(ratings_movies) > min_users_binary],main = ""Heatmap of the top users and movies"") Only a few cells contain non-watched movies. This is just because we selected the top users and movies. Let's use the same approach to compute and visualize the other binary matrix. Now, each cell is one if the rating is above a threshold, for example 3, and 0 otherwise. ratings_movies_good <- binarize(ratings_movies, minRating = 3) Let's build the heat-map: image(ratings_movies_good[rowCounts(ratings_movies) > min_movies_binary, colCounts(ratings_movies) > min_users_binary], main = ""Heatmap of the top users and movies"") As expected, we have more white cells now. Depending on the model, we can leave the ratings matrix as it is or normalize/binarize it. Summary In this article, you learned about data preparation and how you should select, explore, normalize, and binarize the data. Resources for Article: Further resources on this subject: Structural Equation Modeling and Confirmatory Factor Analysis [article] Warming Up [article] https://www.packtpub.com/books/content/supervised-learning [article]
Read more
  • 0
  • 0
  • 2624

article-image-understanding-mutability-and-immutability-python-c-and-javascript
Packt
14 Jul 2015
15 min read
Save for later

Understanding mutability and immutability in Python, C#, and JavaScript

Packt
14 Jul 2015
15 min read
In this article by Gastón C. Hillar, author of the book, Learning Object-Oriented Programming, you will learn the concept of mutability and immutability in the programming languages such as, Python, C#, and JavaScript. What’s the difference? By default, any instance field or attribute works like a variable; therefore we can change their values. When we create an instance of a class that defines many public instance fields, we are creating a mutable object, that is, an object that can change its state. For example, let's think about a class named MutableVector3D that represents a mutable 3D vector with three public instance fields: X, Y, and Z. We can create a new MutableVector3D instance and initialize the X, Y, and Z attributes. Then, we can call the Sum method with their delta values for X, Y, and Z as arguments. The delta values specify the difference between the existing value and the new or desired value. So, for example, if we specify a positive value of 20 in the deltaX parameter, it means that we want to add 20 to the X value. The following lines show pseudocode in a neutral programming language that create a new MutableVector3D instance called myMutableVector, initialized with values for the X, Y, and Z fields. Then, the code calls the Sum method with the delta values for X, Y, and Z as arguments, as shown in the following code: myMutableVector = new MutableVector3D instance with X = 30, Y = 50 and Z = 70 myMutableVector.Sum(deltaX: 20, deltaY: 30, deltaZ: 15) The initial values for the myMutableVector field are 30 for X, 50 for Y, and 70 for Z. The Sum method changes the values of all the three fields; therefore, the object state mutates as follows: myMutableVector.X mutates from 30 to 30 + 20 = 50 myMutableVector.Y mutates from 50 to 50 + 30 = 80 myMutableVector.Z mutates from 70 to 70 + 15 = 85 The values for the myMutableVector field after the call to the Sum method are 50 for X, 80 for Y, and 85 for Z. We can say this method mutated the object's state; therefore, myMutableVector is a mutable object: an instance of a mutable class. Mutability is very important in object-oriented programming. In fact, whenever we expose fields and/or properties, we will create a class that will generate mutable instances. However, sometimes a mutable object can become a problem. In certain situations, we want to avoid objects to change their state. For example, when we work with a concurrent code, an object that cannot change its state solves many concurrency problems and avoids potential bugs. For example, we can create an immutable version of the previous MutableVector3D class to represent an immutable 3D vector. The new ImmutableVector3D class has three read-only properties: X, Y, and Z. Thus, there are only three getter methods without setter methods, and we cannot change the values of the underlying internal fields: m_X, m_Y, and m_Z. We can create a new ImmutableVector3D instance and initialize the underlying internal fields: m_X, m_Y, and m_Z. X, Y, and Z attributes. Then, we can call the Sum method with the delta values for X, Y, and Z as arguments. The following lines show the pseudocode in a neutral programming language that create a new ImmutableVector3D instance called myImmutableVector, which is initialized with values for X, Y, and Z as arguments. Then, the pseudocode calls the Sum method with the delta values for X, Y, and Z as arguments: myImmutableVector = new ImmutableVector3D instance with X = 30, Y = 50 and Z = 70 myImmutableSumVector = myImmutableVector.Sum(deltaX: 20, deltaY: 30, deltaZ: 15) However, this time the Sum method returns a new instance of the ImmutableVector3D class with the X, Y, and Z values initialized to the sum of X, Y, and Z and the delta values for X, Y, and Z. So, myImmutableSumVector is a new ImmutableVector3D instance initialized with X = 50, Y = 80, and Z = 85. The call to the Sum method generated a new instance and didn't mutate the existing object. The immutable version adds an overhead as compared with the mutable version because it's necessary to create a new instance of a class as a result of calling the Sum method. The mutable version just changed the values for the attributes and it wasn't necessary to generate a new instance. Obviously, the immutable version has a memory and a performance overhead. However, when we work with the concurrent code, it makes sense to pay for the extra overhead to avoid potential issues caused by mutable objects. Using methods to add behaviors to classes in Python So far, we have added instance methods to classes and used getter and setter methods combined with decorators to define properties. Now, we want to generate a class to represent the mutable version of a 3D vector. We will use properties with simple getter and setter methods for x, y, and z. The sum public instance method receives the delta values for x, y, and z and mutates an object, that is, the setter method changes the values of x, y, and z. Here is the initial code of the MutableVector3D class: class MutableVector3D: def __init__(self, x, y, z): self.__x = x self.__y = y self.__z = z def sum(self, delta_x, delta_y, delta_z): self.__x += delta_x self.__y += delta_y self.__z += delta_z @property def x(self): return self.__x @x.setter def x(self, x): self.__x = x @property def y(self): return self.__y @y.setter def y(self, y): self.__y = y @property def z(self): return self.__z @z.setter def z(self, z): self.__z = z It's a very common requirement to generate a 3D vector with all the values initialized to 0, that is, x = 0, y = 0, and z = 0. A 3D vector with these values is known as an origin vector. We can add a class method to the MutableVector3D class named origin_vector to generate a new instance of the class initialized with all the values initialized to 0. It's necessary to add the @classmethod decorator before the class method header. Instead of receiving self as the first argument, a class method receives the current class; the parameter name is usually named cls. The following code defines the origin_vector class method: @classmethod def origin_vector(cls): return cls(0, 0, 0) The preceding method returns a new instance of the current class (cls) with 0 as the initial value for the three elements. The class method receives cls as the only argument; therefore, it will be a parameterless method when we call it because Python includes a class as a parameter under the hood. The following command calls the origin_vector class method to generate a 3D vector, calls the sum method for the generated instance, and prints the values for the three elements: mutableVector3D = MutableVector3D.origin_vector() mutableVector3D.sum(5, 10, 15) print(mutableVector3D.x, mutableVector3D.y, mutableVector3D.z) Now, we want to generate a class to represent the immutable version of a 3D vector. In this case, we will use read-only properties for x, y, and z. The sum public instance method receives the delta values for x, y, and z and returns a new instance of the same class with the values of x, y, and z initialized with the results of the sum. Here is the code of the ImmutableVector3D class: class ImmutableVector3D: def __init__(self, x, y, z): self.__x = x self.__y = y self.__z = z def sum(self, delta_x, delta_y, delta_z): return type(self)(self.__x + delta_x, self.__y + delta_y, self.__z + delta_z) @property def x(self): return self.__x @property def y(self): return self.__y @property def z(self): return self.__z @classmethod def equal_elements_vector(cls, initial_value): return cls(initial_value, initial_value, initial_value) @classmethod def origin_vector(cls): return cls.equal_elements_vector(0) Note that the sum method uses type(self) to generate and return a new instance of the current class. In this case, the origin_vector class method returns the results of calling the equal_elements_vector class method with 0 as an argument. Remember that the cls argument refers to the actual class. The equal_elements_vector class method receives an initial_value argument for all the elements of the 3D vector, creates an instance of the actual class, and initializes all the elements with the received unique value. The origin_vector class method demonstrates how we can call another class method in a class method. The following command calls the origin_vector class method to generate a 3D vector, calls the sum method for the generated instance, and prints the values for the three elements of the new instance returned by the sum method: vector0 = ImmutableVector3D.origin_vector() vector1 = vector0.sum(5, 10, 15) print(vector1.x, vector1.y, vector1.z) As explained previously, we can change the values of the private attributes; therefore, the ImmutableVector3D class isn't 100 percent immutable. However, we are all adults and don't expect the users of a class with read-only properties to change the values of private attributes hidden under difficult to access names. Using methods to add behaviors to classes in C# So far, we have added instance methods to a class in C#, and used getter and setter methods to define properties. Now, we want to generate a class to represent the mutable version of a 3D vector in C#. We will use auto-implemented properties for X, Y, and Z. The public Sum instance method receives the delta values for X, Y, and Z (deltaX, deltaY, and deltaZ) and mutates the object, that is, the method changes the values of X, Y, and Z. The following shows the initial code of the MutableVector3D class: class MutableVector3D { public double X { get; set; } public double Y { get; set; } public double Z { get; set; } public void Sum(double deltaX, double deltaY, double deltaZ) { this.X += deltaX; this.Y += deltaY; this.Z += deltaZ; } public MutableVector3D(double x, double y, double z) { this.X = x; this.Y = y; this.Z = z; } } It's a very common requirement to generate a 3D vector with all the values initialized to 0, that is, X = 0, Y = 0, and Z = 0. A 3D vector with these values is known as an origin vector. We can add a class method to the MutableVector3D class named OriginVector to generate a new instance of the class initialized with all the values initialized to 0. Class methods are also known as static methods in C#. It's necessary to add the static keyword after the public access modifier before the class method name. The following commands define the OriginVector static method: public static MutableVector3D OriginVector() { return new MutableVector3D(0, 0, 0); } The preceding method returns a new instance of the MutableVector3D class with 0 as the initial value for all the three elements. The following code calls the OriginVector static method to generate a 3D vector, calls the Sum method for the generated instance, and prints the values for all the three elements on the console output: var mutableVector3D = MutableVector3D.OriginVector(); mutableVector3D.Sum(5, 10, 15); Console.WriteLine(mutableVector3D.X, mutableVector3D.Y, mutableVector3D.Z) Now, we want to generate a class to represent the immutable version of a 3D vector. In this case, we will use read-only properties for X, Y, and Z. We will use auto-generated properties with private set. The Sum public instance method receives the delta values for X, Y, and Z (deltaX, deltaY, and deltaZ) and returns a new instance of the same class with the values of X, Y, and Z initialized with the results of the sum. The code for the ImmutableVector3D class is as follows: class ImmutableVector3D { public double X { get; private set; } public double Y { get; private set; } public double Z { get; private set; } public ImmutableVector3D Sum(double deltaX, double deltaY, double deltaZ) { return new ImmutableVector3D ( this.X + deltaX, this.Y + deltaY, this.Z + deltaZ); } public ImmutableVector3D(double x, double y, double z) { this.X = x; this.Y = y; this.Z = z; } public static ImmutableVector3D EqualElementsVector(double initialValue) { return new ImmutableVector3D(initialValue, initialValue, initialValue); } public static ImmutableVector3D OriginVector() { return ImmutableVector3D.EqualElementsVector(0); } } In the new class, the Sum method returns a new instance of the ImmutableVector3D class, that is, the current class. In this case, the OriginVector static method returns the results of calling the EqualElementsVector static method with 0 as an argument. The EqualElementsVector class method receives an initialValue argument for all the elements of the 3D vector, creates an instance of the actual class, and initializes all the elements with the received unique value. The OriginVector static method demonstrates how we can call another static method in a static method. The following code calls the OriginVector static method to generate a 3D vector, calls the Sum method for the generated instance, and prints all the values for the three elements of the new instance returned by the Sum method on the console output: var vector0 = ImmutableVector3D.OriginVector(); var vector1 = vector0.Sum(5, 10, 15); Console.WriteLine(vector1.X, vector1.Y, vector1.Z); C# doesn't allow users of the ImmutableVector3D class to change the values of X, Y, and Z properties. The code doesn't compile if you try to assign a new value to any of these properties. Thus, we can say that the ImmutableVector3D class is 100 percent immutable. Using methods to add behaviors to constructor functions in JavaScript So far, we have added methods to a constructor function that produced instance methods in a generated object. In addition, we used getter and setter methods combined with local variables to define properties. Now, we want to generate a constructor function to represent the mutable version of a 3D vector. We will use properties with simple getter and setter methods for x, y, and z. The sum public instance method receives the delta values for x, y, and z and mutates an object, that is, the method changes the values of x, y, and z. The following code shows the initial code of the MutableVector3D constructor function: function MutableVector3D(x, y, z) { var _x = x; var _y = y; var _z = z; Object.defineProperty(this, 'x', { get: function(){ return _x; }, set: function(val){ _x = val; } }); Object.defineProperty(this, 'y', { get: function(){ return _y; }, set: function(val){ _y = val; } }); Object.defineProperty(this, 'z', { get: function(){ return _z; }, set: function(val){ _z = val; } }); this.sum = function(deltaX, deltaY, deltaZ) { _x += deltaX; _y += deltaY; _z += deltaZ; } } It's a very common requirement to generate a 3D vector with all the values initialized to 0, that is, x = 0, y = 0, and, z = 0. A 3D vector with these values is known as an origin vector. We can add a function to the MutableVector3D constructor function named originVector to generate a new instance of a class with all the values initialized to 0. The following code defines the originVector function: MutableVector3D.originVector = function() { return new MutableVector3D(0, 0, 0); }; The method returns a new instance built in the MutableVector3D constructor function with 0 as the initial value for all the three elements. The following code calls the originVector function to generate a 3D vector, calls the sum method for the generated instance, and prints all the values for all the three elements: var mutableVector3D = MutableVector3D.originVector(); mutableVector3D.sum(5, 10, 15); console.log(mutableVector3D.x, mutableVector3D.y, mutableVector3D.z); Now, we want to generate a constructor function to represent the immutable version of a 3D vector. In this case, we will use read-only properties for x, y, and z. In this case, we will use the ImmutableVector3D.prototype property to define the sum method. The method receives the values of delta for x, y, and z, and returns a new instance with the values of x, y, and z initialized with the results of the sum. The following code shows the ImmutableVector3D constructor function and the additional code that defines all the other methods: function ImmutableVector3D(x, y, z) { var _x = x; var _y = y; var _z = z; Object.defineProperty(this, 'x', { get: function(){ return _x; } }); Object.defineProperty(this, 'y', { get: function(){ return _y; } }); Object.defineProperty(this, 'z', { get: function(){ return _z; } }); } ImmutableVector3D.prototype.sum = function(deltaX, deltaY, deltaZ) { return new ImmutableVector3D( this.x + deltaX, this.y + deltaY, this.z + deltaZ); }; ImmutableVector3D.equalElementsVector = function(initialValue) { return new ImmutableVector3D(initialValue, initialValue, initialValue); }; ImmutableVector3D.originVector = function() { return ImmutableVector3D.equalElementsVector(0); }; Again, note that the preceding code defines the sum method in the ImmutableVector3D.prototype method. This method will be available to all the instances generated in the ImmutableVector3D constructor function. The sum method generates and returns a new instance of ImmutableVector3D. In this case, the originVector method returns the results of calling the equalElementsVector method with 0 as an argument. The equalElementsVector method receives an initialValue argument for all the elements of the 3D vector, creates an instance of the actual class, and initializes all the elements with the received unique value. The originVector method demonstrates how we can call another function defined in the constructor function. The following code calls the originVector method to generate a 3D vector, calls the sum method for the generated instance, and prints the values for all the three elements of the new instance returned by the sum method: var vector0 = ImmutableVector3D.originVector(); var vector1 = vector0.sum(5, 10, 15); console.log(vector1.x, vector1.y, vector1.z); Summary In this article, you learned the concept of mutability and immutability in the programming languages such as, Python, C#, and JavaScript and used methods to add behaviors in each of the programming language. So, what’s next? Continue Learning Object-Oriented Programming with Gastón’s book – find out more here.
Read more
  • 0
  • 0
  • 2622

article-image-codeigniter-17-and-objects
Packt
27 Nov 2009
9 min read
Save for later

CodeIgniter 1.7 and Objects

Packt
27 Nov 2009
9 min read
Objects confused us, when we started using CodeIgniter. Coming to CodeIgniter through PHP 4, which is a procedural language, and not an object-oriented (OO) language. We duly looked up objects and methods, properties and inheritance, and encapsulation, but our early attempts to write CI code were plagued by the error message "Call to a member function on a non-object". We saw it so often that we were thinking of having it printed on a T-shirt. To save the world from a lot of boring T-shirts, this article covers the way in which CI uses objects, and the different ways you can write and use your own objects. Incidentally, we've used "variables/properties", and "methods/functions" interchangeably, as CI and PHP often do. You write "functions" in your controllers, for instance, when an OO purist would call them "methods". You define class "variables" when the purist would call them "properties". Object-oriented programming We assume that you have basic knowledge of OOP. You may have learned it as an afterthought to "normal" PHP 4. PHP 4 is not an OO language, though some OO functionality has been stacked on to it. PHP 5 is much better, with an underlying engine that was written from the ground up with OO in mind. You can do most of the basics in PHP 4, and CI manages to do everything it needs internally in either language. The key thing to remember—when an OO program is running, there is always one current object (but only one). Objects may call each other or hand over control to each other, in which case the current object changes, but only one of them can be current at any time. The current object defines the scope, in other words, the variables (properties) and methods (functions) that are available to the program at that moment. So it's important to know and control the current object. PHP, being a mixture of functional and OO programming, also offers the possibility where no object is current. You can start off with a functional program, call an object, let it take charge for a while, and then return control to the program. Luckily, CI takes care of this for you. The CI super-object CI works by building one super-object—it runs the entire program as one big object, in order to eliminate scoping issues. When you start CI, a complex chain of events occurs. If you set your CI installation to create a log (in /codeigniter/application/config/config.php set $config['log_threshold'] = 4; value. This will generate a log file in /www/CI_system/logs/), you'll see something like this: 1 DEBUG - 2006-10-03 08:56:39 --> Config Class Initialized2 DEBUG - 2006-10-03 08:56:39 --> No URI present. Default controllerset.3 DEBUG - 2006-10-03 08:56:39 --> Router Class Initialized4 DEBUG - 2006-10-03 08:56:39 --> Output Class Initialized5 DEBUG - 2006-10-03 08:56:39 --> Input Class Initialized6 DEBUG - 2006-10-03 08:56:39 --> Global POST and COOKIE datasanitized7 DEBUG - 2006-10-03 08:56:39 --> URI Class Initialized8 DEBUG - 2006-10-03 08:56:39 --> Language Class Initialized9 DEBUG - 2006-10-03 08:56:39 --> Loader Class Initialized10 DEBUG - 2006-10-03 08:56:39 --> Controller Class Initialized11 DEBUG - 2006-10-03 08:56:39 --> Helpers loaded: security12 DEBUG - 2006-10-03 08:56:40 --> Scripts loaded: errors13 DEBUG - 2006-10-03 08:56:40 --> Scripts loaded: boilerplate14 DEBUG - 2006-10-03 08:56:40 --> Helpers loaded: url15 DEBUG - 2006-10-03 08:56:40 --> Database Driver Class Initialized16 DEBUG - 2006-10-03 08:56:40 --> Model Class Initialized At start up, that is, each time a page request is received over the Internet—CI goes through the same procedure. You can trace the log through the CI files: The index.php file receives a page request. The URL may indicate which controller is required, if not, CI has a default controller (line 2). The index.php file makes some basic checks and calls the codeigniter.php file (codeignitercodeigniter.php). require_once BASEPATH.'codeigniter/CodeIgniter'.EXT; The codeigniter.php file instantiates the Config, Router, Input, URL, and other such, classes (see lines 1, and 3 to 9). These are called the base classes—you rarely interact directly with them, but they underlie almost everything CI does. /** ------------------------------------------------------* Instantiate the base classes* ------------------------------------------------------*/$CFG =& load_class('Config');$URI =& load_class('URI');$RTR =& load_class('Router');$OUT =& load_class('Output'); The file codeigniter.php tests to see the version of PHP it is running on, and calls Base4 or Base5 (/codeigniter/Base4.php or codeigniter/Base5.php). if (floor(phpversion()) < 5){load_class('Loader', FALSE);require(BASEPATH.'codeigniter/Base4'.EXT);}else{require(BASEPATH.'codeigniter/Base5'.EXT);} The above snippet creates an object—one which ensures that a class has only one instance. Each has a public &get_instance() function. Note the &—this is assignment by reference. So, if you assign using &get_instance() method, it assigns to the single running instance of the class. In other words, it points to the same pigeonhole. So, instead of setting up lot of new objects, you start building one super-object, which contains everything related to the framework. function &get_instance(){return CI_Base::get_instance();} A security check, /** ------------------------------------------------------* Security check* ------------------------------------------------------** None of the functions in the app controller or the* loader class can be called via the URI, nor can* controller functions that begin with an underscore*/$class = $RTR->fetch_class();$method = $RTR->fetch_method();if ( !class_exists($class)OR $method == 'controller'OR strncmp($method, '_', 1) == 0OR in_array(strtolower($method), array_map('strtolower',get_class_methods('Controller')))){show_404("{$class}/{$method}");} The file, codeigniter.php instantiates the controller that was requested, or a default controller (line 10). The new class is called $CI. $CI = new $class(); The function specified in the URL (or a default) is then called and life, as we know it, starts to wake up and happen. Depending on what you wrote in your controller, CI will initialize the classes you need, and "include" functional scripts you asked for. So, in the log, the model class is initialized (line 16). The boilerplate script, which is also shown in the log (line 13), is the one we wrote to contain standard chunks of text. It's a .php file, saved in the folder called scripts. It's not a class—just a set of functions. If you were writing pure PHP you might use include or require to bring it into the namespace—CI needs to use its own load function to bring it into the super-object. The concept of namespace or scope is crucial here. When you declare a variable, array, object, and so on, PHP holds the variable name in its memory and assigns a further block of memory to hold its contents. However, problems might arise if you define two variables with the same name. (In a complex site, this is easily done.) For this reason, PHP has several set of rules. Some of them are as listed: Each function has its own namespace or scope, and variables defined within a function are usually local to it. Outside the function, they are meaningless. You can declare global variables, which are held in a special global namespace and are available throughout the program. Objects have their own namespaces—variables exist inside the object as long as the object exists, and can only be referenced by using the object. So, $variable, global $variable, and $this->variable are three different things. Remember, $variable and global $variable can't be used in the same scope. So, inside a function you will have to decide if you want to use $variable or global $variable. Particularly before OO, this could lead to all sort of confusions—you may have too many variables in your namespace (so that conflicting names overwrite each other). You may also find that some variables are just not accessible from whatever scope you happen to be. Copying by reference You may have noticed the function &get_instance() in the previous section. This is to ensure that, as the variables change, the variables of the original class also change. As assignment by reference can be confusing, so here's a short explanation. We're all familiar with simple copying in PHP: $one = 1;$two = $one;echo $two; The previous snippet produces 1, because $two is a copy of $one. However, suppose you reassign $one: $one = 1;$two = $one;$one = 5;echo $two; This code still produces $two = 1, because changes made to $one after assigning $two have not been reflected in $two. This was a one-off assignment of the value that happened to be in variable $one at that time, to a new variable $two. Once that is done, the two variables lead separate lives (in just the same way if we alter $two, $one doesn't change). In effect, PHP creates two pigeonholes—called $one and $two. A separate value lives in each. You may, on any occasion, make the values equal, but after that each does its own work. PHP also allows copying by reference. If you add just a simple & to line 2 of the snippet as shown: $one = 1;$two =& $one;$one = 5;echo $two; The code now echoes 5, the change we made to $one is reflected in $two. Changing the = to =& in the second line means that the assignment is "by reference". It looks as if there was only one pigeonhole, which has two names ($one<.i> and $two). Whatever happens to the contents of the pigeonhole is reflected in both $one and $two, as if they were just different names for the same variables. The principle works for objects as well as simple string variables. You can copy or clone an object using the = operator in PHP 4. Or you can clone keyword in PHP, in which case you make a simple one-off new copy, which then leads an independent life. You can also assign one to the other by reference, so the two objects point to each other. Any changes made to one will also happen to the other. Again, think of them as two different names for the same thing.
Read more
  • 0
  • 0
  • 2621

article-image-creating-our-first-bot-webbot
Packt
03 Oct 2013
9 min read
Save for later

Creating our first bot, WebBot

Packt
03 Oct 2013
9 min read
(For more resources related to this topic, see here.)   With the knowledge you have gained, we are now ready to develop our first bot, which will be a simple bot that gathers data (documents) based on a list of URLs and datasets (field and field values) that we will require. First, let's start by creating our bot package directory. So, create a directory called WebBot so that the files in our project_directory/lib directory look like the following: '-- project_directory|-- lib | |-- HTTP (our existing HTTP package) | | '-- (HTTP package files here) | '-- WebBot | |-- bootstrap.php| |-- Document.php | '-- WebBot.php |-- (our other files)'-- 03_webbot.php As you can see, we have a very clean and simple directory and file structure that any programmer should be able to easily follow and understand. The WebBot class Next, open the file WebBot.php file and add the code from the project_directory/lib/WebBot/WebBot.php file: In our WebBot class, we first use the __construct() method to pass the array of URLs (or documents) we want to fetch, and the array of document fields are used to define the datasets and regular expression patterns. Regular expression patterns are used to populate the dataset values (or document field values). If you are unfamiliar with regular expressions, now would be a good time to study them. Then, in the __construct() method, we verify whether there are URLs to fetch or not. If there , we set an error message stating this problem. Next, we use the __formatUrl() method to properly format URLs we fetch data. This method will also set the correct protocol: either HTTP or HTTPS ( Hypertext Transfer Protocol Secure ). If the protocol is already set for the URL, for example http://www.[dom].com, we ignore setting the protocol. Also, if the class configuration setting conf_force_https is set to true, we force the HTTPS protocol again unless the protocol is already set for the URL. We then use the execute() method to fetch data for each URL, set and add the Document objects to the array of documents, and track document statistics. This method also implements fetchdelay logic that will delay each fetch by x number of seconds if set in the class configuration settings conf_delay_between_fetches. We also include the logic that only allows distinct URL fetches, meaning that, if we have already fetched data for a URL we won't fetch it again; this eliminates duplicate URL data fetches. The Document object is used as a container for the URL data, and we can use the Document object to use the URL data, the data fields, and their corresponding data field values. In the execute() method, you can see that we have performed a HTTPRequest::get() request using the URL and our default timeout value—which is set with the class configuration settings conf_default_timeout. We then pass the HTTPResponse object that is returned by the HTTPRequest::get() method to the Document object. Then, the Document object uses the data from the HTTPResponse object to build the document data. Finally, we include the getDocuments() method, which simply returns all the Document objects in an array that we can use for our own purposes as we desire. The WebBot Document class Next, we need to create a class called Document that can be used to store document data and field names with their values. To do this we will carry out the following steps: We first pass the data retrieved by our WebBot class to the Document class. Then, we define our document's fields and values using regular expression patterns. Next, add the code from the project_directory/lib/WebBot/Document.php file. Our Document class accepts the HTTPResponse object that is set in WebBot class's execute() method, and the document fields and document ID. In the Document __construct() method, we set our class properties: the HTTP Response object, the fields (and regular expression patterns), the document ID, and the URL that we use to fetch the HTTP response. We then check if the HTTP response successful (status code 200), and if it isn't, we set the error with the status code and message. Lastly, we call the __setFields() method. The __setFields() method parses out and sets the field values from the HTTP response body. For example, if in our fields we have a title field defined as $fields = ['title' => '<title>(.*)</title>'];, the __setFields() method will add the title field and pull all values inside the <title>*</title> tags into the HTML response body. So, if there were two title tags in the URL data, the __setField() method would add the field and its values to the document as follows: ['title'] => [ 0 => 'title x', 1 => 'title y' ] If we have the WebBot class configuration variable—conf_include_document_field_raw_values—set to true, the method will also add the raw values (it will include the tags or other strings as defined in the field's regular expression patterns) as a separate element, for example: ['title'] => [ 0 => 'title x', 1 => 'title y', 'raw' => [ 0 => '<title>title x</title>', 1 => '<title>title y</title>' ] ] The preceding code is very useful when we want to extract specific data (or field values) from URL data. To conclude the Document class, we have two more methods as follows: getFields(): This method simply returns the fields and field values getHttpResponse(): This method can be used to get the HTTPResponse object that was originally set by the WebBot execute() method This will allow us to perform logical requests to internal objects if we wish. The WebBot bootstrap file Now we will create a bootstrap.php file (at project_directory/lib/WebBot/) to load the HTTP package and our WebBot package classes, and set our WebBot class configuration settings: <?php namespace WebBot; /** * Bootstrap file * * @package WebBot */ // load our HTTP package require_once './lib/HTTP/bootstrap.php'; // load our WebBot package classes require_once './lib/WebBot/Document.php'; require_once './lib/WebBot/WebBot.php'; // set unlimited execution time set_time_limit(0); // set default timeout to 30 seconds WebBotWebBot::$conf_default_timeout = 30; // set delay between fetches to 1 seconds WebBotWebBot::$conf_delay_between_fetches = 1; // do not use HTTPS protocol (we'll use HTTP protocol) WebBotWebBot::$conf_force_https = false; // do not include document field raw values WebBotWebBot::$conf_include_document_field_raw_values = false; We use our HTTP package to handle HTTP requests and responses. You have seen in our WebBot class how we use HTTP requests to fetch the data, and then use the HTTP Response object to store the fetched data in the previous two sections. That is why we need to include the bootstrap file to load the HTTP package properly. Then, we load our WebBot package files. Because our WebBot class uses the Document class, we load that class file first. Next, we use the built-in PHP function set_time_limit() to tell the PHP interpreter that we want to allow unlimited execution time for our script. You don't necessarily have to use unlimited execute time. However, for testing reasons, we will use unlimited execution time for this example. Finally, we set the WebBot class configuration settings. These settings are used by the WebBot object internally to make our bot work as we desire. We should always make the configuration settings as simple as possible to help other developers understand. This means we should also include detailed comments in our code to ensure easy usage of package configuration settings. We have set up four configuration settings in our WebBot class. These are static and public variables, meaning that we can set them from anywhere after we have included the WebBot class, and once we set them they will remain the same for all WebBot objects unless we change the configuration variables. If you do not understand the PHP keyword static, now would be a good time to research this subject. The first configuration variable is conf_default_timeout. This variable is used to globally set the default timeout (in seconds) for all WebBot objects we create. The timeout value tells the HTTPRequest class how long it continue trying to send a request before stopping and deeming it as a bad request, or a timed-out request. By default, this configuration setting value is set to 30 (seconds). The second configuration variable—conf_delay_between_fetches—is used to set a time delay (in seconds) between fetches (or HTTP requests). This can be very useful when gathering a lot of data from a website or web service. For example, say, you had to fetch one million documents from a website. You wouldn't want to unleash your bot with that type of mission without fetch delays because you could inevitably cause—to that website—problems due to massive requests. By default, this value is set to 0, or no delay. The third WebBot class configuration variable—conf_force_https—when set to true, can be used to force the HTTPS protocol. As mentioned earlier, this will not override any protocol that is already set in the URL. If the conf_force_https variable is set to false, the HTTP protocol will be used. By default, this value is set to false. The fourth and final configuration variable—conf_include_document_field_raw_values—when set to true, will force the Document object to include the raw values gathered from the ' regular expression patterns. We've discussed configuration settings in detail in the WebBot Document Class section earlier in this article. By default, this value is set to false. Summary In this article you have learned how to get started with building your first bot using HTTP requests and responses. Resources for Article : Further resources on this subject: Installing and Configuring Jobs! and Managing Sections, Categories, and Articles using Joomla! [Article] Search Engine Optimization in Joomla! [Article] Adding a Random Background Image to your Joomla! Template [Article]
Read more
  • 0
  • 0
  • 2621

article-image-using-javascript-and-jquery-drupal-themes
Packt
10 Feb 2011
6 min read
Save for later

Using JavaScript and jQuery in Drupal Themes

Packt
10 Feb 2011
6 min read
  Drupal 6 Theming Cookbook Over 100 clear step-by-step recipes to create powerful, great-looking Drupal themes Take control of the look and feel of your Drupal website Tips and tricks to get the most out of Drupal's theming system Learn how to customize existing themes and create unique themes from scratch Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible         Read more about this book       (For more resources on Drupal, see here.) Introduction JavaScript libraries take out the majority of the hassle involved in writing code which will be executed in a variety of browsers each with its own vagaries. Drupal, by default, uses jQuery, a lightweight, robust, and well-supported package which, since its introduction, has become one of the most popular libraries in use today. While it is possible to wax eloquent about its features and ease of use, its most appealing factor is that it is a whole lot of fun! jQuery's efficiency and flexibility lies in its use of CSS selectors to target page elements and its use of chaining to link and perform commands in sequence. As an example, let us consider the following block of HTML which holds the items of a typical navigation menu. <div class="menu"> <ul class="menu-list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> <li>Item 5</li> <li>Item 6</li> </ul></div> Now, let us consider the situation where we want to add the class active to the first menu item in this list and, while we are at it, let us also color this element red. Using arcane JavaScript, we would have accomplished this with something like the following: var elements = document.getElementsByTagName("ul");for (var i = 0; i < elements.length; i++) { if (elements[i].className === "menu-list") { elements[i].childNodes[0].style.color = '#F00'; if (!elements[i].childNodes[0].className) { elements[i].childNodes[0].className = 'active'; } else { elements[i].childNodes[0].className = elements[i].childNodes[0].className + ' active'; } }} Now, we would accomplish the same task using jQuery as follows: $("ul.menu-list li:first-child").css('color', '#F00').addClass('active'); The statement we have just seen can be effectively read as: Retrieve all UL tags classed menu-list and having LI tags as children, take the first of these LI tags, style it with some CSS which sets its color to #F00 (red) and then add a class named active to this element. For better legibility, we can format the previous jQuery with each chained command on a separate line. $("ul.menu-list li:first-child") .css('color', '#F00') .addClass('active'); We are just scratching the surface here. More information and documentation on jQuery's features are available at http://jquery.com and http://www.visualjquery.com. A host of plugins which, like Drupal's modules, extend and provide additional functionality, are available at http://plugins.jquery.com. Another aspect of JavaScript programming that has improved in leaps and bounds is in the field of debugging. With its rising ubiquity, developers have introduced powerful debugging tools that are integrated into browsers and provide tools, such as interactive debugging, flow control, logging and monitoring, and so on, which have traditionally only been available to developers of other high-level languages. Of the many candidates out there, the most popular and feature-rich is Firebug. It can be downloaded and installed from https://addons.mozilla.org/en-US/ firefox/addon/1843. Including JavaScript files from a theme This recipe will list the steps required to include a JavaScript file from the .info file of the theme. We will be using the file to ensure that it is being included by outputting the standard Hello World! string upon page load. Getting ready While the procedure is the same for all the themes, we will be using the Zen-based myzen theme in this recipe. How to do it... The following steps are to be performed inside the myzen theme folder at sites/all/ themes/myzen. Browse into the js subfolder where JavaScript files are conventionally stored. Create a file named hello.js and open it in an editor. Add the following code: alert("Hello World!!"); Save the file and exit the editor. Browse back up to the myzen folder and open myzen.info in an editor. Include our new script using the following syntax: scripts[] = js/hello.js Save the file and exit the editor. Rebuild the theme registry and if JavaScript optimization is enabled for the site, the cache will also need to be cleared. View any page on the site to see our script taking effect. How it works... Once the theme registry is rebuilt and the cache cleared, Drupal adds hello.js to its list of JavaScript files to be loaded and embeds it in the HTML page. The JavaScript is executed before any of the content is displayed on the page and the resulting page with the alert dialog box should look something like the following screenshot: There's more... While we have successfully added our JavaScript in this recipe, Drupal and jQuery provide efficient solutions to work around this issue of the JavaScript being executed as soon as the page is loaded. Executing JavaScript only after the page is rendered A solution to the problem of the alert statement being executed before the page is ready, is to wrap our JavaScript inside jQuery's ready() function. Using it ensures that the code within is executed only once the page has been rendered and is ready to be acted upon. if (Drupal.jsEnabled) { $(document).ready(function () { alert("Hello World!!"); });} Furthermore, we have wrapped the ready() function within a check for Drupal.jsEnabled which acts as a global killswitch. If this variable is set to false, then JavaScript is turned off for the entire site and vice versa. It is set to true by default provided that the user's browser meets Drupal's requirements. Drupal's JavaScript behaviors While jQuery's ready() function works well, Drupal recommends the use of behaviors to manage our use of JavaScript. Our Hello World example would now look like this: Drupal.behaviors.myzenAlert = function (context) { alert("Hello World!!");}; All registered behaviors are called automatically by Drupal once the page is ready. Drupal.behaviors also allows us to forego the call to the ready() function as well as the check for jsEnabled as these are done implicitly. As with most things Drupal, it is always a good idea to namespace our behaviors based on the module or theme name to avoid conflicts. In this case, the behavior name has been prefixed with myzen as it is part of the myzen theme.
Read more
  • 0
  • 0
  • 2620

article-image-learn-data
Packt
09 Mar 2017
6 min read
Save for later

Learn from Data

Packt
09 Mar 2017
6 min read
In this article by Rushdi Shams, the author of the book Java Data Science Cookbook, we will cover recipes that use machine learning techniques to learn patterns from data. These patterns are at the centre of attention for at least three key machine-learning tasks: classification, regression, and clustering. Classification is the task of predicting a value from a nominal class. In contrast to classification, regression models attempt to predict a value from a numeric class. (For more resources related to this topic, see here.) Generating linear regression models Most of the linear regression modelling follows a general pattern—there will be many independent variables that will be collectively produce a result, which is a dependent variable. For instance, we can generate a regression model to predict the price of a house based on different attributes/features of a house (mostly numeric, real values) like its size in square feet, number of bedrooms, number of washrooms, importance of its location, and so on. In this recipe, we will use Weka’s Linear Regression classifier to generate a regression model. Getting ready In order to perform the recipes in this section, we will require the following: To download Weka, go to http://www.cs.waikato.ac.nz/ml/weka/downloading.html and you will find download options for Windows, Mac, and other operating systems such as Linux. Read through the options carefully and download the appropriate version. During the writing of this article, 3.9.0 was the latest version for the developers and as the author already had version 1.8 JVM installed in his 64-bit Windows machine, he has chosen to download a self-extracting executable for 64-bit Windows without a Java Virtual Machine (JVM)   After the download is complete, double-click on the executable file and follow on screen instructions. You need to install the full version of Weka. Once the installation is done, do not run the software. Instead, go to the directory where you have installed it and find the Java Archive File for Weka (weka.jar). Add this file in your Eclipse project as external library. If you need to download older versions of Weka for some reasons, all of them can be found at https://sourceforge.net/projects/weka/files/. Please note that there is a possibility that many of the methods from old versions are deprecated and therefore not supported any more. How to do it… In this recipe, the linear regression model we will be creating is based on the cpu.arff dataset that can be found in the data directory of the Weka installation directory. Our code will have two instance variables: the first variable will contain the data instances of cpu.arff file and the second variable will be our linear regression classifier. Instances cpu = null; LinearRegression lReg ; Next, we will be creating a method to load the ARFF file and assign the last attribute of the ARFF file as its class attribute. public void loadArff(String arffInput){ DataSource source = null; try { source = new DataSource(arffInput); cpu = source.getDataSet(); cpu.setClassIndex(cpu.numAttributes() - 1); } catch (Exception e1) { } } We will be creating a method to build the linear regression model. To do so, we simply need to call the buildClassifier() method of our linear regression variable. The model can directly be sent as parameter to System.out.println(). public void buildRegression(){ lReg = new LinearRegression(); try { lReg.buildClassifier(cpu); } catch (Exception e) { } System.out.println(lReg); } The complete code for the recipe is as follows: import weka.classifiers.functions.LinearRegression; import weka.core.Instances; import weka.core.converters.ConverterUtils.DataSource; public class WekaLinearRegressionTest { Instances cpu = null; LinearRegression lReg ; public void loadArff(String arffInput){ DataSource source = null; try { source = new DataSource(arffInput); cpu = source.getDataSet(); cpu.setClassIndex(cpu.numAttributes() - 1); } catch (Exception e1) { } } public void buildRegression(){ lReg = new LinearRegression(); try { lReg.buildClassifier(cpu); } catch (Exception e) { } System.out.println(lReg); } public static void main(String[] args) throws Exception{ WekaLinearRegressionTest test = new WekaLinearRegressionTest(); test.loadArff("path to the cpu.arff file"); test.buildRegression(); } } The output of the code is as follows: Linear Regression Model class = 0.0491 * MYCT + 0.0152 * MMIN + 0.0056 * MMAX + 0.6298 * CACH + 1.4599 * CHMAX + -56.075 Generating logistic regression models Weka has a class named Logistic that can be used for building and using a multinomial logistic regression model with a ridge estimator. Although original Logistic Regression does not deal with instance weights, the algorithm in Weka has been modified to handle the instance weights. In this recipe, we will use Weka to generate logistic regression model on iris dataset. How to do it… We will be generating a logistic regression model from the iris dataset that can be found in the data directory in the installed folder of Weka. Our code will have two instance variables: one will be containing the data instances of iris dataset and the other will be the logistic regression classifier.  Instances iris = null; Logistic logReg ; We will be using a method to load and read the dataset as well as assign its class attribute (the last attribute of iris.arff file): public void loadArff(String arffInput){ DataSource source = null; try { source = new DataSource(arffInput); iris = source.getDataSet(); iris.setClassIndex(iris.numAttributes() - 1); } catch (Exception e1) { } } Next, we will be creating the most important method of our recipe that builds a logistic regression classifier from the iris dataset: public void buildRegression(){ logReg = new Logistic(); try { logReg.buildClassifier(iris); } catch (Exception e) { } System.out.println(logReg); } The complete executable code for the recipe is as follows: import weka.classifiers.functions.Logistic; import weka.core.Instances; import weka.core.converters.ConverterUtils.DataSource; public class WekaLogisticRegressionTest { Instances iris = null; Logistic logReg ; public void loadArff(String arffInput){ DataSource source = null; try { source = new DataSource(arffInput); iris = source.getDataSet(); iris.setClassIndex(iris.numAttributes() - 1); } catch (Exception e1) { } } public void buildRegression(){ logReg = new Logistic(); try { logReg.buildClassifier(iris); } catch (Exception e) { } System.out.println(logReg); } public static void main(String[] args) throws Exception{ WekaLogisticRegressionTest test = new WekaLogisticRegressionTest(); test.loadArff("path to the iris.arff file "); test.buildRegression(); } } The output of the code is as follows: Logistic Regression with ridge parameter of 1.0E-8 Coefficients... Class Variable Iris-setosa Iris-versicolor =============================================== sepallength 21.8065 2.4652 sepalwidth 4.5648 6.6809 petallength -26.3083 -9.4293 petalwidth -43.887 -18.2859 Intercept 8.1743 42.637 Odds Ratios... Class Variable Iris-setosa Iris-versicolor =============================================== sepallength 2954196659.8892 11.7653 sepalwidth 96.0426 797.0304 petallength 0 0.0001 petalwidth 0 0 The interpretation of the results from the recipe is beyond the scope of this article. Interested readers are encouraged to see a Stack Overflow discussion here: http://stackoverflow.com/questions/19136213/how-to-interpret-weka-logistic-regression-output. Summary In this article, we have covered the recipes that use machine learning techniques to learn patterns from data. These patterns are at the centre of attention for at least three key machine-learning tasks: classification, regression, and clustering. Classification is the task of predicting a value from a nominal class. Resources for Article: Further resources on this subject: The Data Science Venn Diagram [article] Data Science with R [article] Data visualization [article]
Read more
  • 0
  • 0
  • 2620
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-using-processes-microsoft-dynamics-crm-2011
Packt
07 Feb 2013
13 min read
Save for later

Using Processes in Microsoft Dynamics CRM 2011

Packt
07 Feb 2013
13 min read
  (For more resources related to this topic, see here.) Employee Recruitment Management System basics Hiring the right candidate is a challenge for the recruitment team of any company. The process of hiring candidates can differ from company to company. Different sources such as job sites, networking, and consulting firms can be used to get the right candidate, but most companies prefer to hire a candidate from their own employee network. Before starting the hiring process, a recruiter should have a proper understanding of the candidate profile that fits the company's requirements. Normally, this process starts by screening candidate resumes fetched from different sources. Once they have resumes of appropriate candidates, the recruitment team starts working on resumes one by one. Recruiters talk to potential candidates and enquire about their skills and test their interpersonal skills. Recruiters play an important role in the hiring process; they prepare candidates for interview and provide interview feedback. Employee Recruitment Management System design In the employee recruitment applications, we will be using the key objects shown in the following figure to capture the required information: The blocks perform the following tasks: Company: This block stores the company details Candidate: This block stores information about the candidate profile Employee: This block stores employee data CRM User : This block stores Microsoft CRM user information As we are going to use Microsoft CRM 2011 as a platform to build our application, let's map these key blocks with Microsoft CRM 2011 entities: Company: The term "account" in Microsoft CRM represents an organization, so we can map the company object with an account entity and can store company information in the account entity. Candidate: The Candidate object will store information about suitable candidates for our company. We will use the candidate entity to store all interview related feedback, other position details, and address information. We are going to map the candidate entity with a lead entity, because it has most of the fields OOB that we need for our candidate entity. Employee: In Microsoft CRM 2011 sales process, when lead is qualified, it is converted to an account, a contact, and an opportunity, so we utilize this process for our application. When a candidate is selected, we will convert the candidate to an employee using the OOB process, which will map all the candidate information to the Candidate entity automatically. When a lead is converted to an account or contact or opportunity, the lead record is deactivated by Microsoft CRM 2011. Let's talk about the process flow that we are going to use in our employee recruitment application. Recruiters will start the process of hiring a candidate by importing candidate resumes in Microsoft CRM under the Candidate entity; we will customize our OOB entities to include the required information. Once data is imported in Microsoft CRM, the recruiter will start the screening of candidates one by one. He will schedule Technical, Project Manager, and finally HR rounds. Once the candidate is selected the recruiter will create an offer letter for that candidate, send it to the respective candidate, and convert the Candidate entity to Employee. The following flowchart shows our employee recruitment application process flow: Data model We have identified the data model for required entities. We need to customize OOB entities based on the data model tables.   Customizing entities for Employee Recruitment Management System Once we have the data model ready, we need to customize the Microsoft CRM UI and OOB entities. Let's first create our solution called HR Module and add the required entities to that solution. Customizing Microsoft CRM UI We need to customize the Microsoft CRM site map. We have options to modify the sitemap manually or using the site map editor tool. We need to customize the site map based on the following table: Sr No Customization Detail 1 Remove Left Navigation: Marketing, Service, Resource Center 2 Rename Left Navigation: Sales to  HR Module, Setting to  Configuration 3 Remove Left Navigation items under  My Work:  Queues, Articles,Announcements 4 Remove all Left Navigation items under HR Module left navigation: except Lead, Accounts , and Contacts After customizing the site map, Microsoft CRM UI should look like the following screenshot: It is recommended that you comment unwanted navigation areas out of the site map instead of removing them. Customizing OOB entities After we have customized Microsoft CRM UI, we need to rename the entity and entity views. We also need to perform the following actions: Renaming OOB entities: We need to rename the lead, account, and contact entities to candidate, company, and employee. Open the entities in edit mode and rename them. Changing Translation labels: After renaming the OOB entities, we need to change the translation labels in Microsoft CRM. We need to convert Lead to Candidate and Contact to Employee. Creating/customizing entity fields: We need to create and customize entity fields; based on the data model we just saw, let's create candidate entity fields. Use the following steps to create fields: Open our HRModule solution. Navigate to Entities | Candidate | Fields. Click on New to create a new field. Enter the following field properties: Display Name: Text that you want to show to the user on the form. Name: This will be populated automatically as we tab out from the Display Name field. The Display Name field is used as a label in Microsoft CRM 2011 entity form and views, whereas the Name field is used to refer to the field in code. Requirement Level: Used to enforce data validation on the form. Searchable: If this is true, this field will be available in the Advance Finds field list. Field Security: Used to enable field-level security. It is a new feature added in Microsoft CRM 2011. Refer to the Setting field-level security in Microsoft CRM 2011 section for more details. Auditing: Used to enable auditing for entity fields. It is also a new feature added in Microsoft CRM 2011. Using auditing, we can track entity and attribute data changes for an organization. You can refer to http://msdn.microsoft.com/en-us/library/gg309664.aspx for more details on the auditing feature. Description: Used to provide additional information about fields. Type: Represents what type of data we are going to store in this field; based on the type selected, we need to set other properties. You can't change the data type of a created field, but you can change its properties. After filling in this information, our entity form should look like the following screenshot: We need to create fields for all entities based on the preceding steps, one by one. Setting relationship mapping In Microsoft CRM 2011, we can relate two entities by creating a relationship between them. We can create three types of relationships: One-to-many relationship: A one-to-many relationship is created between one primary entity and many related entities. Microsoft CRM 2011 creates a relationship field (lookup field) automatically for each related entity when a one-to-many relationship is created. We can create a self-relationship by selecting a primary entity on both sides. Many-to-one relationship: A many-to-one relationship is created between many related entities and one primary entity. Many-to-many relationship: A many-to-many relationship can be created between many related entities. To create a many-to-many relationship, the user must have Append and Append To privileges in both side entities. We can define different relationship behaviors while creating a relationship; you can refer to http://msdn.microsoft.com/en-us/library/gg309412.aspx for more details. After creating a relationship, we can define a mapping to transfer values from parent entity to child entity, but this functionality can only achieved when a child entity record is created from a parent entity using the Add New button from the Associated view We need to set up relationship mapping so that we can take the candidate field values to the employee entity when the recruiter converts a candidate into an employee. Use the following steps to set the mapping: Navigate to 1:N Relationship under the Candidate entity. Open the contact_originating_lead mapping to edit it. Navigate to Mapping and click on New to add a mapping. Select new_variablecompensation from the Source and Target entities and click on OK. Follow step 4 to add mapping for the fields shown in the following screenshot: Form design Now we need to design forms for our entity, and we need to remove unnecessary fields from entity forms. Use the following steps to customize entity forms: Open the solution that we created. Navigate to Entity | Account | Forms. Open the main form to modify it, as shown in the following screenshot: We can remove unwanted fields easily by selecting them one by one and using the Remove ribbon button on the entity form. To place the field, we just need to drag-and-drop it from the right-hand side field explorer. Account form design Once we have customized the account entity, we need to design the account form shown in the following screenshot: Candidate form design The candidate form should look like the following screenshot after customization: Employee form design After removing unwanted fields and adding required fields, the employee form should look like the following screenshot: Setting a security model for ERMS Microsoft CRM provides us the OOB security model that helps us to prevent unauthorized access to our data. We can enforce security in Microsoft CRM using security roles. A security role is a combination of different privileges and access levels. Privileges: These are actions such as Create , Write, Delete , Read, Append, Append To, Assign, Share, and Reparent that a Microsoft CRM user can perform on entities. The list of the actions performed is as follows: Create : This action is used to create an entity record Read: This action is used to read an entity record Write: This action is used to modify an entity record Delete : This action is used to delete an entity record Append: This action is used to relate one entity record to another entity record Append To: This action is used to relate other entity records to the current entity record Share: This action is used to share an entity record with another user Reparent: This action is used to assign a different owner to an entity record Access level: This defines on which entity record a Microsoft CRM user can perform actions defined by privileges. We have the following actions under access levels: Organization: This action is used to provide access to all records in an organization Parent-child Business Unit: This action is used to provide access to all the records in the user's business unit as well as in all child business units of the user's business unit Business: This action is used to provide access to all records in the user's business unit User: This action allows the user to access records created by him/her, or shared with him/her, or shared with his/her team We must assign at least one security role to access Microsoft CRM applications. Microsoft CRM provides us with 14 OOB security roles that can be customized based on our requirements. The following diagram is the security-role hierarchy that we have identified for the Employee Management System: The blocks in the preceding diagram can be explained as follows: HR Manager : This role will have access to all information for an employee in the ERMS system Recruiter: This role will not have access to information about offered packages to an employee System Administrator: This role will have administrative privileges and will be responsible for customizing and maintaining ERMS We will be customizing the existing security roles for our ERMS . The following table shows the security role mapping that we be will using: Microsoft CRM Security Role ERMS Security Role Sales Manager Manager Salesperson Salesperson System Administrator System Administrator Customizing the existing security role We need to use the following steps to customize the existing security role: Navigation to Setting | Administration | Security Roles. Double-click on the Sales Manager role to open it in edit mode. Change Role Name to Manager. Click on Save and then on Close . Follow the same steps to change the name of the Sales Person role to Recruiter. You can also create a new Manager Security role by copying the Sales Manager role. Once we have changed the security role name, we need to configure the Security Manager and Recruiter roles to remove unnecessary privileges. Follow the ensuing instructions to configure the Manager Security role: Navigate to the Core Records tab in the Manager Security role. Clear all privileges from the Opportunity and Document location entities. Navigate to the Marketing tab and clear all privileges from the Campaign and Marketing list entities. Navigate to the Sales tab and clear all privileges from all sales module entities, as shown in the following screenshot: Navigate to the Service tab and clear all privileges from all service module entities. Click on Save and Close . Follow all the preceding steps to remove the same privileges from the Recruiter role as well. Setting field-level security in Microsoft CRM 2011 Microsoft CRM 2011 contains an OOB feature for field-level security. Using field-level security, we can protect Microsoft CRM form fields from unauthorized access. This feature is only available in custom attributes. You can only apply field-level security to the custom fields of system entities. While creating/modifying fields, you can enable field-level security. The following screenshot shows how we can Enable/Disable the Field Security option: Once field-level security is enabled, we can set the field-level security profile. Let's apply field-level security in the offered package section in the Candidate entity. We have already enabled field-level security for these three fields under the offered package section in Candidate entity. Use the following steps to set the field-level security profile: Navigate to Settings | Administration | Field Security Profiles. Click on New to create the new security profile. Fill in the following information: Name: Recruitment Team Profile Description: Security profile for recruitment team Click on Save. Navigate to Users, under the Members section, in the left-hand navigation. Click on Add to add a user from whom you want to secure these fields. Navigate to Field Permission under the Common section in the left-hand navigation. Select all records and click on the Edit button. Select No from all drop-down fields. These fields can be implemented as shown in the following screenshot: Now all Microsoft CRM users with the Recruitment security role won't be able to see the values in these fields. They won't even be able to set values for these fields.
Read more
  • 0
  • 0
  • 2615

Packt
17 Sep 2014
12 min read
Save for later

What is REST?

Packt
17 Sep 2014
12 min read
This article by Bhakti Mehta, the author of Restful Java Patterns and Best Practices, starts with the basic concepts of REST, how to design RESTful services, and best practices around designing REST resources. It also covers the architectural aspects of REST. (For more resources related to this topic, see here.) Where REST has come from The confluence of social networking, cloud computing, and era of mobile applications creates a generation of emerging technologies that allow different networked devices to communicate with each other over the Internet. In the past, there were traditional and proprietary approaches for building solutions encompassing different devices and components communicating with each other over a non-reliable network or through the Internet. Some of these approaches such as RPC, CORBA, and SOAP-based web services, which evolved as different implementations for Service Oriented Architecture (SOA) required a tighter coupling between components along with greater complexities in integration. As the technology landscape evolves, today’s applications are built on the notion of producing and consuming APIs instead of using web frameworks that invoke services and produce web pages. This requirement enforces the need for easier exchange of information between distributed services along with predictable, robust, well-defined interfaces. API based architecture enables agile development, easier adoption and prevalence, scale and integration with applications within and outside the enterprise HTTP 1.1 is defined in RFC 2616, and is ubiquitously used as the standard protocol for distributed, collaborative and hypermedia information systems. Representational State Transfer (REST) is inspired by HTTP and can be used wherever HTTP is used. The widespread adoption of REST and JSON opens up the possibilities of applications incorporating and leveraging functionality from other applications as needed. Popularity of REST is mainly because it enables building lightweight, simple, cost-effective modular interfaces, which can be consumed by a variety of clients. This article covers the following topics Introduction to REST Safety and Idempotence HTTP verbs and REST Best practices when designing RESTful services REST architectural components Introduction to REST REST is an architectural style that conforms to the Web Standards like using HTTP verbs and URIs. It is bound by the following principles. All resources are identified by the URIs. All resources can have multiple representations All resources can be accessed/modified/created/deleted by standard HTTP methods. There is no state on the server. REST is extensible due to the use of URIs for identifying resources. For example, a URI to represent a collection of book resources could look like this: http://foo.api.com/v1/library/books A URI to represent a single book identified by its ISBN could be as follows: http://foo.api.com/v1/library/books/isbn/12345678 A URI to represent a coffee order resource could be as follows: http://bar.api.com/v1/coffees/orders/1234 A user in a system can be represented like this: http://some.api.com/v1/user A URI to represent all the book orders for a user could be: http://bar.api.com/v1/user/5034/book/orders All the preceding samples show a clear readable pattern, which can be interpreted by the client. All these resources could have multiple representations. These resource examples shown here can be represented by JSON or XML and can be manipulated by HTTP methods: GET, PUT, POST, and DELETE. The following table summarizes HTTP Methods and descriptions for the actions taken on the resource with a simple example of a collection of books in a library. HTTP method Resource URI Description GET /library/books Gets a list of books GET /library/books/isbn/12345678 Gets a book identified by ISBN “12345678” POST /library/books Creates a new book order DELETE /library/books/isbn/12345678 Deletes a book identified by ISBN “12345678” PUT /library/books/isbn/12345678 Updates a specific book identified by ISBN “12345678’ PATCH /library/books/isbn/12345678 Can be used to do partial update for a book identified by ISBN “12345678” REST and statelessness REST is bound by the principle of statelessness. Each request from the client to the server must have all the details to understand the request. This helps to improve visibility, reliability and scalability for requests. Visibility is improved, as the system monitoring the requests does not have to look beyond one request to get details. Reliability is improved, as there is no check-pointing/resuming to be done in case of partial failures. Scalability is improved, as the number of requests that can be processed is increases as the server is not responsible for storing any state. Roy Fielding’s dissertation on the REST architectural style provides details on the statelessness of REST, check http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm With this initial introduction to basics of REST, we shall cover the different maturity levels and how REST falls in it in the following section. Richardson Maturity Model Richardson maturity model is a model, which is developed by Leonard Richardson. It talks about the basics of REST in terms of resources, verbs and hypermedia controls. The starting point for the maturity model is to use HTTP layer as the transport. Level 0 – Remote Procedure Invocation This level contains SOAP or XML-RPC sending data as POX (Plain Old XML). Only POST methods are used. This is the most primitive way of building SOA applications with a single method POST and using XML to communicate between services. Level 1 – REST resources This uses POST methods and instead of using a function and passing arguments uses the REST URIs. So it still uses only one HTTP method. It is better than Level 0 that it breaks a complex functionality into multiple resources with one method. Level 2 – more HTTP verbs This level uses other HTTP verbs like GET, HEAD, DELETE, PUT along with POST methods. Level 2 is the real use case of REST, which advocates using different verbs based on the HTTP request methods and the system can have multiple resources. Level 3 – HATEOAS Hypermedia as the Engine of Application State (HATEOAS) is the most mature level of Richardson’s model. The responses to the client requests, contains hypermedia controls, which can help the client decide what the next action they can take. Level 3 encourages easy discoverability and makes it easy for the responses to be self- explanatory. Safety and Idempotence This section discusses in details about what are safe and idempotent methods. Safe methods Safe methods are methods that do not change the state on the server. GET and HEAD are safe methods. For example GET /v1/coffees/orders/1234 is a safe method. Safe methods can be cached. PUT method is not safe as it will create or modify a resource on the server. POST method is not safe for the same reasons. DELETE method is not safe as it deletes a resource on the server. Idempotent methods An idempotent method is a method that will produce the same results irrespective of how many times it is called. For example GET method is idempotent, as multiple calls to the GET resource will always return the same response. PUT method is idempotent as calling PUT method multiple times will update the same resource and not change the outcome. POST is not idempotent and calling POST method multiple times can have different results and will result in creating new resources. DELETE is idempotent because once the resource is deleted it is gone and calling the method multiple times will not change the outcome. HTTP verbs and REST HTTP verbs inform the server what to do with the data sent as part of the URL GET GET is the simplest verb of HTTP, which enables to get access to a resource. Whenever the client clicks a URL in the browser it sends a GET request to the address specified by the URL. GET is safe and idempotent. GET requests are cached. Query parameters can be used in GET requests. For example a simple GET request is as follows: curl http://api.foo.com/v1/user/12345 POST POST is used to create a resource. POST requests are neither idempotent nor safe. Multiple invocations of the POST requests can create multiple resources. POST requests should invalidate a cache entry if exists. Query parameters with POST requests are not encouraged For example a POST request to create a user can be curl –X POST -d’{“name”:”John Doe”,“username”:”jdoe”, “phone”:”412-344-5644”} http://api.foo.com/v1/user PUT PUT is used to update a resource. PUT is idempotent but not safe. Multiple invocations of PUT requests should produce the same results by updating the resource. PUT requests should invalidate the cache entry if exists. For example a PUT request to update a user can be curl –X PUT -d’{ “phone”:”413-344-5644”} http://api.foo.com/v1/user DELETE DELETE is used to delete a resource. DELETE is idempotent but not safe. DELETE is idempotent because based on the RFC 2616 "the side effects of N > 0 requests is the same as for a single request". This means once the resource is deleted calling DELETE multiple times will get the same response. For example, a request to delete a user is as follows: curl –X DELETE http://foo.api.com/v1/user/1234 HEAD HEAD is similar like GET request. The difference is that only HTTP headers are returned and no content is returned. HEAD is idempotent and safe. For example, a request to send HEAD request with curl is as follows: curl –X HEAD http://foo.api.com/v1/user It can be useful to send a HEAD request to see if the resource has changed before trying to get a large representation using a GET request. PUT vs POST According to RFC the difference between PUT and POST is in the Request URI. The URI identified by POST defines the entity that will handle the POST request. The URI in the PUT request includes the entity in the request. So POST /v1/coffees/orders means to create a new resource and return an identifier to describe the resource In contrast PUT /v1/coffees/orders/1234 means to update a resource identified by “1234” if it does not exist else create a new order and use the URI orders/1234 to identify it. Best practices when designing resources This section highlights some of the best practices when designing RESTful resources: The API developer should use nouns to understand and navigate through resources and verbs with the HTTP method. For example the URI /user/1234/books is better than /user/1234/getBook. Use associations in the URIs to identify sub resources. For example to get the authors for book 5678 for user 1234 use the following URI /user/1234/books/5678/authors. For specific variations use query parameters. For example to get all the books with 10 reviews /user/1234/books?reviews_counts=10. Allow partial responses as part of query parameters if possible. An example of this case is to get only the name and age of a user, the client can specify, ?fields as a query parameter and specify the list of fields which should be sent by the server in the response using the URI /users/1234?fields=name,age. Have defaults for the output format for the response incase the client does not specify which format it is interested in. Most API developers choose to send json as the default response mime type. Have camelCase or use _ for attribute names. Support a standard API for count for example users/1234/books/count in case of collections so the client can get the idea of how many objects can be expected in the response. This will also help the client, with pagination queries. Support a pretty printing option users/1234?pretty_print. Also it is a good practice to not cache queries with pretty print query parameter. Avoid chattiness by being as verbose as possible in the response. This is because if the server does not provide enough details in the response the client needs to make more calls to get additional details. That is a waste of network resources as well as counts against the client’s rate limits. REST architecture components This section will cover the various components that must be considered when building RESTful APIs As seen in the preceding screenshot, REST services can be consumed from a variety of clients and applications running on different platforms and devices like mobile devices, web browsers etc. These requests are sent through a proxy server. The HTTP requests will be sent to the resources and based on the various CRUD operations the right HTTP method will be selected. On the response side there can be Pagination, to ensure the server sends a subset of results. Also the server can do Asynchronous processing thus improving responsiveness and scale. There can be links in the response, which deals with HATEOAS. Here is a summary of the various REST architectural components: HTTP requests use REST API with HTTP verbs for the uniform interface constraint Content negotiation allows selecting a representation for a response when there are multiple representations available. Logging helps provide traceability to analyze and debug issues Exception handling allows sending application specific exceptions with HTTP codes Authentication and authorization with OAuth2.0 gives access control to other applications, to take actions without the user having to send their credentials Validation provides support to send back detailed messages with error codes to the client as well as validations for the inputs received in the request. Rate limiting ensures the server is not burdened with too many requests from single client Caching helps to improve application responsiveness. Asynchronous processing enables the server to asynchronously send back the responses to the client. Micro services which comprises breaking up a monolithic service into fine grained services HATEOAS to improve usability, understandability and navigability by returning a list of links in the response Pagination to allow clients to specify items in a dataset that they are interested in. The REST Architectural components in the image can be chained one after the other as shown priorly. For example, there can be a filter chain, consisting of filters related with Authentication, Rate limiting, Caching, and Logging. This will take care of authenticating the user, checking if the requests from the client are within rate limits, then a caching filter which can check if the request can be served from the cache respectively. This can be followed by a logging filter, which can log the details of the request. For more details, check RESTful Patterns and best practices.
Read more
  • 0
  • 0
  • 2615

article-image-developing-web-applications-using-javaserver-faces-part-1
Packt
27 Oct 2009
6 min read
Save for later

Developing Web Applications using JavaServer Faces: Part 1

Packt
27 Oct 2009
6 min read
Although a lot of applications have been written using these APIs, most modern Java applications are written using some kind of web application framework. As of Java EE 5, the standard framework for building web applications is Java Server Faces (JSF). Introduction to JavaServer Faces Before JSF was developed, Java web applications were typically developed using non-standard web application frameworks such as Apache Struts, Tapestry, Spring Web MVC, or many others. These frameworks are built on top of the Servlet and JSP standards, and automate a lot of functionality that needs to be manually coded when using these APIs directly. Having a wide variety of web application frameworks available (at the time of writing, Wikipedia lists 35 Java web application frameworks, and this list is far from extensive!), often resulted in "analysis paralysis", that is, developers often spend an inordinate amount of time evaluating frameworks for their applications. The introduction of JSF to the Java EE 5 specification resulted in having a standard web application framework available in any Java EE 5 compliant application server. We don't mean to imply that other web application frameworks are obsolete or that they shouldn't be used at all, however, a lot of organizations consider JSF the "safe" choice since it is part of the standard and should be well supported for the foreseeable future. Additionally, NetBeans offers excellent JSF support, making JSF a very attractive choice. Strictly speaking, JSF is not a web application framework as such, but a component framework. In theory, JSF can be used to write applications that are not web-based, however, in practice JSF is almost always used for this purpose. In addition to being the standard Java EE 5 component framework, one benefit of JSF is that it was designed with graphical tools in mind, making it easy for tools and IDEs such as NetBeans to take advantage of the JSF component model with drag-and-drop support for components. NetBeans provides a Visual Web JSF Designer that allow us to visually create JSF applications. Developing Our first JSF Application From an application developer's point of view, a JSF application consists of a series of JSP pages containing custom JSF tags, one or more JSF managed beans, and a configuration file named faces-config.xml. The faces-config.xml file declares the managed beans in the application, as well as the navigation rules to follow when navigating from one JSF page to another. Creating a New JSF Project To create a new JSF project, we need to go to File | New Project, select the Java Web project category, and Web Application as the project type. After clicking Next, we need to enter a Project Name, and optionally change other information for our project, although NetBeans provides sensible defaults. On the next page in the wizard, we can select the Server, Java EE Version, and Context Path of our application. In our example, we will simply pick the default values. On the next page of the new project wizard, we can select what frameworks our web application will use. Unsurprisingly, for JSF applications we need to select the JavaServer Faces framework. The Visual Web JavaServer Faces framework allows us to quickly build web pages by dragging-and-dropping components from the NetBeans palette into our pages. Although it certainly allows us to develop applications a lot quicker than manually coding, it hides a lot of the "ins" and "outs" of JSF. Having a background in standard JSF development will help us understand what the NetBeans Visual Web functionality does behind the scenes. When clicking Finish, the wizard generates a skeleton JSF project for us, consisting of a single JSP file called welcomeJSF.jsp, and a few configuration files: web.xml, faces-config.xml and, if we are using the default bundled GlassFish server, the GlassFish specific sun-web.xml file is generated as well. web.xml is the standard configuration file needed for all Java web applications. faces-config.xml is a JSF-specific configuration file used to declare JSF-managed beans and navigation rules. sun-web.xml is a GlassFish-specific configuration file that allows us to override the application's default context root, add security role mappings, and perform several other configuration tasks. The generated JSP looks like this: <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%-- This file is an entry point for JavaServer Faces application. --%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <f:view> <h1> <h:outputText value="JavaServer Faces"/> </h1> </f:view> </body> </html> As we can see, a JSF enabled JSP file is a standard JSP file using a couple of JSF-specific tag libraries. The first tag library, declared in our JSP by the following line: <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> is the core JSF tag library, this library includes a number of tags that are independent of the rendering mechanism of the JSF application (recall that JSF can be used for applications other than web applications). By convention, the prefix f (for faces) is used for this tag library. The second tag library in the generated JSP, declared by the following line: <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> is the JSF HTML tag library. This tag library includes a number of tags that are used to implement HTML specific functionality, such as creating HTML forms and input fields. By convention, the prefix h (for HTML) is used for this tag library. The first JSF tag we see in the generated JSP file is the <f:view> tag. When writing a Java web application using JSF, all JSF custom tags must be enclosed inside an <f:view> tag. In addition to JSF-specific tags, this tag can contain standard HTML tags, as well as tags from other tag libraries, such as the JSTL tags. The next JSF-specific tag we see in the above JSP is <h:outputText>. This tag simply displays the value of its value attribute in the rendered page. The application generated by the new project wizard is a simple, but complete, JSF web application. We can see it in action by right-clicking on our project in the project window and selecting Run. At this point the application server is started (if it wasn't already running), the application is deployed and the default system browser opens, displaying our application's welcome page.
Read more
  • 0
  • 0
  • 2614

article-image-project-setup-and-modeling-residential-project
Packt
08 Jul 2015
20 min read
Save for later

Project Setup and Modeling a Residential Project

Packt
08 Jul 2015
20 min read
In this article by Scott H. MacKenzie and Adam Rendek, authors of the book ArchiCAD 19 – The Definitive Guide, we will see how our journey, into ArchiCAD 19, begins with an introduction to the graphic user interface, also known as the GUI. As with any software program, there is a menu bar along the top that gives access to all the tools and features. There are also toolbars and tool palettes that can be docked anywhere you like. In addition to this, there are some special palettes that pop up only when you need them. After your introduction to ArchiCAD's user interface, you can jump right in and start creating the walls and floors for your new house. Then you will learn how to create ceilings and the stairs. Before too long you will have a 3D model to orbit around. It is really fun and probably easier than you would expect. (For more resources related to this topic, see here.) The ArchiCAD GUI The first time you open ArchiCAD you will find the toolbars along the top, just under the menu bar and there will be palettes docked to the left and right of the drawing area. We will focus on the 3 following palettes to get started: The Toolbox palette: This contains all of your selection, modeling, and drafting tools. It will be located on the left hand side by default. The Info Box palette: This is your context menu that changes according to whatever tool is currently in use. By default, this will be located directly under the toolbars at the top. It has a scrolling function; hover your cursor over the palette and spin the scroll wheel on your mouse to reveal everything on the palette. The Navigator palette: This is your project navigation window. This palette gives you access to all your views, sheets, and lists. It will be located on the right-hand side by default. These three palettes can be seen in the following screenshot: All of the mentioned palettes are dockable and can be arranged however you like on your screen. They can also be dragged away from the main ArchiCAD interface. For instance, you could have palettes on a second monitor. Panning and Zooming ArchiCAD has the same panning and zooming interface as most other CAD (Computer-aided design) and BIM (Building Information Modeling) programs. Rolling the scroll wheel on your mouse will zoom in and out. Pressing down on the scroll wheel (or middle button) and moving your cursor will execute a pan. Each drawing view window has a row of zoom commands along the bottom. You should try each one to get familiar with each of their functions. View toggling When you have multiple views open, you can toggle through them by pressing the Ctrl key and tapping on the Tab key. Or, you can pick any of the open views from the bottom of the Window pull-down menu. Pressing the F2 key will open a 2D floor plan view and pressing the F3 key will open the default 3D view. Pressing the F5 key will open a 3D view of selected items. In other words, if you want to isolate specific items in a 3D view, select those items and press F5. The function keys are second nature to those that have been using ArchiCAD for a long time. If a feature has a function key shortcut, you should use it. Project setup ArchiCAD is available in multiple different language versions. The exercises in this book use the USA version of ArchiCAD. Obviously this version is in English. There is another version in English and that is referred to as the International (INT) version. You can use the International version to do the exercises in the book, just be aware that there may be some subtle differences in the way that something is named or designed. When you create a new project in ArchiCAD, you start by opening a project template. The template will have all the basic stuff you need to get started including layers, line types, wall types, doors, windows, and more. The following lesson will take you through the first steps in creating a new ArchiCAD project: Open ArchiCAD. The Start ArchiCAD dialog box will appear. Select the Create a New Project radio button at the top. Select the Use a Template radio button under Set up Project Settings. Select ArchiCAD 19 Residential Template.tpl from the drop-down list. If you have the International version of ArchiCAD, then the residential template may not be available. Therefore you can use ArchiCAD 19 Template.tpl. Click on New. This will open a blank project file. Project Settings Now that you have opened your new project, we are going to create a house with 4 stories (which includes a story for the roof). We create a story for the roof in order to facilitate a workspace to model the elements on that level. The template we just opened only has 2 stories, so we will need to add 2 more. Then we need to look at some other settings. Stories The settings for the stories are as follows: On the Navigator palette, select the Project Map icon . Double click on 1st FLOOR. Right click on Stories and select Create New Story. You will be prompted to give the new story a name. Enter the name BASEMENT. Click on the button next to Below. Enter 9' into the Height box and click on the Create button. Then double click on 2. 2nd FLOOR. Right click on Stories and then select Create New Story. You will be prompted to give the new story a name. Enter the name ROOF. Click on the button next to Above. Enter 9' into the Height box and click on the Create button. Your list of stories should now look like this 3. ROOF 2. 2nd Floor 1. 1st Floor -1. BASEMENT The International version of ArchiCAD (INT) will give the first floor the index number of 0. The second floor index number will be 1. And the roof will be 2. Now we need to adjust the heights of the other stories: Right click on Stories (on the Navigator palette) and select Story Settings. Change the number in the Height to Next box for 1st FLOOR to 9'. Do the same for 2nd FLOOR. Units On the menu bar, go to Options | Project Preferences | Working Units and perform the following steps: Ensure Model Units is set to feet & fractional inches. Ensure that Fractions is set to 1/64. Ensure that Layout Units is set to feet & fractional inches. Ensure that Angle Unit is set to Decimal degrees. Ensure that Decimals is set to 2. You are now ready to begin modeling your house, but first let's save the project. To save the project, perform the following steps: Navigate to the File menu and click on Save. If by chance you have saved it already, then click on Save As. Name your file Colonial House. Click on Save. Renovation filters The Renovation Filter feature allows you to differentiate how your drawing elements will appear in different construction phases. For renovation projects that have demolition and new work phases, you need to show the items to be demolished differently than the existing items that are to remain, or that are new. The projects we will work on in this book do not require this feature to manage phases because we will only be creating a new construction. However, it is essential that your renovation filter setting is set to New Construction. We will do this in the first modeling exercise. Selection methods Before you can do much in ArchiCAD, you need to be familiar with selecting elements. There are several ways to select something in ArchiCAD, which are as follows: Single cursor click Pick the Arrow tool from the toolbox or hold the Shift key down on the keyboard and click on what you want to select. As you click on the elements, hold the Shift key down to add them to your selection set. To remove elements from the selection set, just click on them again with the Shift key pressed. There is a mode within this mode called Quick Selection. It is toggled on and off from the Info Box palette. The icon looks like a magnet. When it is on, it works like a magnet because it will stick to faces or surfaces, such as slabs or fill patterns. If this mode is not on, then you are required to find an edge, endpoint, or hotspot node to select an element with a single click. Hold the Space button down to temporarily change the mode while selecting elements. Window Pick the Arrow tool from the toolbox or hold the Shift key down and draw your selection window. Click once for the window starting corner and click a second time for the end corner. This works just as windowing does in AutoCAD. Not as Revit does, where you need to hold the mouse button down while you draw your window. There are 3 different windowing methods. Each one is set from the Info Box palette: Partial Elements: Anything that is inside of or touching the window will be selected. AutoCAD users will know this as a Crossing Window. Entire Elements: Anything completely encapsulated by the window will be selected. If something is not completely inside the window then it will not be selected. Direction Dependent: Click and window to the left, the Partial Elements window will be used. Click and window to the right, the Entire Elements window will be used. Marquee A marquee is a selection window that stays on the screen after you create it. If you are a MicroStation CAD program user, this will be similar to a selection window. It can be used for printing a specific area in a drawing view and performing what AutoCAD users would refer to as a Stretch command. There are 2 types of marquees; single story (skinny) and multi story (fat). The single story marquee is used when you want to select elements on your current story view only. The multi-story marquee will select everything on your current story as well as the stories above and below your selections. The Find & Select tool This lets ArchiCAD select elements for you, based on the attribute criteria that you define, such as element type, layer, and pen number. When you have the criteria defined, click on the plus sign button on the palette and all the elements within that criterion inside your current view or marquee will be selected. The quickest way to open the Find & Select tool is with the Ctrl + F key combination Modification commands As you draw, you will inevitably need to move, copy, stretch, or trim something. Select your items first, and then execute the modification command. Here are the basic commands you will need to get things moving: Adjust (Extend): Press Ctrl + - or navigate to Edit | Reshape | Adjust Drag (Move): Press Ctrl + D or…navigate to Edit | Move | Drag Drag a Copy (Copy): Press Ctrl + Shift + D or navigate to Edit | Move | Drag a Copy Intersect (Fillet): Click on the Intersect button on the Standard toolbar or navigate to Edit | Reshape | Intersect Resize (Scale): Press Ctrl + K or navigate to Edit | Reshape | Resize Rotate: Press Ctrl + E or navigate to Edit | Move | Rotate Stretch: Press Ctrl + H or navigate to Edit | Reshape | Stretch Trim: Press Ctrl or click on the Trim button on the Standard toolbar or navigate to Edit | Reshape | Trim. Hold the Ctrl key down and click on the portion of wall or line that you want trimmed off. This is the fastest way to trim anything! Memorizing the keyboard combinations above is a sure way to increase your productivity. Modeling – part I We will start with the wall tool to create the main exterior walls on the 1st floor of our house, and then create the floor with the slab tool. However, before we begin, let's make sure your Renovation Filter is set to New Construction. Setting the Renovation Filter The Renovation Filter is an active setting that controls how the elements you create are displayed. Everything we create in this project is for new construction so we need the new construction filter to be active. To do so, go to the Document menu, click on Renovation and then click on 04 New Construction. Using the Wall tool The Wall tool has settings for height, width, composite, layer, pen weight and more. We will learn about these things as we go along, and learn a little bit more each time we progress into to the project. Double click on 1. 1st Story in the Navigator palette to ensure we are working on story 1. Select the Wall tool from the Toolbox palette or from the menu bar under Design | Design Tools | Wall. Notice that this will automatically change the contents of the Info Box palette. Click on the wall icon inside Info Box. This will bring up the active properties of the wall tool in the form of the Wall Default Settings window. (This can also be achieved by double clicking on the wall tool button in Toolbox). Change the composite type to Siding 2x6 Wd. Stud. Click on the wall composite button to do this.   Creating the exterior walls of the 1st Story To create the exterior walls of the 1st story perform the following steps: Select the Wall tool from the Toolbox palette, or from the menu bar under Design | Design Tools | Wall. Double click on 1. 1st Story in the Navigator palette to ensure that we are working on story 1. Select the Wall tool from the Toolbox palette, or from the menu bar under Design | Design Tools | Wall. Change the composite type to be Siding 2x6 Wd. Stud. Click on the wall composite button to do this. Notice at the bottom of the Wall Default Settings window is the layer currently assigned to the wall tool. It should be set to A-WALL-EXTR. Click on OK to start your first wall. Click near the center of the drawing screen and move your cursor to the left, notice the orange dashed line that appears. That is your guide line. Keep your cursor over the guide line so that it keeps you locked in the orthogonal direction. You should also immediately see the Tracker palette pop up, displaying your distance drawn and angle after your first click. Before you make your second click, enter the number 24 from your keyboard and press Enter. You should now have 24-0" long wall. If your Tracker palette does not appear, it may be toggled off. Go up to the Standard tool bar and click on the Tracker button to turn it on. Select this again and make your first click on the upper left end corner of your first wall. Move your cursor down, so that it snaps to the guideline, enter the number 28, and press the Enter key. Draw your third wall by clicking on the bottom left endpoint of your second wall, move your cursor to the right, snapped over the guide line, type in the number 24 and press Enter. Draw your fourth wall by clicking on the bottom right end point of your third wall and the starting point of your first wall. You should now have four walls that measure 24'-0" x 28"-0, outside edge to outside edge. Move your four walls to the center of the drawing view and perform the following steps: Click on the Arrow tool at the top of the Toolbox. Click outside one of the corners of the walls, and then click on the opposite side. All four walls should be selected now. Use the Drag command to move the walls. The quickest way to activate the Drag command is by pressing Ctrl + D. The long way is from the menu bar by navigating to Edit | Move | Drag. Drag (move) the walls to the center of your drawing window. Press the Esc key or click on a blank space in your drawing window to deselect the walls. You can select all the walls in a view by activating the Wall tool and pressing Ctrl + A. You are now ready to create a floor with the slab tool. But first, let's have a little fun and see how it looks in 3D (press the F3 key): From the Navigator palette, double click on Generic Axonometry under the 3D folder icon. This will open a 3D view window. Hold your Shift key down, press down on your scroll wheel button, and slowly move your mouse around. You are now orbiting! Play around with it a little, then get back to work and go to the next step to create your first floor slab. Press the F2 key to get back to a 2D view. You can also perform a 3D orbit via the Orbit button at the bottom of any 3D view window. Creating the first story's floor with the Slab tool The slab tool is used to create floors. It is also used to create ceilings. We will begin using it now to create the first floor for our house. Similar to the Wall tool, it also has settings for layer, pen weight and composite. To create the first story's floor using the Slab tool, perform the following steps: Select the Slab tool from the Toolbox palette or from the menu bar under Design | Design Tools | Slab. This will change the contents of the Info Box palette. Click on the Slab icon in Info Box. This will bring up the Slab Default Settings (active properties) window for the Slab tool. As with the Wall tool, you have a composite setting for the slab tool. Set the composite type for the slab tool to FLR Wd Flr + 2x10. The layer should be set to A-FLOR. Click OK. You could draw the shape of the slab by tracing over the outside lines of your walls but we are going to use the Magic Wand feature. Hover your cursor over the space inside your four walls and press the space bar on your keyboard. This will automatically create the slab using the boundary created by the walls. Then, open a 3D view and look at your floor. Instead of using the tool icon inside the Info Box palette, double click on any tool icon inside the Toolbox palette to bring up the default settings window for that tool. Creating the exterior walls and floor slabs for the basement and the second story We could repeat all of the previous steps to create the floor and walls for the second story and the basement, but in this case, it will be quicker to copy what we have already drawn on the first story and copy it up with the Edit Elements by Stories tool. Perform the following steps to create the exterior walls and floor slabs for the basement and second story: Go to the Navigator palette and right click over Stories, select Edit Elements by Stories. The Edit Elements by Stories window will open. Under Select Action, you want to set it to Copy. Under From Story, set it to 1. 1st FLOOR. In the To Story section, check the box for 2nd FLOOR and -1. BASEMENT. Click on OK. You should see a dialog box appear, stating that as a result of the last operation, elements have been created and/or have changed their position on currently unseen stories. Whenever you get this message, you should confirm that you have not created any unwanted elements. Click on the Continue button. Now you should have walls and a floor on three stories; Basement, 1st FLOOR, and 2nd FLOOR. The quickest way to jump to the next story up or the next story down is with the Ctrl + Arrow Up or Ctrl + Arrow Down key combination. Basement element modification The floor and the walls on the BASEMENT story need to be changed to a different composite type. Do this by performing the following steps: Open the BASEMENT view and select the four walls by clicking on one at a time while holding down the Shift key. Right click over your selection and click on Wall Selection Settings. Change the walls to the EIFS on 8" CMU composite type. Then, click on OK. Move your cursor over the floor slab. The quick selection cursor should appear. This selection mode allows you to click on an object without needing to find an edge or endpoint. Click on the slab. Open the Slab Selection Setting window but this time, do it by pressing the Ctrl + T key combination. Change the floor slab composite to Conc. Slab: 4" on gravel. Click on OK. The Ctrl + T key combination is the quickest way to bring up an element's selection settings window when an element is selected. Open a 3D view (by pressing the F3 key) and orbit around your house. It should look similar to the following screenshot: Adding the garage We need to add the garage and the laundry room, which connects the garage to the house. Do this by performing the following steps: Open the 1st FLOOR story from the project map. Start the Wall tool. From the Info Box palette, set the wall composite setting to Siding 2x6 Wd. Stud. Click on the upper-left corner of your house for your wall starting point. Move your cursor to the left, snap to the guide line, type 6'-10", and press Enter. Change the Geometry Method setting on Info Box to Chained. Refer to the following screenshot: Start your next wall by clicking on the endpoint of your last wall, move your cursor up, snap to the guideline and type 5', and press Enter. Move your cursor to the left, snap to grid line, type in 12'-6", and press Enter. Move your cursor down, snap to grid line, type in 22'-4", and press Enter. Move your cursor to the right, snap to grid line and double click on the perpendicular west wall (double pressing your Enter key will work the same as a double click). Now we want to create the floor for this new set of walls. To do that, perform the following steps: Start the Slab tool. Change the composite to Conc. Slab: 4" on gravel. Hover your cursor inside the new set of walls and press the Space key to use the magic wand. This will create the floor slab for the garage and laundry room. There is still one more wall to create, but this time we will use the Adjust command to, in effect, create a new wall: Select the 5'-0" wall drawn in the previous exercise. Go to the Edit menu, click on Reshape, and then click on Adjust. Click on the bottom edge of the perpendicular wall down below. The wall should extend down. Refer to the following screenshot: Then Change to a 3D view (by pressing F3) and examine your work. The 3D view If you switch to a 3D view and your new modeling does not show, zoom in or out to refresh the view, or double click your scroll wheel (middle button). Your new work will appear. Summary In this article you were introduced to the ArchiCAD Graphical User Interface (GUI), project settings and learned how to select stuff. You created all the major modeling for your house and got a primer on layers. Now you should have a good understanding of the ArchiCAD way of creating architectural elements and how to control their parameters. Resources for Article: Further resources on this subject: Let There be Light! [article] Creating an AutoCAD command [article] Setting Up for Photoreal Rendering [article]
Read more
  • 0
  • 0
  • 2614
article-image-sharing-mind-map-using-best-mobile-and-web-featuressil
Packt
29 Nov 2012
14 min read
Save for later

Sharing a Mind Map: Using the Best of Mobile and Web Featuressil

Packt
29 Nov 2012
14 min read
(For more resources related to this topic, see here.) Mind Mapping Sharing the mind map, using the exporting features of FreeMind, is to be explored in this Article. Besides, we can export and upload the mind map on the Web. We are going to deal with the options offered, and we are also adding another condiment to the recipes to spice them up. There are plenty of features that can make our mind map more attractive to the reader, but we have to dig into the different alternatives to make it happen. Moreover, taking into account the pros and cons of each exporting feature, we are going to consider them before exporting our mind map. When designing the activity considering how useful the reader can find the mind map, we are also bearing in mind, at the same time, which exporting features to work with afterwards. Therefore, it is very important to learn the options and their possibilities. Besides, we can improve the exporting possibilities by using a multimedia asset, which can enhance our mind map as well. Exporting the mind map in different formats is going to be the main concern when designing and creating mind maps. We are working with FreeMind, and we see the maps as we design them. However, when exporting the maps, we can see them in different ways; thus the importance of the exporting feature. Exporting a branch as a new map or HTML In this recipe we are going to split the mind map in order to create a new one, using one part of the original one. It is very important to do it when the mind map is getting overwritten, that is to say when we add too much information and we want to represent the subject matter and write the exact information. Getting ready It is time to design a new mind map out of a node that already exists in the one that we are designing; therefore, we will export a branch in order to create a new one. Another option for exporting a branch is to export it as HTML. How to do it... When writing the mind map, if we feel that we do need to split it or if we want to keep on writing but the space that we have is not enough, it means that we have to export a branch as a new mind map. We must bear in mind that this branch appears as the root node of the new one. The sibling nodes that it has are to be exported as well. In the first part of the recipe we are going to focus on the two ways to export the branch; in the second part of the recipe we will compare the results when exporting them in one way or another. The following are the steps that you have to perform: Open the file that you are going to work with. In case you are working with a new file, you do need to save it before exporting the branch. Click on the node that you want to make the root node, as shown in the following screenshot: Click on File | Export | Branch As New Mind, as shown in the following screenshot: A pop-up window appears. Write a name for your file and click on Save. A red arrow appears on the branch, indicating that the branch was exported as a new mind map, as shown in the following screenshot: The branch exported as a mind map looks like the following screenshot: It is important to point out that when exporting the branch of the mind map, the nodes—whether folded or not—no longer appear in the original one, as they are going to be exported to the new mind map. To export another branch of the mind map as HTML, click on the node to export, as shown in the following screenshot: Click on File | Export | Branch as HTML, as shown in the following screenshot: How it works... The main difference between exporting the branch as HTML instead of exporting the branch itself, is that the sibling nodes remain in the original mind map. So, we only export the branch and it appears in our default web browser. Another relevant feature is that when exporting the branch of the mind map as HTML, we see the map in a different format, not as a mind map itself. It is shown in the following screenshot: We can also save this HTML file. Click on the down arrow next to Firefox. Click on Save Page As, write a name for the file, and click on Save. The file is saved as shown in the preceding screenshot, on your computer. Exporting the mind map to bitmaps or vector graphics We can export a mind map as an image, using any of the following three graphic file formats—JPEG, PNG, and SVG. We are going to analyze the options, although they are very simple. If the mind map has bitmaps, we can export the mind map as PNG (short for Portable Network Graphics). It is a file format that provides advanced graphic features and lossless compression. It is advisable to use this type of file format while working with bitmaps when we don't want to lose image quality while rendering the mind map to the final bitmap. In case we want to export the mind map in the file form with the smallest possible size, we can use the JPEG (short for Joint Photographic Experts Group) file format, which uses lossy compression. Pixels with different colors add noise to the image, and delete color information and replace it with pixels of approximated values. If the mind map has many photographs, the best choice for the smallest file size that will lose some image quality is JPEG. JPEG is a compressed graphic file that is used for images that have many colors, that is to say, pictures taken with any type of photographic camera. The third option is to export the mind map as SVG (short for Scalable Vector Graphics). It is advisable to export the mind map in this format if we want to edit the geometric forms that make up the mind map. We can use software that deals with vector graphics and can edit this format. An example of such software is Inkscape. Getting ready It is time to think which mind map we want to export! The steps are the same for any of the exports, what differs is that we are going to choose a different type of file extension. How to do it... We have designed several types of mind maps, using different elements. We are now going to choose a mind map to export and a file extension that suits it. The following are the steps to be performed: Open the file that you want to export. Remember to unfold all the nodes, otherwise they are going to be exported as folded. Click on File | Export | As SVG…, as shown in the following screenshot: Write a name for the file and click on Save. How it works... We must take into consideration that the software that deals with SVG should be Inkscape or any other similar commercial one, such as Paint. When we look for the file on our computer and click on it, any of the said software will open and show the file. It is shown in the following screenshot: Uploading the mind map on Flickr and sharing it In this recipe we are going to upload our mind map on Flickr in order to share it. We must bear in mind that we have to unfold all its branches at the time of exporting, because we won't be able to unfold a branch if it is exported in a folded form. So, the first step is to prepare a mind map in order to be exported. Another important aspect to consider when uploading a file on Flickr is that it does not accept SVG files; therefore, we have to export our mind map either as PNG or JPEG, taking into account how they are designed. So, let's get ready! Getting ready It is time to sign up on Flickr; to do it, we must go to http://www.flickr.com/. In this recipe, we are going to upload that mind map on Flickr. Why? So that we can have access to the HTML code and embed it, and have the URL and create a link with it. There are plenty of options to have our mind map uploaded on this photo-sharing site. Furthermore, there are several activities that teachers can create using this mind map. How to do it... The first step that we have to perform in order to upload the mind map is to export it. We have to choose a mind map with pictures or photographs. After that, we have to export it as PNG or JPEG. In this recipe we are going to export it as PNG, because the mind map has bitmaps. The following are the steps that you have to perform: Open the file that you are going to work with. Click on File | Export | As PNG.... Write a name for the file and click on Save, as shown in the following screenshot: The file is saved in order to upload it on Flickr Sign in to your Flickr account and personalize your profile. Go to http://www.flickr.com/, and sign in for your account. You can also sign in with your Facebook account if you happen to have one. Click on Upload, as shown in the following screenshot: Click on Choose photos and videos. Search for the mind map that you have just exported as PNG. Click on the name of the file and click on Open. Choose the type of privacy for this file, within the Set Privacy block, as shown in the following screenshot: Click on Upload Photos and Videos. Wait for the file to upload. Click on add a description, as shown in the following screenshot: Complete the blocks, as shown in the following screenshot: Click on SAVE. How it works... After uploading the mind map to Flickr, we can now click on it. We can share it through different ways—by grabbing the link or copying and pasting the HTML/BBCode, as shown in the following screenshot: Exporting the mind map as HTML In this recipe we are going to export the mind map as HTML. In order to export the mind map as HTML, it is important to consider the fact that it has to be designed using words rather than images. Furthermore, it is also convenient to create the mind map using different types of sizes, fonts, as well as colors, in order to show the importance and differences after being exported. Getting ready The mind map has only text, and it is appropriate for exporting as HTML. How to do it... First, we have to choose the mind map to export; in this case, the one of British onarchs. After exporting the mind map, we can also save it in this new format on our computer. When exporting as HTML, we have two options. We can export the mind map folded or unfolded. If we export it as folded, we also have the possibility to unfold it when exported; but if we export it as unfolded, we do not have the possibility to fold it afterwards. These possibilities are explored in this recipe. So, the following are the steps that we have to perform: Open the file to export. Fold all the nodes. Click on File | Export | As HTML…, as shown in the following screenshot: The mind map is exported. There appear + signs next to the nodes that have subnodes, as shown in the following screenshot: Click on the + sign to unfold the nodes, as shown in the following screenshot: How it works... When exporting the mind map with its nodes folded, the result is different. The mind map looks the same as the previous screenshot, but the + or - signs do not appear next to the nodes that contain subnodes. The exported mind map, with its nodes unfolded, appears as shown in the following screenshot: Exporting the mind map as XHTML There are three options when exporting our mind maps as XHTML. Two of them are available in the menu, but the third one depends on whether the mind map is folded or not. Therefore, before exporting it, we have to analyze the options. When the mind map is exported, it looks similar to HTML, but it is more colorful and the information in the note window appears below the node in which we have added it. Getting ready We are going to export the same mind map using the three different alternatives, so that we can notice the different results. The mind map to be exported is the one of British monarchs. In the previous recipe we exported the mind map as HTML, so we can also compare the difference with that exportation. How to do it... We are going to export the mind map as XHTML (clickable map image version). But, we are going to export it with its nodes folded. So, the following are the steps that you have to perform: Open the file that you are going to work with. Fold all the nodes containing subnodes. Click on File | Export | As XHTML (Clickable map image version) …, as shown in the following screenshot: Enter a name for the file and click on Save. The exported map appears in the default web browser, as shown in the following screenshot: Minimize your default web browser and go back to FreeMind. Unfold all the nodes in the same mind map. Repeat steps 3 and 4. The exported map appears in your default web browser, as shown in the following screenshot: How it works... It is time to explore the third option when exporting the mind map as XHTML. The option that we are exploring here does not export the image of the map, so it does not matter whether the nodes are folded or not. The information about the different nodes is exported, and we can expand or collapse the nodes, by clicking on the upper part. Perform the following steps: Open the mind map you want to export. Click on File | Export | As XHTML (JavaScript version)…, as shown in the following screenshot: Enter a name for the file. Click on Save. The mind map is exported to your default web browser, as shown in the following screenshot: Save the files on your computer in any of these cases, when the mind map is exported. Exporting the mind map as Flash Exporting the mind map as Flash is very interesting, because it maintains the characteristics that we have added to the mind map. Besides, whether exported with the nodes folded or not, we can open them by clicking on the nodes. In the case that the nodes contain information in the note window, we can read them if we hover the mouse over those nodes. Getting ready It is time to see how to export the mind map in a different way. We have to bear in mind that Flash is not available in some operating systems. How to do it... We are going to keep on exporting the same mind map, so that the difference in the exportations is noticeable. The following are the steps to perform: Open the file that you are going to work with. Click on File | Export | As Flash…, as shown in the following screenshot: Write a name for the file. Click on Save. How it works... The exported mind map appears in the default web browser. The mind map looks the same as in FreeMind. When clicking on the nodes, they fold or unfold. If there is a node that contains information in the note window, it appears while hovering the mouse over it. It is shown in the following screenshot:
Read more
  • 0
  • 0
  • 2613

article-image-use-real-world-application
Packt
23 Jun 2017
11 min read
Save for later

Use in Real World Application

Packt
23 Jun 2017
11 min read
In this article by Giorgio Zarrelli author of the book Mastering Bash, we are moving a step now into the real world creating something that can turn out handy for your daily routine and during this process we will have a look at the common pitfalls in coding and how to make our script reliable. Be short or a long script, we must always ask ourselves the same questions: What do we really want to accomplish? How much time do we have? Do we have all the resources needed? Do we have the knowledge required for the task? (For more resources related to this topic, see here.) We will start coding with a Nagios plugin which will give us a broad understanding of how this monitoring system is and how to make a script dynamically interact with other programs. What is Nagios Nagios is one of the most widely adopted Open Source IT infrastructure monitoring tool whose main interesting feature being the fact that it does not know how to monitor anything. Well, it can sound like a joke but actually Nagios can be defined as an evaluating core which takes some informations as input and reacting accordingly. How this information is gathered? It is not the main concern of this tool and this leads us to an interesting point: Nagios leave sthe task of getting the monitored data to an external plugin which: Knows how to connect to the monitored services Knows how to collect the data from the monitored services Knows how to evaluate the data Inform Nagios if the values gathered are beyond or in the boundaries to raise an alarm. So, a plugin does a lot of things and one would ask himself what does Nagios do then? Imagine it as an exchange pod where information is flowing in and out and decisions are taken based on the configurations set; the core triggers the plugin to monitor a service, the plugin itself returns some information and Nagios takes a decision about: If to raise an alarm Send a notification Whom to notify For how long Which, if any action is taken in order to get back into normality The core Nagios program does everything except actually knock at the door of a service, ask for information and decide if this information shows some issues or not. Planning must be done, but it can be fun. Active and passive checks To understand how to code a plugin we have first to grasp how, on a broad scale, a Nagios check works. There are two different kinds of checks: Active check Based on a time range, or manually triggered, an active check sees a plugin actively connecting to a service and collecting informations. A typical example could be a plugin to check the disk space: once invoked it interfaces with (usually) the operating system, execute a df command, works on the output, extracts the value related to the disk space, evaluates it against some thresholds and report back a status, like OK , WARNING , CRITICAL or UNKNOWN. Passive check In this case, Nagios does not trigger anything but waits to be contacted by some means by the service which must be monitored. It seems quite confusing but let’s make a real life example. How would you monitor if a disk backup has been completed successfully? One quick answer would be: knowing when the backup task starts and how long it lasts, we can define a time and invoke a script to check the task at that given hour. Nice, but when we plan something we must have a full understanding of how real life goes and a backup is not our little pet in the living room, it’s rather a beast which does what it wants. A backup can last a variable amount of time depending on unpredictable factor. For instance, your typical backup task would copy 1 TB of data in 2 hours, starting at 03:00, out of a 6 TB disk. So, the next backup task would start at 03:00+02:00=05:00 AM, give or take some minutes, and you setup an active check for it at 05:30 and it works well for a couple of months. Then, one early morning your receive a notification on your smartphone, the backup is in CRITICAL. You wake up, connect to the backup console and see that at 06:00 in the morning you are asleep and the backup task has not even been started by the console. Then you have to wait until 08:00 AM until some of your colleagues shows up at the office to find out that the day before the disk you backup has been filled with 2 extra TB of data due to an unscheduled data transfer. So, the backup task preceding the one you are monitoring lasted not for a couple of hours but 6 hours, and the task you are monitoring then started at 09:30 AM. Long story short, your active check has been fired up too early, that is why it failed. Maybe your are tempted to move your schedule some hours ahead, but simply do not do it, these time slots are not sliding frames. If you move your check ahead you should then move all the checks for the subsequent tasks ahead. You do it in one week, the project manager will ask someone to delete the 2 TB in excess (they are no more of any use for the project), and your schedules will be 2 hours ahead making your monitoring useless. So, as we insisted before, planning and analyzing the context are the key factors in making a good script and, in this case, a good plugin. We have a service that does not run 24/7 like a web service or a mail service, what is specific to the backup is that it is run periodically but we do not know exactly when. The best approach to this kind of monitoring is letting the service itself to notify us when it finished its task and what was its outcome. That is usually accomplished using the ability of most of the backup programs to send a Simple Network Monitoring Protocol (SNMP) trap to a destination to inform it of the outcome and for our case it would be the Nagios server which would have been configured to receive the trap and analyze. Add to this an event horizon so that if you do not receive that specific trap in, let’s say, 24 hours we raise an alarm anyway and you are covered: whenever the backup task gets completed, or when it times out, we receive a notification. Nagios notifications flowchart Return codes and thresholds Before coding a plugin we must face some concepts that will be the stepping stone of our Nagios coding in base, one of these being the return codes of the plugin itself. As we already discussed, once the plugin collects the data about how the service is going, it evaluates these data and determines if the situation falls under one of the following status: Return code Status Description 0 OK The plugin checked the service and the results are inside the acceptable range 1 WARNING The plugin checked the service and the results are above a warning threshold. We must keep an eye on the service 2 CRITICAL The plugin checked the service and the results are above a CRITICAL threshold or the service not responding. We must react now. 3 UNKNOWN Either we passed the wrong arguments to the plugin or there is some internal error in it. So, our plugin will check a service, evaluate the results, and based on a threshold will return to Nagios one of the values listed in the tables and a meaningful message like we can see in the description column in the following image: Notice the service check in red and the message in the figure above. In the image we can see that some checks are green, meaning ok, and they have an explicative message in the description section: what we see in this section is the output of the plugin written in the stdout and it is what we will craft as a response to Nagios. Pay attention at the ssh check, it is red, it is failing because it is checking the service at the default port which is 22 but on this server the ssh daemon is listening on a different port. This leads us to a consideration: our plugin will need a command line parser able to receive some configuration options and some threshold limits as well because we need to know what to check, where to check and what are the acceptable working limits for a service: Where: In Nagios there can be a host without service checks (except for the implicit host alive carried on by a ping), but no services without a host to be performed onto. So any plugin must receive on the command line the indication of the host to be run against, be it a dummy host but there must be one. How: This is where our coding comes in, we will have to write the lines of code that instruct the plugin how to connect to the server, query, collect and parse the answer. What: We must instruct the plugin, usually with some meaningful options on the command line, on what are the acceptable working limits so that it can evaluate them and decide if notify an OK, WARNING or CRITICAL message. That is all for our script, who to notify, when, how, for how many times and so forth. These are tasks carried on by the core, a Nagios plugin is unaware of all of this. What he really must know for an effective monitoring is what are the correct values that identify a working service. We can pass to our script two different kinds of value: Range:A series of numeric values with a starting and ending point, like from 3 to 7 or from one number to infinite. Threshold: It is a range with an associated alert level. So, when our plugins perform its check, it collects a numeric value that is within or outside a range, based on the threshold we impose then, based on the evaluation it replies to Nagios with a return code and a message. How do we specify some ranges on the command line? Essentially in the following way: [@] start_value:end_value If the range starts from 0, the part from : to the left can be omitted. The start_value must always be a lower number than end_value. If the range starts as start_value, it means from that number to infinity. Negative infinity can be specified using ~ Alert is generated when the collected value resides outside the range specified, comprised of the endpoints. If @ is specified, the alert is generated if the value resides inside the range. Let's see some practical example on how we would call our script imposing some thresholds: Plugin call Meaning ./my_plugin -c 10 CRITICAL if less than 0 or higher than 10 ./my_plugin -w 10:20 WARNING if less than 10 or higher than 20 /my_plugin -w ~:15 -c 16 WARNING if between -infinite and 15, critical from 16 and higher ./my_plugin -c 35: CRITICAL if the value collected is below 35 ./my_plugin -w @100:200 CRITICAL if the value is from 100 to 200, OK otherwise We covered the basic requirements for our plugin that in its simplest form should be called with the following syntax: ./my_plugin -h hostaddress|hostname -w value -c value We already talked about the need to relate a check to a host and we can do this either using a host name or a host address. It is up to us what to use but we will not fill in this piece of information because it will be drawn by the service configuration as a standard macro. We just introduced a new concept, service configuration, which is essential in making our script work in Nagios. Summary In this article, we learned that how the real world can turn out handy for your daily routine and during this process we also looked at the common pitfalls in coding and how we make our script reliable. Resources for Article: Further resources on this subject: From Code to the Real World [article] Getting Ready to Launch Your PhoneGap App in the Real World [article] Implementing a WCF Service in the Real World [article]
Read more
  • 0
  • 0
  • 2613

article-image-building-images
Packt
27 Dec 2016
26 min read
Save for later

Building Images

Packt
27 Dec 2016
26 min read
In this article by Jeeva Chelladhurai, Pethuru Raj Chelliah, and Vinod Singh, the authors of the book Learning Docker, Second Edition, we will learn how the Docker images are built by using Dockerfile, which is the standard way for bringing forth highly usable Docker images. Leveraging Dockerfile is the most competent way for building powerful images for the software development community. (For more resources related to this topic, see here.) Docker's integrated image building system The Docker images are the fundamental building blocks of containers. These images could be very basic operating environments such, as busybox or Ubuntu. Or the images could craft advanced application stacks for the enterprise and cloud IT environments. We could craft an image manually by launching a container from a base image, install all the required applications, make the necessary configuration file changes, and then commit the container as an image. As a better alternative, we could resort to the automated approach of crafting the images by using Dockerfile. Dockerfile is a text-based build script that contains special instructions in a sequence for building the right and the relevant images from the base images. The sequential instructions inside the Dockerfile can include the base image selection, installing the required application, adding the configuration and the data files, and automatically running the services as well as exposing those services to the external world. Thus, Docker file-based automated build system has remarkably simplified the image-building process. It also offers a great deal of flexibility in the way in which the build instructions are organized and in the way in which they visualize the complete build process. The Docker Engine tightly integrates this build process with the help of the docker build subcommand. In the client-server paradigm of Docker, the Docker server (or daemon) is responsible for the complete build process and the Docker command line interface is responsible for transferring the build context, including transferring Dockerfile to the daemon. In order to have a sneak peak into the Dockerfile integrated build system in this section, we introduce you to a basic Dockerfile. Then, we explain the steps for converting that Dockerfile into an image, and then launching a container from that image. Our Dockerfile is made up of two instructions, as shown here: $cat Dockerfile FROM busybox:latest CMD echo Hello World!! In the following, we cover/discuss the two instructions mentioned earlier: The first instruction is for choosing the base image selection. In this example, we select the busybox: latest image The second instruction is for carrying out the command CMD, that instructs the container to echo Hello World!! Now, let's proceed towards generating a Docker image by using the preceding Dockerfile by calling docker build along with the path of Dockerfile. In our example, we will invoke the docker build subcommand from the directory where we have stored Dockerfile, and the path will be specified by the following command: $sudo docker build . After issuing the preceding command, the build process will begin by sending build context to the daemon and then display the text shown here: Sending build context to Docker daemon 2.048 kB Step 1 : FROM busybox:latest The build process would continue and after completing itself, it will display the following: Successfully built 0a2abe57c325 In the preceding example, the image was built with the IMAGE ID0a2abe57c325. Let's use this image to launch a container by using the docker run subcommand as follows: $sudo docker run 0a2abe57c325 Hello World!! Cool, isn't it? With very little effort, we have been able to craft an image with busybox as the base image, and we have been able to extend that image to produce Hello World!!. This is a simple application, but the enterprise-scale images can also be realized by using the same technology. Now, let's look at the image details by using the docker images subcommand, as shown here: $ sudo docker images REPOSITORYTAG IMAGE IDCREATED VIRTUAL SIZE <none><none>0a2abe57c3252 hours ago2.433 MB Here, you may be surprised to see that the IMAGE(REPOSITORY) and TAG name have been listed as <none>.This is because we did not specify any image or any TAG name when we built this image. You could specify an IMAGE name and optionally a TAG name by using the docker tag subcommand, as shown here: $ sudo docker tag 0a2abe57c325 busyboxplus The alternative approach is to build the image with an image name during the build time by using the-t option for the docker build subcommand, as shown here: $sudo docker build -t busyboxplus . Since there is no change in the instructions in Dockerfile, the Docker Engine will efficiently reuse the old image that has ID0a2abe57c325 and update the image name to busyboxplus. By default, the build system would apply latest as the TAG name. This behavior can be modified by specifying the TAG name after the IMAGE name by having a : separator placed in between them. That is, <image name>:<tag name> is the correct syntax for modifying behaviors, wherein <image name> is the name of the image and <tag name> is the name of the tag. Once again, let's look at the image details by using the docker images subcommand, and you will notice that the image (Repository) name is busyboxplus and the tag name is latest: $ sudo docker images REPOSITORYTAG IMAGE IDCREATED VIRTUAL SIZE busyboxplus latest0a2abe57c3252 hours ago2.433 MB Building images with an image name is always recommended as the best practice. A quick overview of the Dockerfile's syntax In this section, we explain the syntax or the format of Dockerfile. A Dockerfile is made up of instructions, comments, parser directives, and empty lines, as shown here: # Comment INSTRUCTION arguments The instruction line of Dockerfile is made up of two components, where the instruction line begins with the instruction itself, which is followed by the arguments for the instruction. The instruction could be written in any case, in other words, it is case-insensitive. However, the standard practice or the convention is to use uppercase in order to differentiate it from the arguments. Let's take a relook at the content of Dockerfile in our previous example: FROM busybox:latest CMD echo Hello World!! Here, FROM is an instruction which has taken busybox:latest as an argument, and CMD is an instruction which has taken echo Hello World!! as an argument. The commentline The comment line in Dockerfile must begin with the# symbol. The # symbol after an instruction is considered as an argument. If the # symbol is preceded by a whitespace, then the docker build system would consider that as an unknown instruction and skip the line. Now, let's understand the preceding cases with the help of an example to get a better understanding of the comment line: A valid Dockerfile comment line always begins with a# symbol as the first character of the line: # This is my first Dockerfile comment The # symbol can be a part of an argument CMD echo ### Welcome to Docker ### If the # symbol is preceded by a whitespace, then it is considered as an unknown instruction by the build system # this is an invalid comment line The docker build system ignores any empty line in the Dockerfile and hence, the author of Dockerfile is encouraged to add comments and empty lines to substantially improve the readability of Dockerfile. The parser directives As the name implies, the parser directives instruct the Dockerfile parser to handle the content of the Dockerfile as specified in the directives. The parser directives are optional and they must be at the very top of a Dockerfile. Currently escape is the only supported directive. We use escape character to escape characters in a line or to extend a single line to multiple lines. On UNIX like platform is the escape character whereas on windows is a directory path separator and ` is the escape character. By default, Dockerfile parser considers as the escape character and you could override this on windows using escape parser directive as shown here: # escape=` The Dockerfile build instructions So far, we have looked at the integrated build system, the Dockerfile syntax and a sample lifecycle, wherein how a sample Dockerfile is leveraged for generating an image and how a container gets spun off from that image was discussed. In this section, we will introduce the Dockerfile instructions, their syntax, and a few befitting examples. The FROM instruction The FROM instruction is the most important one and it is the first valid instruction of a Dockerfile. It sets the base image for the build process. The subsequent instructions would use this base image and build on top of it. The Docker build system lets you flexibly use the images built by anyone. You can also extend them by adding more precise and practical features to them. By default, the Docker build system looks in the Docker host for the images. However, if the image is not found in the Docker host, then the Docker build system will pull the image from the publicly available Docker Hub Registry. The Docker build system will return an error if it could not find the specified image in the Docker host and the Docker Hub Registry. The FROM instruction has the following syntax: FROM <image>[:<tag>|@<digest>] In the preceding code statement, note the following: <image>: This is the name of the image which will be used as the base image <tag> or<digest>:Both tag and digest are optional attributes and you could qualify a particular Docker image version using either a tag or a digest. Tag latest is assumed by default if both tag and digest are not present. Here is an example of the FROM instruction with the image name centos: FROM centos The MAINTAINER instruction The MAINTAINER instruction is an informational instruction of a Dockerfile. This instruction capability enables the authors' to set the details in an image. Docker does not place any restrictions on placing the MAINTAINER instruction in Dockerfile. However, it is strongly recommended that you should place it after the FROM instruction. The following is the syntax of the MAINTAINER instruction, where <author's detail> can be in any text. However, it is strongly recommended that you should use the image, author's name and the e-mail address as shown in this code syntax: MAINTAINER <author's detail> Here is an example of the MAINTAINER instruction with the author name and the e-mail address: MAINTAINER Dr. Peter <peterindia@gmail.com> The COPY instruction The COPY instruction enables you to copy the files from the Docker host to the file system of the new image. The following is the syntax of the COPY instruction: COPY <src> ... <dst> The preceding code terms bear the explanations shown here: <src>: This is the source directory, the file in the build context, or the directory from where the docker build subcommand was invoked. ...: This indicates that multiple source files can either be specified directly or be specified by wildcards. <dst>:This is the destination path for the new image into which the source file or directory will get copied. If multiple files have been specified, then the destination path must be a directory and it must end with a slash /. Using an absolute path for the destination directory or a file has been recommended. In the absence of an absolute path, the COPY instruction will assume that the destination path will start from root /.The COPY instruction is powerful enough for creating a new directory and for overwriting the file system in the newly created image. The ADD instruction The ADD instruction is similar to the COPY instruction. However, in addition to the functionality supported by the COPY instruction, the ADD instruction can handle the TAR files and the remote URLs. We can annotate the ADD instruction as COPY on steroids. The following is the syntax of the ADD instruction: ADD <src> ... <dst> The arguments of the ADD instruction are very similar to those of the COPY instruction, as shown here: <src>: This is either the source directory or the file that is in the build context or in the directory from where the docker build subcommand will be invoked. However, the noteworthy difference is that the source can either be a tar file stored in the build context or be a remote URL. ...: This indicates that the multiple source files can either be specified directly or be specified by using wildcards. <dst>: This is the destination path for the new image into which the source file or directory will be copied. The ENV instruction The ENV instruction sets an environment variable in the new image. An environment variable is a key-value pair, which can be accessed by any script or application. The Linux applications use the environment variables a lot for a starting configuration. The following line forms the syntax of the ENV instruction: ENV <key><value> Here, the code terms indicate the following: <key>: This is the environment variable <value>: This is the value that is to be set for the environment variable The following lines give two examples for the ENV instruction, where, in the first line, DEBUG_LVL has been set to 3 and in the second line, APACHE_LOG_DIR has been set to /var/log/apache: ENV DEBUG_LVL 3 ENV APACHE_LOG_DIR /var/log/apache The ARG instruction The ARG instruction lets you define variables that can be passed during the Docker image build time. The Docker build subcommand supports --build-arg flag to pass value to the variables defined using ARG instruction. If you specify a build argument that was not defined in your Dockerfile, the build would fail. In other words, the build argument variables must be defined in the Dockerfile to be passed during the Docker image build time. The syntax of the ARG instruction is as follows: ARG<variable>[=<default value>] Wherein, the code terms mean the following: <variable>: This is the build argument variable <default value>: This is the default value you could optionally specify to the build argument variable The environmentvariables The environment variables declared using ENV or ARG instruction can be used in ADD, COPY, ENV, EXPOSE, LABEL, USER, WORKDIR, VOLUME, STOPSIGNAL and ONBUILD instruction. Here is an example of environment variable usage: ARGBUILD_VERSION LABEL com.example.app.build_version=${ BUILD_VERSION} The USER instruction The USER instruction sets the startup user ID or username in the new image. By default, the containers will be launched with root as the user ID or UID. Essentially, the USER instruction will modify the default user ID from root to the one specified in this instruction. The syntax of the USER instruction is as follows: USER <UID>|<UName> The USER instructions accept either <UID> or <UName> as its argument. <UID>: This is a numerical user ID <UName>: This is a valid user Name Following is an example for setting the default user ID at the time of startup to 73. Here 73 is the numerical ID of the user: USER 73 Though, it is recommended that you have a valid user ID to match with the /etc/passwd file, the user ID can contain any random numerical value. However, the username must match with a valid username in the /etc/passwd file, otherwise the docker run subcommand will fail and it will display the following error message: finalize namespace setup user get supplementary groups Unable to find user The WORKDIR instruction The WORKDIR instruction changes the current working directory from / to the path specified by this instruction. The ensuing instructions, such as RUN, CMD, and ENTRYPOINT will also work on the directory set by the WORKDIR instruction. The following line gives the appropriate syntax for the WORKDIR instruction: WORKDIR <dirpath> Here, <dirpath> is the path for the working directory to set in. The path can be either absolute or relative. In case of a relative path, it will be relative to the previous path set by the WORKDIR instruction. If the specified directory is not found in the target image file system, then the director will be created. The following line is a clear example of the WORKDIR instruction in a Dockerfile: WORKDIR /var/log The VOLUME instruction The VOLUME instruction creates a directory in the image file system, which can later be used for mounting volumes from the Docker host or the other containers. The VOLUME instruction has two types of syntax, as shown here: The first type is either exec or JSON array (all values must be within double-quotes (")). VOLUME ["<mountpoint>"] The second type is shell, as shown here: VOLUME <mountpoint> In the preceding lines, <mountpoint> is the mount point that has to be created in the new image. The EXPOSE instruction The EXPOSE instruction opens up a container network port for communicating between the container and the external world. The syntax of the EXPOSE instruction is as follows: EXPOSE <port>[/<proto>] [<port>[/<proto>]...] Here, the code terms mean the following: <port>:This is the network port that has to be exposed to the outside world. <proto>: This is an optional field provided for a specific transport protocol, such as TCP and UDP. If no transport protocol has been specified, then TCP is assumed to be the transport protocol. The EXPOSE instruction allows you to specify multiple ports in a single line. The LABEL instruction The LABEL instruction enables you to add key-value pairs as metadata to your Docker images. These metadata can be further leveraged to provide meaningful Docker image management and orchestration. The syntax of the LABEL instruction is as follows: LABEL<key-1>=<val-1><key-2>=<val-2> ... <key-n>=<val-n> The LABEL instruction can have one or more key-value pair. Though a Dockerfile can have more than one LABEL instruction, it is recommended to use single LABEL instruction with multiple key-value pairs. Here is an example for the LABEL instruction: LABEL version=”2.0” release-date=”2016-08-05” The preceding label keys are very simple and this could result in naming conflicts. Hence Docker recommends using namespaces to label keys using reverse domain notation. There is a community project called Label Schema that provides shared namespace. The shared namespace acts as a glue between the image creators and tool builders to provide standardized Docker image management and orchestration. Here is an example of LABEL instruction using Label Schema: LABELorg.label-schema.schema-version=”1.0” org.label-schema.version=”2.0” org.label-schema.description=”Learning Docker Example” The RUN instruction The RUN instruction is the real workhorse during the build time, and it can run any command. The general recommendation is to execute the multiple commands by using one RUN instruction. This reduces the layers in the resulting Docker image because the Docker system inherently creates a layer for each time an instruction is called in Dockerfile. The RUN instruction has two types of syntax. The first is the shell type, as shown here: RUN <command> Here, the <command> is the shell command that has to be executed during the build time. If this type of syntax is to be used, then the command is always executed by using /bin/sh -c. And, the second syntax type is either exec or the JSON array, as shown here: RUN ["<exec>", "<arg-1>", ..., "<arg-n>"] Wherein, the code terms mean the following: <exec>: This is the executable to run during the build time. <arg-1>, ..., <arg-n>: These are the variables (zero or more) number of the arguments for the executable. Unlike the first type of syntax, this type does not invoke /bin/sh -c. Hence, the types of shell processing, such as the variable substitution ($USER) and the wild card substitution (*,?), does not happen in this type. If shell processing is critical for you, then you are encouraged to use the shell type. However, if you still prefer the exec (JSON array type) type, then use your preferred shell as the executable and supply the command as an argument. For example, RUN ["bash", "-c", "rm", "-rf", "/tmp/abc"]. The CMD instruction The CMD instruction can run any command (or application), which is similar to the RUN instruction. However, the major difference between those two is the time of execution. The command supplied through the RUN instruction is executed during the build time, whereas the command specified through the CMD instruction is executed when the container is launched from the newly created image. Thus, the CMD instruction provides a default execution for this container. However, it can be overridden by the docker run subcommand arguments. When the application terminates, the container will also terminate along with the application and vice versa. The CMD instruction has three types of syntax, as shown here: The first syntax type is the shell type, as shown here: CMD <command> Wherein, the <command> is the shell command, which has to be executed during the launch of the container. If this type of syntax is used, then the command is always executed by using /bin/sh -c. The second type of syntax is exec or the JSON array, as shown here: CMD ["<exec>", "<arg-1>", ..., "<arg-n>"] Wherein, the code terms mean the following: <exec>: This is the executable, which is to be run during the container launch time <arg-1>, ..., <arg-n>: These are the variable (zero or more) number of the arguments for the executable The third type of syntax is also exec or the JSON array, which is similar to the previous type. However, this type is used for setting the default parameters to the ENTRYPOINT instruction, as shown here: CMD ["<arg-1>", ..., "<arg-n>"] Wherein, the code terms mean the following: <arg-1>, ..., <arg-n>: These are the variables (zero or more) number of the arguments for the ENTRYPOINT instruction Now, let's build a Docker image by using the docker build subcommand and cmd-demo as the image name. The docker build system will read the instruction from the Dockerfile that is stored in the current directory (.), and craft the image accordingly as shown here: $sudo docker build -t cmd-demo . Having built the image, we can launch the container by using the docker run subcommand, as shown here: $sudo docker run cmd-demo Dockerfile CMD demo Cool, isn't it? We have given a default execution for our container and our container has faithfully echoed Dockerfile CMD demo. However, this default execution can be easily overridden by passing another command as an argument to the docker run subcommand, as shown in the following example: $sudo docker run cmd-demo echo Override CMD demo Override CMD demo The ENTRYPOINT instruction The ENTRYPOINT instruction will help in crafting an image for running an application (entry point) during the complete lifecycle of the container, which would have been spun out of the image. When the entry point application is terminated, the container would also be terminated along with the application and vice versa. Thus, the ENTRYPOINT instruction would make the container function like an executable. Functionally, ENTRYPOINT is akin to the CMD instruction, but the major difference between the two is that the entry point application is launched by using the ENTRYPOINT instruction, which cannot be overridden by using the docker run subcommand arguments. However, these docker run subcommand arguments will be passed as additional arguments to the entry point application. Having said this, Docker provides a mechanism for overriding the entry point application through the--entrypoint option in the docker run subcommand. The --entrypoint option can accept only word as its argument and hence, it has limited functionality. Syntactically, the ENTRYPOINT instruction is very similar to the RUN, and the CMD instructions, and it has two types of syntax, as shown here: The first type of syntax is the shell type, as shown here: ENTRYPOINT <command> Here, <command> is the shell command, which is executed during the launch of the container. If this type of syntax is used, then the command is always executed by using /bin/sh -c. The second type of syntax is exec or the JSON array, as shown here: ENTRYPOINT ["<exec>", "<arg-1>", ..., "<arg-n>"] Wherein, the code terms mean the following: <exec>: This is the executable, which has to be run during the container launch time <arg-1>, ..., <arg-n>: These are the variable (zero or more) number of arguments for the executable Now, let's build a Docker image by using the docker build as the subcommand and entrypoint-demo as the image name. The docker build system would read the instruction from Dockerfile stored in the current directory (.) and craft the image, as shown here: $sudo docker build -t entrypoint-demo . Having built the image, we can launch the container by using the docker run subcommand: $sudo docker run entrypoint-demo Dockerfile ENTRYPOINT demo Here, the container will run like an executable by echoing the Dockerfile ENTRYPOINT demo string and then it will exit immediately. If we pass any additional arguments to the docker run subcommand, then the additional argument would be passed to the entry point command. Following is the demonstration of launching the same image with the additional arguments given to the docker run subcommand: $sudo docker run entrypoint-demo with additional arguments Dockerfile ENTRYPOINT demo with additional arguments Now, let's see an example where we override the build time entry point application with the--entrypoint option and then launch a shell (/bin/sh) in the docker run subcommand, as shown here: $sudo docker run --entrypoint="/bin/sh" entrypoint-demo / # The HEALTHCHECK instruction Any Docker container is designed to run just one process / application / service as a best practice and also to be uniquely compatible for the fast-evolving Micro services Architecture (MSA) The container dies if the process running inside the container dies. There is a possibility that the application running inside the container might be in an unhealthy state and such state must be externalized for effective container management. Here the HEALTHCHECK instruction comes handy to monitor the health of the containerized application by running a health monitoring command (or tool) on a prescribed interval. The syntax of the HEALTHCHECK instruction is as follows: HEALTHCHECK[<options>] CMD <command> Wherein, the code terms mean the following: <command>: The health check command is to be executed on a prescribed interval. If the command exit status is 0, the container is considered to be in health state. If the command exit status is 1, the container is considered to be in unhealthy state. <options>: By default the health check command is invoked every 30 seconds, the command timeout 30 seconds and the command is retried 3 times before the container is declared unhealthy. Optionally, you can modify the default interval, timeout and retries values using the following options: --interval=<DURATION> [default: 30s] --timeout=<DURATION> [default: 30s] --retries=<N> [default: 3] Here is an example for the HEALTHCHECK instruction: HEALTHCHECK--interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1 The ONBUILD instruction The ONBUILD instruction registers a build instruction to an image and this gets triggered when another image is built by using this image as its base image. Any build instruction can be registered as a trigger and those instructions will be triggered immediately after the FROM instruction in the downstream Dockerfile. Thus, the ONBUILD instruction can be used for deferring the execution of the build instruction from the base image to the target image. The syntax of the ONBUILD instruction is as follows: ONBUILD <INSTRUCTION> Wherein, <INSTRUCTION> is another Dockerfile build instruction, which will be triggered later. The ONBUILD instruction does not allow the chaining of another ONBUILD instruction. In addition, it does not allow the FROM, and MAINTAINER instruction as an ONBUILD trigger. Here is an example for the ONBUILD instruction: ONBUILD ADD config /etc/appconfig The STOPSIGNAL instruction The STOPSIGNAL instruction enables you to configure an exit signal for your container. The STOPSIGNAL instruction has the following syntax: STOPSIGNAL<signal> Wherein, <signal>is either a valid signal name like SIGKILL or a valid unsigned signal number The SHELL instruction The SHELL instruction allows us to override the default shell, that is,sh on Linux and cmd on Windows. The syntax of the SHELL instruction is as follows: SHELL ["<shell>", "<arg-1>", ..., "<arg-n>"] Wherein, the code terms mean the following: <shell>: The shell to be used during container runtime <arg-1>, ..., <arg-n>: These are the variables (zero or more) number of the arguments for the shell Summary Building the Docker images is a critical aspect of the Docker technology for streamlining the grueling journey of containerization. As indicated before, the Docker initiative has turned out to be disruptive and transformative for the containerization paradigm which has been present for a while now. Dockerfile is the most prominent one for producing the competent Docker images, which can be meticulously used across. We have illustrated all the commands, their syntax, and their usage techniques in order to empower you with all the easy-to-grasp details and this will simplify the image-building process for you. We have supplied a bevy of examples in order to substantiate the inner meaning of each command. Resources for Article: Further resources on this subject: Benefits and Components of Docker [article] Let's start with Extending Docker [article] Container Linking and Docker DNS [article]
Read more
  • 0
  • 0
  • 2613
article-image-creating-cartesian-based-graphs
Packt
17 Jan 2013
19 min read
Save for later

Creating Cartesian-based Graphs

Packt
17 Jan 2013
19 min read
(For more resources related to this topic, see here.) Introduction Our first graph/chart under the microscope is the most popular and simplest one to create. We can classify them all roughly under Cartesian-based graphs. Altogether this graph style is relatively simple; it opens the door to creating amazingly creative ways of exploring data. In this article we will lay down the foundations to building charts in general and hopefully motivate you to come up with your own ideas on how to create engaging data visualizations. Building a bar chart from scratch The simplest chart around is the one that holds only one dimensional data (only one value per type). There are many ways to showcase this type of data but the most popular, logical, and simple way is by creating a simple bar chart. The steps involved in creating this bar chart will be very similar even in very complex charts. The ideal usage of this type of chart is when the main goal is to showcase simple data, as follows: Getting ready Create a basic HTML file that contains a canvas and an onLoad event that will trigger the init function. Load the 03.01.bar.js script. We will create the content of the JavaScript file in our recipe as follows: <!DOCTYPE html> <html> <head> <title>Bar Chart</title> <meta charset="utf-8" /> <script src="03.01.bar.js"></script> </head> <body onLoad="init();" style="background:#fafafa"> <h1>How many cats do they have?</h1> <canvas id="bar" width="550" height="400"> </canvas> </body> </html> Creating a graph in general has three steps: defining the work area, defining the data sources, and then drawing in the data. How to do it... In our first case, we will compare a group of friends and how many cats they each own. We will be performing the following steps: Define your data set: var data = [{label:"David", value:3, style:"rgba(241, 178, 225, 0.5)"}, {label:"Ben", value:2, style:"#B1DDF3"}, {label:"Oren", value:9, style:"#FFDE89"}, {label:"Barbera", value:6, style:"#E3675C"}, {label:"Belann", value:10, style:"#C2D985"}]; For this example I've created an array that can contain an unlimited number of elements. Each element contains three values: a label, a value, and a style for its fill color. Define your graph outlines. Now that we have a data source, it's time to create our basic canvas information, which we create in each sample: var can = document.getElementById("bar"); var wid = can.width; var hei = can.height; var context = can.getContext("2d"); context.fillStyle = "#eeeeee"; context.strokeStyle = "#999999"; context.fillRect(0,0,wid,hei); The next step is to define our chart outlines: var CHART_PADDING = 20; context.font = "12pt Verdana, sans-serif"; context.fillStyle = "#999999"; context.moveTo(CHART_PADDING,CHART_PADDING); context.lineTo(CHART_PADDING,hei-CHART_PADDING); context.lineTo(wid-CHART_PADDING,hei-CHART_PADDING); var stepSize = (hei - CHART_PADDING*2)/10; for(var i=0; i<10; i++){ context.moveTo(CHART_PADDING, CHART_PADDING + i* stepSize); context.lineTo(CHART_PADDING*1.3,CHART_PADDING + i* stepSize); context.fillText(10-i, CHART_PADDING*1.5, CHART_PADDING + i* stepSize + 6); } context.stroke(); Our next and final step is to create the actual data bars: var elementWidth =(wid-CHART_PADDING*2)/ data.length; context.textAlign = "center"; for(i=0; i<data.length; i++){ context.fillStyle = data[i].style; context.fillRect(CHART_PADDING +elementWidth*i ,hei- CHART_PADDING - data[i].value*stepSize,elementWidth,data[i]. value*stepSize); context.fillStyle = "rgba(255, 255, 225, 0.8)"; context.fillText(data[i].label, CHART_PADDING +elementWidth*(i+.5), hei-CHART_PADDING*1.5); } That's it. Now, if you run the application in your browser, you will find a bar chart rendered. How it works... I've created a variable called CHART_PADDING that is used throughout the code to help me position elements (the variable is in uppercase because I want it to be a constant; so it's to remind myself that this is not a value that will change in the lifetime of the application). Let's delve deeper into the sample we created starting from our outline area: context.moveTo(CHART_PADDING,CHART_PADDING); context.lineTo(CHART_PADDING,hei-CHART_PADDING); context.lineTo(wid-CHART_PADDING,hei-CHART_PADDING); In these lines we are creating the L-shaped frame for our data; this is just to help and provide a visual aid. The next step is to define the number of steps that we will use to represent the numeric data visually. var stepSize = (hei - CHART_PADDING*2)/10; In our sample we are hardcoding all of the data. So in the step size we are finding the total height of our chart (the height of our canvas minus our padding at the top and bottom), which we then divide by the number of the steps that will be used in the following for loop: for(var i=0; i<10; i++){ context.moveTo(CHART_PADDING, CHART_PADDING + i* stepSize); context.lineTo(CHART_PADDING*1.3,CHART_PADDING + i* stepSize); context.fillText(10-i, CHART_PADDING*1.5, CHART_PADDING + i* stepSize + 6); } We loop through 10 times going through each step to draw a short line. We then add numeric information using the fillText method. Notice that we are sending in the value 10-i. This value works well for us as we want the top value to be 10. We are starting at the top value of the chart; we want the displayed value to be 10 and as the value of i increases, we want our value to get smaller as we move down the vertical line in each step of the loop. Next we want to define the width of each bar. In our case, we want the bars to touch each other and to do that we will take the total space available, and divide it by the number of data elements. var elementWidth =(wid-CHART_PADDING*2)/ data.length; At this stage we are ready to draw the bar but before we do that, we should calculate the width of the bars. We then loop through all the data we have and create the bars: context.fillStyle = data[i].style; context.fillRect(CHART_PADDING +elementWidth*i ,hei-CHART_PADDING - data[i].value*stepSize,elementWidth,data[i].value*stepSize); context.fillStyle = "rgba(255, 255, 225, 0.8)"; Notice that we are resetting the style twice each time the loop runs. If we didn't, we wouldn't get the colors we are hoping to get. We then place our text in the middle of the bar that was created. context.textAlign = "center"; There's more... In our example, we created a non-flexible bar chart, and if this is the way we create charts we will need to recreate them from scratch each time. Let's revisit our code and tweak it to make it more reusable. Revisiting the code Although everything is working exactly as we want it to work, if we played around with the values, it would stop working. For example, what if I only wanted to have five steps; if we go back to our code, we will locate the following lines: var stepSize = (hei - CHART_PADDING*2)/10; for(var i=0; i<10; i++){ We can tweak it to handle five steps: var stepSize = (hei - CHART_PADDING*2)5; for(var i=0; i<5; i++){ We would very quickly find out that our application is not working as expected. To solve this problem let's create a new function that will deal with creating the outlines of the chart. Before we do that, let's extract the data object and create a new object that will contain the steps. Let's move the data and format it in an accessible format: var data = [...];var chartYData = [{label:"10 cats", value:1}, {label:"5 cats", value:.5}, {label:"3 cats", value:.3}];var range = {min:0, max:10};var CHART_PADDING = 20;var wid;var hei;function init(){ Take a deep look into chartYData object as it enables us to put in as many steps as we want without a defined spacing rule and the range object that will store the minimum and maximum values of the overall graph. Before creating the new functions, let's add them into our init function (changes marked in bold). function init(){var can = document.getElementById("bar");wid = can.width;hei = can.height;var context = can.getContext("2d");context.fillStyle = "#eeeeee";context.strokeStyle = "#999999";context.fillRect(0,0,wid,hei);context.font = "12pt Verdana, sans-serif";context.fillStyle = "#999999";context.moveTo(CHART_PADDING,CHART_PADDING);context.lineTo(CHART_PADDING,hei-CHART_PADDING);context.lineTo(wid-CHART_PADDING,hei-CHART_PADDING);fillChart(context,chartYData);createBars(context,data);} All we did in this code is to extract the creation of the chart and its bars into two separate functions. Now that we have an external data source both for the chart data and the content, we can build up their logic. Using the fillChart function The fillChart function's main goal is to create the foundation of the chart. We are integrating our new stepData object information and building up the chart based on its information. function fillChart(context, stepsData){ var steps = stepsData.length; var startY = CHART_PADDING; var endY = hei-CHART_PADDING; var chartHeight = endY-startY; var currentY; var rangeLength = range.max-range.min; for(var i=0; i<steps; i++){ currentY = startY + (1-(stepsData[i].value/rangeLength)) * chartHeight; context.moveTo(CHART_PADDING, currentY ); context.lineTo(CHART_PADDING*1.3,currentY); context.fillText(stepsData[i].label, CHART_PADDING*1.5, currentY+6); } context.stroke(); } Our changes were not many, but with them we turned our function to be much more dynamic than it was before. This time around we are basing the positions on the stepsData objects and the range length that is based on that. Using the createBars function Our next step is to revisit the createBars area and update the information so it can be created dynamically using external objects. function createBars(context,data){ var elementWidth =(wid-CHART_PADDING*2)/ data.length; var startY = CHART_PADDING; var endY = hei-CHART_PADDING; var chartHeight = endY-startY; var rangeLength = range.max-range.min; var stepSize = chartHeight/rangeLength; context.textAlign = "center"; for(i=0; i<data.length; i++){ context.fillStyle = data[i].style; context.fillRect(CHART_PADDING +elementWidth*i ,hei- CHART_PADDING - data[i].value*stepSize,elementWidth,data[i].value*stepSize); context.fillStyle = "rgba(255, 255, 225, 0.8)"; context.fillText(data[i].label, CHART_PADDING +elementWidth*(i+.5), hei-CHART_PADDING*1.5); } } Almost nothing changed here apart from a few changes in the way we positioned the data and extracted hardcoded values. Spreading data in a scatter chart The scatter chart is a very powerful chart and is mainly used to get a bird's-eye view while comparing two data sets. For example, comparing the scores in an English class and the scores in a Math class to find a correlative relationship. This style of visual comparison can help find surprising relationships between unexpected data sets. This is ideal when the goal is to show a lot of details in a very visual way. Getting ready If you haven't had a chance yet to scan through the logic of our first section in this article, I recommend you take a peek at it as we are going to base a lot of our work on that while expanding and making it a bit more complex to accommodate two data sets. I've revisited our data source from the previous section and modified it to store three variables of students' exam scores in Math, English, and Art. var data = [{label:"David",math:50,english:80,art:92,style:"rgba(241, 178, 225, 0.5)"},{label:"Ben",math:80,english:60,art:43,style:"#B1DDF3"},{label:"Oren",math:70,english:20,art:92,style:"#FFDE89"},{label:"Barbera",math:90,english:55,art:81,style:"#E3675C"},{label:"Belann",math:50,english:50,art:50,style:"#C2D985"}]; Notice that this data is totally random so we can't learn anything from the data itself; but we can learn a lot about how to get our chart ready for real data. We removed the value attribute and instead replaced it with math, english, and art attributes. How to do it... Let's dive right into the JavaScript file and the changes we want to make: Define the y space and x space. To do that, we will create a helper object that will store the required information: var chartInfo= { y:{min:40, max:100, steps:5,label:"math"}, x:{min:40, max:100, steps:4,label:"english"} }; It's time for us to set up our other global variables and start up our init function: var CHART_PADDING = 30;var wid;var hei;function init(){var can = document.getElementById("bar");wid = can.width;hei = can.height;var context = can.getContext("2d");context.fillStyle = "#eeeeee";context.strokeStyle = "#999999";context.fillRect(0,0,wid,hei);context.font = "10pt Verdana, sans-serif";context.fillStyle = "#999999";context.moveTo(CHART_PADDING,CHART_PADDING);context.lineTo(CHART_PADDING,hei-CHART_PADDING);context.lineTo(wid-CHART_PADDING,hei-CHART_PADDING);fillChart(context,chartInfo);createDots(context,data);} Not much is new here. The major changes are highlighted. Let's get on and start creating our fillChart and createDots functions. If you worked on our previous section, you might notice that there are a lot of similarities between the functions in the previous section and this function. I've deliberately changed the way we create things just to make them more interesting. We are now dealing with two data points as well, so many details have changed. Let's review them: function fillChart(context, chartInfo){ var yData = chartInfo.y; var steps = yData.steps; var startY = CHART_PADDING; var endY = hei-CHART_PADDING; var chartHeight = endY-startY; var currentY; var rangeLength = yData.max-yData.min; var stepSize = rangeLength/steps; context.textAlign = "left"; for(var i=0; i<steps; i++){ currentY = startY + (i/steps) * chartHeight; context.moveTo(wid-CHART_PADDING, currentY ); context.lineTo(CHART_PADDING,currentY); context.fillText(yData.min+stepSize*(steps-i), 0, currentY+4); } currentY = startY + chartHeight; context.moveTo(CHART_PADDING, currentY ); context.lineTo(CHART_PADDING/2,currentY); context.fillText(yData.min, 0, currentY-3); var xData = chartInfo.x; steps = xData.steps; var startX = CHART_PADDING; var endX = wid-CHART_PADDING; var chartWidth = endX-startX; var currentX; rangeLength = xData.max-xData.min; stepSize = rangeLength/steps; context.textAlign = "left"; for(var i=0; i<steps; i++){ currentX = startX + (i/steps) * chartWidth; context.moveTo(currentX, startY ); context.lineTo(currentX,endY); context.fillText(xData.min+stepSize*(i), currentX-6, endY+CHART_PADDING/2); } currentX = startX + chartWidth; context.moveTo(currentX, startY ); context.lineTo(currentX,endY); context.fillText(xData.max, currentX-3, endY+CHART_PADDING/2); context.stroke(); } When you review this code you will notice that our logic is almost duplicated twice. While in the first loop and first batch of variables we are figuring out the positions of each element in the y space, we move on in the second half of this function to calculate the layout for the x area. The y axis in canvas grows from top to bottom (top lower, bottom higher) and as such we need to calculate the height of the full graph and then subtract the value to find positions. Our last function is to render the data points and to do that we create the createDots function: function createDots(context,data){ var yDataLabel = chartInfo.y.label; var xDataLabel = chartInfo.x.label; var yDataRange = chartInfo.y.max-chartInfo.y.min; var xDataRange = chartInfo.x.max-chartInfo.x.min; var chartHeight = hei- CHART_PADDING*2; var chartWidth = wid- CHART_PADDING*2; var yPos; var xPos; for(var i=0; i<data.length;i++){ xPos = CHART_PADDING + (data[i][xDataLabel]-chartInfo.x.min)/ xDataRange * chartWidth; yPos = (hei - CHART_PADDING) -(data[i][yDataLabel]- chartInfo.y.min)/yDataRange * chartHeight; context.fillStyle = data[i].style; context.fillRect(xPos-4 ,yPos-4,8,8); } } Here we are figuring out the same details for each point—both the y position and the x position—and then we draw a rectangle. Let's test our application now! How it works... We start by creating a new chartInfo object: var chartInfo= { y:{min:40, max:100, steps:5,label:"math"}, x:{min:40, max:100, steps:4,label:"english"} }; This very simple object encapsulates the rules that will define what our chart will actually output. Looking closely you will see that we set an object named chartInfo that has information on the y and x axes. We have a minimum value ( min property), maximum value ( max property), and the number of steps we want to have in our chart ( steps property), and we define a label. Let's look deeper into the way the fillChart function works. In essence we have two numeric values; one is the actual space on the screen and the other is the value the space represents. To match these values we need to know what our data range is and also what our view range is, so we first start by finding our startY point and our endY point followed by calculating the number of pixels between these two points: var startY = CHART_PADDING; var endY = hei-CHART_PADDING; var chartHeight = endY-startY; These values will be used when we try to figure out where to place the data from the chartInfo object. As we are already speaking about that object, let's look at what we do with it: var yData = chartInfo.y; var steps = yData.steps; var rangeLength = yData.max-yData.min; var stepSize = rangeLength/steps; As our focus right now is on the height, we are looking deeper into the y property and for the sake of comfort we will call it yData. Now that we are focused on this object, it's time to figure out what is the actual data range (rangeLength) of this value, which will be our converter number. In other words we want to take a visual space between the points startY and endY and based on the the range, position it in this space. When we do so we can convert any data into a range between 0-1 and then position them in a dynamic visible area. Last but not least, as our new data object contains the number of steps we want to add into the chart, we use that data to define the step value. In this example it would be 12. The way we get to this value is by taking our rangeLength (100 - 40 = 60) value and then dividing it by the number of steps (in our case 5). Now that we have got the critical variables out of the way, it's time to loop through the data and draw our chart: var currentY; context.textAlign = "left"; for(var i=0; i<steps; i++){ currentY = startY + (i/steps) * chartHeight; context.moveTo(wid-CHART_PADDING, currentY ); context.lineTo(CHART_PADDING,currentY); context.fillText(yData.min+stepSize*(steps-i), 0, currentY+4); } This is where the magic comes to life. We run through the number of steps and then calculate the new Y position again. If we break it down we will see: currentY = startY + (i/steps) * chartHeight; We start from the start position of our chart (upper area) and then we add to it the steps by taking the current i position and dividing it by the total possible steps (0/5, 1/5, 2/5 and so on). In our demo it's 5, but it can be any value and should be inserted into the chartInfo steps attribute. We multiply the returned value by the height of our chart calculated earlier. To compensate for the fact that we started from the top we need to reverse the actual text we put into the text field: yData.min+stepSize*(steps-i) This code takes our earlier variables and puts them to work. We start by taking the minimal value possible and then add into it stepSize times the total number of steps subtracted by the number of the current step. Let's dig into the createDots function and see how it works. We start with our setup variables: var yDataLabel = chartInfo.y.label; var xDataLabel = chartInfo.x.label; This is one of my favorite parts of this section. We are grabbing the label from our chartInfo object and using that as our ID; this ID will be used to grab information from our data object. If you wish to change the values, all you need to do is switch the labels in the chartInfo object. Again it's time for us to figure out our ranges as we've done earlier in the fillChart function. This time around we want to get the actual ranges for both the x and y axes and the actual width and height of the area we have to work with: var yDataRange = chartInfo.y.max-chartInfo.y.min; var xDataRange = chartInfo.x.max-chartInfo.x.min; var chartHeight = hei- CHART_PADDING*2; var chartWidth = wid- CHART_PADDING*2; We also need to get a few variables to help us keep track of our current x and y positions within loops: var yPos; var xPos; Let's go deeper into our loop, mainly into the highlighted code snippets: for(var i=0; i<data.length;i++){xPos = CHART_PADDING + (data[i][xDataLabel]-chartInfo.x.min)/xDataRange * chartWidth;yPos = (hei - CHART_PADDING) -(data[i][yDataLabel]-chartInfo.y.min)/yDataRange * chartHeight;context.fillStyle = data[i].style;context.fillRect(xPos-4 ,yPos-4,8,8);} The heart of everything here is discovering where our elements need to be. The logic is almost identical for both the xPos and yPos variables with a few variations. The first thing we need to do to calculate the xPos variable is: (data[i][xDataLabel]-chartInfo.x.min) In this part we are using the label, xDataLabel, we created earlier to get the current student score in that subject. We then subtract from it the lowest possible score. As our chart doesn't start from 0, we don't want the values between 0 and our minimum value to affect the position on the screen. For example, let's say we are focused on math and our student has a score of 80; we subtract 40 out of that (80 - 40 = 40) and then apply the following formula: (data[i][xDataLabel] - chartInfo.x.min) / xDataRange We divide that value by our data range; in our case that would be (100 - 40)/60. The returned result will always be between 0 and 1. We can use the returned number and multiply it by the actual space in pixels to know exactly where to position our element on the screen. We do so by multiplying the value we got, that is between 0 and 1, by the total available space (in this case, width). Once we know where it needs to be located we add the starting point on our chart (the padding): xPos = CHART_PADDING + (data[i][xDataLabel]-chartInfo.x.min)/xDataRange * chartWidth; The yPos variable has the same logic as that of the xPos variable, but here we focus only on the height.
Read more
  • 0
  • 0
  • 2612

article-image-working-data-components
Packt
22 Nov 2013
15 min read
Save for later

Working with Data Components

Packt
22 Nov 2013
15 min read
(For more resources related to this topic, see here.) Introducing the DataList component The DataList component displays a collection of data in the list layout with several display types and supports AJAX pagination. The DataList component iterates through a collection of data and renders its child components for each item. Let us see how to use <p:dataList>to display a list of tag names as an unordered list: <p:dataList value="#{tagController.tags}" var="tag" type="unordered" itemType="disc"> #{tag.label} </p:dataList> The preceding <p:dataList> component displays tag names as an unordered list of elements marked with disc type bullets. The valid type options are unordered, ordered, definition, and none. We can use type="unordered" to display items as an unordered collection along with various itemType options such as disc, circle, and square. By default, type is set to unordered and itemType is set to disc. We can set type="ordered" to display items as an ordered list with various itemType options such as decimal, A, a, and i representing numbers, uppercase letters, lowercase letters, and roman numbers respectively. Time for action – displaying unordered and ordered data using DataList Let us see how to display tag names as unordered and ordered lists with various itemType options. Create <p:dataList> components to display items as unordered and ordered lists using the following code: <h:form> <p:panel header="Unordered DataList"> <h:panelGrid columns="3"> <h:outputText value="Disc"/> <h:outputText value="Circle" /> <h:outputText value="Square" /> <p:dataList value="#{tagController.tags}" var="tag" itemType="disc"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" itemType="circle"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" itemType="square"> #{tag.label} </p:dataList> </h:panelGrid> </p:panel> <p:panel header="Ordered DataList"> <h:panelGrid columns="4"> <h:outputText value="Number"/> <h:outputText value="Uppercase Letter" /> <h:outputText value="Lowercase Letter" /> <h:outputText value="Roman Letter" /> <p:dataList value="#{tagController.tags}" var="tag" type="ordered"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" type="ordered" itemType="A"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" type="ordered" itemType="a"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" type="ordered" itemType="i"> #{tag.label} </p:dataList> </h:panelGrid> </p:panel> </h:form> Implement the TagController.getTags() method to return a collection of tag objects: public class TagController { private List<Tag> tags = null; public TagController() { tags = loadTagsFromDB(); } public List<Tag> getTags() { return tags; } } What just happened? We have created DataList components to display tag names as an unordered list using type="unordered" and as an ordered list using type="ordered" with various supported itemTypes values. This is shown in the following screenshot: Using DataList with pagination support DataList has built-in pagination support that can be enabled by setting paginator="true". By enabling pagination, the various page navigation options will be displayed using the default paginator template. We can customize the paginator template to display only the desired options. The paginator can be customized using the paginatorTemplate option that accepts the following keys of UI controls: FirstPageLink LastPageLink PreviousPageLink NextPageLink PageLinks CurrentPageReport RowsPerPageDropdown Note that {RowsPerPageDropdown} has its own template, and options to display is provided via the rowsPerPageTemplate attribute (for example, rowsPerPageTemplate="5,10,15"). Also, {CurrentPageReport} has its own template defined with the currentPageReportTemplate option. You can use the {currentPage}, {totalPages}, {totalRecords}, {startRecord}, and {endRecord} keywords within the currentPageReport template. The default is "{currentPage} of {totalPages}". The default paginator template is "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}". We can customize the paginator template to display only the desired options. For example: {CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown} The paginator can be positioned using the paginatorPosition attribute in three different locations: top, bottom, or both(default). The DataList component provides the following attributes for customization: rows: This is the number of rows to be displayed per page. first: This specifies the index of the first row to be displayed. The default is 0. paginator: This enables pagination. The default is false. paginatorTemplate: This is the template of the paginator. rowsPerPageTemplate: This is the template of the rowsPerPage dropdown. currentPageReportTemplate: This is the template of the currentPageReport UI. pageLinks: This specifies the maximum number of page links to display. The default value is 10. paginatorAlwaysVisible: This defines if paginator should be hidden when the total data count is less than the number of rows per page. The default is true. rowIndexVar: This specifies the name of the iterator to refer to for each row index. varStatus: This specifies the name of the exported request scoped variable to represent the state of the iteration same as in <ui:repeat> attribute varStatus. Time for action – using DataList with pagination Let us see how we can use the DataList component's pagination support to display five tags per page. Create a DataList component with pagination support along with custom paginatorTemplate: <p:panel header="DataList Pagination"> <p:dataList value="#{tagController.tags}" var="tag" id="tags" type="none" paginator="true" rows="5" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" rowsPerPageTemplate="5,10,15"> <f:facet name="header"> Tags </f:facet> <h:outputText value="#{tag.id} - #{tag.label}" style="margin-left:10px" /> <br/> </p:dataList> </p:panel> What just happened? We have created a DataList component along with pagination support by setting paginator="true". We have customized the paginator template to display additional information such as CurrentPageReport and RowsPerPageDropdown. Also, we have used the rowsPerPageTemplate attribute to specify the values for RowsPerPageDropdown. The following screenshot displays the result: Displaying tabular data using the DataTable component DataTable is an enhanced version of the standard DataTable that provides various additional features such as: Pagination Lazy loading Sorting Filtering Row selection Inline row/cell editing Conditional styling Expandable rows Grouping and SubTable and many more In our TechBuzz application, the administrator can view a list of users and enable/disable user accounts. First, let us see how we can display list of users using basic DataTable as follows: <p:dataTable id="usersTbl" var="user" value="#{adminController.users}"> <f:facet name="header"> List of Users </f:facet> <p:column headerText="Id"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName"> <h:outputText value="#{user.firstName}" /> </p:column> <p:column headerText="Disabled"> <h:outputText value="#{user.disabled}" /> </p:column> <f:facet name="footer"> Total no. of Users: #{fn:length(adminController.users)}. </f:facet> </p:dataTable> The following screenshot shows us the result: PrimeFaces 4.0 introduced the Sticky component and provides out-of-the-box support for DataTable to make the header as sticky while scrolling using the stickyHeader attribute: <p:dataTable var="user" value="#{adminController.users}" stickyHeader="true"> ... </p:dataTable> Using pagination support If there are a large number of users, we may want to display users in a page-by-page style. DataTable has in-built support for pagination. Time for action – using DataTable with pagination Let us see how we can display five users per page using pagination. Create a DataTable component using pagination to display five records per page, using the following code: <p:dataTable id="usersTbl" var="user" value="#{adminController.users}" paginator="true" rows="5" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" currentPageReportTemplate="( {startRecord} - {endRecord}) of {totalRecords} Records." rowsPerPageTemplate="5,10,15"> <p:column headerText="Id"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName"> <h:outputText value="#{user.firstName}" /> </p:column> <p:column headerText="Disabled"> <h:outputText value="#{user.disabled}" /> </p:column> </p:dataTable> What just happened? We have created a DataTable component with the pagination feature to display five rows per page. Also, we have customized the paginator template and provided an option to change the page size dynamically using the rowsPerPageTemplate attribute. Using columns sorting support DataTable comes with built-in support for sorting on a single column or multiple columns. You can define a column as sortable using the sortBy attribute as follows: <p:column headerText="FirstName" sortBy="#{user.firstName}"> <h:outputText value="#{user.firstName}" /> </p:column> You can specify the default sort column and sort order using the sortBy and sortOrder attributes on the <p:dataTable> element: <p:dataTable id="usersTbl2" var="user" value="#{adminController.users}" sortBy="#{user.firstName}" sortOrder="descending"> </p:dataTable> The <p:dataTable> component's default sorting algorithm uses a Java comparator, you can use your own customized sort method as well: <p:column headerText="FirstName" sortBy="#{user.firstName}" sortFunction="#{adminController.sortByFirstName}"> <h:outputText value="#{user.firstName}" /> </p:column> public int sortByFirstName(Object firstName1, Object firstName2) { //return -1, 0 , 1 if firstName1 is less than, equal to or greater than firstName2 respectively return ((String)firstName1).compareToIgnoreCase(((String)firstName2)); } By default, DataTable's sortMode is set to single, to enable sorting on multiple columns set sortMode to multiple. In multicolumns' sort mode, you can click on a column while the metakey (Ctrl or command) adds the column to the order group: <p:dataTable id="usersTbl" var="user" value="#{adminController.users}" sortMode="multiple"> </p:dataTable> Using column filtering support DataTable provides support for column-level filtering as well as global filtering (on all columns) and provides an option to hold the list of filtered records. In addition to the default match mode startsWith, we can use various other match modes such as endsWith, exact, and contains. Time for action – using DataTable with filtering Let us see how we can use filters with users' DataTable. Create a DataTable component and apply column-level filters and a global filter to apply filter on all columns: <p:dataTable widgetVar="userTable" var="user" value="#{adminController.users}" filteredValue="#{adminController.filteredUsers}" emptyMessage="No Users found for the given Filters"> <f:facet name="header"> <p:outputPanel> <h:outputText value="Search all Columns:" /> <p:inputText id="globalFilter" onkeyup="userTable.filter()" style="width:150px" /> </p:outputPanel> </f:facet> <p:column headerText="Id"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email" filterBy="#{user.emailId}" footerText="contains" filterMatchMode="contains"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName" filterBy="#{user.firstName}" footerText="startsWith"> <h:outputText value="#{user.firstName}" /> </p:column> <p:column headerText="LastName" filterBy="#{user.lastName}" filterMatchMode="endsWith" footerText="endsWith"> <h:outputText value="#{user.lastName}" /> </p:column> <p:column headerText="Disabled" filterBy="#{user.disabled}" filterOptions="#{adminController.userStatusOptions}" filterMatchMode="exact" footerText="exact"> <h:outputText value="#{user.disabled}" /> </p:column> </p:dataTable> Initialize userStatusOptions in AdminController ManagedBean. @ManagedBean @ViewScoped public class AdminController { private List<User> users = null; private List<User> filteredUsers = null; private SelectItem[] userStatusOptions; public AdminController() { users = loadAllUsersFromDB(); this.userStatusOptions = new SelectItem[3]; this.userStatusOptions[0] = new SelectItem("", "Select"); this.userStatusOptions[1] = new SelectItem("true", "True"); this.userStatusOptions[2] = new SelectItem("false", "False"); } //setters and getters } What just happened? We have used various filterMatchMode instances, such as startsWith, endsWith, and contains, while applying column-level filters. We have used the filterOptions attribute to specify the predefined filter values, which is displayed as a select drop-down list. As we have specified filteredValue="#{adminController.filteredUsers}", once the filters are applied the filtered users list will be populated into the filteredUsers property. This following is the resultant screenshot: Since PrimeFaces Version 4.0, we can specify the sortBy and filterBy properties as sortBy="emailId" and filterBy="emailId" instead of sortBy="#{user.emailId}" and filterBy="#{user.emailId}". A couple of important tips It is suggested to use a scope longer than the request such as the view scope to keep the filteredValue attribute so that the filtered list is still accessible after filtering. The filter located at the header is a global one applying on all fields; this is implemented by calling the client-side API method called filter(). The important part is to specify the ID of the input text as globalFilter, which is a reserved identifier for DataTable. Selecting DataTable rows Selecting one or more rows from a table and performing operations such as editing or deleting them is a very common requirement. The DataTable component provides several ways to select a row(s). Selecting single row We can use a PrimeFaces' Command component, such as commandButton or commandLink, and bind the selected row to a server-side property using <f:setPropertyActionListener>, shown as follows: <p:dataTable id="usersTbl" var="user" value="#{adminController.users}"> <!-- Column definitions --> <p:column style="width:20px;"> <p:commandButton id="selectButton" update=":form:userDetails" icon="ui-icon-search" title="View"> <f:setPropertyActionListener value="#{user}" target="#{adminController.selectedUser}" /> </p:commandButton> </p:column> </p:dataTable> <h:panelGrid id="userDetails" columns="2" > <h:outputText value="Id:" /> <h:outputText value="#{adminController.selectedUser.id}"/> <h:outputText value="Email:" /> <h:outputText value="#{adminController.selectedUser.emailId}"/> </h:panelGrid> Selecting rows using a row click Instead of having a separate button to trigger binding of a selected row to a server-side property, PrimeFaces provides another simpler way to bind the selected row by using selectionMode, selection, and rowKey attributes. Also, we can use the rowSelect and rowUnselect events to update other components based on the selected row, shown as follows: <p:dataTable var="user" value="#{adminController.users}" selectionMode="single" selection="#{adminController.selectedUser}" rowKey="#{user.id}"> <p:ajax event="rowSelect" listener="#{adminController.onRowSelect}" update=":form:userDetails"/> <p:ajax event="rowUnselect" listener="#{adminController.onRowUnselect}" update=":form:userDetails"/> <!-- Column definitions --> </p:dataTable> <h:panelGrid id="userDetails" columns="2" > <h:outputText value="Id:" /> <h:outputText value="#{adminController.selectedUser.id}"/> <h:outputText value="Email:" /> <h:outputText value="#{adminController.selectedUser.emailId}"/> </h:panelGrid> Similarly, we can select multiple rows using selectionMode="multiple" and bind the selection attribute to an array or list of user objects: <p:dataTable var="user" value="#{adminController.users}" selectionMode="multiple" selection="#{adminController.selectedUsers}" rowKey="#{user.id}"> <!-- Column definitions --> </p:dataTable> rowKey should be a unique identifier from your data model and should be used by DataTable to find the selected rows. You can either define this key by using the rowKey attribute or by binding a data model that implements org.primefaces.model.SelectableDataModel. When the multiple selection mode is enabled, we need to hold the Ctrl or command key and click on the rows to select multiple rows. If we don't hold on to the Ctrl or command key and click on a row and the previous selection will be cleared with only the last clicked row selected. We can customize this behavior using the rowSelectMode attribute. If you set rowSelectMode="add", when you click on a row, it will keep the previous selection and add the current selected row even though you don't hold the Ctrl or command key. The default rowSelectMode value is new. We can disable the row selection feature by setting disabledSelection="true". Selecting rows using a radio button / checkbox Another very common scenario is having a radio button or checkbox for each row, and the user can select one or more rows and then perform actions such as edit or delete. The DataTable component provides a radio-button-based single row selection using a nested <p:column> element with selectionMode="single": <p:dataTable var="user" value="#{adminController.users}" selection="#{adminController.selectedUser}" rowKey="#{user.id}"> <p:column selectionMode="single"/> <!-- Column definitions --> </p:dataTable> The DataTable component also provides checkbox-based multiple row selection using a nested <p:column> element with selectionMode="multiple": <p:dataTable var="user" value="#{adminController.users}" selection="#{adminController.selectedUsers}" rowKey="#{user.id}"> <p:column selectionMode="multiple"/> <!-- Column definitions --> </p:dataTable> In our TechBuzz application, the administrator would like to have a facility to be able to select multiple users and disable them at one go. Let us see how we can implement this using the checkbox-based multiple rows selection.
Read more
  • 0
  • 0
  • 2611
Modal Close icon
Modal Close icon