Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
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

7018 Articles
article-image-animating-graphic-objects-using-python
Packt
01 Dec 2010
9 min read
Save for later

Animating Graphic Objects using Python

Packt
01 Dec 2010
9 min read
Python 2.6 Graphics Cookbook Over 100 great recipes for creating and animating graphics using Python Create captivating graphics with ease and bring them to life using Python Apply effects to your graphics using powerful Python methods Develop vector as well as raster graphics and combine them to create wonders in the animation world Create interactive GUIs to make your creation of graphics simpler Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to accomplish the task of creation and animation of graphics as efficiently as possible        Precise collisions using floating point numbers Here the simulation flaws caused by the coarseness of integer arithmetic are eliminated by using floating point numbers for all ball position calculations. How to do it... All position, velocity, and gravity variables are made floating point by writing them with explicit decimal points. The result is shown in the following screenshot, showing the bouncing balls with trajectory tracing. from Tkinter import * root = Tk() root.title("Collisions with Floating point") cw = 350 # canvas width ch = 200 # canvas height GRAVITY = 1.5 chart_1 = Canvas(root, width=cw, height=ch, background="black") chart_1.grid(row=0, column=0) cycle_period = 80 # Time between new positions of the ball # (milliseconds). time_scaling = 0.2 # This governs the size of the differential steps # when calculating changes in position. # The parameters determining the dimensions of the ball and it's # position. ball_1 = {'posn_x':25.0, # x position of box containing the # ball (bottom). 'posn_y':180.0, # x position of box containing the # ball (left edge). 'velocity_x':30.0, # amount of x-movement each cycle of # the 'for' loop. 'velocity_y':100.0, # amount of y-movement each cycle of # the 'for' loop. 'ball_width':20.0, # size of ball - width (x-dimension). 'ball_height':20.0, # size of ball - height (y-dimension). 'color':"dark orange", # color of the ball 'coef_restitution':0.90} # proportion of elastic energy # recovered each bounce ball_2 = {'posn_x':cw - 25.0, 'posn_y':300.0, 'velocity_x':-50.0, 'velocity_y':150.0, 'ball_width':30.0, 'ball_height':30.0, 'color':"yellow3", 'coef_restitution':0.90} def detectWallCollision(ball): # Collision detection with the walls of the container if ball['posn_x'] > cw - ball['ball_width']: # Collision # with right-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] # reverse direction. ball['posn_x'] = cw - ball['ball_width'] if ball['posn_x'] < 1: # Collision with left-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] ball['posn_x'] = 2 # anti-stick to the wall if ball['posn_y'] < ball['ball_height'] : # Collision # with ceiling. ball['velocity_y'] = -ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ball['ball_height'] if ball['posn_y'] > ch - ball['ball_height']: # Floor # collision. ball['velocity_y'] = - ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ch - ball['ball_height'] def diffEquation(ball): # An approximate set of differential equations of motion # for the balls ball['posn_x'] += ball['velocity_x'] * time_scaling ball['velocity_y'] = ball['velocity_y'] + GRAVITY # a crude # equation incorporating gravity. ball['posn_y'] += ball['velocity_y'] * time_scaling chart_1.create_oval( ball['posn_x'], ball['posn_y'], ball['posn_x'] + ball['ball_width'], ball ['posn_y'] + ball['ball_height'], fill= ball['color']) detectWallCollision(ball) # Has the ball collided with # any container wall? for i in range(1,2000): # end the program after 1000 position shifts. diffEquation(ball_1) diffEquation(ball_2) chart_1.update() # This refreshes the drawing on the canvas. chart_1.after(cycle_period) # This makes execution pause for 200 # milliseconds. chart_1.delete(ALL) # This erases everything on the root.mainloop() How it works... Use of precision arithmetic has allowed us to notice simulation behavior that was previously hidden by the sins of integer-only calculations. This is the UNIQUE VALUE OF GRAPHIC SIMULATION AS A DEBUGGING TOOL. If you can represent your ideas in a visual way rather than as lists of numbers you will easily pick up subtle quirks in your code. The human brain is designed to function best in graphical images. It is a direct consequence of being a hunter. A graphic debugging tool... There is another very handy trick in the software debugger's arsenal and that is the visual trace. A trace is some kind of visual trail that shows the history of dynamic behavior. All of this is revealed in the next example. Trajectory tracing and ball-to-ball collisions Now we introduce one of the more difficult behaviors in our simulation of ever increasing complexity – the mid-air collision. The hardest thing when you are debugging a program is to try to hold in your short term memory some recently observed behavior and compare it meaningfully with present behavior. This kind of memory is an imperfect recorder. The way to overcome this is to create a graphic form of memory – some sort of picture that shows accurately what has been happening in the past. In the same way that military cannon aimers use glowing tracer projectiles to adjust their aim, a graphic programmer can use trajectory traces to examine the history of execution. How to do it... In our new code there is a new function called detect_ball_collision (ball_1, ball_2) whose job is to anticipate imminent collisions between the two balls no matter where they are. The collisions will come from any direction and therefore we need to be able to test all possible collision scenarios and examine the behavior of each one and see if it does not work as planned. This can be too difficult unless we create tools to test the outcome. In this recipe, the tool for testing outcomes is a graphic trajectory trace. It is a line that trails behind the path of the ball and shows exactly where it went right since the beginning of the simulation. The result is shown in the following screenshot, showing the bouncing with ball-to-ball collision rebounds. # kinetic_gravity_balls_1.py # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> from Tkinter import * import math root = Tk() root.title("Balls bounce off each other") cw = 300 # canvas width ch = 200 # canvas height GRAVITY = 1.5 chart_1 = Canvas(root, width=cw, height=ch, background="white") chart_1.grid(row=0, column=0) cycle_period = 80 # Time between new positions of the ball # (milliseconds). time_scaling = 0.2 # The size of the differential steps # The parameters determining the dimensions of the ball and its # position. ball_1 = {'posn_x':25.0, 'posn_y':25.0, 'velocity_x':65.0, 'velocity_y':50.0, 'ball_width':20.0, 'ball_height':20.0, 'color':"SlateBlue1", 'coef_restitution':0.90} ball_2 = {'posn_x':180.0, 'posn_y':ch- 25.0, 'velocity_x':-50.0, 'velocity_y':-70.0, 'ball_width':30.0, 'ball_height':30.0, 'color':"maroon1", 'coef_restitution':0.90} def detect_wall_collision(ball): # detect ball-to-wall collision if ball['posn_x'] > cw - ball['ball_width']: # Right-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] ball['posn_x'] = cw - ball['ball_width'] if ball['posn_x'] < 1: # Left-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] ball['posn_x'] = 2 if ball['posn_y'] < ball['ball_height'] : # Ceiling. ball['velocity_y'] = -ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ball['ball_height'] if ball['posn_y'] > ch - ball['ball_height'] : # Floor ball['velocity_y'] = - ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ch - ball['ball_height'] def detect_ball_collision(ball_1, ball_2): #detect ball-to-ball collision # firstly: is there a close approach in the horizontal direction if math.fabs(ball_1['posn_x'] - ball_2['posn_x']) < 25: # secondly: is there also a close approach in the vertical # direction. if math.fabs(ball_1['posn_y'] - ball_2['posn_y']) < 25: ball_1['velocity_x'] = -ball_1['velocity_x'] # reverse # direction. ball_1['velocity_y'] = -ball_1['velocity_y'] ball_2['velocity_x'] = -ball_2['velocity_x'] ball_2['velocity_y'] = -ball_2['velocity_y'] # to avoid internal rebounding inside balls ball_1['posn_x'] += ball_1['velocity_x'] * time_scaling ball_1['posn_y'] += ball_1['velocity_y'] * time_scaling ball_2['posn_x'] += ball_2['velocity_x'] * time_scaling ball_2['posn_y'] += ball_2['velocity_y'] * time_scaling def diff_equation(ball): x_old = ball['posn_x'] y_old = ball['posn_y'] ball['posn_x'] += ball['velocity_x'] * time_scaling ball['velocity_y'] = ball['velocity_y'] + GRAVITY ball['posn_y'] += ball['velocity_y'] * time_scaling chart_1.create_oval( ball['posn_x'], ball['posn_y'], ball['posn_x'] + ball['ball_width'], ball['posn_y'] + ball['ball_height'], fill= ball['color'], tags="ball_tag") chart_1.create_line( x_old, y_old, ball['posn_x'], ball ['posn_y'], fill= ball['color']) detect_wall_collision(ball) # Has the ball # collided with any container wall? for i in range(1,5000): diff_equation(ball_1) diff_equation(ball_2) detect_ball_collision(ball_1, ball_2) chart_1.update() chart_1.after(cycle_period) chart_1.delete("ball_tag") # Erase the balls but # leave the trajectories root.mainloop() How it works... Mid-air ball against ball collisions are done in two steps. In the first step, we test whether the two balls are close to each other inside a vertical strip defined by if math.fabs(ball_1['posn_x'] - ball_2['posn_x']) < 25. In plain English, this asks "Is the horizontal distance between the balls less than 25 pixels?" If the answer is yes, then the region of examination is narrowed down to a small vertical distance less than 25 pixels by the statement if math.fabs(ball_1['posn_y'] - ball_2['posn_y']) < 25. So every time the loop is executed, we sweep the entire canvas to see if the two balls are both inside an area where their bottom-left corners are closer than 25 pixels to each other. If they are that close then we simply cause a rebound off each other by reversing their direction of travel in both the horizontal and vertical directions. There's more... Simply reversing the direction is not the mathematically correct way to reverse the direction of colliding balls. Certainly billiard balls do not behave that way. The law of physics that governs colliding spheres demands that momentum be conserved. Why do we sometimes get tkinter.TckErrors? If we click the close window button (the X in the top right) while Python is paused, when Python revives and then calls on Tcl (Tkinter) to draw something on the canvas we will get an error message. What probably happens is that the application has already shut down, but Tcl has unfinished business. If we allow the program to run to completion before trying to shut the window then termination is orderly.
Read more
  • 0
  • 0
  • 8314

article-image-oracle-bi-publisher-11g-working-multiple-data-sources
Packt
25 Oct 2011
5 min read
Save for later

Oracle BI Publisher 11g: Working with Multiple Data Sources

Packt
25 Oct 2011
5 min read
(For more resources on Oracle 11g, see here.) The Data Model Editor's interface deals with all the components and functionalities needed for the data model to achieve the structure you need. However, the main component is the Data Set. In order to create a data model structure in BIP, you can choose from a variety of data set types, such as: SQL Query MDX Query Oracle BI Analysis View Object Web Service LDAP Query XML file Microsoft Excel file Oracle BI Discoverer HTTP Taking advantage of this variety requires multiple Data Sources of different types to be defined in the BIP. In this article, we will see: How data sources are configured How the data is retrieved from different data sets How data set type characteristics and the links between elements influence the data model structure Administration Let's first see, how you can verify or configure your data sources. You must choose the Administration link found in the upper-right corner of any of the BIP interface pages, as shown in the following screenshot:     The connection to your database can be choosen from the following connection types: Java Database Connectivity (JDBC) Java Naming and Directory Interface (JNDI) Lightweight Directory Access Protocol (LDAP) Online Analytical Processing (OLAP) Available Data Sources To get to your data source, BIP offers two possibilities: YOu can use a connection. In order to use a connection, these are the available connection types: JDBC JNDI LDAP OLAP You can also use a file. In the following sections, the Data Source types&mdashJDBC, JNDI, OLAP Connections, and File&mdashwill be explained in detail. JDBC Connection Let's take the first example. To configure a Data Source to use JDBC, from the Administration page, choose JDBC Connection from the Data Sources types list, as shown in the following screenshot:     You can see the requested parameters for configuring a JDBC connection in the following screenshot: Data Source Name: Enter a name of your choice. Driver Type: Choose a type from the list. The relating parameters are: Database Driver Class: A driver, matching your database type. Connection String: Information containing the computer name on which your database server is running, for example, port, database name, and so on. Username: Enter a database username. Password: Provide the database user's password. The Use System User option allows you to use the operating system's credentials as your credentials. For example, in this case, your MS SQL Database Server uses Windows authentication as the only authentication method. When you have a system administrator in-charge of these configurations, all you have to do is to find which are the available Data Sources and eventually you can check if the connection works. Click on the Test Connection button at the bottom of the page to test the connection:     JNDI Connection JNDI Connection pool is in fact another way to access your JDBC Data Sources. Using a connection pool increases efficiency by maintaining a cache of physical connections that can be reused, allowing multiple clients to share a small number of physical connections. In order to configure a Data Source to use JNDI, from the Administration page, choose JNDI Connection from the Data Sources types list. The following screen will appear:     As you can see in the preceding screenshot, on the Add Data Source page you must enter the following parameters: Data Source Name: Enter a name of your choice JNDI Name: This is the JNDI location for the pool set up in your application server, for example, jdbc/BIP10gSource The users having roles included in Allowed Roles list only will be able to create reports using this Data Source. OLAP Connection Use the OLAP Connection to connect to OLAP databases. BI Publisher supports the following OLAP types: Oracle Hyperion Essbase Microsoft SQL Server 2000 Analysis Services Microsoft SQL Server 2005 Analysis Services SAP BW In order to configure a connection to an OLAP database, from the Administration page, choose OLAP Connection from the Data Sources types list. The following screen will appear:     On the Add Data Source page, the following parameters must be entered: Data Source Name: Enter a name of your choice OLAP Type: Choose a type from the list Connection String: Depending on the supported OLAP databases, the connection string format is as follows: Oracle Hyperion Essbase Format: [server name] Microsoft SQL Server 2000 Analysis Services Format: Data Source=[server];Provider=msolap;Initial Catalog=[catalog] Microsoft SQL Server 2005 Analysis Services Format: Data Source=[server];Provider=msolap.3;Initial Catalog=[catalog] SAP BW Format: ASHOST=[server] SYSNR=[system number] CLIENT=[client] LANG=[language] Username and Password: Used for OLAP database authentication File Another example of a data source type is File. In order to gain access to XML or Excel files, you need a File Data Source. In order to set up this kind of Data Source, only one step is required&mdashenter the path to the Directory in which your files reside. You can see in the following screenshot that demo files Data Source points to the default BIP files directory. The file needs to be accessible from the BI Server (not on your local machine):    
Read more
  • 0
  • 0
  • 8313

article-image-c-language-support-asynchrony
Packt
28 Oct 2015
25 min read
Save for later

C# Language Support for Asynchrony

Packt
28 Oct 2015
25 min read
In this article by Eugene Agafonov and Andrew Koryavchenko, the authors of the book, Mastering C# Concurrency, talks about Task Parallel Library in detail. Also, the C# language infrastructure that supports asynchronous calls have been explained. The Task Parallel Library makes it possible to combine asynchronous tasks and set dependencies between them. To get a clear understanding, in this article, we will use this approach to solve a real problem—downloading images from Bing (the search engine). Also, we will do the following: Implement standard synchronous approach Use Task Parallel Library to create an asynchronous version of the program Use C# 5.0 built-in asynchrony support to make the code easier to read and maintain Simulate C# asynchronous infrastructure with the help of iterators Learn about other useful features of Task Parallel Library Make any C# type compatible with built-in asynchronous keywords (For more resources related to this topic, see here.) Implementing the downloading of images from Bing Everyday Bing.com publishes its background image that can be used as desktop wallpaper. There is an XML API to get information about these pictures that can be found at http://www.bing.com/hpimagearchive.aspx. Creating a simple synchronous solution Let's try to write a program to download the last eight images from this site. We will start by defining objects to store image information. This is where a thumbnail image and its description will be stored: using System.Drawing; public class WallpaperInfo{   private readonly Image _thumbnail;   private readonly string _description;   public WallpaperInfo(Image thumbnail, string description) {     _thumbnail = thumbnail;     _description = description;   }   public Image Thumbnail {     get { return _thumbnail; }   }   public string Description {     get { return _description; }   } } The next container type is for all the downloaded pictures and the time required to download and make the thumbnail images from the original pictures: public class WallpapersInfo {   private readonly long _milliseconds;   private readonly WallpaperInfo[] _wallpapers;   public WallpapersInfo(long milliseconds, WallpaperInfo[]     wallpapers) {     _milliseconds = milliseconds;     _wallpapers = wallpapers;   }   public long Milliseconds {     get { return _milliseconds; }   }   public WallpaperInfo[] Wallpapers {     get { return _wallpapers; }   } } Now we need to create a loader class to download images from Bing. We need to define a Loader static class and follow with an implementation. Let's create a method that will make a thumbnail image from the source image stream: private static Image GetThumbnail(Stream imageStream) {   using (imageStream) {     var fullBitmap = Image.FromStream(imageStream);     return new Bitmap(fullBitmap, 192, 108);   } } To communicate via the HTTP protocol, it is recommended to use the System.Net.HttpClient type from the System.Net.dll assembly. Let's create the following extension methods that will allow us to use the POST HTTP method to download an image and get an opened stream: private static Stream DownloadData(this HttpClient client,   string uri) {   var response = client.PostAsync(     uri, new StringContent(string.Empty)).Result;   return response.Content.ReadAsStreamAsync().Result; } private static Task<Stream> DownloadDataAsync(this HttpClient   client, string uri) {   Task<HttpResponseMessage> responseTask = client.PostAsync(     uri, new StringContent(string.Empty));   return responseTask.ContinueWith(task =>     task.Result.Content.ReadAsStreamAsync()).Unwrap(); } To create the easiest implementation possible, we will implement downloading without any asynchrony. Here, we will define HTTP endpoints for the Bing API: private const string _catalogUri =   "http://www.bing.com/hpimagearchive.aspx?     format=xml&idx=0&n=8&mbl=1&mkt=en-ww"; private const string _imageUri =   "http://bing.com{0}_1920x1080.jpg"; Then, we will start measuring the time required to finish downloading and download an XML catalog that has information about the images that we need: var sw = Stopwatch.StartNew(); var client = new HttpClient(); var catalogXmlString = client.DownloadString(_catalogUri); Next, the XML string will be parsed to an XML document: var xDoc = XDocument.Parse(catalogXmlString); Now using LINQ to XML, we will query the information needed from the document and run the download process for each image: var wallpapers = xDoc   .Root   .Elements("image")   .Select(e =>     new {       Desc = e.Element("copyright").Value,       Url = e.Element("urlBase").Value     })   .Select(item =>     new {       item.Desc,       FullImageData = client.DownloadData(         string.Format(_imageUri, item.Url))     })   .Select( item =>     new WallpaperInfo(       GetThumbnail(item.FullImageData),       item.Desc))   .ToArray(); sw.Stop(); The first Select method call extracts image URL and description from each image XML element that is a direct child of root element. This information is contained inside the urlBase and copyright XML elements inside the image element. The second one downloads an image from the Bing site. The last Select method creates a thumbnail image and stores all the information needed inside the WallPaperInfo class instance. To display the results, we need to create a user interface. Windows Forms is a simple and fast to implement technology, so we use it to show the results to the user. There is a button that runs the download, a panel to show the downloaded pictures, and a label that will show the time required to finish downloading. Here is the implementation code. This includes a calculation of the top co-ordinate for each element, a code to display the images and start the download process: private int GetItemTop(int height, int index) {   return index * (height + 8) + 8; } private void RefreshContent(WallpapersInfo info) {   _resultPanel.Controls.Clear();   _resultPanel.Controls.AddRange(     info.Wallpapers.SelectMany((wallpaper, i) => new Control[] {     new PictureBox {       Left = 4,       Image = wallpaper.Thumbnail,       AutoSize = true,       Top = GetItemTop(wallpaper.Thumbnail.Height, i)     },     new Label {       Left = wallpaper.Thumbnail.Width + 8,       Top = GetItemTop(wallpaper.Thumbnail.Height, i),       Text = wallpaper.Description,       AutoSize = true     }   }).ToArray());     _timeLabel.Text = string.Format( "Time: {0}ms", info.Milliseconds); } private void _loadSyncBtn_Click(object sender, System.EventArgs e) {   var info = Loader.SyncLoad();   RefreshContent(info); } The result looks as follows: So the time to download all these images should be about several seconds if the internet connection is broadband. Can we do this faster? We certainly can! Now we will download and process the images one by one, but we totally can process each image in parallel. Creating a parallel solution with Task Parallel Library The Task Parallel Library and the code that shows the relationships between tasks naturally splits into several stages as follows: Load images catalog XML from Bing Parsing the XML document and get the information needed about the images Load each image's data from Bing Create a thumbnail image for each image downloaded The process can be visualized with the dependency chart: HttpClient has naturally asynchronous API, so we only need to combine everything together with the help of a Task.ContinueWith method: public static Task<WallpapersInfo> TaskLoad() {   var sw = Stopwatch.StartNew();   var downloadBingXmlTask = new HttpClient().GetStringAsync(_catalogUri);   var parseXmlTask = downloadBingXmlTask.ContinueWith(task => {     var xmlDocument = XDocument.Parse(task.Result);     return xmlDocument.Root       .Elements("image")       .Select(e =>         new {           Description = e.Element("copyright").Value,           Url = e.Element("urlBase").Value         });   });   var downloadImagesTask = parseXmlTask.ContinueWith(     task => Task.WhenAll(       task.Result.Select(item => new HttpClient()         .DownloadDataAsync(string.Format(_imageUri, item.Url))         .ContinueWith(downloadTask => new WallpaperInfo(           GetThumbnail(downloadTask.Result), item.Description)))))         .Unwrap();   return downloadImagesTask.ContinueWith(task => {     sw.Stop();     return new WallpapersInfo(sw.ElapsedMilliseconds,       task.Result);   }); } The code has some interesting moments. The first task is created by the HttpClient instance, and it completes when the download process succeeds. Now we will attach a subsequent task, which will use the XML string downloaded by the previous task, and then we will create an XML document from this string and extract the information needed. Now this is becoming more complicated. We want to create a task to download each image and continue until all these tasks complete successfully. So we will use the LINQ Select method to run downloads for each image that was defined in the XML catalog, and after the download process completes, we will create a thumbnail image and store the information in the WallpaperInfo instance. This creates IEnumerable<Task<WallpaperInfo>> as a result, and to wait for all these tasks to complete, we will use the Task.WhenAll method. However, this is a task that is inside a continuation task, and the result is going to be of the Task<Task<WallpaperInfo[]>> type. To get the inner task, we will use the Unwrap method, which has the following syntax: public static Task Unwrap(this Task<Task> task) This can be used on any Task<Task> instance and will create a proxy task that represents an entire asynchronous operation properly. The last task is to stop the timer and return the downloaded images and is quite straightforward. We have to add another button to the UI to run this implementation. Notice the implementation of the button click handler: private void _loadTaskBtn_Click(object sender, System.EventArgs e) {   var info = Loader.TaskLoad();   info.ContinueWith(task => RefreshContent(task.Result),     CancellationToken.None,     TaskContinuationOptions.None,     TaskScheduler.FromCurrentSynchronizationContext()); } Since the TaskLoad method is asynchronous, it returns immediately. To display the results, we have to define a continuation task. The default task scheduler will run a task code on a thread pool worker thread. To work with UI controls, we have to run the code on the UI thread, and we use a task scheduler that captures the current synchronization context and runs the continuation task on this. Let's name the button as Load using TPL and test the results. If your internet connection is fast, this implementation will download the images in parallel much faster compared to the previous sequential download process. If we look back at the code, we will see that it is quite hard to understand what it actually does. We can see how one task depends on other, but the original goal is unclear despite the code being very compact and easy. Imagine what will happen if we would try to add exception handling here. We will have to append an additional continuation task with exception handling to each task. This will be much harder to read and understand. In a real-world program, it will be a challenging task to keep in mind these tasks composition and support a code written in such a paradigm. Enhancing the code with C# 5.0 built-in support for asynchrony Fortunately, C# 5.0 introduced the async and await keywords that are intended to make asynchronous code look like synchronous, and thus, makes reading of code and understanding the program flow easier. However, this is another abstraction and it hides many things that happen under the hood from the programmer, which in several situations is not a good thing. Now let's rewrite the previous code using new C# 5.0 features: public static async Task<WallpapersInfo> AsyncLoad() {   var sw = Stopwatch.StartNew();   var client = new HttpClient();   var catalogXmlString = await client.GetStringAsync(_catalogUri);   var xDoc = XDocument.Parse(catalogXmlString);   var wallpapersTask = xDoc     .Root     .Elements("image")     .Select(e =>       new {         Description = e.Element("copyright").Value,         Url = e.Element("urlBase").Value       })     .Select(async item =>       new {         item.Description,         FullImageData = await client.DownloadDataAsync(           string.Format(_imageUri, item.Url))       });   var wallpapersItems = await Task.WhenAll(wallpapersTask);   var wallpapers = wallpapersItems.Select(     item => new WallpaperInfo(       GetThumbnail(item.FullImageData), item.Description));   sw.Stop();   return new WallpapersInfo(sw.ElapsedMilliseconds,     wallpapers.ToArray()); } Now the code looks almost like the first synchronous implementation. The AsyncLoad method has a async modifier and a Task<T> return value, and such methods must always return Task or be declared as void—this is enforced by the compiler. However, in the method's code, the type that is returned is just T. This is strange at first, but the method's return value will be eventually turned into Task<T> by the C# 5.0 compiler. The async modifier is necessary to use await inside the method. In the further code, there is await inside a lambda expression, and we need to mark this lambda as async as well. So what is going on when we use await inside our code? It does not always mean that the call is actually asynchronous. It can happen that by the time we call the method, the result is already available, so we just get the result and proceed further. However, the most common case is when we make an asynchronous call. In this case, we start. for example by downloading a XML string from Bing via HTTP and immediately return a task that is a continuation task and contains the rest of the code after the line with await. To run this, we need to add another button named Load using async. We are going to use await in the button click event handler as well, so we need to mark it with the async modifier: private async void _loadAsyncBtn_Click(object sender, System.EventArgs e) {   var info = await Loader.AsyncLoad();   RefreshContent(info); } Now if the code after await is being run in a continuation task, why is there no multithreaded access exception? The RefreshContent method runs in another task, but the C# compiler is aware of the synchronization context and generates a code that executes the continuation task on the UI thread. The result should be as fast as a TPL implementation but the code is much cleaner and easy to follow. The last but not least, is possibility to put asynchronous method calls inside a try block. The C# compiler generates a code that will propagate the exception into the current context and unwrap the AggregateException instance to get the original exception from it. In C# 5.0, it was impossible to use await inside catch and finally blocks, but C# 6.0 introduced a new async/await infrastructure and this limitation was removed. Simulating C# asynchronous infrastructure with iterators To dig into the implementation details, it makes sense to look at the decompiled code of the AsyncLoad method: public static Task<WallpapersInfo> AsyncLoad() {   Loader.<AsyncLoad>d__21 stateMachine;   stateMachine.<>t__builder =     AsyncTaskMethodBuilder<WallpapersInfo>.Create();   stateMachine.<>1__state = -1;   stateMachine     .<>t__builder     .Start<Loader.<AsyncLoad>d__21>(ref stateMachine);   return stateMachine.<>t__builder.Task; } The method body was replaced by a compiler-generated code that creates a special kind of state machine. We will not review the further implementation details here, because it is quite complicated and is subject to change from version to version. However, what's going on is that the code gets divided into separate pieces at each line where await is present, and each piece becomes a separate state in the generated state machine. Then, a special System.Runtime.CompilerServices.AsyncTaskMethodBuilder structure creates Task that represents the generated state machine workflow. This state machine is quite similar to the one that is generated for the iterator methods that leverage the yield keyword. In C# 6.0, the same universal code gets generated for the code containing yield and await. To illustrate the general principles behind the generated code, we can use iterator methods to implement another version of asynchronous images download from Bing. Therefore, we can turn an asynchronous method into an iterator method that returns the IEnumerable<Task> instance. We replace each await with yield return making each iteration to be returned as Task. To run such a method, we need to execute each task and return the final result. This code can be considered as an analogue of AsyncTaskMethodBuilder: private static Task<TResult> ExecuteIterator<TResult>(   Func<Action<TResult>,IEnumerable<Task>> iteratorGetter) {   return Task.Run(() => {     var result = default(TResult);     foreach (var task in iteratorGetter(res => result = res))       task.Wait();     return result;   }); } We iterate through each task and await its completion. Since we cannot use the out and ref parameters in iterator methods, we use a lambda expression to return the result from each task. To make the code easier to understand, we have created a new container task and used the foreach loop; however, to be closer to the original implementation, we should get the first task and use the ContinueWith method providing the next task to it and continue until the last task. In this case, we will end up having one final task representing an entire sequence of asynchronous operations, but the code will become more complicated as well. Since it is not possible to use the yield keyword inside a lambda expressions in the current C# versions, we will implement image download and thumbnail generation as a separate method: private static IEnumerable<Task> GetImageIterator(   string url,   string desc,   Action<WallpaperInfo> resultSetter) {   var loadTask = new HttpClient().DownloadDataAsync(     string.Format(_imageUri, url));   yield return loadTask;   var thumbTask = Task.FromResult(GetThumbnail(loadTask.Result));   yield return thumbTask;   resultSetter(new WallpaperInfo(thumbTask.Result, desc)); } It looks like a common C# async code with yield return used instead of the await keyword and resultSetter used instead of return. Notice the Task.FromResult method that we used to get Task from the synchronous GetThumbnail method. We can use Task.Run and put this operation on a separate worker thread, but it will be an ineffective solution; Task.FromResult allows us to get Task that is already completed and has a result. If you use await with such task, it will be translated into a synchronous call. The main code can be rewritten in the same way: private static IEnumerable<Task> GetWallpapersIterator(   Action<WallpaperInfo[]> resultSetter) {   var catalogTask = new HttpClient().GetStringAsync(_catalogUri);   yield return catalogTask;   var xDoc = XDocument.Parse(catalogTask.Result);   var imagesTask = Task.WhenAll(xDoc     .Root     .Elements("image")     .Select(e => new {       Description = e.Element("copyright").Value,         Url = e.Element("urlBase").Value     })     .Select(item => ExecuteIterator<WallpaperInfo>(       resSetter => GetImageIterator(         item.Url, item.Description, resSetter))));   yield return imagesTask;   resultSetter(imagesTask.Result); } This combines everything together: public static WallpapersInfo IteratorLoad() {   var sw = Stopwatch.StartNew();   var wallpapers = ExecuteIterator<WallpaperInfo[]>(     GetWallpapersIterator)       .Result;   sw.Stop();   return new WallpapersInfo(sw.ElapsedMilliseconds, wallpapers); } To run this, we will create one more button called Load using iterator. The button click handler just runs the IteratorLoad method and then refreshes the UI. This also works with about the same speed as other asynchronous implementations. This example can help us to understand the logic behind the C# code generation for asynchronous methods used with await. Of course, the real code is much more complicated, but the principles behind it remain the same. Is the async keyword really needed? It is a common question about why do we need to mark methods as async? We have already mentioned iterator methods in C# and the yield keyword. This is very similar to async/await, and yet we do not need to mark iterator methods with any modifier. The C# compiler is able to determine that it is an iterator method when it meets the yield return or yield break operators inside such a method. So the question is, why is it not the same with await and the asynchronous methods? The reason is that asynchrony support was introduced in the latest C# version, and it is very important not to break any legacy code while changing the language. Imagine if any code used await as a name for a field or variable. If C# developers make await a keyword without any conditions, this old code will break and stop compiling. The current approach guarantees that if we do not mark a method with async, the old code will continue to work. Fire-and-forget tasks Besides Task and Task<T>, we can declare an asynchronous method as void. It is useful in the case of top-level event handlers, for example, the button click or text changed handlers in the UI. An event handler that returns a value is possible, but is very inconvenient to use and does not make much sense. So allowing async void methods makes it possible to use await inside such event handlers: private async void button1_Click(object sender, EventArgs e) {   await SomeAsyncStuff(); } It seems that nothing bad is happening, and the C# compiler generates almost the same code as for the Task returning method, but there is an important catch related to exceptions handling. When an asynchronous method returns Task, exceptions are connected to this task and can be handled both by TPL and the try/catch block in case await is used. However, if we have a async void method, we have no Task to attach the exceptions to and those exceptions just get posted to the current synchronization context. These exceptions can be observed using AppDomain.UnhandledException or similar events in a GUI application, but this is very easy to miss and not a good practice. The other problem is that we cannot use a void returning asynchronous method with await, since there is no return value that can be used to await on it. We cannot compose such a method with other asynchronous tasks and participate in the program workflow. It is basically a fire-and-forget operation that we start, and then we have no way to control how it will proceed (if we did not write the code for this explicitly). Another problem is void returning async lambda expression. It is very hard to notice that lambda returns void, and all problems related to usual methods are related to lambda expression as well. Imagine that we want to run some operation in parallel. To achieve this, we can use the Parallel.ForEach method. To download some news in parallel, we can write a code like this: Parallel.ForEach(Enumerable.Range(1,10), async i => {   var news = await newsClient.GetTopNews(i);   newsCollection.Add(news); }); However, this will not work, because the second parameter of the ForEach method is Action<T>, which is a void returning delegate. Thus, we will spawn 10 download processes, but since we cannot wait for completion, we abandon all asynchronous operations that we just started and ignore the results. A general rule of thumb is to avoid using async void methods. If this is inevitable and there is an event handler, then always wrap the inner await method calls in try/catch blocks and provide exception handling. Other useful TPL features Task Parallel Library has a large codebase and some useful features such as Task.Unwrap or Task.FromResult that are not very well known to developers. We have still not mentioned two more extremely useful methods yet. They are covered in the following sections. Task.Delay Often, it is required to wait for a certain amount of time in the code. One of the traditional ways to wait is using the Thread.Sleep method. The problem is that Thread.Sleep blocks the current thread, and it is not asynchronous. Another disadvantage is that we cannot cancel waiting if something has happened. To implement a solution for this, we will have to use system synchronization primitives such as an event, but this is not very easy to code. To keep the code simple, we can use the Task.Delay method: // Do something await Task.Delay(1000); // Do something This method can be canceled with a help of the CancellationToken infrastructure and uses system timer under the hood, so this kind of waiting is truly asynchronous. Task.Yield Sometimes we need a part of the code to be guaranteed to run asynchronously. For example, we need to keep the UI responsive, or maybe we would like to implement a fine-grained scenario. Anyway, as we already know that using await does not mean that the call will be asynchronous. If we want to return control immediately and run the rest of the code as a continuation task, we can use the Task.Yield method: // Do something await Task.Yield(); // Do something Task.Yield just causes a continuation to be posted on the current synchronization context, or if the synchronization context is not available, a continuation will be posted on a thread pool worker thread. Implementing a custom awaitable type Until now we have only used Task with the await operator. However, it is not the only type that is compatible with await. Actually, the await operator can be used with every type that contains the GetAwaiter method with no parameters and the return type that does the following: Implements the INotifyCompletion interface Contains the IsCompleted boolean property Has the GetResult method with no parameters This method can even be an extension method, so it is possible to extend the existing types and add the await compatibility to them. In this example, we will create such a method for the Uri type. This method will download content as a string via HTTP from the address provided in the Uri instance: private static TaskAwaiter<string> GetAwaiter(this Uri url) {   return new HttpClient().GetStringAsync(url).GetAwaiter(); } var content = await new Uri("http://google.com"); Console.WriteLine(content.Substring(0, 10)); If we run this, we will see the first 10 characters of the Google website content. As you may notice, here we used the Task type indirectly, returning the already provided awaiter method for the Task type. We can implement an awaiter method manually from scratch, but it really does not make any sense. To understand how this works it will be enough to create a custom wrapper around an already existing TaskAwaiter: struct DownloadAwaiter : INotifyCompletion {   private readonly TaskAwaiter<string> _awaiter;   public DownloadAwaiter(Uri uri) {     Console.WriteLine("Start downloading from {0}", uri);     var task = new HttpClient().GetStringAsync(uri);     _awaiter = task.GetAwaiter();     Task.GetAwaiter().OnCompleted(() => Console.WriteLine(       "download completed"));   }   public bool IsCompleted {     get { return _awaiter.IsCompleted; }   }   public void OnCompleted(Action continuation) {     _awaiter.OnCompleted(continuation);   }   public string GetResult() {     return _awaiter.GetResult();   } } With this code, we have customized asynchronous execution that provides diagnostic information to the console. To get rid of TaskAwaiter, it will be enough to change the OnCompleted method with custom code that will execute some operation and then a continuation provided in this method. To use this custom awaiter, we need to change GetAwaiter accordingly: private static DownloadAwaiter GetAwaiter(this Uri uri) {   return new DownloadAwaiter(uri); } If we run this, we will see additional information on the console. This can be useful for diagnostics and debugging. Summary In this article, we have looked at the C# language infrastructure that supports asynchronous calls. We have covered the new C# keywords, async and await, and how we can use Task Parallel Library with the new C# syntax. We have learned how C# generates code and creates a state machine that represents an asynchronous operation, and we implemented an analogue solution with the help of iterator methods and the yield keyword. Besides this, we have studied additional Task Parallel Library features and looked at how we can use await with any custom type. Resources for Article: Further resources on this subject: R ─ CLASSIFICATION AND REGRESSION TREES [article] INTRODUCING THE BOOST C++ LIBRARIES [article] CLIENT AND SERVER APPLICATIONS [article]
Read more
  • 0
  • 0
  • 8297

article-image-large-language-model-operations-llmops-in-action
Mostafa Ibrahim
11 Oct 2023
6 min read
Save for later

Large Language Model Operations (LLMOps) in Action

Mostafa Ibrahim
11 Oct 2023
6 min read
Dive deeper into the world of AI innovation and stay ahead of the AI curve! Subscribe to our AI_Distilled newsletter for the latest insights. Don't miss out – sign up today!IntroductionIn an era dominated by the rise of artificial intelligence, the power and promise of Large Language Models (LLMs) stand distinct. These colossal architectures, designed to understand and generate human-like text, have revolutionized the realm of natural language processing. However, with great power comes great responsibility – the onus of managing, deploying, and refining these models in real-world scenarios. This article delves into the world of Large Language Model Operations (LLMOps), an emerging field that bridges the gap between the potential of LLMs and their practical application.BackgroundThe last decade has seen a significant evolution in language models, with models growing in size and capability. Starting with smaller models like Word2Vec and LSTM, we've advanced to behemoths like GPT-3, BERT, and T5.  With that said, as these models grew in size and complexity, so did their operational challenges. Deploying, maintaining, and updating these models requires substantial computational resources, expertise, and effective management strategies.MLOps vs LLMOpsIf you've ventured into the realm of machine learning, you've undoubtedly come across the term MLOps. MLOps, or Machine Learning Operations, encapsulates best practices and methodologies for deploying and maintaining machine learning models throughout their lifecycle. It caters to the wide spectrum of models that fall under the machine learning umbrella.On the other hand, with the growth of vast and intricate language models, a more specialized operational domain has emerged: LLMOps. While both MLOps and LLMOps share foundational principles, the latter specifically zeros in on the challenges and nuances of deploying and managing large-scale language models. Given the colossal size, data-intensive nature, and unique architecture of these models, LLMOps brings to the fore bespoke strategies and solutions that are fine-tuned to ensure the efficiency, efficacy, and sustainability of such linguistic powerhouses in real-world scenarios.Core Concepts of LLMOpsLarge Language Models Operations (LLMOps) focuses on the management, deployment, and optimization of large language models (LLMs). One of its foundational concepts is model deployment, emphasizing scalability to handle varied loads, reducing latency for real-time responses, and maintaining version control. As these LLMs demand significant computational resources, efficient resource management becomes pivotal. This includes the use of optimized hardware like GPUs and TPUs, effective memory optimization strategies, and techniques to manage computational costs.Continuous learning and updating, another core concept, revolve around fine-tuning models with new data, avoiding the pitfall of 'catastrophic forgetting', and effectively managing data streams for updates. Parallelly, LLMOps emphasizes the importance of continuous monitoring for performance, bias, fairness, and iterative feedback loops for model improvement. To cater to the vastness of LLMs, model compression techniques like pruning, quantization, and knowledge distillation become crucial.How do LLMOps workPre-training Model DevelopmentLarge Language Models typically start their journey through a process known as pre-training. This involves training the model on vast amounts of text data. The objective during this phase is to capture a broad understanding of language, learning from billions of sentences and paragraphs. This foundational knowledge helps the model grasp grammar, vocabulary, factual information, and even some level of reasoning.This massive-scale training is what makes them "large" and gives them a broad understanding of language. Optimization & CompressionModels trained to this extent are often so large that they become impractical for daily tasks.To make these models more manageable without compromising much on performance, techniques like model pruning, quantization, and knowledge distillation are employed.Model Pruning: After training, pruning is typically the first optimization step. This begins with trimming model weights and may advance to more intensive methods like neuron or channel pruning.Quantization: Following pruning, the model's weights, and potentially its activations, are streamlined. Though weight quantization is generally a post-training process, for deeper reductions, such as very low-bit quantization, one might adopt quantization-aware training from the beginning.Additional recommendations are:Optimizing the model specifically for the intended hardware can elevate its performance. Before initiating training, selecting inherently efficient architectures with fewer parameters is beneficial. Approaches that adopt parameter sharing or tensor factorization prove advantageous. For those planning to train a new model or fine-tune an existing one with an emphasis on sparsity, starting with sparse training is a prudent approach.Deployment Infrastructure After training and compressing our LLM, we will be using technologies like Docker and Kubernetes to deploy models scalably and consistently. This approach allows us to flexibly scale using as many pods as needed. Concluding the deployment process, we'll implement edge deployment strategies. This positions our models nearer to the end devices, proving crucial for applications that demand real-time responses.Continuous Monitoring & FeedbackThe process starts with the Active model in production. As it interacts with users and as language evolves, it can become less accurate, leading to the phase where the Model becomes stale as time passes.To address this, feedback and interactions from users are captured, forming a vast range of new data. Using this data, adjustments are made, resulting in a New fine-tuned model.As user interactions continue and the language landscape shifts, the current model is replaced with the new model. This iterative cycle of deployment, feedback, refinement, and replacement ensures the model always stays relevant and effective.Importance and Benefits of LLMOpsMuch like the operational paradigms of AIOps and MLOps, LLMOps brings a wealth of benefits to the table when managing Large Language Models.MaintenanceAs LLMs are computationally intensive. LLMOps streamlines their deployment, ensuring they run smoothly and responsively in real-time applications. This involves optimizing infrastructure, managing resources effectively, and ensuring that models can handle a wide variety of queries without hiccups.Consider the significant investment of effort, time, and resources required to maintain Large Language Models like Chat GPT, especially given its vast user base.Continuous ImprovementLLMOps emphasizes continuous learning, allowing LLMs to be updated with fresh data. This ensures that models remain relevant, accurate, and effective, adapting to the evolving nature of language and user needs.Building on the foundation of GPT-3, the newer GPT-4 model brings enhanced capabilities. Furthermore, while ChatGPT was previously trained on data up to 2021, it has now been updated to encompass information through 2022.It's important to recognize that constructing and sustaining large language models is an intricate endeavor, necessitating meticulous attention and planning.ConclusionThe ascent of Large Language Models marks a transformative phase in the evolution of machine learning. But it's not just about building them; it's about harnessing their power efficiently, ethically, and sustainably. LLMOps emerge as the linchpin, ensuring that these models not only serve their purpose but also evolve with the ever-changing dynamics of language and user needs. As we continue to innovate, the principles of LLMOps will undoubtedly play a pivotal role in shaping the future of language models and their place in our digital world.Author BioMostafa Ibrahim is a dedicated software engineer based in London, where he works in the dynamic field of Fintech. His professional journey is driven by a passion for cutting-edge technologies, particularly in the realms of machine learning and bioinformatics. When he's not immersed in coding or data analysis, Mostafa loves to travel.Medium
Read more
  • 0
  • 0
  • 8293

article-image-setting-microsoft-dynamics-gp-system
Packt
11 Jan 2011
9 min read
Save for later

Setting up the Microsoft Dynamics GP System

Packt
11 Jan 2011
9 min read
  Microsoft Dynamics GP 2010 Implementation A step-by-step guide to implementing Microsoft Dynamics GP 2010 Master how to implement Microsoft Dynamics GP 2010 with real world examples and guidance from a Microsoft Dynamics GP MVP Understand how to install Microsoft Dynamics GP 2010 and related applications, following detailed, step-by-step instructions Learn how to set-up the core Microsoft Dynamics GP modules effectively Discover the additional tools available from Microsoft for Dynamics GP           When you launch Dynamics GP for the first time on a new computer, you will be prompted for a Server, User ID, and Password: For the Server, choose the ODBC data source pointing to your SQL Server (remember this will need to be created identically on each computer). The first time you log in, use sa for the User ID. Dynamics GP will detect that this is a new installation and will prompt you to run Dynamics GP Utilities. Choose Yes, log into Dynamics GP Utilities as sa, and follow the prompts. Your local Dynamics GP application will be initialized and synchronized to the settings on the server. Once done, click the Launch Microsoft Dynamics GP button at the bottom of the Additional Tasks window. Log into Dynamics GP again as sa and you will see the Company Login window with a drop-down selection for the companies that have been created in Dynamics GP. For performing system setup steps, you can choose any company on the list. To perform company setup, you will need to choose the specific company you will be setting up. System setup System setup for Dynamics GP includes settings that are global to your entire Dynamics GP installation such as the system password, registration, creating users, setting up user security, currency settings, exchange rates, and additional system-wide settings. A very useful feature in Dynamics GP is the Setup Checklist, which lists all of the setup steps with a brief description of each and provides automatic links to the related setup windows. The setup checklist also gives you the ability to assign tasks to others and change the status of the various installation tasks as you go through them. In the following sections, the navigation paths to get to each setup window will be detailed using the Dynamics GP menus, however you may find that bringing up the setup checklist can save you time during the setup. The setup checklist is found under Microsoft Dynamics GP | Tools | Setup | Setup Checklist. Show required fields To help with system setup you may want to have Dynamics GP highlight the required fields on windows for you. This option is turned off by default. To turn it on: Click on the Help icon in the upper-right corner and click on Show required fields. This setting is a toggle, once clicked it will display a checkmark next to it to show it is activated. Navigate to Microsoft Dynamics GP |User Preferences. On the User Preferences window, click on Display to open the User Display Preferences window. Change the settings under Required Fields to be something other than the default settings. You can click on Apply to preview your changes and click OK to close the window. Changes to the display preferences are specific to the Dynamics GP user. Once set, they will be used on any computer where the user logs into Dynamics GP. System password Most system setup windows will require the Dynamics GP system password you entered during the initial Dynamics GP installation. You can set this password to be blank while performing the system setup, so that you are not constantly prompted for it. To change the system password navigate to Microsoft Dynamics GP | Tools | Setup | System | System Password. It is highly recommended to assign a system password once you are done with the system setup. System preferences You can set overall system preferences for Dynamics GP by navigating to Microsoft Dynamics GP | Tools | Setup | System | System Preferences. All of these settings are optional. The Office SharePoint Server is used to enable searching Dynamics GP data from SharePoint. The Home Page Defaults control what loads for newly created users in Dynamics GP. Note the critical word loads. These sections will still exist on the home page for new users, but they will not load with initial data if unchecked on this window. It is recommended to uncheck all of the Home Page Defaults to save time during initial login, especially when installing on a computer where there may not be Outlook installed, or when logged in with a Windows user ID that might not have an Outlook profile. Changes to these settings will only apply to newly created users, no existing user setup will be changed. Remember User is a new feature in Dynamics GP 2010. This activates the Remember user and password and Remember this company checkboxes on the Dynamics GP login windows. Unfortunately, there is no way to separate these two options. While many companies may feel that remembering the company is a nice option for users, remembering the User ID and password may be against security policies in many organizations. Dynamics GP registration Dynamics GP will typically install without asking for registration keys, however this should be the first thing entered as part of system setup to ensure that the system is set up with the modules you are registered for. Registration keys can be obtained either from your Dynamics GP partner or from Microsoft. To enter your registration keys, navigate to Microsoft Dynamics GP | Tools | Setup | System | Registration. On the Registration window enter your Site Name and Registration Keys. The Site Name is listed under License Holder on your licensing information and must appear the exact same way, with the same punctuation, spelling, and spacing. Even though there are five Registration Keys possible, you may have less. The keys listed as – No key – on the licensing information should be left blank on the Registration window. Click on the Validate button and the Modules list will populate with the Dynamics GP modules you have purchased. It is recommended to uncheck any modules that you are not planning to use. Leaving all the modules activated may cause some functionality not to work as expected and to require setup for those modules prior to entering transaction for other modules. Modules can be activated at a later time if needed. Some of the modules may not sound familiar, but may be core or internal modules needed for other functionality you are using. If you are unsure about some of the modules on the list, consult with your Dynamics GP resource. Creating Dynamics GP users Dynamics GP is licensed for concurrent users, so you can create as many named users as you would like. It is recommended to create a Dynamics GP user for each individual that will be using Dynamics GP. The following are the steps to create new Dynamics GP users: Log into Dynamics GP as either sa, DYNSA, or a user that has been set up in SQL Server with the sysadmin server role. Navigate to Microsoft Dynamics GP | Tools | Setup | System | User. Enter a User ID. Unlike most user IDs, the Dynamics GP user IDs are case sensitive. Consider making user IDs the same as the users' Windows logins. Even though Dynamics GP uses SQL Server authentication, it may be easier to administer users when all the IDs follow the same pattern. Enter the User Name. While not required, it is helpful to enter the full name of the user, so that this information is available when looking through a list of users in the future. Enter and confirm the Password. Dynamics GP passwords are case sensitive. If you leave the password blank, the user will be required to create a password the first time they log into Dynamics GP. While that sounds like a handy feature, this can be a security risk because while the password is blank anyone can log in with just the user ID. This is not a concern if the user will be logging in immediately, however if users may log in for the first time days or even weeks later, this is not very secure. Users can change their own passwords in Dynamics GP at any time, so create a unique password for each user and ask them to change it as soon as they log in the first time. Class ID is an optional setting that may be useful for grouping users in the future. With the changes to the Dynamics GP security model starting with version 10.0, user classes are not widely used anymore and are not needed for security setup. The Class ID can be changed at any time. Setting the Home Page Role is also optional. If set while creating the user, this will save the user from having to pick their home page role when they first log into Dynamics GP. Set the Advanced SQL Server options. These options allow using your Active Directory domain password policies with Dynamics GP. This is another feature that sounds more useful than it often proves to be. There are many limitations and workarounds for this, detailed in KB article 922456, Frequently asked questions about the advanced SQL Server options in the User Setup window in Microsoft Dynamics GP: https://mbs.microsoft.com/knowledgebase/KBDisplay.aspx?scid=kb;en-us;922456 (requires login). A common recommendation is to uncheck the Advanced SQL Server options when creating new Dynamics GP users. If the Collections Management module has been installed and activated for Dynamics GP, once you click Save on the User Setup window you will receive the following pop-up message: Clicking on Add will open the Collections Management Collector Setup window where you can set up this user as a collector. Clicking Cancel will allow you to continue without setting the user up as a collector. A user can be set up as a collector at any time, so if you are not sure, click on Cancel. When a user ID is created in Dynamics GP, a SQL Server login is created with the DYNGRP role. The user password is encrypted by Dynamics GP so that this login cannot be used outside of the Dynamics GP application.
Read more
  • 0
  • 0
  • 8290

Packt
19 Jun 2010
10 min read
Save for later

Getting Started with Blender’s Particle System

Packt
19 Jun 2010
10 min read
We’ll cover a general introduction about Blender’s particle system; how to use it, when to use it, how useful it is on both small scale and large scale projects, and an overview of its implications. In this article, I’ll also discuss how to use the particle system to instance objects These are just but very few examples of what can really be achieved with the particle system, there’s a vast array of possibilities out there that can be discovered. But I’m hoping with these examples and definitions, you’ll find your way through the wonderful world of visual effects with the particle system. If you remember watching Blender Foundation’s Big Buck Bunny, it might not seem as a surprise to you that almost the entire film is filled up with so much particle goodness. Thanks to that, great improvements have been made to Blender’s particle system. As compared to my previous articles, this one uses Blender 2.5, the latest version of Blender which is currently in Alpha stage right now but is fully workable. However, in this article I wouldn’t be telling you what each of the button would do since that would take another article in itself and might deviate from an introductory approach. If you wanted to know more in-depth information about the whole particle system, you can check out the official Blender documentation or the Blender wiki. There had been great improvements on the particle system and now is the right time to start trying it out. So what are you waiting for? Hop on and ride with me in this journey! You can watch the video here. Prerequisites Before we begin with this article, it’s vital to first determine our requirements before proceeding on the actual application. Before going on, we need to have the following: Latest Blender 2.5 (you can grab a copy at http://www.blender.org or http://www.graphicall.org) Adequate hard disk space Decent processor and graphics card What is a Particle System and where can we find it in Blender? A particle system is a technique in Computer Graphics that is used to simulate a visual effect that would otherwise be very difficult and cumbersome if not impossible to do in traditional 3D techniques. These effects include crowd simulation, hair, fur, grass, fire, smoke, fluids, dust, snowflakes, and more. Particle Systems are calculated inside of your simulation program in several ways and one of the most common ones is the Newtonian Physics calculation which regards forces like wind, magnetism, friction, gravity, etc. to generate the particle’s motion along a controllable environment. Properties or parameters of particle systems include: mass, speed, velocity, size, life, color, transparency, softness, damping, and many more. Particle’s behavior along a certain span of time are then saved and written on to your disk. This process is called caching, which enables you to view and edit the particle’s behavior within the timeframe set. And when you’re satisfied with the way your particles act on your simulation space, you can now permanently write these settings to the disk, called baking. Be aware that the longer your particle system’s life is and the greater the number, the more hard disk space it uses, so for testing purposes, it is best to keep the particles number low, then progressively increase them as needed. Particle mass refers the natural weight (in a gravitational field) of a single particle object/point, where higher mass means a heavier particle and a lower mass implies a lighter particle. A heavy particle is more resistant to external forces such as wind but more reactive to gravitational force as compared to a lighter particle system which is a direct opposite. Particle speed/velocity refers to how fast or slow the particle points are being thrown or emitted from their source within a given time. They can be displaced and controlled in the x, y, or z directions accordingly. A higher velocity will create a faster shooting particle (as seen in muzzle flares/flash) and a lower one will create slower particle shots. Size of the particles is one of the most important setting when using a particle system as object instances, since this will better control the size of the objects on the emitting plane as compared to manually resizing the original object. With this option, you can have random sizes which will give the scene a more believable and natural look and offcourse, an easier setup as compared to creating numerous objects for this matter. Particle life refers to the lifespan of the particles, for how long they will be existent until they disappear and die from the system. In some cases, having a large particle life is useful but it can have some speed drawbacks on your machine. Imagine emitting one million particles within 5 seconds where only half of it is relevant within the first few seconds. That could mean 500,000 particles cached is a sheer waste and rendering your machine slower. Having smaller particle lives sometimes is also useful especially when you’re creating small scale smoke and fire. But all these really depend on the way you setup your scenes. Play around and you’ll find the best settings that suit your needs. Note though that in Blender, only Mesh objects can be particle emitters (which is simply rational for this purpose). You can modify the size and shape of the mesh object and the particle system reacts accordingly. The direction from which particles are emitted is dictated by the mesh normals, which I will discuss along the way. In Blender 2.5, we can find the Particle System by selecting any mesh object and clicking the Particles Button in the Properties Editor, as seen in the screenshot. Later, we’ll add and name particle systems and go over their settings more closely. Blender 2.5’s Particle System   What are the types of Blender particle system? Currently, there are only two types of particle systems in Blender 2.5, namely Emmiter and Hair.  With few on the list, these two have already proved to be very handy tools in creating robust simulations. Particle System Types   Let’s begin by learning what an Emitter Type is. Aside from the fact that the term emitter is used to define the source of the particles, the emitter type is one different thing on its own. The Emitter, being the default particle type, is one of the most commonly used particle system type. With it you can create dust, smoke, fire, fluids, snowflakes, and the like. Inside Blender, make the default cube a particle emitter with the type set as Emitter. Leave the default settings as they are and press ALT+A in the 3D Viewport to playback the animation and observe the way the particles act in your observable space, that is, the 3D space that your object is in. During the playback process, the particle system is already caching the position of the particle points in your space and writing these on to the disk. Naturally, this is how the emitter type will act on our space, with a slight pulse from emitter then it drops down as an effect of the gravity. That pulse is coming from the Normal value which tells how strong the points are spurted out until they get affected by external forces. There’s more to the emitter type than there seems to be, so don’t hold back and keep changing the settings and see where they lead you to. And if you can, please send me what you got, I’d be very pleased to see what fun things you came up with. Emitter Type   Leaving from the default settings we had awhile back, change your current frame to 1 (if it is not yet set as such) then let’s change the type from Emitter to Hair. Instantly, you’ll notice that strands come bursting out of our default mesh. This is the particle hair’s nature, whichever frame you are in now, it will stay in the same frame, regardless of any explicit animation you add in. As compared to the Emitter type, Hair doesn’t need to be cached to see the results, it’s an on-the-fly process of editing particle settings. Another great advantage of the hair type over the emitter type is that it has a dedicated Particle Mode which enables you to edit the strands as though you were actually touching real hair. With the hair type, you can create systems like fur, grass, static particle instances/grouping, and more. Hair Type   Basic and Practical Uses of the Particle System Now let’s on the real business. From here on, I’ll approach the proceeding steps in a practical application manner. First, let’s check some of the default settings and see where they lead us. Fire up a fresh Blender session by opening up Blender or by pressing CTRL+N (when you already have it open from our steps awhile ago). Fresh Blender 2.5 Session   Delete the default cube and add in a Plane object. Adding a Plane Primitive   Position the camera’s view such that the plane is just on top of the viewing range, this will give us more space to see the particles falling. Adjusting the View   Select the Plane Mesh and in the Particle Buttons window, add a new Particle System and leave the default values as they are. In the 3D Viewport, press ALT+A to play and pause the animation or use the play buttons in the Timeline Window. Pick a frame you’re satisfied with, any will do right now. New Particle System   Next, add a new material to the Plane Mesh and the Particle System. Activate the Material Buttons and add a new material, then change the material type from Surface to Halo. Halos is a special material type for particles; they give each point a unique shading system compared to the Surface shaders. With halos, you can control the size of the particles, their transparency, color, brightness, hardness, textures, flares, and other interesting effects. With just the default values, let’s render out our scene and see what we get. Halo Material   Halo Rendered   Right now, this doesn’t look too pleasing, but it will be once we get the combinations right. Next, let’s try activating Rings under the halo menu, then Lines, Star, and finally a combination of the three. Below are rendered versions of each and their combination. Additional Options for Halo   Halo with Rings   Halo with Lines   Halo with Star   Halo with Rings, Lines, and Star   Just by altering the halo settings alone, we can achieve particle effects like pollen dust as seen in the image below where the particle effect was composited over a photo. Particle Pollen Dust  
Read more
  • 0
  • 0
  • 8290
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 €18.99/month. Cancel anytime
article-image-monitoring-cups-part2
Packt
15 Oct 2009
7 min read
Save for later

Monitoring CUPS- part2

Packt
15 Oct 2009
7 min read
How SNMP Behaves in the CUPS Web Interface In the CUPS web interface under the Administration tab, the option Find New Printers is used to discover printers that support SNMPv1. This will search and list the available network printers. The discovery of printers is based on the directive configuration done in the /etc/cups/snmp.conf file. On the basis of the search list, you can add a printer using the Add This Printer option. The process is very similar to the Add Printer wizard. Overview of Basic Debugging in CUPS-SNMP In the snmp.conf, we started discussion about various debugging levels in CUPS support. If the directive DebugLevel is set to anything other than 0, you will get the output accordingly. The debugging mode can be made active using the following command. As the SNMP backend supports debugging mode, the command for setting up debugging mode changes depending on the shell prompt. The SNMP backend is located at /usr/lib/cups/backend/snmp when using the Bourne, Bash, Z, or Korn shells. The following command will output verbose debugging information into the cupssnmp.log file when using those shells: $CUPS_DEBUG_LEVEL=1 /usr/lib/cups/backend/snmp 2>&1 | tee cupssnmp.log On Mac OS X, the SNMP backend is located /usr/libexec/cups. The following command will be used: $CUPS_DEBUG_LEVEL=1 /usr/libexec/cups/backend/snmp 2>&1 | tee cupssnmp.log If you are using the C or Tcsh shells, you can use the following command. $(setenv CUPS_DEBUG_LEVEL 1; /usr/lib/cups/backend/snmp) |& tee cupssnmp.log An example of the output might look like this: DEBUG: Scanning for devices in "public" via "@LOCAL"... DEBUG: 0.000 Sending 46 bytes to 192.168.0.255... DEBUG: 0.001 Received 50 bytes from 192.168.0.250... DEBUG: community="public" DEBUG: request-id=1213875587 DEBUG: error-status=0 DEBUG: 1.001 Scan complete! The above output shows that doesn't find any printer at the specified DeviceURI. The above shows the output at the basic debugging level; more information can be found if we use level 2 or 3. Overview of mailto.conf The CUPS provides the facility to send notifications through email. It can be done by integrating the local mail server with CUPS. The configuration file is /etc/cups/mailto.conf, and contains several directives and the characteristics and behavior of the local mail server and email notification for CUPS. We normally use each of the following directives in our daily communication done through mail. The Cc Directive The directive Cc (carbon copy) is used to specify an additional recipient for all email notifications. By default, the value directive is not set and the email is sent only to the administrator. The following examples shows that how email IDs can be specified with this directive. Cc kajol@cupsgrp.com Cc Kajol Shah <ks@cupsgrp.com> The From Directive This directive is used to specify the sender's name in the email notifications. By default, the ServerAdmin address specified in the cupsd.conf file is used. The following are some examples that show how the sender's email is specified with this directive: From cupsadmin@cupsgrp.com From Your CUPS Printer <cupsadmin@cupsgrp.com> The Sendmail Directive The directive Sendmail specifies the command to run and deliver an email locally. If there is an SMTPServer directive, then this directive cannot be used. If both directives appear in the mailto.conf file, then only the last directive is used. The following example shows how this directive can be specified. The default value for this directive is /usr/sbin/sendmail. Sendmail /usr/sbin/sendmail Sendmail /usr/lib/sendmail -bm -i The SMTPServer Directive This directive is used to specify an IP address or hostname of an SMTP mail server. As we have seen previously, this directive cannot be used with the Sendmail directive, and if both Sendmail and SMTPServer directives don't appear in the mailto.conf file, then the default Sendmail will be considered. The following are examples of the SMTP server: SMTPServer mail.mailforcups.com SMTPServer 192.168.0.17 The Subject Directive The Subject directive is used if you want to prefix some text to the subject line in each email that CUPS sends out. The following examples show how a prefix can be specified with this directive. By default, no prefix string is added: Subject [CUPS_ALERTS] Subject URGENT CUPS NOTICE Monitoring SNMP Printers As discussed, CUPS supports SNMPv1 for discovering SNMP enabled printers. This Simple Network Management Protocol-SNMP is used for managing networking printers. We can use any network monitoring tools that supports SNMP for monitoring these SNMP-enabled printers. You can check various open-source network monitoring tools at: http://www.openxtra.co.uk/network-management/monitor/open-source/ I would recommend you to use Cacti, which is a frontend to an RRDTool (Round Robin Database Tool) that collects and stores data in a MySQL database. The frontend is completely written in PHP. The advantage of Cacti over other network monitoring tool is that it has built-in SNMP capabilities and like other monitoring tools such as Nagios, it has its internal mechanism to check certain aspects of the infrastructure. It also provides a frontend for maintaining customized scripts, which an administrator normally creates. But the most important factor is that it is much easier to configure than Nagios. RRDTool is a system that stores high performance logging data and displays related time-series graphs. You can get more information about RRDTool from: http://oss.oetiker.ch/rrdtool/ Downloading and Installing Cacti The pre-requisites of Cacti include MySQL database, PHP, RRDTool, net-snmp, and PHP supported web servers such as Apache or IIS. You can get detailed information about the pre-requisites for Cacti installation at: http://www.cacti.net/downloads/docs/html/requirements.html The current stable release of Cacti is 0.8.7b. You can download various versions of Cacti for different platforms from: http://www.cacti.net/download_cacti.php You can get installation information for Cacti and its pre-requisites on the UNIX/Linux platform from: http://www.cacti.net/downloads/docs/html/install_unix.html The following URL will help you install Cacti on the Windows platform: http://www.cacti.net/downloads/docs/html/install_windows.html You can proceed further by clicking on Next. The next screen shows two options for a new install or an upgrade. If you want to do fresh installation, use the option New Install and click on Next. The screen also displays some useful information such as database user, database hostname, database name, and OS that was specified while configuring Cacti. If you want to upgrade the Cacti, follow the instructions mentioned here: http://www.cacti.net/downloads/docs/html/upgrade.html And then select the upgrade from cacti-current-version option and click on Next to proceed further. The following screen appears, which shows the recommended path of the binary files such as RRDTool, PHP, snmpwalk, snmpgetV, snmpbulkwalk, snmpgetnext, and information related to the Cacti log file and versions for net-snmp and RRDTool. If you found any change in the path with your installation, it should be modified first. Otherwise, Cacti may not work properly. Click on Finish to complete the installation procedure. Once the installation is finished and the next screen will ask for authentication. You need to use the username and the password mentioned in your database configuration to log into a Cacti application: You can use default login information to log in for the first time. Once you click on Login, the next screen will force you to change your password. Once the password is changed, you can see the main page of Cacti that contains two major tabs: console and graphs apart from other generalized options. The console tab contains various options related to the template and graphs management, whereas the graphs tab contains related graphs.  
Read more
  • 0
  • 0
  • 8288

article-image-calendars-jquery-13-php-using-jquery-week-calendar-plugin-part-1
Packt
19 Nov 2009
7 min read
Save for later

Calendars in jQuery 1.3 with PHP using jQuery Week Calendar Plugin: Part 1

Packt
19 Nov 2009
7 min read
There are many reasons why you would want to display a calendar. You can use it to display upcoming events, to keep a diary, or to show a timetable. Recently, for example, I combined a calendar with an online store for a client to book meetings and receive payments more intuitively. Google calendar is probably what springs to mind when people think of calendars online. There is a very good plugin called jquery-week-calendar that shows a week with events in a fashion similar to Google's calendar. Its homepage is at http://www.redredred.com.au/projects/jquery-week-calendar/. To get the latest copy of the plugin, go to http://code.google.com/p/jquery-week-calendar/downloads/list and get the highest-numbered file. The examples in this article are done with version 1.2.0. Download the library and extract it so that there is a directory named jquery-weekcalendar-1.2.0 in the root of your demo directory. Displaying the calendar As usual, the HTML for the simplest configuration is very simple. Save this as calendar.html: <html> <head> <script src="../jquery.min.js"></script> <script src="../jquery-ui.min.js"></script> <script src="../jquery-weekcalendar-1.2.0/jquery.weekcalendar.js"> </script> <script src="calendar.js"></script> <link rel="stylesheet" type="text/css" href="../jquery-ui.css" /> <link rel="stylesheet" type="text/css" href="../jquery-weekcalendar-1.2.0/jquery.weekcalendar.css"/> </head> <body> <div id="calendar_wrapper" style="height:500px"></div> </body> </html> We will keep all of our JavaScript in an external file called calendar.js, which will initially contain just this: $(document).ready(function() { $('#calendar_wrapper').weekCalendar({ 'height':function($calendar){ return $('#calendar_wrapper')[0].offsetHeight; } }); }); This is fairly straightforward. The script will apply the widget to the #calendar_wrapper element, and the widget's height will be set to that of the wrapper element. Even with this tiny bit of code, we already have a good-looking calendar, and when you drag your mouse cursor around it, you'll see that events are created as you lift the mouse up: It looks good, but it doesn't do anything yet. The events are temporary, and will vanish as soon as you change the week or reload the page. In order to make them permanent, we need to send details of the events to the server and save them there. Creating an event What we need to do is to have the client save the event on the server when it is created. In this article, we'll use PHP sessions to save the data for the sake of simplicity. Sessions are chunks of data, which are kept on the server side and are related to the cookie or PHPSESSID parameter that the client uses to access that session. We will use sessions in these examples because they do not need as much setup as databases. For your own projects, you should adapt the PHP side in order to connect to a database instead. If you are using this article to create a full application, you will obviously want to use something more permanent than sessions, in which case the PHP code should be adapted such that all references to sessions are replaced with database references instead. This is beyond the scope of this book, but as you are a PHP developer, you probably do this everyday anyway! When the event has been created, we want a modal dialog to appear and ask for more details. In this test case, we'll add a text area for further details, which allows for more data than would appear in the small visible area in the calendar itself. A modal dialog is a "pop up" that appears and blocks all other actions on the page until it has been taken care of. It's useful in cases where the answer to a question must be known before a script can carry on with its work. Now, let's create an event and add it to our calendar. Client-side code In the calendar.js file, add an eventNew event to the weekCalendar call: $(document).ready(function() { $('#calendar_wrapper').weekCalendar({ 'height':function($calendar){ return $('#calendar_wrapper')[0].offsetHeight; }, 'eventNew':function(calEvent, $event) { calendar_new_entry(calEvent,$event); } }); }); When an event is created, the calendar_new_entry function will be called with details of the new event in the calEvent parameter. Now, add the function calendar_new_entry: function calendar_new_entry(calEvent,$event){ var ds=calEvent.start, df=calEvent.end; $('<div id="calendar_new_entry_form" title="New Calendar Entry"> event name<br /> <input value="new event" id="calendar_new_entry_form_title" /> <br /> body text<br /> <textarea style="width:400px;height:200px" id="calendar_new_entry_form_body">event description </textarea> </div>').appendTo($('body')); $("#calendar_new_entry_form").dialog({ bgiframe: true, autoOpen: false, height: 440, width: 450, modal: true, buttons: { 'Save': function() { var $this=$(this); $.getJSON('./calendar.php?action=save&id=0&start=' +ds.getTime()/1000+'&end='+df.getTime()/1000, { 'body':$('#calendar_new_entry_form_body').val(), 'title':$('#calendar_new_entry_form_title').val() }, function(ret){ $this.dialog('close'); $('#calendar_wrapper').weekCalendar('refresh'); $("#calendar_new_entry_form").remove(); } ); }, Cancel: function() { $event.remove(); $(this).dialog('close'); $("#calendar_new_entry_form").remove(); } }, close: function() { $('#calendar').weekCalendar('removeUnsavedEvents'); $("#calendar_new_entry_form").remove(); } }); $("#calendar_new_entry_form").dialog('open'); } What's happening here is that a form is created and added to the body (the second line of the function), then the third line of the function creates a modal window from that form and adds some buttons to it. Our modal dialog should look like this: The Save button, when pressed, calls the server-side file calendar.php with the parameters needed to save the event, including the start and end, and the title and body. When the result returns, the calendar is refreshed with the new event's data included. When any of the buttons are clicked, we close the dialog and remove it from the page completely. Note how we are sending time information to the server (shown highlighted in the code we just saw). JavaScript time functions usually measure in milliseconds, but we want to send it to PHP, which generally measures time in seconds. So, we convert the value on the client so that the PHP can use the received data as it is, without needing to do anything to it. Every little helps! Server-side code On the server side, we want to take the new event and save it. Remember that we're doing it in sessions in this example, but you should feel free to adapt this to any other model that you wish. Create a file called calendar.php and save it with this source in it: <?php session_start(); if(!isset($_SESSION['calendar'])){ $_SESSION['calendar']=array( 'ids'=>0, ); } if(isset($_REQUEST['action'])){ switch($_REQUEST['action']){ case 'save': // { $start_date=(int)$_REQUEST['start']; $data=array( 'title'=>(isset($_REQUEST['title'])?$_REQUEST['title']:''), 'body' =>(isset($_REQUEST['body'])?$_REQUEST['body']:''), 'start'=>date('c',$start_date), 'end' =>date('c',(int)$_REQUEST['end']) ); $id=(int)$_REQUEST['id']; if($id && isset($_SESSION['calendar'][$id])){ $_SESSION['calendar'][$id]=$data; } else{ $id= ++$_SESSION['calendar']['ids']; $_SESSION['calendar'][$id]=$data; } echo 1; exit; // } } } ?> In the server-side code of this project, all the requested actions are handled by a switch statement. This is done for demonstration purposes—whenever we add a new action, we simply add a new switch case. If you are using this for your own purposes, you may wish to rewrite it using functions instead of large switch cases. The date function is used to convert the start and end parameters into ISO 8601 date format. That's the format jquery-week-calendar prefers, so we'll try to keep everything in that format. Visually, nothing appears to happen, but the data is actually being saved. To see what's being saved, create a new file named test.php, and use the var_dump function in it to examine the session data (view it in your browser): <?php session_start(); var_dump($_SESSION); ?> Here's an example from my test machine:
Read more
  • 0
  • 0
  • 8277

article-image-creating-a-3d-printed-kite
Michael Ang
30 Oct 2014
9 min read
Save for later

Polygon Construction - Make a 3D printed kite

Michael Ang
30 Oct 2014
9 min read
3D printers are incredible machines, but let's face it, it takes them a long time to work their magic! Printing small objects takes a relatively short amount of time, but larger objects can take hours and hours to print. Is there a way we can get the speed of printing small objects, while still making something big—even bigger than our printer can make in one piece? This tutorial shows a technique I'm calling "polygon construction", where you 3D print connectors and attach them with rods to make a larger structure. This technique is the basis for my Polygon Construction Kit (Polycon). A Polycon object, with 3D printer for scale I’m going to start simple, showing how even one connector can form the basis of a rather delightful object—a simple flying kite! The kite we're making today is a version of the Eddy diamond kite, originally invented in the 1890s by William Eddy. This classic diamond kite is easy to make, and flies well. We'll design and print the central connector in the kite, and use wooden rods to extend the shape. The total size of the kite is 50 centimeters (about 20 inches) tall and wide, which is bigger than most print beds. We'll design the connector so that it's parametric—we'll be able to change the important sizes of the connector just by changing a few numbers. Because the connector is a small object to print out, and the design is parametric, we'll be able to iterate quickly if we want to make changes. A finished kite The connector we need is a cross that holds two of the "arms" up at an angle. This angle is called the dihedral angle, and is one of the secrets to why the Eddy kite flies well. We'll use the OpenSCAD modeling program to create the connector. OpenSCAD allows you to create solid objects for printing by combining simple shapes such as cylinders and boxes using a basic programming language. It's open source and multi-platform. You can download OpenSCAD from http://openscad.org. Open OpenSCAD. You should have a blank document. Let's set up a few variables to represent the important dimensions in our connector, and make the first part of our connector, which is a cylinder that will be one of the four "arms" of the cross. Go to Design->Compile  to see the result. rod_diameter = 4; // in millimeters wall_thickness = 2; tube_length = 20; angle = 15; // degrees cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); First part of the connector Now let's add the same shape, but translate down. You can see the axis indicator in the lower-left corner of the output window. The blue axis pointing up is the Z-axis, so you want to move down (negative) in the Z-axis. Add this line to your file and recompile (Design->Compile). translate([0,0,-tube_length]) cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); Second part of the main tube Now that we have the long straight part of our connector, let's add the angled arms. We want the angled part of the connector to be 90 degrees from the straight part, and then rotated by our dihedral angle (in this case 15 degrees). In OpenSCAD, rotations can be specified as a rotation around X, Y, and then Z axes. If you look at the axis indicator, you can see that a rotation around the Y-axis of 90 degrees, followed by a rotation around the Z-axis of 15 degrees that will get us to the right place. Here's the code: rotate([0,90,angle]) cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length);    First angled part Let's do the same thing, but for the other side. Instead of rotating by 15 degrees, we'll rotate by 180 degrees and then subtract out the 15 degrees to put the new cylinder on the opposite side. rotate([0,90,180-angle]) cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); Opposite angled part Awesome, we have the shape of our connector! There's only one problem: how do we make the holes for the rods to go in? To do this we'll make the same shape, but a little smaller, and then subtract it out of the shape we already made. OpenSCAD supports Boolean operations on shapes, and in this case the Boolean operation we want is difference. To make the Boolean operation easier, we'll group the different parts of the shape together by putting them into modules. Once we have the parts we want together in a module, we can make a difference of the two modules. Here's the complete new version: rod_diameter = 4; // in millimeters wall_thickness = 2; tube_length = 20; angle = 15; // degrees // Connector as a solid object (no holes) module solid() { cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); translate([0,0,-tube_length]) cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); rotate([0,90,angle]) cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); rotate([0,90,180-angle]) cylinder(r = rod_diameter + wall_thickness * 2, h = tube_length); } // Object representing the space for the rods. module hole_cutout() { cut_overlap = 0.2; // Extra length to make clean cut out of main shape cylinder(r = rod_diameter, h = tube_length + cut_overlap); translate([0,0,-tube_length-cut_overlap]) cylinder(r = rod_diameter, h = tube_length + cut_overlap); rotate([0,90,angle]) cylinder(r = rod_diameter, h = tube_length + cut_overlap); rotate([0,90,180-angle]) cylinder(r = rod_diameter, h = tube_length + cut_overlap); } difference() { solid(); hole_cutout(); } Completed connector We've finished modeling our kite connector! But what if our rod isn't 4mm in diameter? What if it's 1/8"? Since we've written a program to describe our kite connector, making the change is easy. We can change the parameters at the beginning of the file to change the shape of the connector. There are 25.4 millimeters in an inch, and OpenSCAD can do the math for us to convert from inches to millimeters. Let's change the rod diameter to 1/8" and also change the dihedral angle, so there's more of a visible change. Change the parameters at the top of the file and recompile (Design->Compile). rod_diameter = 1/8 * 25.4; // inches to millimeters wall_thickness = 2; tube_length = 20; angle = 20; // degrees Different angle and rod diameter Now you start to see the power of using a parametric model—making a new connector can be as simple as changing a few numbers and recompiling the design. To get the model ready for printing, change the rod diameter to the size of the rod you actually have, and change the angle back to 15 degrees. Now go to Design->Compile and Render so that the connector is fully rendered inside OpenSCAD. Go to File->Export->Export as STL and save the file. Open the .stl file in the software for your 3D printer. I have a Prusa i3 Berlin RepRap printer and use Cura as my printer software, but almost any printer/software combination should work. You may want to rotate the part so that it doesn't need as much support under the overhanging arms, but be aware that the orientation of the layers will affect the final strength (if the tube breaks, it's almost always from the layers splitting apart). It's worth experimenting with changing the orientation of the part to increase its strength. Orienting the layers slightly at an angle to the length of the tube seems to give the best strength. Cura default part orientation Part reoriented for printing, showing layers Print your connector, and see if it fits on your rods. You may need to adjust the size a little to get a tight fit. Since the model is parametric, adjusting the size of the connector should just take a few minutes! To get the most strength in your print you can make multiple prints of the connector with different settings (temperature, wall thickness, and so on) and see how much force it takes to break them. This is a good technique in general for getting strong prints. A printed connector Kite dimensions Now that we have the connector printed, we need to finish off the rest of the kite. You can see full instructions on making an Eddy kite, but here's the short version. I've built this kite by taking a 1m long 4mm diameter wooden rod from a kite store and cutting it into one 50cm piece and two 25cm pieces. The center connector goes 10cm from the top of the long rod. For the "sail", paper does fine (cut to fit the frame, making sure that the sail is symmetrical), and you can just tape the paper to the rods. Tie a piece of string about 80cm long between the center connector and a point 4cm from the tail to make a bridle. To find the right place to tie on the long flying line, take the kite out on a breezy day and hold by the bridle, moving your hand up and down until you find a spot where the kite doesn't try to fly up too much, or fall back down. That's the spot to tie on your long flying line. If the kite is unstable while flying, you can add a long tail to the kite, but I haven't found it to be necessary (though it adds to the classic look). Assembled kite Back side of kite, showing printed connector Being able to print your own kite parts makes it easy to experiment. If you want to try a different dihedral angle, just print a new center connector. It's quite a sight to see your kite flying high up in the sky, held together by a part you printed yourself. You can download a slightly different version of this code that includes additional bracing between the angled arms at http://www.thingiverse.com/thing:415345. For an idea of what's possible using the "polygon construction" technique, have a look at my Polygon Construction Kit for some examples of larger structures with multiple connectors. Happy flying! Sky high About the Author Michael Ang is a Berlin-based artist and engineer working at the intersection of art, engineering, and the natural world. His latest project is the Polygon Construction Kit, a toolkit for bridging the virtual and physical worlds by translating simple 3D models into physical structures.
Read more
  • 0
  • 0
  • 8270

article-image-pentaho-data-integration-4-working-complex-data-flows
Packt
27 Jun 2011
7 min read
Save for later

Pentaho Data Integration 4: working with complex data flows

Packt
27 Jun 2011
7 min read
Joining two or more streams based on given conditions There are occasions where you will need to join two datasets. If you are working with databases, you could use SQL statements to perform this task, but for other kinds of input (XML, text, Excel), you will need another solution. Kettle provides the Merge Join step to join data coming from any kind of source. Let's assume that you are building a house and want to track and manage the costs of building it. Before starting, you prepared an Excel file with the estimated costs for the different parts of your house. Now, you are given a weekly file with the progress and the real costs. So, you want to compare both to see the progress. Getting ready To run this recipe, you will need two Excel files, one for the budget and another with the real costs. The budget.xls has the estimated starting date, estimated end date, and cost for the planned tasks. The costs.xls has the real starting date, end date, and cost for tasks that have already started. You can download the sample files from here. How to do it... Carry out the following steps: Create a new transformation. Drop two Excel input steps into the canvas. Use one step for reading the budget information (budget.xls file) and the other for reading the costs information (costs.xls file). Under the Fields tab of these steps, click on the Get fields from header row... button in order to populate the grid automatically. Apply the format dd/MM/yyyy to the fields of type Date and $0.00 to the fields with costs. Add a Merge Join step from the Join category, and create a hop from each Excel input step toward this step. The following diagram depicts what you have so far: Configure the Merge Join step, as shown in the following screenshot: If you do a preview on this step, you will obtain the result of the two Excel files merged. In order to have the columns more organized, add a Select values step from the Transform category. In this new step, select the fields in this order: task, starting date (est.), starting date, end date (est.), end date, cost (est.), cost. Doing a preview on the last step, you will obtain the merged data with the columns of both Excel files interspersed, as shown in the following screenshot: How it works... In the example, you saw how to use the Merge Join step to join data coming from two Excel files. You can use this step to join any other kind of input. In the Merge Join step, you set the name of the incoming steps, and the fields to use as the keys for joining them. In the recipe, you joined the streams by just a single field: the task field. The rows are expected to be sorted in an ascending manner on the specified key fields. There's more... In the example, you set the Join Type to LEFT OUTER JOIN. Let's see explanations of the possible join options: Interspersing new rows between existent rows In most Kettle datasets, all rows share a common meaning; they represent the same kind of entity, for example: In a dataset with sold items, each row has data about one item In a dataset with the mean temperature for a range of days in five different regions, each row has the mean temperature for a different day in one of those regions In a dataset with a list of people ordered by age range (0-10, 11-20, 20-40, and so on), each row has data about one person Sometimes, there is a need of interspersing new rows between your current rows. Taking the previous examples, imagine the following situations: In the sold items dataset, every 10 items, you have to insert a row with the running quantity of items and running sold price from the first line until that line. In the temperature's dataset, you have to order the data by region and the last row for each region has to have the average temperature for that region. In the people's dataset, for each age range, you have to insert a header row just before the rows of people in that range. In general, the rows you need to intersperse can have fixed data, subtotals of the numbers in previous rows, header to the rows coming next, and so on. What they have in common is that they have a different structure or meaning compared to the rows in your dataset. Interspersing these rows is not a complicated task, but is a tricky one. In this recipe, you will learn how to do it. Suppose that you have to create a list of products by category. For each category, you have to insert a header row with the category description and the number of products inside that category. The final result should be as follows: Getting ready This recipe uses an outdoor database with the structure shown in Appendix, Data Structures (Download here). As source, you can use a database like this or any other source, for example a text file with the same structure. How to do it... Carry out the following steps: Create a transformation, drag into the canvas a Table Input step, select the connection to the outdoor database, or create it if it doesn't exist. Then enter the following statement: SELECT category , desc_product FROM products p ,categories c WHERE p.id_category = c.id_category ORDER by category Do a preview of this step. You already have the product list! Now, you have to create and intersperse the header rows. In order to create the headers, do the following: From the Statistics category, add a Group by step and fill in the grids, as shown in the following screenshot: From the Scripting category, add a User Defined Java Expression step, and use it to add two fields: The first will be a String named desc_product, with value ("Category: " + category).toUpperCase(). The second will be an Integer field named order with value 1. Use a Select values step to reorder the fields as category, desc_product, qty_product, and order. Do a preview on this step; you should see the following result: Those are the headers. The next step is mixing all the rows in the proper order. Drag an Add constants step into the canvas and a Sort rows step. Link them to the other steps as shown: Use the Add constants to add two Integer fields: qty_prod and order. As Value, leave the first field empty, and type 2 for the second field. Use the Sort rows step for sorting by category, order, and desc_product. Select the last step and do a preview. You should see the rows exactly as shown in the introduction. How it works... When you have to intersperse rows between existing rows, there are just four main tasks to do, as follows: Create a secondary stream that will be used for creating new rows. In this case, the rows with the headers of the categories. In each stream, add a field that will help you intersperse rows in the proper order. In this case, the key field was named order. Before joining the two streams, add, remove, and reorder the fields in each stream to make sure that the output fields in each stream have the same metadata. Join the streams and sort by the fields that you consider appropriate, including the field created earlier. In this case, you sorted by category, inside each category by the field named order and finally by the products description. Note that in this case, you created a single secondary stream. You could create more if needed, for example, if you need a header and footer for each category.
Read more
  • 0
  • 0
  • 8270
article-image-introduction-oracle-service-bus-oracle-service-registry
Packt
15 Sep 2010
6 min read
Save for later

Introduction to Oracle Service Bus & Oracle Service Registry

Packt
15 Sep 2010
6 min read
(For more resources on BPEL, SOA and Oracle see here.) If we want our SOA architecture to be highly fexible and agile, we have to ensure loose coupling between different components. As service interfaces and endpoint addresses change over time, we have to remove all point-to-point connections between service providers and service consumers by introducing an intermediate layer—Enterprise Service Bus (ESB). ESB is a key component of every mature SOA architecture and provides several important functionalities, such as message routing, transformation between message types and protocols, the use of adapters, and so on. Another important requirement for providing fexibility is service-reuse. This can be achieved through the use of UDDI (Universal Description, Discovery and Integration) compliant service registry, which enables us to publish and discover services. Using service registry we can also implement dynamic endpoint lookup, so that service consumers retrieve actual service endpoint address from registry in runtime. Oracle Service Bus architecture and features ESB provides means to manage connections, control the communication between services, supervise the services and their SLAs (Service Level Agreements), and much more. The importance of the ESB often becomes visible after the frst development iteration of SOA composite application has taken place. For example, when a service requires a change in its interface or payload, the ESB can provide the transformation capabilities to mask the differences to existing service consumers. ESB can also mask the location of services, making it easy to migrate services to different servers. There are plenty other scenarios, where ESB is important. In this article, we will look at the Oracle Service Bus (OSB). OSB presents a communication backbone for transport and routing of messages across an enterprise. It is designed for high-throughput and reliable message delivery to a variety of service providers and consumers. It supports XML as a native data type, however, other data types are also supported. As an intermediary, it processes incoming service request messages, executes the routing logic and transforms these messages if needed. It can also transform between different transport protocols (HTTP, JMS, File, FTP, and so on.). Service response messages follow the inverse path. The message processing is specifed in the message fow defnition of a proxy service. OSB provides some functionalities that are similar to the functionalities of the Mediator component within the SOA Composite, such as routing, validation, fltering, and transformation. The major difference is that the Mediator is a mediation component that is meant to work within the SOA Composite and is deployed within a SOA composition application. The OSB on the other hand is a standalone service bus. In addition to providing the communication backbone for all SOA (and non-SOA) applications, OSB mission is to shield application developers from changes in the service endpoints and to prevent those systems from being overloaded with requests from upstream applications. In addition to the Oracle Service Bus, we can also use the Mediator service component, which also provides mediation capabilities, but only within SOA composite applications. On the other hand, OSB is used for inter-application communication. The following figure shows the functional architecture of Oracle Service Bus (OSB). We can see that OSB can be categorized into four functional layers: Messaging layer: Provides support to reliably connect any service by leveraging standards, such as HTTP/SOAP, WS-I, WS-Security, WS-Policy, WS-Addressing, SOAP v1.1, SOAP v1.2, EJB, RMI, and so on. It even supports the creation of custom transports using the Custom Transport Software Development Kit (SDK). Security layer: Provides security at all levels: Transport Security (SSL), Message Security (WS-Policy, WS-Security, and so on), Console Security (SSO and role based access) and Policy (leverages WS-Security and WS-Policy). Composition layer: Provides confguration-driven composition environment. We can use either the Eclipse plug-in environment or web-based Oracle Service Bus Console. We can model message fows that contain content-based routing, message validation, and exception handling. We can also use message transformations (XSLT, XQuery), service callouts (POJO, Web Services), and a test browser. Automatic synchronization with UDDI registries is also supported. Management layer: Provides a unifed dashboard for service monitoring and management. We can defne and monitor Service Level Agreements (SLAs), alerts on operation metrics and message pipelines, and view reports. Proxy services and business services OSB uses a specifc terminology of proxy and business services. The objective of OSB is to route message between business services and service consumers through proxy services. Proxy services are generic intermediary web services that implement the mediation logic and are hosted locally on OSB. Proxy services route messages to business services and are exposed to service consumers. A proxy service is confgured by specifying its interface, type of transport, and its associated message processing logic. Message fow defnitions are used to defne the proxy service message handling capabilities. Business services describe the enterprise services that exchange messages with business processes and which we want to virtualize using the OSB. The defnition of a business service is similar to that of a proxy service, however, the business services does not have a message fow defnition. Message fow modeling Message fows are used to defne message processing logic of proxy services. Message fow modeling includes defning a sequence of activities, where activities are individual actions, such as transformations, reporting, publishing and exception management. Message fow modeling can be performed using a visual development environment (Eclipse or Oracle Service Bus Console). Message fow defnitions are defned using components, such as pipelines, branch nodes and route nodes, as shown in the following fgure: A pipeline is a sequence of stages, representing a one-way processing path. It is used to specify message fow for service requests and responses. If a service defnes more operations, a pipeline might optionally branch into operational pipelines. There are three types of pipelines: Request pipelines are used to specify the request path of the message flow Response pipelines are used to specify the response path of a message flow Error pipelines are used as error handlers. Request and response pipelines are paired together as pipeline pairs. Branch nodes are used as exclusive switches, where the processing can follow one of the branches. A variable in the message context is used as a lookup variable to determine which branch to follow. Route nodes are used to communicate with another service (in most cases a business service). They cannot have any descendants in the message fow. When the route node sends the request message, the request processing is fnished. On the other side, when it receives a response message, the response processing begins. Each pipeline is a sequence of stages that contain user-defned message processing actions. We can choose between a variety of supported actions, such as Publish, Service Callout, For Each, If... Then..., Raise Error, Reply, Resume, Skip, Delete, Insert, Replace, Validate, Alert, Log, Report, and more. Later in this article, we will show you how to use a pipeline on the Travel Approval process. However, let us frst look at the Oracle Service Registry, which we will use together with the OSB.
Read more
  • 0
  • 0
  • 8269

article-image-lets-build-angularjs-and-bootstrap
Packt
03 Jun 2015
14 min read
Save for later

Let's Build with AngularJS and Bootstrap

Packt
03 Jun 2015
14 min read
In this article by Stephen Radford, author of the book Learning Web Development with Bootstrap and AngularJS, we're going to use Bootstrap and AngularJS. We'll look at building a maintainable code base as well as exploring the full potential of both frameworks. (For more resources related to this topic, see here.) Working with directives Something we've been using already without knowing it is what Angular calls directives. These are essentially powerful functions that can be called from an attribute or even its own element, and Angular is full of them. Whether we want to loop data, handle clicks, or submit forms, Angular will speed everything up for us. We first used a directive to initialize Angular on the page using ng-app, and all of the directives we're going to look at in this article are used in the same way—by adding an attribute to an element. Before we take a look at some more of the built-in directives, we need to quickly make a controller. Create a new file and call it controller.js. Save this to your js directory within your project and open it up in your editor. Controllers are just standard JS constructor functions that we can inject Angular's services such as $scope into. These functions are instantiated when Angular detects the ng-controller attribute. As such, we can have multiple instances of the same controller within our application, allowing us to reuse a lot of code. This familiar function declaration is all we need for our controller. function AppCtrl(){} To let the framework know this is the controller we want to use, we need to include this on the page after Angular is loaded and also attach the ng-controller directive to our opening <html> tag: <html ng-controller="AppCtl">…<script type="text/javascript"src="assets/js/controller.js"></script> ng-click and ng-mouseover One of the most basic things you'll have ever done with JavaScript is listened for a click event. This could have been using the onclick attribute on an element, using jQuery, or even with an event listener. In Angular, we use a directive. To demonstrate this, we'll create a button that will launch an alert box—simple stuff. First, let's add the button to our content area we created earlier: <div class="col-sm-8"><button>Click Me</button></div> If you open this up in your browser, you'll see a standard HTML button created—no surprises there. Before we attach the directive to this element, we need to create a handler in our controller. This is just a function within our controller that is attached to the scope. It's very important we attach our function to the scope or we won't be able to access it from our view at all: function AppCtl($scope){$scope.clickHandler = function(){window.alert('Clicked!');};} As we already know, we can have multiple scopes on a page and these are just objects that Angular allows the view and the controller to have access to. In order for the controller to have access, we've injected the $scope service into our controller. This service provides us with the scope Angular creates on the element we added the ng-controller attribute to. Angular relies heavily on dependency injection, which you may or may not be familiar with. As we've seen, Angular is split into modules and services. Each of these modules and services depend upon one another and dependency injection provides referential transparency. When unit testing, we can also mock objects that will be injected to confirm our test results. DI allows us to tell Angular what services our controller depends upon, and the framework will resolve these for us. An in-depth explanation of AngularJS' dependency injection can be found in the official documentation at https://docs.angularjs.org/guide/di. Okay, so our handler is set up; now we just need to add our directive to the button. Just like before, we need to add it as an additional attribute. This time, we're going to pass through the name of the function we're looking to execute, which in this case is clickHandler. Angular will evaluate anything we put within our directive as an AngularJS expression, so we need to be sure to include two parentheses indicating that this is a function we're calling: <button ng-click="clickHandler()">Click Me</button> If you load this up in your browser, you'll be presented with an alert box when you click the button. You'll also notice that we don't need to include the $scope variable when calling the function in our view. Functions and variables that can be accessed from the view live within the current scope or any ancestor scope.   Should we wish to display our alert box on hover instead of click, it's just a case of changing the name of the directive to ng-mouseover, as they both function in the exact same way. ng-init The ng-init directive is designed to evaluate an expression on the current scope and can be used on its own or in conjunction with other directives. It's executed at a higher priority than other directives to ensure the expression is evaluated in time. Here's a basic example of ng-init in action: <div ng-init="test = 'Hello, World'"></div>{{test}} This will display Hello, World onscreen when the application is loaded in your browser. Above, we've set the value of the test model and then used the double curly-brace syntax to display it. ng-show and ng-hide There will be times when you'll need to control whether an element is displayed programmatically. Both ng-show and ng-hide can be controlled by the value returned from a function or a model. We can extend upon our clickHandler function we created to demonstrate the ng-click directive to toggle the visibility of our element. We'll do this by creating a new model and toggling the value between true or false. First of all, let's create the element we're going to be showing or hiding. Pop this below your button: <div ng-hide="isHidden">Click the button above to toggle.</div> The value within the ng-hide attribute is our model. Because this is within our scope, we can easily modify it within our controller: $scope.clickHandler = function(){$scope.isHidden = !$scope.isHidden;}; Here we're just reversing the value of our model, which in turn toggles the visibility of our <div>. If you open up your browser, you'll notice that the element isn't hidden by default. There are a few ways we could tackle this. Firstly, we could set the value of $scope.hidden to true within our controller. We could also set the value of hidden to true using the ng-init directive. Alternatively, we could switch to the ng-show directive, which functions in reverse to ng-hide and will only make an element visible if a model's value is set to true. Ensure Angular is loaded within your header or ng-hide and ng-show won't function correctly. This is because Angular uses its own classes to hide elements and these need to be loaded on page render. ng-if Angular also includes an ng-if directive that works in a similar fashion to ng-show and ng-hide. However, ng-if actually removes the element from the DOM whereas ng-show and ng-hide just toggles the elements' visibility. Let's take a quick look at how we'd use ng-if with the preceding code: <div ng-if="isHidden">Click the button above to toggle.</div> If we wanted to reverse the statement's meaning, we'd simply just need to add an exclamation point before our expression: <div ng-if="!isHidden">Click the button above to toggle.</div> ng-repeat Something you'll come across very quickly when building a web app is the need to render an array of items. For example, in our contacts manager, this would be a list of contacts, but it could be anything. Angular allows us to do this with the ng-repeat directive. Here's an example of some data we may come across. It's array of objects with multiple properties within it. To display the data, we're going to need to be able to access each of the properties. Thankfully, ng-repeat allows us to do just that. Here's our controller with an array of contact objects assigned to the contacts model: function AppCtrl($scope){$scope.contacts = [{name: 'John Doe',phone: '01234567890',email: 'john@example.com'},{name: 'Karan Bromwich',phone: '09876543210',email: 'karan@email.com'}];} We have just a couple of contacts here, but as you can imagine, this could be hundreds of contacts served from an API that just wouldn't be feasible to work with without ng-repeat. First, add an array of contacts to your controller and assign it to $scope.contacts. Next, open up your index.html file and create a <ul> tag. We're going to be repeating a list item within this unordered list so this is the element we need to add our directive to: <ul><li ng-repeat="contact in contacts"></li></ul> If you're familiar with how loops work in PHP or Ruby, then you'll feel right at home here. We create a variable that we can access within the current element being looped. The variable after the in keyword references the model we created on $scope within our controller. This now gives us the ability to access any of the properties set on that object with each iteration or item repeated gaining a new scope. We can display these on the page using Angular's double curly-brace syntax. <ul><li ng-repeat="contact in contacts">{{contact.name}}</li></ul> You'll notice that this outputs the name within our list item as expected, and we can easily access any property on our contact object by referencing it using the standard dot syntax. ng-class Often there are times where you'll want to change or add a class to an element programmatically. We can use the ng-class directive to achieve this. It will let us define a class to add or remove based on the value of a model. There are a couple of ways we can utilize ng-class. In its most simple form, Angular will apply the value of the model as a CSS class to the element: <div ng-class="exampleClass"></div> Should the model referenced be undefined or false, Angular won't apply a class. This is great for single classes, but what if you want a little more control or want to apply multiple classes to a single element? Try this: <div ng-class="{className: model, class2: model2}"></div> Here, the expression is a little different. We've got a map of class names with the model we wish to check against. If the model returns true, then the class will be added to the element. Let's take a look at this in action. We'll use checkboxes with the ng-model attribute, to apply some classes to a paragraph: <p ng-class="{'text-center': center, 'text-danger': error}">Lorem ipsum dolor sit amet</p> I've added two Bootstrap classes: text-center and text-danger. These observe a couple of models, which we can quickly change with some checkboxes: The single quotations around the class names within the expression are only required when using hyphens, or an error will be thrown by Angular. <label><input type="checkbox" ng-model="center"> textcenter</label><label><input type="checkbox" ng-model="error"> textdanger</label> When these checkboxes are checked, the relevant classes will be applied to our element. ng-style In a similar way to ng-class, this directive is designed to allow us to dynamically style an element with Angular. To demonstrate this, we'll create a third checkbox that will apply some additional styles to our paragraph element. The ng-style directive uses a standard JavaScript object, with the keys being the property we wish to change (for example, color and background). This can be applied from a model or a value returned from a function. Let's take a look at hooking it up to a function that will check a model. We can then add this to our checkbox to turn the styles off and on. First, open up your controller.js file and create a new function attached to the scope. I'm calling mine styleDemo: $scope.styleDemo = function(){if(!$scope.styler){return;}return {background: 'red',fontWeight: 'bold'};}; Inside the function, we need to check the value of a model; in this example, it's called styler. If it's false, we don't need to return anything, otherwise we're returning an object with our CSS properties. You'll notice that we used fontWeight rather than font-weight in our returned object. Either is fine, and Angular will automatically switch the CamelCase over to the correct CSS property. Just remember than when using hyphens in JavaScript object keys, you'll need to wrap them in quotation marks. This model is going to be attached to a checkbox, just like we did with ng-class: <label><input type="checkbox" ng-model="styler"> ng-style</label> The last thing we need to do is add the ng-style directive to our paragraph element: <p .. ng-style="styleDemo()">Lorem ipsum dolor sit amet</p> Angular is clever enough to recall this function every time the scope changes. This means that as soon as our model's value changes from false to true, our styles will be applied and vice versa. ng-cloak The final directive we're going to look at is ng-cloak. When using Angular's templates within our HTML page, the double curly braces are temporarily displayed before AngularJS has finished loading and compiling everything on our page. To get around this, we need to temporarily hide our template before it's finished rendering. Angular allows us to do this with the ng-cloak directive. This sets an additional style on our element whilst it's being loaded: display: none !important;. To ensure there's no flashing while content is being loaded, it's important that Angular is loaded in the head section of our HTML page. Summary We've covered a lot in this article, let's recap it all. Bootstrap allowed us to quickly create a responsive navigation. We needed to include the JavaScript file included with our Bootstrap download to enable the toggle on the mobile navigation. We also looked at the powerful responsive grid system included with Bootstrap and created a simple two-column layout. While we were doing this, we learnt about the four different column class prefixes as well as nesting our grid. To adapt our layout, we discovered some of the helper classes included with the framework to allow us to float, center, and hide elements. In this article, we saw in detail Angular's built-in directives: functions Angular allows us to use from within our view. Before we could look at them, we needed to create a controller, which is just a function that we can pass Angular's services into using dependency injection. Directives such as ng-click and ng-mouseover are essentially just new ways of handling events that you will have no doubt done using either jQuery or vanilla JavaScript. However, directives such as ng-repeat will probably be a completely new way of working. It brings some logic directly within our view to loop through data and display it on the page. We also looked at directives that observe models on our scope and perform different actions based on their values. Directives like ng-show and ng-hide will show or hide an element based on a model's value. We also saw this in action in ng-class, which allowed us to add some classes to our elements based on our models' values. Resources for Article: Further resources on this subject: AngularJS Performance [Article] AngularJS Web Application Development Cookbook [Article] Role of AngularJS [Article]
Read more
  • 0
  • 0
  • 8267

article-image-integrating-twitter-and-youtube-mediawiki
Packt
23 Oct 2009
5 min read
Save for later

Integrating Twitter and YouTube with MediaWiki

Packt
23 Oct 2009
5 min read
Twitter in MediaWiki Twitter (http://www.twitter.com) is a micro-blogging service that allows users to convey the world (or at least the small portion of it on Twitter) what they are doing, in messages of 140 characters or less. It is possible to embed these messages in external websites, which is what we will be doing for JazzMeet. We can use the updates to inform our wiki's visitors of the latest JazzMeet being held across the world, and they can send a response to the JazzMeet Twitter account. Shorter Links Because Twitter only allows posts of up to 140 characters, many Twitter usersmake use of URL-shortening services such as Tiny URL (http://tinyurl.com), and notlong (http://notlong.com) to turn long web addresses into short, more manageable URLs. Tiny URL assigns a random URL such as http://tinyurl.com/3ut9p4, while notlong allows you to pick a free sub-domain to redirect to your chosen address, such as http://asgkasdgadg.notlong.com. Twitter automatically shortens web addresses in your posts. Creating a Twitter Account Creating a Twitter account is quite easy. Just fill in the username, password, and email address fields, and submit the registration form, once you have read and accepted the terms and conditions. If your chosen username is free, your account is created instantly. Once your account has been created, you can change the settings such as your display name and your profile's background image, to help blur the distinction between your website and your Twitter profile. Colors can be specified as "hex" values under the Design tab of your Twitter account's settings section. The following color codes change the link colors to our JazzMeet's palette of browns and reds: As you can see in the screenshot, JazzMeet's Twitter profile now looks a little more like the JazzMeet wiki. By doing this, the visitors catching up with JazzMeet's events on Twitter will not be confused by a sudden change in color scheme:   Embedding Twitter Feeds in MediaWiki Twitter provides a few ways to embed your latest posts in to your own website(s); simply log in and go to http://www.twitter.com/badges. Flash: With this option you can show just your posts, or your posts and your friends' most recent posts on Twitter. HTML and JavaScript: You can configure the code to show between 1 and 20 of your most recent Twitter posts. As JazzMeet isn't really the sort of wiki the visitors would expect to find on Flash, we will be using the HTML and JavaScript version. You are provided with the necessary code to embed in your website or wiki. We will add it to the JazzMeet skin template, as we want it to be displayed on every page of our wiki, just beneath our sponsor links. Refer to the following code: <div id="twitter_div"><h2 class="twitter-title">Twitter Updates</h2><ul id="twitter_update_list"></ul></div><script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script><script type="text/javascript" src="http://twitter.com/statuses/user_timeline/jazzmeet.json?callback=twitterCallback2&count=5"></script> The JavaScript given at the bottom of the code can be moved just above the </body> tag of your wiki's skin template. This will help your wiki to load other important elements of your wiki before the Twitter status. You will need to replace "jazzmeet" in the code with your own Twitter username, otherwise you will receive JazzMeet's Twitter updates, and not your own. It is important to leave the unordered list of ID twitter_update_list as it is, as this is the element the JavaScript code looks for to insert a list item containing each of your twitter messages in the page. Styling Twitter's HTML We need to style the Twitter HTML by adding some CSS to change the colors and style of the Twitter status code: #twitter_div {background: #FFF;border: 3px #BEB798 solid;color: #BEB798;margin: 0;padding: 5px;width: 165px;}#twitter_div a {color: #8D1425 !important;}ul#twitter_update_list {list-style-type: none;margin: 0;padding: 0;}#twitter_update_list li {color: #38230C;display: block;}h2.twitter-title {color: #BEB798;font-size: 100%;} There are only a few CSS IDs and classes that need to be taken care of. They are as follows: #twitter_div is the element that contains the Twitter feeds. #twitter_update_list is the ID applied to the unordered list. Styling this affects how your Twitter feeds are displayed. .twitter-title is the class applied to the Twitter feed's heading (which you can remove, if necessary). Our wiki's skin for JazzMeet now has JazzMeet's Twitter feed embedded in the righthand column, allowing visitors to keep up-to-date with the latest JazzMeet news. Inserting Twitter as Page Content Media Wiki does not allow JavaScript to be embedded in a page via the "edit" function, so you won't be able to insert a Twitter status feed directly in a page unless it is in the template itself. Even if you inserted the relevant JavaScript links into your MediaWiki skin template, they are relevant only for one Twitter profile ("jazzmeet", in our case).  
Read more
  • 0
  • 0
  • 8266
article-image-application-development-workflow
Packt
08 Sep 2015
15 min read
Save for later

Application Development Workflow

Packt
08 Sep 2015
15 min read
 In this article by Ivan Turkovic, author of the book PhoneGap Essentials, you will learn some of the basics on how to work with the PhoneGap application development and how to start building the application. We will go over some useful steps and tips to get the most out of your PhoneGap application. In this article, you will learn the following topics: An introduction to a development workflow Best practices Testing (For more resources related to this topic, see here.) An introduction to a development workflow PhoneGap solves a great problem of developing mobile applications for multiple platforms at the same time, but still it is pretty much open about how you want to approach the creation of an application. You do not have any predefined frameworks that come out of-the-box by default. It just allows you to use the standard web technologies such as the HTML5, CSS3, and JavaScript languages for hybrid mobile application development. The applications are executed in wrappers that are custom-built to work on every platform and the underlying web view behaves in the same way on all the platforms. For accessing device APIs, it relies on the standard API bindings to access every device's sensors or the other features. The developers who start using PhoneGap usually come from different backgrounds, as shown in the following list: Mobile developers who want to expand the functionality of their application on other platforms but do not want to learn a new language for each platform Web developers who want to port their existing desktop web application to a mobile application; if they are using a responsive design, it is quite simple to do this Experienced mobile developers who want to use both the native and web components in their application, so that the web components can communicate with the internal native application code as well The PhoneGap project itself is pretty simple. By default, it can open an index.html page and load the initial CSS file, JavaScript, and other resources needed to run it. Besides the user's resources, it needs to refer the cordova.js file, which provides the API bindings for all the plugins. From here onwards, you can take different steps but usually the process falls in two main workflows: web development workflow and native platform development. Web project development A web project development workflow can be used when you want to create a PhoneGap application that runs on many mobile operating systems with as little as possible changes to a specific one. So there is a single codebase that is working along with all the different devices. It has become possible with the latest versions since the introduction of the command-line interface (CLI). This automates the tedious work involved in a lot of the functionalities while taking care of each platform, such as building the app, copying the web assets in the correct location for every supported platform, adding platform-specific changes, and finally running build scripts to generate binaries. This process can be automated even more with build system automating tasks such as Gulp or Grunt. You can run these tasks before running PhoneGap commands. This way you can optimize the assets before they are used. Also you can run JSLint automatically for any change or doing automatic builds for every platform that is available. Native platform development A native platform development workflow can be imagined as a focus on building an application for a single platform and the need to change the lower-level platform details. The benefit of using this approach is that it gives you more flexibility and you can mix the native code with a WebView code and impose communication between them. This is appropriate for those functionalities that contain a section of the features that are not hard to reproduce with web views only; for example, a video app where you can do the video editing in the native code and all the social features and interaction can be done with web views. Even if you want to start with this approach, it is better to start the new project as a web project development workflow and then continue to separate the code for your specific needs. One thing to keep in mind is that, to develop with this approach, it is better to develop the application in more advanced IDE environments, which you would usually use for building native applications. Best practices                            The running of hybrid mobile applications requires some sacrifices in terms of performance and functionality; so it is good to go over some useful tips for new PhoneGap developers. Use local assets for the UI As mobile devices are limited by the connection speeds and mobile data plans are not generous with the bandwidth, you need to prepare all the UI components in the application before deploying to the app store. Nobody will want to use an application that takes a few seconds to load the server-rendered UI when the same thing could be done on the client. For example, the Google Fonts or other non-UI assets that are usually loaded from the server for the web applications are good enough as for the development process, but for the production; you need to store all the assets in the application's container and not download them during its run process. You do not want the application to wait while an important part is being loaded. The best advice on the UI that I can give you is to adopt the Single Page Application (SPA) design; it is a client-side application that is run from one request from a web page. Initial loading means taking care of loading all the assets that are required for the application in order to function, and any further updates are done via AJAX (such as loading data). When you use SPA, not only do you minimize the amount of interaction with the server, you also organize your application in a more efficient manner. One of the benefits is that the application doesn't need to wait for every deviceready event for each additional page that it loads from the start. Network access for data As you have seen in the previous section, there are many limitations that mobile applications face with the network connection—from mobile data plans to the network latency. So you do not want it to rely on the crucial elements, unless real-time communication is required for the application. Try to keep the network access only to access crucial data and everything else that is used frequently can be packed into assets. If the received data does not change often, it is advisable to cache it for offline use. There are many ways to achieve this, such as localStorage, sessionStorage, WebSQL, or a file. When loading data, try to load only the data you need at that moment. If you have a comment section, it will make sense if you load all thousand comments; the first twenty comments should be enough to start with. Non-blocking UI When you are loading additional data to show in the application, don't try to pause the application until you receive all the data that you need. You can add some animation or a spinner to show the progress. Do not let the user stare at the same screen when he presses the button. Try to disable the actions once they are in motion in order to prevent sending the same action multiple times. CSS animations As most of the modern mobile platforms now support CSS3 with a more or less consistent feature set, it is better to make the animations and transitions with CSS rather than with the plain JavaScript DOM manipulation, which was done before CSS3. CSS3 is much faster as the browser engine supports the hardware acceleration of CSS animations and is more fluid than the JavaScript animations. CSS3 supports translations and full keyframe animations as well, so you can be really creative in making your application more interactive. Click events You should avoid click events at any cost and use only touch events. They work in the same way as they do in the desktop browser. They take a longer time to process as the mobile browser engine needs to process the touch or touchhold events before firing a click event. This usually takes 300 ms, which is more than enough to give an additional impression of slow responses. So try to start using touchstart or touchend events. There is a solution for this called FastClick.js. It is a simple, easy-to-use library for eliminating the 300 ms delay between a physical tap and the firing of a click event on mobile browsers. Performance The performance that we get on the desktops isn't reflected in mobile devices. Most of the developers assume that the performance doesn't change a lot, especially as most of them test the applications on the latest mobile devices and a vast majority of the users use mobile devices that are 2-3 years old. You have to keep in mind that even the latest mobile devices have a slower CPU, less RAM, and a weaker GPU. Recently, mobile devices are catching up in the sheer numbers of these components but, in reality, they are slower and the maximum performance is limited due to the battery life that prevents it from using the maximum performance for a prolonged time. Optimize the image assets We are not limited any more by the app size that we need to deploy. However, you need to optimize the assets, especially images, as they take a large part of the assets, and make them appropriate for the device. You should prepare images in the right size; do not add the biggest size of the image that you have and force the mobile device to scale the image in HTML. Choosing the right image size is not an easy task if you are developing an application that should support a wide array of screens, especially for Android that has a very fragmented market with different screen sizes. The scaled images might have additional artifacts on the screen and they might not look so crisp. You will be hogging additional memory just for an image that could leave a smaller memory footprint. You should remember that mobile devices still have limited resources and the battery doesn't last forever. If you are going to use PhoneGap Build, you will need to make sure you do not exceed the limit as the service still has a limited size. Offline status As we all know, the network access is slow and limited, but the network coverage is not perfect so it is quite possible that your application will be working in the offline mode even in the usual locations. Bad reception can be caused by being inside a building with thick walls or in the basement. Some weather conditions can affect the reception too. The application should be able to handle this situation and respond to it properly, such as by limiting the parts of the application that require a network connection or caching data and syncing it when you are online once again. This is one of the aspects that developers usually forget to test in the offline mode to see how the app behaves under certain conditions. You should have a plugin available in order to detect the current state and the events when it passes between these two modes. Load only what you need There are a lot of developers that do this, including myself. We need some part of the library or a widget from a framework, which we don't need for anything other than this, and yet we are a bit lazy about loading a specific element and the full framework. This can load an immense amount of resources that we will never need but they will still run in the background. It might also be the root cause of some of the problems as some libraries do not mix well and we can spend hours trying to solve this problem. Transparency You should try to use as little as possible of the elements that have transparent parts as they are quite processor-intensive because you need to update screen on every change behind them. The same things apply to the other visual elements that are processor-intensive such as shadows or gradients. The great thing is that all the major platforms have moved away from flashy graphical elements and started using the flat UI design. JSHint If you use JSHint throughout the development, it will save you a lot of time when developing things in JavaScript. It is a static code analysis tool for checking whether the JavaScript source code complies with the coding rules. It will detect all the common mistakes done with JavaScript, as JavaScript is not a compiled language and you can't see the error until you run the code. At the same time, JSHint can be a very restrictive and demanding tool. Many beginners in JavaScript, PhoneGap, or mobile programming could be overwhelmed with the number of errors or bad practices that JSHint will point out. Testing The testing of applications is an important aspect of build applications, and mobile applications are no exception. With a slight difference for most of the development that doesn't require native device APIs, you can use the platform simulators and see the results. However, if you are using the native device APIs that are not supported through simulators, then you need to have a real device in order to run a test on it. It is not unusual to use desktop browsers resized to mobile device screen resolution to emulate their screen while you are developing the application just to test the UI screens, since it is much faster and easier than building and running the application on a simulator or real device for every small change. There is a great plugin for the Google Chrome browser called Apache Ripple. It can be run without any additional tools. The Apache Ripple simulator runs as a web app in the Google Chrome browser. In Cordova, it can be used to simulate your app on a number of iOS and Android devices and it provides basic support for the core Cordova plugins such as Geolocation and Device Orientation. You can run the application in a real device browser or use the PhoneGap developer app. This simplifies the workflow as you can test the application on your mobile device without the need to re-sign, recompile, or reinstall your application to test the code. The only disadvantage is that with simulators, you cannot access the device APIs that aren't available in the regular web browsers. The PhoneGap developer app allows you to access device APIs as long as you are using one of the supplied APIs. It is good if you remember to always test the application on real devices at least before deploying to the app store. Computers have almost unlimited resources as compared to mobile devices, so the application that runs flawlessly on the computer might fail on mobile devices due to low memory. As simulators are faster than the real device, you might get the impression that it will work on every device equally fast, but it won't—especially with older devices. So, if you have an older device, it is better to test the response on it. Another reason to use the mobile device instead of the simulator is that it is hard to get a good usability experience from clicking on the interface on the computer screen without your fingers interfering and blocking the view on the device. Even though it is rare that you would get some bugs with the plain PhoneGap that was introduced with the new version, it might still happen. If you use the UI framework, it is good if you try it on the different versions of the operating systems as they might not work flawlessly on each of them. Even though hybrid mobile application development has been available for some time, it is still evolving, and as yet there are no default UI frameworks to use. Even the PhoneGap itself is still evolving. As with the UI, the same thing applies to the different plugins. Some of the features might get deprecated or might not be supported, so it is good if you implement alternatives or give feedback to the users about why this will not work. From experience, the average PhoneGap application will use at least ten plugins or different libraries for the final deployment. Every additional plugin or library installed can cause conflicts with another one. Summary In this article, we learned more advanced topics that any PhoneGap developer should get into more detail once he/she has mastered the essential topics. Resources for Article: Further resources on this subject: Building the Middle-Tier[article] Working with the sharing plugin[article] Getting Ready to Launch Your PhoneGap App in the Real World [article]
Read more
  • 0
  • 0
  • 8258

article-image-how-to-stream-and-store-tweets-in-apache-kafka
Fatema Patrawala
22 Dec 2017
8 min read
Save for later

How to stream and store tweets in Apache Kafka

Fatema Patrawala
22 Dec 2017
8 min read
[box type="note" align="" class="" width=""]This article is an excerpt from a book authored by Ankit Jain titled Mastering Apache Storm. This book explores various real-time processing functionalities offered by Apache Storm such as parallelism, data partitioning, and more.[/box] Today, we are going to cover how to stream tweets from Twitter using the twitter streaming API. We are also going to explore how we can store fetched tweets in Kafka for later processing through Storm. Setting up a single node Kafka cluster Following are the steps to set up a single node Kafka cluster:   Download the Kafka 0.9.x binary distribution named kafka_2.10-0.9.0.1.tar.gz from http://apache.claz.org/kafka/0.9.0. or 1/kafka_2.10-0.9.0.1.tgz. Extract the archive to wherever you want to install Kafka with the following command: tar -xvzf kafka_2.10-0.9.0.1.tgz cd kafka_2.10-0.9.0.1   Change the following properties in the $KAFKA_HOME/config/server.properties file: log.dirs=/var/kafka- logszookeeper.connect=zoo1:2181,zoo2:2181,zoo3:2181 Here, zoo1, zoo2, and zoo3 represent the hostnames of the ZooKeeper nodes. The following are the definitions of the important properties in the server.properties file: broker.id: This is a unique integer ID for each of the brokers in a Kafka cluster. port: This is the port number for a Kafka broker. Its default value is 9092. If you want to run multiple brokers on a single machine, give a unique port to each broker. host.name: The hostname to which the broker should bind and advertise itself. log.dirs: The name of this property is a bit unfortunate as it represents not the log directory for Kafka, but the directory where Kafka stores the actual data sent to it. This can take a single directory or a comma-separated list of directories to store data. Kafka throughput can be increased by attaching multiple physical disks to the broker node and specifying multiple data directories, each lying on a different disk. It is not much use specifying multiple directories on the same physical disk, as all the I/O will still be happening on the same disk. num.partitions: This represents the default number of partitions for newly created topics. This property can be overridden when creating new topics. A greater number of partitions results in greater parallelism at the cost of a larger number of files. log.retention.hours: Kafka does not delete messages immediately after consumers consume them. It retains them for the number of hours defined by this property so that in the event of any issues the consumers can replay the messages from Kafka. The default value is 168 hours, which is 1 week. zookeeper.connect: This is the comma-separated list of ZooKeeper nodes in hostname:port form.    Start the Kafka server by running the following command: > ./bin/kafka-server-start.sh config/server.properties [2017-04-23 17:44:36,667] INFO New leader is 0 (kafka.server.ZookeeperLeaderElector$LeaderChangeListener) [2017-04-23 17:44:36,668] INFO Kafka version : 0.9.0.1 (org.apache.kafka.common.utils.AppInfoParser) [2017-04-23 17:44:36,668] INFO Kafka commitId : a7a17cdec9eaa6c5 (org.apache.kafka.common.utils.AppInfoParser) [2017-04-23 17:44:36,670] INFO [Kafka Server 0], started (kafka.server.KafkaServer) If you get something similar to the preceding three lines on your console, then your Kafka broker is up-and-running and we can proceed to test it. Now we will verify that the Kafka broker is set up correctly by sending and receiving some test messages. First, let's create a verification topic for testing by executing the following command: > bin/kafka-topics.sh --zookeeper zoo1:2181 --replication-factor 1 --partition 1 --topic verification-topic --create Created topic "verification-topic".    Now let's verify if the topic creation was successful by listing all the topics: > bin/kafka-topics.sh --zookeeper zoo1:2181 --list verification-topic    The topic is created; let's produce some sample messages for the Kafka cluster. Kafka comes with a command-line producer that we can use to produce messages: > bin/kafka-console-producer.sh --broker-list localhost:9092 -- topic verification-topic    Write the following messages on your console: Message 1 Test Message 2 Message 3 Let's consume these messages by starting a new console consumer on a new console window: > bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic verification-topic --from-beginning Message 1 Test Message 2 Message 3 Now, if we enter any message on the producer console, it will automatically be consumed by this consumer and displayed on the command line. Collecting Tweets We are assuming you already have a twitter account, and that the consumer key and access token are generated for your application. You can refer to: https://bdthemes.com/support/knowledge-base/generate-api-key-consumer-token-acc ess-key-twitter-oauth/ to generate a consumer key and access token. Take the following steps: Create a new maven project with groupId, com.storm advance and artifactId, kafka_producer_twitter. Add the following dependencies to the pom.xml file. We are adding the Kafka and Twitter streaming Maven dependencies to pom.xml to support the Kafka Producer and the streaming tweets from Twitter: <dependencies> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka_2.10</artifactId> <version>0.9.0.1</version> <exclusions> <exclusion> <groupId>com.sun.jdmk</groupId> <artifactId>jmxtools</artifactId> </exclusion> <exclusion> <groupId>com.sun.jmx</groupId> <artifactId>jmxri</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.0-beta9</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> <version>2.0-beta9</version> </dependency> <!-- https://mvnrepository.com/artifact/org.twitter4j/twitter4j-stream --> <dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-stream</artifactId> <version>4.0.6</version> </dependency> </dependencies> 3. Now, we need to create a class, TwitterData, that contains the code to consume/stream data from Twitter and publish it to the Kafka cluster. We are assuming you already have a running Kafka cluster and topic, twitterData, created in the Kafka cluster. for information on the installation of the Kafka cluster and the creation of a Kafka please refer to . The class contains an instance of the twitter4j.conf.ConfigurationBuilder class; we need to set the access token and consumer keys in configuration, as mentioned in the source code.4. The twitter4j.StatusListener class returns the continuous stream of tweets inside the onStatus() method. We are using the Kafka Producer code inside the onStatus() method to publish the tweets in Kafka. The following is the source code for the TwitterData class: public class TwitterData { /** The actual Twitter stream. It's set up to collect raw JSON data */ private TwitterStream twitterStream; static String consumerKeyStr = "r1wFskT3q"; static String consumerSecretStr = "fBbmp71HKbqalpizIwwwkBpKC"; static String accessTokenStr = "298FPfE16frABXMcRIn7aUSSnNneMEPrUuZ"; static String accessTokenSecretStr = "1LMNZZIfrAimpD004QilV1pH3PYTvM"; public void start() { ConfigurationBuilder cb = new ConfigurationBuilder(); cb.setOAuthConsumerKey(consumerKeyStr); cb.setOAuthConsumerSecret(consumerSecretStr); cb.setOAuthAccessToken(accessTokenStr); cb.setOAuthAccessTokenSecret(accessTokenSecretStr); cb.setJSONStoreEnabled(true); cb.setIncludeEntitiesEnabled(true); // instance of TwitterStreamFactory twitterStream = new TwitterStreamFactory(cb.build()).getInstance(); final Producer<String, String> producer = new KafkaProducer<String, String>(getProducerConfig());// topicDetails CreateTopic("127.0.0.1:2181").createTopic("twitterData", 2, 1); /** Twitter listener **/ StatusListener listener = new StatusListener() { public void onStatus(Status status) { ProducerRecord<String, String> data = new ProducerRecord<String, String>("twitterData", DataObjectFactory.getRawJSON(status)); // send the data to kafka producer.send(data); } public void onException(Exception arg0) { System.out.println(arg0); } arg0) {  }; public void onDeletionNotice(StatusDeletionNotice } public void onScrubGeo(long arg0, long arg1) { } public void onStallWarning(StallWarning arg0) { } public void onTrackLimitationNotice(int arg0) { } /** Bind the listener **/ twitterStream.addListener(listener); /** GOGOGO **/ twitterStream.sample(); } private Properties getProducerConfig() { Properties props = new Properties(); // List of kafka borkers. Complete list of brokers is not required as // the producer will auto discover the rest of the brokers. props.put("bootstrap.servers", "localhost:9092"); props.put("batch.size", 1); // new sending // Serializer used for sending data to kafka. Since we are // string, // we are using StringSerializer. props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("producer.type", "sync"); return props; } public static void main(String[] args) throws InterruptedException { new TwitterData().start(); } Use valid Kafka properties before executing the TwitterData. After executing the preceding class, the user will have a real-time stream of Twitter tweets in Kafka. In the next section, we are going to cover how we can use Storm to calculate the sentiments of the collected tweets. To summarize we covered how to install a single node Apache Kafka cluster and how to collect tweet from Twitter to store in a Kafka cluster If you enjoyed this post, check out the book Mastering Apache Storm to know more about different types of real time processing techniques used to create distributed applications.
Read more
  • 0
  • 0
  • 8247
Modal Close icon
Modal Close icon